aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am43
-rw-r--r--src/arch-alpha.c505
-rw-r--r--src/arch-arm.c950
-rw-r--r--src/arch-cris.c412
-rw-r--r--src/arch-i386.c1133
-rw-r--r--src/arch-ia64.c533
-rw-r--r--src/arch-mips.c1444
-rw-r--r--src/arch-ppc.c1191
-rw-r--r--src/arch-ppc64.c900
-rw-r--r--src/arch-s390.c632
-rw-r--r--src/arch-s390x.c658
-rw-r--r--src/arch-sh.c453
-rw-r--r--src/arch-sparc.c645
-rw-r--r--src/arch-sparc64.c849
-rw-r--r--src/arch-x86_64.c643
-rw-r--r--src/cache.c861
-rw-r--r--src/canonicalize.c374
-rw-r--r--src/checksum.c89
-rw-r--r--src/conflict.c832
-rw-r--r--src/crc32.c87
-rw-r--r--src/cxx.c643
-rw-r--r--src/data.c339
-rw-r--r--src/doit.c256
-rw-r--r--src/dso.c2013
-rw-r--r--src/dwarf2.c1388
-rw-r--r--src/dwarf2.h570
-rw-r--r--src/elf.h3562
-rw-r--r--src/exec.c1074
-rw-r--r--src/execle_open.c81
-rw-r--r--src/execstack.c483
-rw-r--r--src/fptr.c465
-rw-r--r--src/fptr.h67
-rw-r--r--src/gather.c1496
-rw-r--r--src/get.c760
-rw-r--r--src/hashtab.c609
-rw-r--r--src/hashtab.h155
-rw-r--r--src/layout.c656
-rw-r--r--src/layout.h35
-rw-r--r--src/main.c570
-rw-r--r--src/makecrc.c63
-rw-r--r--src/md5.c362
-rw-r--r--src/md5.h105
-rw-r--r--src/mdebug.c692
-rw-r--r--src/prelink.c995
-rw-r--r--src/prelink.h632
-rw-r--r--src/prelinktab.h27
-rw-r--r--src/reloc-info.c215
-rw-r--r--src/reloc-info.h35
-rw-r--r--src/reloc.c427
-rw-r--r--src/reloc.h44
-rw-r--r--src/rtld/COPYING339
-rw-r--r--src/rtld/COPYING.LIB502
-rw-r--r--src/rtld/ChangeLog267
-rw-r--r--src/rtld/Makefile.am32
-rw-r--r--src/rtld/README-rtld18
-rw-r--r--src/rtld/dl-hash.h77
-rw-r--r--src/rtld/dl-load.c279
-rw-r--r--src/rtld/dl-lookup.c131
-rw-r--r--src/rtld/dl-lookupX.h896
-rw-r--r--src/rtld/dl-misc.c106
-rw-r--r--src/rtld/dl-object.c57
-rw-r--r--src/rtld/dl-tls.c287
-rw-r--r--src/rtld/dl-version.c369
-rw-r--r--src/rtld/rtld.c1425
-rw-r--r--src/rtld/rtld.h338
-rw-r--r--src/sha.c331
-rw-r--r--src/sha.h69
-rw-r--r--src/space.c767
-rw-r--r--src/space.h39
-rw-r--r--src/stabs.c188
-rw-r--r--src/undo.c713
-rw-r--r--src/undoall.c175
-rw-r--r--src/verify.c458
-rw-r--r--src/wrap-file.c399
74 files changed, 40315 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..7372fc1
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,43 @@
+## Process this file with automake to create Makefile.in
+
+AUTOMAKE_OPTIONS = 1.4 gnu
+
+SUBDIRS = rtld
+
+PKGVERSION = "\"@PKGVERSION@\""
+REPORT_BUGS_TO = "\"@REPORT_BUGS_TO@\""
+
+DEFS = -D_GNU_SOURCE -DHAVE_CONFIG_H -Wall -Wno-pointer-sign
+AM_CFLAGS = -Wall -Wno-pointer-sign
+AM_CPPFLAGS = -DSBINDIR='"@sbindir@"' -DBINDIR='"@bindir@"' \
+ -DEXECSTACK_PROG="\"`echo execstack | sed '$(transform)'`\"" \
+ -DPRELINK_PROG="\"`echo prelink | sed '$(transform)'`\"" \
+ -DPRELINK_RTLD_PROG="\"`echo prelink-rtld | \
+ sed '$(transform)'`\"" \
+ -DEXEEXT='"$(EXEEXT)"' \
+ -DPKGVERSION=$(PKGVERSION) \
+ -DREPORT_BUGS_TO=$(REPORT_BUGS_TO)
+INCLUDES = @GELFINCLUDE@
+
+sbin_PROGRAMS = prelink
+bin_PROGRAMS = execstack
+
+arch_SOURCES = arch-i386.c arch-alpha.c arch-ppc.c arch-ppc64.c \
+ arch-sparc.c arch-sparc64.c arch-x86_64.c arch-mips.c \
+ arch-s390.c arch-s390x.c arch-arm.c arch-sh.c arch-ia64.c
+common_SOURCES = checksum.c data.c dso.c dwarf2.c dwarf2.h fptr.c fptr.h \
+ hashtab.c hashtab.h mdebug.c prelink.h stabs.c crc32.c \
+ wrap-file.c canonicalize.c reloc-info.c reloc-info.h
+prelink_SOURCES = cache.c conflict.c cxx.c doit.c exec.c execle_open.c get.c \
+ gather.c layout.c main.c prelink.c \
+ prelinktab.h reloc.c reloc.h space.c undo.c undoall.c \
+ verify.c md5.c md5.h sha.c sha.h \
+ $(common_SOURCES) $(arch_SOURCES)
+prelink_LDADD = @LIBGELF@ -liberty
+prelink_LDFLAGS =
+
+execstack_SOURCES = execstack.c $(common_SOURCES) $(arch_SOURCES)
+execstack_LDADD = -liberty
+execstack_LDFLAGS =
+
+extra_DIST = makecrc.c
diff --git a/src/arch-alpha.c b/src/arch-alpha.c
new file mode 100644
index 0000000..7802a3e
--- /dev/null
+++ b/src/arch-alpha.c
@@ -0,0 +1,505 @@
+/* Copyright (C) 2001, 2002, 2003, 2004, 2009 Red Hat, Inc.
+ Written by Jakub Jelinek <jakub@redhat.com>, 2001.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include <config.h>
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <locale.h>
+#include <error.h>
+#include <argp.h>
+#include <stdlib.h>
+
+#include "prelink.h"
+
+static int
+alpha_adjust_dyn (DSO *dso, int n, GElf_Dyn *dyn, GElf_Addr start,
+ GElf_Addr adjust)
+{
+ return 0;
+}
+
+static int
+alpha_adjust_rel (DSO *dso, GElf_Rel *rel, GElf_Addr start,
+ GElf_Addr adjust)
+{
+ error (0, 0, "%s: Alpha doesn't support REL relocs", dso->filename);
+ return 1;
+}
+
+static int
+alpha_adjust_rela (DSO *dso, GElf_Rela *rela, GElf_Addr start,
+ GElf_Addr adjust)
+{
+ if (GELF_R_TYPE (rela->r_info) == R_ALPHA_RELATIVE
+ || GELF_R_TYPE (rela->r_info) == R_ALPHA_JMP_SLOT)
+ {
+ GElf_Addr val = read_ule64 (dso, rela->r_offset);
+
+ if (val >= start)
+ {
+ write_le64 (dso, rela->r_offset, val + adjust);
+ if (val == rela->r_addend)
+ rela->r_addend += adjust;
+ }
+ }
+ else if (GELF_R_TYPE (rela->r_info) == R_ALPHA_GLOB_DAT)
+ {
+ GElf_Addr val = read_ule64 (dso, rela->r_offset) - rela->r_addend;
+
+ if (val && val >= start)
+ write_le64 (dso, rela->r_offset, val + adjust + rela->r_addend);
+ }
+ return 0;
+}
+
+static int
+alpha_prelink_rel (struct prelink_info *info, GElf_Rel *rel,
+ GElf_Addr reladdr)
+{
+ error (0, 0, "%s: Alpha doesn't support REL relocs", info->dso->filename);
+ return 1;
+}
+
+static void
+alpha_fixup_plt (DSO *dso, GElf_Rela *rela, GElf_Addr relaaddr,
+ GElf_Addr value)
+{
+ Elf64_Sxword disp;
+ Elf64_Addr plt;
+
+ relaaddr -= dso->info[DT_JMPREL];
+ relaaddr /= sizeof (Elf64_Rela);
+ relaaddr *= 12;
+ plt = dso->info[DT_PLTGOT] + 32 + relaaddr;
+ disp = ((Elf64_Sxword) (value - plt - 12)) / 4;
+ if (disp >= -0x100000 && disp < 0x100000)
+ {
+ int32_t hi, lo;
+
+ hi = value - plt;
+ lo = (int16_t) hi;
+ hi = (hi - lo) >> 16;
+
+ /* ldah $27,hi($27)
+ lda $27,lo($27)
+ br $31,value */
+ write_le32 (dso, plt, 0x277b0000 | (hi & 0xffff));
+ write_le32 (dso, plt + 4, 0x237b0000 | (lo & 0xffff));
+ write_le32 (dso, plt + 8, 0xc3e00000 | (disp & 0x1fffff));
+ }
+ else
+ {
+ int32_t hi, lo;
+
+ hi = rela->r_offset - plt;
+ lo = (int16_t) hi;
+ hi = (hi - lo) >> 16;
+
+ /* ldah $27,hi($27)
+ ldq $27,lo($27)
+ jmp $31,($27) */
+ write_le32 (dso, plt, 0x277b0000 | (hi & 0xffff));
+ write_le32 (dso, plt + 4, 0xa77b0000 | (lo & 0xffff));
+ write_le32 (dso, plt + 8, 0x6bfb0000);
+ }
+}
+
+static int
+alpha_is_indirect_plt (DSO *dso, GElf_Rela *rela, GElf_Addr relaaddr)
+{
+ Elf64_Addr pltaddr;
+ uint32_t plt[3];
+ int32_t hi, lo;
+
+ relaaddr -= dso->info[DT_JMPREL];
+ relaaddr /= sizeof (Elf64_Rela);
+ relaaddr *= 12;
+ pltaddr = dso->info[DT_PLTGOT] + 32 + relaaddr;
+ hi = rela->r_offset - pltaddr;
+ lo = (int16_t) hi;
+ hi = (hi - lo) >> 16;
+ plt[0] = read_ule32 (dso, pltaddr);
+ plt[1] = read_ule32 (dso, pltaddr + 4);
+ plt[2] = read_ule32 (dso, pltaddr + 8);
+ if (plt[0] == (0x277b0000 | (hi & 0xffff))
+ && plt[1] == (0xa77b0000 | (lo & 0xffff))
+ && plt[2] == 0x6bfb0000)
+ return 1;
+ return 0;
+}
+
+static int
+alpha_prelink_rela (struct prelink_info *info, GElf_Rela *rela,
+ GElf_Addr relaaddr)
+{
+ DSO *dso;
+ GElf_Addr value;
+
+ if (GELF_R_TYPE (rela->r_info) == R_ALPHA_RELATIVE
+ || GELF_R_TYPE (rela->r_info) == R_ALPHA_NONE)
+ /* Fast path: nothing to do. */
+ return 0;
+ dso = info->dso;
+ value = info->resolve (info, GELF_R_SYM (rela->r_info),
+ GELF_R_TYPE (rela->r_info));
+ value += rela->r_addend;
+ switch (GELF_R_TYPE (rela->r_info))
+ {
+ case R_ALPHA_GLOB_DAT:
+ case R_ALPHA_REFQUAD:
+ case R_ALPHA_DTPREL64:
+ write_le64 (dso, rela->r_offset, value);
+ break;
+ case R_ALPHA_JMP_SLOT:
+ write_le64 (dso, rela->r_offset, value);
+ alpha_fixup_plt (dso, rela, relaaddr, value);
+ break;
+ /* DTPMOD64 and TPREL64 is impossible to predict in shared libraries
+ unless prelink sets the rules. */
+ case R_ALPHA_DTPMOD64:
+ if (dso->ehdr.e_type == ET_EXEC)
+ {
+ error (0, 0, "%s: R_ALPHA_DTPMOD64 reloc in executable?",
+ dso->filename);
+ return 1;
+ }
+ break;
+ case R_ALPHA_TPREL64:
+ if (dso->ehdr.e_type == ET_EXEC && info->resolvetls)
+ write_le64 (dso, rela->r_offset, value + info->resolvetls->offset);
+ break;
+ default:
+ error (0, 0, "%s: Unknown alpha relocation type %d", dso->filename,
+ (int) GELF_R_TYPE (rela->r_info));
+ return 1;
+ }
+ return 0;
+}
+
+static int
+alpha_apply_conflict_rela (struct prelink_info *info, GElf_Rela *rela,
+ char *buf, GElf_Addr dest_addr)
+{
+ switch (GELF_R_TYPE (rela->r_info) & 0xff)
+ {
+ case R_ALPHA_GLOB_DAT:
+ case R_ALPHA_REFQUAD:
+ case R_ALPHA_JMP_SLOT:
+ buf_write_le64 (buf, rela->r_addend);
+ break;
+ default:
+ abort ();
+ }
+ return 0;
+}
+
+static int
+alpha_apply_rel (struct prelink_info *info, GElf_Rel *rel, char *buf)
+{
+ error (0, 0, "%s: Alpha doesn't support REL relocs", info->dso->filename);
+ return 1;
+}
+
+static int
+alpha_apply_rela (struct prelink_info *info, GElf_Rela *rela, char *buf)
+{
+ GElf_Addr value;
+
+ value = info->resolve (info, GELF_R_SYM (rela->r_info),
+ GELF_R_TYPE (rela->r_info));
+ switch (GELF_R_TYPE (rela->r_info))
+ {
+ case R_ALPHA_NONE:
+ break;
+ case R_ALPHA_GLOB_DAT:
+ case R_ALPHA_REFQUAD:
+ case R_ALPHA_JMP_SLOT:
+ buf_write_le64 (buf, value + rela->r_addend);
+ break;
+ case R_ALPHA_RELATIVE:
+ error (0, 0, "%s: R_ALPHA_RELATIVE in ET_EXEC object?", info->dso->filename);
+ return 1;
+ default:
+ return 1;
+ }
+ return 0;
+}
+
+static int
+alpha_prelink_conflict_rel (DSO *dso, struct prelink_info *info,
+ GElf_Rel *rel, GElf_Addr reladdr)
+{
+ error (0, 0, "%s: Alpha doesn't support REL relocs", dso->filename);
+ return 1;
+}
+
+static int
+alpha_prelink_conflict_rela (DSO *dso, struct prelink_info *info,
+ GElf_Rela *rela, GElf_Addr relaaddr)
+{
+ GElf_Addr value;
+ struct prelink_conflict *conflict;
+ struct prelink_tls *tls;
+ GElf_Rela *ret;
+
+ if (GELF_R_TYPE (rela->r_info) == R_ALPHA_RELATIVE
+ || GELF_R_TYPE (rela->r_info) == R_ALPHA_NONE
+ || info->dso == dso)
+ /* Fast path: nothing to do. */
+ return 0;
+ conflict = prelink_conflict (info, GELF_R_SYM (rela->r_info),
+ GELF_R_TYPE (rela->r_info));
+ if (conflict == NULL)
+ {
+ if (info->curtls == NULL)
+ return 0;
+ switch (GELF_R_TYPE (rela->r_info))
+ {
+ /* Even local DTPMOD64 and TPREL64 relocs need conflicts. */
+ case R_ALPHA_DTPMOD64:
+ case R_ALPHA_TPREL64:
+ break;
+ default:
+ return 0;
+ }
+ value = 0;
+ }
+ else if (conflict->ifunc)
+ {
+ error (0, 0, "%s: STT_GNU_IFUNC not handled on Alpha yet",
+ dso->filename);
+ return 1;
+ }
+ else
+ {
+ /* DTPREL64 wants to see only real conflicts, not lookups
+ with reloc_class RTYPE_CLASS_TLS. */
+ if (GELF_R_TYPE (rela->r_info) == R_ALPHA_DTPREL64
+ && conflict->lookup.tls == conflict->conflict.tls
+ && conflict->lookupval == conflict->conflictval)
+ return 0;
+
+ value = conflict_lookup_value (conflict);
+ }
+ ret = prelink_conflict_add_rela (info);
+ if (ret == NULL)
+ return 1;
+ ret->r_offset = rela->r_offset;
+ ret->r_info = GELF_R_INFO (0, GELF_R_TYPE (rela->r_info));
+ switch (GELF_R_TYPE (rela->r_info))
+ {
+ case R_ALPHA_GLOB_DAT:
+ case R_ALPHA_REFQUAD:
+ ret->r_addend = value + rela->r_addend;
+ break;
+ case R_ALPHA_JMP_SLOT:
+ ret->r_addend = value + rela->r_addend;
+ if (alpha_is_indirect_plt (dso, rela, relaaddr))
+ ret->r_info = GELF_R_INFO (0, R_ALPHA_GLOB_DAT);
+ else
+ {
+ relaaddr -= dso->info[DT_JMPREL];
+ relaaddr /= sizeof (Elf64_Rela);
+ if (relaaddr > 0xffffff)
+ {
+ error (0, 0, "%s: Cannot create R_ALPHA_JMP_SLOT conflict against .rel.plt with more than 16M entries",
+ dso->filename);
+ return 1;
+ }
+ ret->r_info = GELF_R_INFO (0, (relaaddr << 8) | R_ALPHA_JMP_SLOT);
+ }
+ break;
+ case R_ALPHA_DTPMOD64:
+ case R_ALPHA_DTPREL64:
+ case R_ALPHA_TPREL64:
+ if (conflict != NULL
+ && (conflict->reloc_class != RTYPE_CLASS_TLS
+ || conflict->lookup.tls == NULL))
+ {
+ error (0, 0, "%s: TLS reloc not resolving to STT_TLS symbol",
+ dso->filename);
+ return 1;
+ }
+ tls = conflict ? conflict->lookup.tls : info->curtls;
+ ret->r_info = GELF_R_INFO (0, R_ALPHA_GLOB_DAT);
+ switch (GELF_R_TYPE (rela->r_info))
+ {
+ case R_ALPHA_DTPMOD64:
+ ret->r_addend = tls->modid;
+ break;
+ case R_ALPHA_DTPREL64:
+ ret->r_addend = value + rela->r_addend;
+ break;
+ case R_ALPHA_TPREL64:
+ ret->r_addend = value + rela->r_addend + tls->offset;
+ break;
+ }
+ break;
+ default:
+ error (0, 0, "%s: Unknown Alpha relocation type %d", dso->filename,
+ (int) GELF_R_TYPE (rela->r_info));
+ return 1;
+ }
+ return 0;
+}
+
+static int
+alpha_rel_to_rela (DSO *dso, GElf_Rel *rel, GElf_Rela *rela)
+{
+ error (0, 0, "%s: Alpha doesn't support REL relocs", dso->filename);
+ return 1;
+}
+
+static int
+alpha_need_rel_to_rela (DSO *dso, int first, int last)
+{
+ return 0;
+}
+
+static int
+alpha_arch_prelink (struct prelink_info *info)
+{
+ DSO *dso;
+
+ /* Correct sh_entsize on .plt sections. */
+ dso = info->dso;
+ if (dso->info[DT_PLTGOT])
+ {
+ int sec = addr_to_sec (dso, dso->info[DT_PLTGOT] + 16);
+ assert (sec != -1);
+ if (dso->shdr[sec].sh_type == SHT_PROGBITS
+ && dso->shdr[sec].sh_entsize == 32)
+ dso->shdr[sec].sh_entsize = 0;
+ }
+ return 0;
+}
+
+static int
+alpha_undo_prelink_rela (DSO *dso, GElf_Rela *rela, GElf_Addr relaaddr)
+{
+ int sec;
+ Elf_Scn *scn;
+ Elf_Data *data;
+ GElf_Sym sym;
+
+ switch (GELF_R_TYPE (rela->r_info))
+ {
+ case R_ALPHA_NONE:
+ case R_ALPHA_RELATIVE:
+ break;
+ case R_ALPHA_JMP_SLOT:
+ relaaddr -= dso->info[DT_JMPREL];
+ relaaddr /= sizeof (Elf64_Rela);
+ relaaddr *= 12;
+ relaaddr += dso->info[DT_PLTGOT] + 32;
+ /* br at,.plt */
+ write_le32 (dso, relaaddr,
+ 0xc39fffff - (relaaddr - dso->info[DT_PLTGOT]) / 4);
+ write_le64 (dso, relaaddr + 4, 0);
+ write_le64 (dso, rela->r_offset, relaaddr);
+ break;
+ case R_ALPHA_GLOB_DAT:
+ /* This is ugly. Linker doesn't clear memory at r_offset of GLOB_DAT
+ reloc, but instead puts in sym.st_value + addend. */
+ sec = addr_to_sec (dso, relaaddr);
+ assert (sec != -1);
+ sec = dso->shdr[sec].sh_link;
+ assert (sec > 0 && sec < dso->ehdr.e_shnum);
+ scn = dso->scn[sec];
+ data = elf_getdata (scn, NULL);
+ assert (data != NULL && elf_getdata (scn, data) == NULL);
+ assert (GELF_R_SYM (rela->r_info)
+ <= dso->shdr[sec].sh_size / sizeof (Elf64_Sym));
+ gelfx_getsym (dso->elf, data, GELF_R_SYM (rela->r_info), &sym);
+ write_le64 (dso, rela->r_offset, sym.st_value + rela->r_addend);
+ break;
+ case R_ALPHA_REFQUAD:
+ case R_ALPHA_DTPMOD64:
+ case R_ALPHA_DTPREL64:
+ case R_ALPHA_TPREL64:
+ write_le64 (dso, rela->r_offset, 0);
+ break;
+ default:
+ error (0, 0, "%s: Unknown alpha relocation type %d", dso->filename,
+ (int) GELF_R_TYPE (rela->r_info));
+ return 1;
+ }
+ return 0;
+}
+
+static int
+alpha_reloc_size (int reloc_type)
+{
+ return 8;
+}
+
+static int
+alpha_reloc_class (int reloc_type)
+{
+ switch (reloc_type)
+ {
+ case R_ALPHA_JMP_SLOT:
+ return RTYPE_CLASS_PLT;
+ case R_ALPHA_DTPMOD64:
+ case R_ALPHA_DTPREL64:
+ case R_ALPHA_TPREL64:
+ return RTYPE_CLASS_TLS;
+ default:
+ return RTYPE_CLASS_VALID;
+ }
+}
+
+PL_ARCH(alpha) = {
+ .name = "Alpha",
+ .class = ELFCLASS64,
+ .machine = EM_ALPHA,
+ .alternate_machine = { EM_FAKE_ALPHA },
+ .R_JMP_SLOT = R_ALPHA_JMP_SLOT,
+ .R_COPY = -1,
+ .R_RELATIVE = R_ALPHA_RELATIVE,
+ .rtype_class_valid = RTYPE_CLASS_VALID,
+ .dynamic_linker = "/lib/ld-linux.so.2",
+ .adjust_dyn = alpha_adjust_dyn,
+ .adjust_rel = alpha_adjust_rel,
+ .adjust_rela = alpha_adjust_rela,
+ .prelink_rel = alpha_prelink_rel,
+ .prelink_rela = alpha_prelink_rela,
+ .prelink_conflict_rel = alpha_prelink_conflict_rel,
+ .prelink_conflict_rela = alpha_prelink_conflict_rela,
+ .apply_conflict_rela = alpha_apply_conflict_rela,
+ .apply_rel = alpha_apply_rel,
+ .apply_rela = alpha_apply_rela,
+ .rel_to_rela = alpha_rel_to_rela,
+ .need_rel_to_rela = alpha_need_rel_to_rela,
+ .reloc_size = alpha_reloc_size,
+ .reloc_class = alpha_reloc_class,
+ .max_reloc_size = 8,
+ .arch_prelink = alpha_arch_prelink,
+ .undo_prelink_rela = alpha_undo_prelink_rela,
+ /* Although TASK_UNMAPPED_BASE is 0x0000020000000000, we leave some
+ area so that mmap of /etc/ld.so.cache and ld.so's malloc
+ does not take some library's VA slot.
+ Also, if this guard area isn't too small, typically
+ even dlopened libraries will get the slots they desire. */
+ .mmap_base = 0x0000020001000000LL,
+ .mmap_end = 0x0000020100000000LL,
+ .max_page_size = 0x10000,
+ .page_size = 0x02000
+};
diff --git a/src/arch-arm.c b/src/arch-arm.c
new file mode 100644
index 0000000..c8febcd
--- /dev/null
+++ b/src/arch-arm.c
@@ -0,0 +1,950 @@
+/* Copyright (C) 2001, 2002, 2004, 2009, 2011, 2013 Red Hat, Inc.
+ Written by Jakub Jelinek <jakub@redhat.com>, 2001.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include <config.h>
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <locale.h>
+#include <error.h>
+#include <argp.h>
+#include <stdlib.h>
+
+#include "prelink.h"
+
+#ifndef R_ARM_TLS_DTPMOD32
+#define R_ARM_TLS_DTPMOD32 17 /* ID of module containing symbol */
+#define R_ARM_TLS_DTPOFF32 18 /* Offset in TLS block */
+#define R_ARM_TLS_TPOFF32 19 /* Offset in static TLS block */
+#endif
+
+static int
+arm_adjust_dyn (DSO *dso, int n, GElf_Dyn *dyn, GElf_Addr start,
+ GElf_Addr adjust)
+{
+ if (dyn->d_tag == DT_PLTGOT)
+ {
+ int sec = addr_to_sec (dso, dyn->d_un.d_ptr);
+ Elf32_Addr data;
+
+ if (sec == -1)
+ return 0;
+
+ data = read_une32 (dso, dyn->d_un.d_ptr);
+ /* If .got.plt[0] points to _DYNAMIC, it needs to be adjusted. */
+ if (data == dso->shdr[n].sh_addr && data >= start)
+ write_ne32 (dso, dyn->d_un.d_ptr, data + adjust);
+
+ data = read_une32 (dso, dyn->d_un.d_ptr + 4);
+ /* If .got.plt[1] points to .plt, it needs to be adjusted. */
+ if (data && data >= start)
+ {
+ int i;
+
+ for (i = 1; i < dso->ehdr.e_shnum; i++)
+ if (data == dso->shdr[i].sh_addr
+ && dso->shdr[i].sh_type == SHT_PROGBITS
+ && strcmp (strptr (dso, dso->ehdr.e_shstrndx,
+ dso->shdr[i].sh_name), ".plt") == 0)
+ {
+ write_ne32 (dso, dyn->d_un.d_ptr + 4, data + adjust);
+ break;
+ }
+ }
+ }
+ return 0;
+}
+
+static int
+arm_adjust_rel (DSO *dso, GElf_Rel *rel, GElf_Addr start,
+ GElf_Addr adjust)
+{
+ Elf32_Addr data;
+ switch (GELF_R_TYPE (rel->r_info))
+ {
+ case R_ARM_RELATIVE:
+ case R_ARM_JUMP_SLOT:
+ case R_ARM_IRELATIVE:
+ data = read_une32 (dso, rel->r_offset);
+ if (data >= start)
+ write_ne32 (dso, rel->r_offset, data + adjust);
+ break;
+ }
+ return 0;
+}
+
+static int
+arm_adjust_rela (DSO *dso, GElf_Rela *rela, GElf_Addr start,
+ GElf_Addr adjust)
+{
+ Elf32_Addr data;
+
+ switch (GELF_R_TYPE (rela->r_info))
+ {
+ case R_ARM_RELATIVE:
+ case R_ARM_IRELATIVE:
+ if ((Elf32_Addr) rela->r_addend >= start)
+ {
+ rela->r_addend += (Elf32_Sword) adjust;
+ /* Write it to the memory location as well.
+ Not necessary, but we can do it. */
+ write_ne32 (dso, rela->r_offset, rela->r_addend);
+ }
+ break;
+ case R_ARM_JUMP_SLOT:
+ data = read_une32 (dso, rela->r_offset);
+ if (data >= start)
+ write_ne32 (dso, rela->r_offset, data + adjust);
+ break;
+ break;
+ }
+ return 0;
+}
+
+static int
+arm_prelink_rel (struct prelink_info *info, GElf_Rel *rel, GElf_Addr reladdr)
+{
+ DSO *dso;
+ GElf_Addr value;
+ Elf32_Sword val;
+
+ if (GELF_R_TYPE (rel->r_info) == R_ARM_RELATIVE
+ || GELF_R_TYPE (rel->r_info) == R_ARM_IRELATIVE
+ || GELF_R_TYPE (rel->r_info) == R_ARM_NONE)
+ /* Fast path: nothing to do. */
+ return 0;
+ dso = info->dso;
+ value = info->resolve (info, GELF_R_SYM (rel->r_info),
+ GELF_R_TYPE (rel->r_info));
+ switch (GELF_R_TYPE (rel->r_info))
+ {
+ case R_ARM_GLOB_DAT:
+ case R_ARM_JUMP_SLOT:
+ write_ne32 (dso, rel->r_offset, value);
+ break;
+ case R_ARM_ABS32:
+ {
+ if (read_une32 (dso, rel->r_offset))
+ {
+ error (0, 0, "%s: R_ARM_ABS32 relocs with non-zero addend should not be present in prelinked REL sections",
+ dso->filename);
+ return 1;
+ }
+ rel->r_info = GELF_R_INFO (GELF_R_SYM (rel->r_info), R_ARM_GLOB_DAT);
+ write_ne32 (dso, rel->r_offset, value);
+ /* Tell prelink_rel routine *rel has changed. */
+ return 2;
+ }
+ case R_ARM_PC24:
+ error (0, 0, "%s: R_ARM_PC24 relocs with non-zero addend should not be present in prelinked REL sections",
+ dso->filename);
+ return 1;
+ case R_ARM_COPY:
+ if (dso->ehdr.e_type == ET_EXEC)
+ /* COPY relocs are handled specially in generic code. */
+ return 0;
+ error (0, 0, "%s: R_ARM_COPY reloc in shared library?", dso->filename);
+ return 1;
+ case R_ARM_TLS_DTPOFF32:
+ write_ne32 (dso, rel->r_offset, value);
+ break;
+ /* DTPMOD32 and TPOFF32 is impossible to predict in shared libraries
+ unless prelink sets the rules. */
+ case R_ARM_TLS_DTPMOD32:
+ if (dso->ehdr.e_type == ET_EXEC)
+ {
+ error (0, 0, "%s: R_ARM_TLS_DTPMOD32 reloc in executable?",
+ dso->filename);
+ return 1;
+ }
+ break;
+ case R_ARM_TLS_TPOFF32:
+ if (dso->ehdr.e_type == ET_EXEC)
+ error (0, 0, "%s: R_ARM_TLS_TPOFF32 relocs should not be present in "
+ "prelinked ET_EXEC REL sections",
+ dso->filename);
+ break;
+ case R_ARM_TLS_DESC:
+ if (!dso->info_DT_TLSDESC_PLT)
+ {
+ error (0, 0,
+ "%s: Unsupported R_ARM_TLS_DESC relocation in non-lazily bound object.",
+ dso->filename);
+ return 1;
+ }
+ val = read_une32 (dso, rel->r_offset + 4);
+ if (val != 0 && !dynamic_info_is_set (dso, DT_GNU_PRELINKED_BIT))
+ {
+ error (0, 0,
+ "%s: Unexpected non-zero value (0x%x) in R_ARM_TLS_DESC?",
+ dso->filename, val);
+ return 1;
+ }
+ write_ne32 (dso, rel->r_offset + 4, dso->info_DT_TLSDESC_PLT);
+ break;
+ default:
+ error (0, 0, "%s: Unknown arm relocation type %d", dso->filename,
+ (int) GELF_R_TYPE (rel->r_info));
+ return 1;
+ }
+ return 0;
+}
+
+static int
+arm_prelink_rela (struct prelink_info *info, GElf_Rela *rela,
+ GElf_Addr relaaddr)
+{
+ DSO *dso;
+ GElf_Addr value;
+ Elf32_Sword val;
+
+ if (GELF_R_TYPE (rela->r_info) == R_ARM_RELATIVE
+ || GELF_R_TYPE (rela->r_info) == R_ARM_IRELATIVE
+ || GELF_R_TYPE (rela->r_info) == R_ARM_NONE)
+ /* Fast path: nothing to do. */
+ return 0;
+ dso = info->dso;
+ value = info->resolve (info, GELF_R_SYM (rela->r_info),
+ GELF_R_TYPE (rela->r_info));
+ switch (GELF_R_TYPE (rela->r_info))
+ {
+ case R_ARM_GLOB_DAT:
+ case R_ARM_JUMP_SLOT:
+ write_ne32 (dso, rela->r_offset, value + rela->r_addend);
+ break;
+ case R_ARM_ABS32:
+ write_ne32 (dso, rela->r_offset, value + rela->r_addend);
+ break;
+ case R_ARM_PC24:
+ val = value + rela->r_addend - rela->r_offset;
+ val >>= 2;
+ if ((Elf32_Word) val + 0x800000 >= 0x1000000)
+ {
+ error (0, 0, "%s: R_ARM_PC24 overflow", dso->filename);
+ return 1;
+ }
+ val &= 0xffffff;
+ write_ne32 (dso, rela->r_offset,
+ (read_une32 (dso, rela->r_offset) & 0xff000000) | val);
+ break;
+ case R_ARM_COPY:
+ if (dso->ehdr.e_type == ET_EXEC)
+ /* COPY relocs are handled specially in generic code. */
+ return 0;
+ error (0, 0, "%s: R_ARM_COPY reloc in shared library?", dso->filename);
+ return 1;
+ case R_ARM_TLS_DTPOFF32:
+ write_ne32 (dso, rela->r_offset, value + rela->r_addend);
+ break;
+ /* DTPMOD32 and TPOFF32 is impossible to predict in shared libraries
+ unless prelink sets the rules. */
+ case R_ARM_TLS_DTPMOD32:
+ if (dso->ehdr.e_type == ET_EXEC)
+ {
+ error (0, 0, "%s: R_ARM_TLS_DTPMOD32 reloc in executable?",
+ dso->filename);
+ return 1;
+ }
+ break;
+ case R_ARM_TLS_TPOFF32:
+ if (dso->ehdr.e_type == ET_EXEC && info->resolvetls)
+ write_ne32 (dso, rela->r_offset,
+ value + rela->r_addend + info->resolvetls->offset);
+ break;
+ case R_ARM_TLS_DESC:
+ if (!dso->info_DT_TLSDESC_PLT)
+ {
+ error (0, 0,
+ "%s: Unsupported R_ARM_TLS_DESC relocation in non-lazily bound object.",
+ dso->filename);
+ return 1;
+ }
+ val = read_une32 (dso, rela->r_offset + 4);
+ if (val != 0 && !dynamic_info_is_set (dso, DT_GNU_PRELINKED_BIT))
+ {
+ error (0, 0,
+ "%s: Unexpected non-zero value (0x%x) in R_ARM_TLS_DESC?",
+ dso->filename, val);
+ return 1;
+ }
+ write_ne32 (dso, rela->r_offset + 4, dso->info_DT_TLSDESC_PLT);
+ break;
+ default:
+ error (0, 0, "%s: Unknown arm relocation type %d", dso->filename,
+ (int) GELF_R_TYPE (rela->r_info));
+ return 1;
+ }
+ return 0;
+}
+
+static int
+arm_apply_conflict_rela (struct prelink_info *info, GElf_Rela *rela,
+ char *buf, GElf_Addr dest_addr)
+{
+ GElf_Rela *ret;
+
+ switch (GELF_R_TYPE (rela->r_info))
+ {
+ case R_ARM_GLOB_DAT:
+ case R_ARM_JUMP_SLOT:
+ case R_ARM_ABS32:
+ buf_write_ne32 (info->dso, buf, rela->r_addend);
+ break;
+ case R_ARM_IRELATIVE:
+ if (dest_addr == 0)
+ return 5;
+ ret = prelink_conflict_add_rela (info);
+ if (ret == NULL)
+ return 1;
+ ret->r_offset = dest_addr;
+ ret->r_info = GELF_R_INFO (0, R_ARM_IRELATIVE);
+ ret->r_addend = rela->r_addend;
+ break;
+ default:
+ abort ();
+ }
+ return 0;
+}
+
+static int
+arm_apply_rel (struct prelink_info *info, GElf_Rel *rel, char *buf)
+{
+ GElf_Addr value;
+ Elf32_Sword val;
+
+ value = info->resolve (info, GELF_R_SYM (rel->r_info),
+ GELF_R_TYPE (rel->r_info));
+ switch (GELF_R_TYPE (rel->r_info))
+ {
+ case R_ARM_NONE:
+ break;
+ case R_ARM_GLOB_DAT:
+ case R_ARM_JUMP_SLOT:
+ buf_write_ne32 (info->dso, buf, value);
+ break;
+ case R_ARM_ABS32:
+ buf_write_ne32 (info->dso, buf, value + read_une32 (info->dso, rel->r_offset));
+ break;
+ case R_ARM_PC24:
+ val = value + rel->r_offset;
+ value = read_une32 (info->dso, rel->r_offset) << 8;
+ value = ((Elf32_Sword) value) >> 6;
+ val += value;
+ val >>= 2;
+ if ((Elf32_Word) val + 0x800000 >= 0x1000000)
+ {
+ error (0, 0, "%s: R_ARM_PC24 overflow", info->dso->filename);
+ return 1;
+ }
+ val &= 0xffffff;
+ buf_write_ne32 (info->dso, buf, (buf_read_une32 (info->dso, buf) & 0xff000000) | val);
+ break;
+ case R_ARM_COPY:
+ abort ();
+ case R_ARM_RELATIVE:
+ error (0, 0, "%s: R_ARM_RELATIVE in ET_EXEC object?", info->dso->filename);
+ return 1;
+ default:
+ return 1;
+ }
+ return 0;
+}
+
+static int
+arm_apply_rela (struct prelink_info *info, GElf_Rela *rela, char *buf)
+{
+ GElf_Addr value;
+ Elf32_Sword val;
+
+ value = info->resolve (info, GELF_R_SYM (rela->r_info),
+ GELF_R_TYPE (rela->r_info));
+ switch (GELF_R_TYPE (rela->r_info))
+ {
+ case R_ARM_NONE:
+ break;
+ case R_ARM_GLOB_DAT:
+ case R_ARM_JUMP_SLOT:
+ case R_ARM_ABS32:
+ buf_write_ne32 (info->dso, buf, value + rela->r_addend);
+ break;
+ case R_ARM_PC24:
+ val = value + rela->r_addend - rela->r_offset;
+ val >>= 2;
+ if ((Elf32_Word) val + 0x800000 >= 0x1000000)
+ {
+ error (0, 0, "%s: R_ARM_PC24 overflow", info->dso->filename);
+ return 1;
+ }
+ val &= 0xffffff;
+ buf_write_ne32 (info->dso, buf, (buf_read_une32 (info->dso, buf) & 0xff000000) | val);
+ break;
+ case R_ARM_COPY:
+ abort ();
+ case R_ARM_RELATIVE:
+ error (0, 0, "%s: R_ARM_RELATIVE in ET_EXEC object?", info->dso->filename);
+ return 1;
+ default:
+ return 1;
+ }
+ return 0;
+}
+
+static int
+arm_prelink_conflict_rel (DSO *dso, struct prelink_info *info, GElf_Rel *rel,
+ GElf_Addr reladdr)
+{
+ GElf_Addr value;
+ struct prelink_conflict *conflict;
+ struct prelink_tls *tls;
+ GElf_Rela *ret;
+
+ if (GELF_R_TYPE (rel->r_info) == R_ARM_RELATIVE
+ || GELF_R_TYPE (rel->r_info) == R_ARM_NONE)
+ /* Fast path: nothing to do. */
+ return 0;
+ conflict = prelink_conflict (info, GELF_R_SYM (rel->r_info),
+ GELF_R_TYPE (rel->r_info));
+ if (conflict == NULL)
+ {
+ switch (GELF_R_TYPE (rel->r_info))
+ {
+ /* Even local DTPMOD and TPOFF relocs need conflicts. */
+ case R_ARM_TLS_DTPMOD32:
+ case R_ARM_TLS_TPOFF32:
+ if (info->curtls == NULL || info->dso == dso)
+ return 0;
+ break;
+ /* Similarly IRELATIVE relocations always need conflicts. */
+ case R_ARM_IRELATIVE:
+ break;
+ /* Likewise TLS_DESC. */
+ case R_ARM_TLS_DESC:
+ break;
+ default:
+ return 0;
+ }
+ value = 0;
+ }
+ else if (info->dso == dso && !conflict->ifunc)
+ return 0;
+ else
+ {
+ /* DTPOFF32 wants to see only real conflicts, not lookups
+ with reloc_class RTYPE_CLASS_TLS. */
+ if (GELF_R_TYPE (rel->r_info) == R_ARM_TLS_DTPOFF32
+ && conflict->lookup.tls == conflict->conflict.tls
+ && conflict->lookupval == conflict->conflictval)
+ return 0;
+
+ value = conflict_lookup_value (conflict);
+ }
+
+ ret = prelink_conflict_add_rela (info);
+ if (ret == NULL)
+ return 1;
+ ret->r_offset = rel->r_offset;
+ ret->r_info = GELF_R_INFO (0, GELF_R_TYPE (rel->r_info));
+ switch (GELF_R_TYPE (rel->r_info))
+ {
+ case R_ARM_GLOB_DAT:
+ case R_ARM_JUMP_SLOT:
+ ret->r_addend = (Elf32_Sword) value;
+ if (conflict != NULL && conflict->ifunc)
+ ret->r_info = GELF_R_INFO (0, R_ARM_IRELATIVE);
+ break;
+ case R_ARM_IRELATIVE:
+ ret->r_addend = (Elf32_Sword) read_une32 (dso, rel->r_offset);
+ break;
+ case R_ARM_ABS32:
+ case R_ARM_PC24:
+ error (0, 0, "%s: R_ARM_%s relocs should not be present in prelinked REL sections",
+ dso->filename, GELF_R_TYPE (rel->r_info) == R_ARM_ABS32 ? "ABS32" : "PC24");
+ return 1;
+ case R_ARM_COPY:
+ error (0, 0, "R_ARM_COPY should not be present in shared libraries");
+ return 1;
+ case R_ARM_TLS_DTPMOD32:
+ case R_ARM_TLS_DTPOFF32:
+ case R_ARM_TLS_TPOFF32:
+ if (conflict != NULL
+ && (conflict->reloc_class != RTYPE_CLASS_TLS
+ || conflict->lookup.tls == NULL))
+ {
+ error (0, 0, "%s: TLS reloc not resolving to STT_TLS symbol",
+ dso->filename);
+ return 1;
+ }
+ tls = conflict ? conflict->lookup.tls : info->curtls;
+ ret->r_info = GELF_R_INFO (0, R_ARM_ABS32);
+ switch (GELF_R_TYPE (rel->r_info))
+ {
+ case R_ARM_TLS_DTPMOD32:
+ ret->r_addend = tls->modid;
+ break;
+ case R_ARM_TLS_DTPOFF32:
+ ret->r_addend = value + read_une32 (dso, rel->r_offset);
+ break;
+ case R_ARM_TLS_TPOFF32:
+ ret->r_addend = (value + read_une32 (dso, rel->r_offset)
+ + tls->offset);
+ break;
+ }
+ break;
+ case R_ARM_TLS_DESC:
+ /* Nothing to do. */
+ break;
+ default:
+ error (0, 0, "%s: Unknown arm relocation type %d", dso->filename,
+ (int) GELF_R_TYPE (rel->r_info));
+ return 1;
+ }
+ return 0;
+}
+
+static int
+arm_prelink_conflict_rela (DSO *dso, struct prelink_info *info,
+ GElf_Rela *rela, GElf_Addr relaaddr)
+{
+ GElf_Addr value;
+ struct prelink_conflict *conflict;
+ struct prelink_tls *tls;
+ GElf_Rela *ret;
+ Elf32_Sword val;
+
+ if (GELF_R_TYPE (rela->r_info) == R_ARM_RELATIVE
+ || GELF_R_TYPE (rela->r_info) == R_ARM_NONE)
+ /* Fast path: nothing to do. */
+ return 0;
+ conflict = prelink_conflict (info, GELF_R_SYM (rela->r_info),
+ GELF_R_TYPE (rela->r_info));
+
+ if (conflict == NULL)
+ {
+ if (info->curtls == NULL)
+ return 0;
+
+ switch (GELF_R_TYPE (rela->r_info))
+ {
+ /* Even local DTPMOD and TPOFF relocs need conflicts. */
+ case R_ARM_TLS_DTPMOD32:
+ case R_ARM_TLS_TPOFF32:
+ break;
+ /* Likewise TLS_DESC. */
+ case R_ARM_TLS_DESC:
+ break;
+ default:
+ return 0;
+ }
+ value = 0;
+ }
+ else if (conflict->ifunc)
+ {
+ error (0, 0, "%s: STT_GNU_IFUNC not handled on ARM yet",
+ dso->filename);
+ return 1;
+ }
+ else
+ {
+ /* DTPOFF32 wants to see only real conflicts, not lookups
+ with reloc_class RTYPE_CLASS_TLS. */
+ if (GELF_R_TYPE (rela->r_info) == R_ARM_TLS_DTPOFF32
+ && conflict->lookup.tls == conflict->conflict.tls
+ && conflict->lookupval == conflict->conflictval)
+ return 0;
+
+ value = conflict_lookup_value (conflict);
+ }
+
+ ret = prelink_conflict_add_rela (info);
+ if (ret == NULL)
+ return 1;
+ ret->r_offset = rela->r_offset;
+ ret->r_info = GELF_R_INFO (0, GELF_R_TYPE (rela->r_info));
+ switch (GELF_R_TYPE (rela->r_info))
+ {
+ case R_ARM_GLOB_DAT:
+ case R_ARM_JUMP_SLOT:
+ case R_ARM_ABS32:
+ case R_ARM_IRELATIVE:
+ ret->r_addend = (Elf32_Sword) (value + rela->r_addend);
+ if (conflict && conflict->ifunc)
+ ret->r_info = GELF_R_INFO (0, R_ARM_IRELATIVE);
+ break;
+ case R_ARM_PC24:
+ val = value + rela->r_addend - rela->r_offset;
+ val >>= 2;
+ if ((Elf32_Word) val + 0x800000 >= 0x1000000)
+ {
+ error (0, 0, "%s: R_ARM_PC24 overflow", dso->filename);
+ return 1;
+ }
+ value = read_une32 (dso, rela->r_offset) & 0xff000000;
+ ret->r_addend = (Elf32_Sword) (value | (val & 0xffffff));
+ ret->r_info = GELF_R_INFO (0, R_ARM_ABS32);
+ break;
+ case R_ARM_COPY:
+ error (0, 0, "R_ARM_COPY should not be present in shared libraries");
+ return 1;
+ case R_ARM_TLS_DTPMOD32:
+ case R_ARM_TLS_DTPOFF32:
+ case R_ARM_TLS_TPOFF32:
+ if (conflict != NULL
+ && (conflict->reloc_class != RTYPE_CLASS_TLS
+ || conflict->lookup.tls == NULL))
+ {
+ error (0, 0, "%s: TLS reloc not resolving to STT_TLS symbol",
+ dso->filename);
+ return 1;
+ }
+ tls = conflict ? conflict->lookup.tls : info->curtls;
+ ret->r_info = GELF_R_INFO (0, R_ARM_ABS32);
+ switch (GELF_R_TYPE (rela->r_info))
+ {
+ case R_ARM_TLS_DTPMOD32:
+ ret->r_addend = tls->modid;
+ break;
+ case R_ARM_TLS_DTPOFF32:
+ ret->r_addend = value + rela->r_addend;
+ break;
+ case R_ARM_TLS_TPOFF32:
+ ret->r_addend = value + rela->r_addend + tls->offset;
+ break;
+ }
+ break;
+ case R_ARM_TLS_DESC:
+ /* Nothing to do. */
+ break;
+ default:
+ error (0, 0, "%s: Unknown arm relocation type %d", dso->filename,
+ (int) GELF_R_TYPE (rela->r_info));
+ return 1;
+ }
+ return 0;
+}
+
+static int
+arm_rel_to_rela (DSO *dso, GElf_Rel *rel, GElf_Rela *rela)
+{
+ rela->r_offset = rel->r_offset;
+ rela->r_info = rel->r_info;
+ switch (GELF_R_TYPE (rel->r_info))
+ {
+ case R_ARM_JUMP_SLOT:
+ /* We should be never converting .rel.plt into .rela.plt. */
+ abort ();
+ case R_ARM_RELATIVE:
+ case R_ARM_IRELATIVE:
+ case R_ARM_ABS32:
+ case R_ARM_TLS_TPOFF32:
+ case R_ARM_TLS_DTPOFF32:
+ rela->r_addend = (Elf32_Sword) read_une32 (dso, rel->r_offset);
+ break;
+ case R_ARM_PC24:
+ rela->r_addend = read_une32 (dso, rel->r_offset) << 8;
+ rela->r_addend = ((Elf32_Sword) rela->r_addend) >> 6;
+ break;
+ case R_ARM_COPY:
+ case R_ARM_GLOB_DAT:
+ case R_ARM_TLS_DTPMOD32:
+ case R_ARM_TLS_DESC:
+ rela->r_addend = 0;
+ break;
+ }
+ return 0;
+}
+
+static int
+arm_rela_to_rel (DSO *dso, GElf_Rela *rela, GElf_Rel *rel)
+{
+ rel->r_offset = rela->r_offset;
+ rel->r_info = rela->r_info;
+ switch (GELF_R_TYPE (rel->r_info))
+ {
+ case R_ARM_JUMP_SLOT:
+ /* We should be never converting .rel.plt into .rela.plt
+ and thus never .rela.plt back to .rel.plt. */
+ abort ();
+ case R_ARM_RELATIVE:
+ case R_ARM_IRELATIVE:
+ case R_ARM_ABS32:
+ case R_ARM_TLS_TPOFF32:
+ case R_ARM_TLS_DTPOFF32:
+ write_ne32 (dso, rela->r_offset, rela->r_addend);
+ break;
+ case R_ARM_PC24:
+ write_ne32 (dso, rela->r_offset,
+ (read_une32 (dso, rela->r_offset) & 0xff000000)
+ | ((rela->r_addend >> 2) & 0xffffff));
+ break;
+ case R_ARM_GLOB_DAT:
+ case R_ARM_TLS_DTPMOD32:
+ write_ne32 (dso, rela->r_offset, 0);
+ break;
+ }
+ return 0;
+}
+
+static int
+arm_need_rel_to_rela (DSO *dso, int first, int last)
+{
+ Elf_Data *data;
+ Elf_Scn *scn;
+ Elf32_Rel *rel, *relend;
+ unsigned int val;
+
+ while (first <= last)
+ {
+ data = NULL;
+ scn = dso->scn[first++];
+ while ((data = elf_getdata (scn, data)) != NULL)
+ {
+ rel = (Elf32_Rel *) data->d_buf;
+ relend = rel + data->d_size / sizeof (Elf32_Rel);
+ for (; rel < relend; rel++)
+ switch (ELF32_R_TYPE (rel->r_info))
+ {
+ case R_ARM_ABS32:
+ val = read_une32 (dso, rel->r_offset);
+ /* R_ARM_ABS32 with addend 0 can be converted
+ to R_ARM_GLOB_DAT and we don't have to convert
+ to RELA because of that. */
+ if (val == 0)
+ break;
+ /* FALLTHROUGH */
+ case R_ARM_PC24:
+ return 1;
+ case R_ARM_TLS_TPOFF32:
+ /* In shared libraries TPOFF is changed always into
+ conflicts, for executables we need to preserve
+ original addend. */
+ if (dso->ehdr.e_type == ET_EXEC)
+ return 1;
+ case R_ARM_TLS_DTPOFF32:
+ /* We can prelink these fields, and the addend is relative
+ to the symbol value. A RELA entry is needed. */
+ return 1;
+
+ break;
+ }
+ }
+ }
+ return 0;
+}
+
+static int
+arm_arch_prelink (struct prelink_info *info)
+{
+ DSO *dso;
+ int i;
+
+ dso = info->dso;
+ if (dso->info[DT_PLTGOT])
+ {
+ /* Write address of .plt into got[1].
+ .plt is what got[3] contains unless prelinking. */
+ int sec = addr_to_sec (dso, dso->info[DT_PLTGOT]);
+ Elf32_Addr data;
+
+ if (sec == -1)
+ return 1;
+
+ for (i = 1; i < dso->ehdr.e_shnum; i++)
+ if (dso->shdr[i].sh_type == SHT_PROGBITS
+ && ! strcmp (strptr (dso, dso->ehdr.e_shstrndx,
+ dso->shdr[i].sh_name),
+ ".plt"))
+ break;
+
+ if (i == dso->ehdr.e_shnum)
+ return 0;
+ data = dso->shdr[i].sh_addr;
+ write_ne32 (dso, dso->info[DT_PLTGOT] + 4, data);
+ }
+
+ return 0;
+}
+
+static int
+arm_arch_undo_prelink (DSO *dso)
+{
+ int i;
+
+ if (dso->info[DT_PLTGOT])
+ {
+ /* Clear got[1] if it contains address of .plt. */
+ int sec = addr_to_sec (dso, dso->info[DT_PLTGOT]);
+ Elf32_Addr data;
+
+ if (sec == -1)
+ return 1;
+
+ for (i = 1; i < dso->ehdr.e_shnum; i++)
+ if (dso->shdr[i].sh_type == SHT_PROGBITS
+ && ! strcmp (strptr (dso, dso->ehdr.e_shstrndx,
+ dso->shdr[i].sh_name),
+ ".plt"))
+ break;
+
+ if (i == dso->ehdr.e_shnum)
+ return 0;
+ data = read_une32 (dso, dso->info[DT_PLTGOT] + 4);
+ if (data == dso->shdr[i].sh_addr)
+ write_ne32 (dso, dso->info[DT_PLTGOT] + 4, 0);
+ }
+
+ return 0;
+}
+
+static int
+arm_undo_prelink_rel (DSO *dso, GElf_Rel *rel, GElf_Addr reladdr)
+{
+ int sec;
+ const char *name;
+
+ switch (GELF_R_TYPE (rel->r_info))
+ {
+ case R_ARM_RELATIVE:
+ case R_ARM_IRELATIVE:
+ case R_ARM_NONE:
+ break;
+ case R_ARM_JUMP_SLOT:
+ sec = addr_to_sec (dso, rel->r_offset);
+ name = strptr (dso, dso->ehdr.e_shstrndx, dso->shdr[sec].sh_name);
+ if (sec == -1 || (strcmp (name, ".got") && strcmp (name, ".got.plt")))
+ {
+ error (0, 0, "%s: R_ARM_JMP_SLOT not pointing into .got section",
+ dso->filename);
+ return 1;
+ }
+ else
+ {
+ Elf32_Addr data = read_une32 (dso, dso->shdr[sec].sh_addr + 4);
+
+ assert (rel->r_offset >= dso->shdr[sec].sh_addr + 12);
+ assert (((rel->r_offset - dso->shdr[sec].sh_addr) & 3) == 0);
+ write_ne32 (dso, rel->r_offset, data);
+ }
+ break;
+ case R_ARM_GLOB_DAT:
+ sec = addr_to_sec (dso, rel->r_offset);
+
+ write_ne32 (dso, rel->r_offset, 0);
+ if (sec != -1)
+ {
+ if (strcmp (strptr (dso, dso->ehdr.e_shstrndx,
+ dso->shdr[sec].sh_name),
+ ".got"))
+ {
+ rel->r_info = GELF_R_INFO (GELF_R_SYM (rel->r_info), R_ARM_ABS32);
+ return 2;
+ }
+ }
+ break;
+ case R_ARM_ABS32:
+ case R_ARM_PC24:
+ error (0, 0, "%s: R_ARM_%s relocs should not be present in prelinked REL sections",
+ GELF_R_TYPE (rel->r_info) == R_ARM_ABS32 ? "ABS32" : "PC24",
+ dso->filename);
+ return 1;
+ case R_ARM_COPY:
+ if (dso->ehdr.e_type == ET_EXEC)
+ /* COPY relocs are handled specially in generic code. */
+ return 0;
+ error (0, 0, "%s: R_ARM_COPY reloc in shared library?", dso->filename);
+ return 1;
+ case R_ARM_TLS_DTPMOD32:
+ case R_ARM_TLS_DTPOFF32:
+ write_ne32 (dso, rel->r_offset, 0);
+ break;
+ case R_ARM_TLS_TPOFF32:
+ break;
+ case R_ARM_TLS_DESC:
+ write_ne32 (dso, rel->r_offset + 4, 0);
+ break;
+ default:
+ error (0, 0, "%s: Unknown arm relocation type %d", dso->filename,
+ (int) GELF_R_TYPE (rel->r_info));
+ return 1;
+ }
+ return 0;
+}
+
+static int
+arm_reloc_size (int reloc_type)
+{
+ assert (reloc_type != R_ARM_COPY);
+ return 4;
+}
+
+static int
+arm_reloc_class (int reloc_type)
+{
+ switch (reloc_type)
+ {
+ case R_ARM_COPY: return RTYPE_CLASS_COPY;
+ case R_ARM_JUMP_SLOT: return RTYPE_CLASS_PLT;
+ case R_ARM_TLS_DTPMOD32:
+ case R_ARM_TLS_DTPOFF32:
+ case R_ARM_TLS_TPOFF32:
+ case R_ARM_TLS_DESC:
+ return RTYPE_CLASS_TLS;
+ default: return RTYPE_CLASS_VALID;
+ }
+}
+
+PL_ARCH(arm) = {
+ .name = "ARM",
+ .class = ELFCLASS32,
+ .machine = EM_ARM,
+ .alternate_machine = { EM_NONE },
+ .R_JMP_SLOT = R_ARM_JUMP_SLOT,
+ .R_COPY = R_ARM_COPY,
+ .R_RELATIVE = R_ARM_RELATIVE,
+ .rtype_class_valid = RTYPE_CLASS_VALID,
+ .dynamic_linker = "/lib/ld-linux.so.3",
+ .dynamic_linker_alt = "/lib/ld-linux-armhf.so.3",
+ .adjust_dyn = arm_adjust_dyn,
+ .adjust_rel = arm_adjust_rel,
+ .adjust_rela = arm_adjust_rela,
+ .prelink_rel = arm_prelink_rel,
+ .prelink_rela = arm_prelink_rela,
+ .prelink_conflict_rel = arm_prelink_conflict_rel,
+ .prelink_conflict_rela = arm_prelink_conflict_rela,
+ .apply_conflict_rela = arm_apply_conflict_rela,
+ .apply_rel = arm_apply_rel,
+ .apply_rela = arm_apply_rela,
+ .rel_to_rela = arm_rel_to_rela,
+ .rela_to_rel = arm_rela_to_rel,
+ .need_rel_to_rela = arm_need_rel_to_rela,
+ .reloc_size = arm_reloc_size,
+ .reloc_class = arm_reloc_class,
+ .max_reloc_size = 4,
+ .arch_prelink = arm_arch_prelink,
+ .arch_undo_prelink = arm_arch_undo_prelink,
+ .undo_prelink_rel = arm_undo_prelink_rel,
+ /* Although TASK_UNMAPPED_BASE is 0x40000000, we leave some
+ area so that mmap of /etc/ld.so.cache and ld.so's malloc
+ does not take some library's VA slot.
+ Also, if this guard area isn't too small, typically
+ even dlopened libraries will get the slots they desire. */
+ .mmap_base = 0x41000000,
+ .mmap_end = 0x50000000,
+ .max_page_size = 0x10000,
+ .page_size = 0x1000
+};
diff --git a/src/arch-cris.c b/src/arch-cris.c
new file mode 100644
index 0000000..3272779
--- /dev/null
+++ b/src/arch-cris.c
@@ -0,0 +1,412 @@
+/* Copyright (C) 2001, 2002, 2004, 2009 Red Hat, Inc.
+ Written by Jakub Jelinek <jakub@redhat.com>, 2001.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include <config.h>
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <locale.h>
+#include <error.h>
+#include <argp.h>
+#include <stdlib.h>
+
+#include "prelink.h"
+
+static int
+cris_adjust_dyn (DSO *dso, int n, GElf_Dyn *dyn, GElf_Addr start,
+ GElf_Addr adjust)
+{
+ if (dyn->d_tag == DT_PLTGOT)
+ {
+ int sec = addr_to_sec (dso, dyn->d_un.d_ptr);
+ Elf32_Addr data;
+
+ if (sec == -1)
+ return 0;
+
+ data = read_ule32 (dso, dyn->d_un.d_ptr);
+ /* If .got[0] points to _DYNAMIC, it needs to be adjusted. */
+ if (data == dso->shdr[n].sh_addr && data >= start)
+ write_le32 (dso, dyn->d_un.d_ptr, data + adjust);
+
+ data = read_ule32 (dso, dyn->d_un.d_ptr + 4);
+ /* If .got[1] points to .plt + 28, it needs to be adjusted. */
+ if (data && data >= start)
+ {
+ int i;
+
+ for (i = 1; i < dso->ehdr.e_shnum; i++)
+ if (data == dso->shdr[i].sh_addr + 28
+ && dso->shdr[i].sh_type == SHT_PROGBITS
+ && strcmp (strptr (dso, dso->ehdr.e_shstrndx,
+ dso->shdr[i].sh_name), ".plt") == 0)
+ {
+ write_le32 (dso, dyn->d_un.d_ptr + 4, data + adjust);
+ break;
+ }
+ }
+ }
+ return 0;
+}
+
+static int
+cris_adjust_rel (DSO *dso, GElf_Rel *rel, GElf_Addr start,
+ GElf_Addr adjust)
+{
+ error (0, 0, "%s: CRIS doesn't support REL relocs", dso->filename);
+ return 1;
+}
+
+static int
+cris_adjust_rela (DSO *dso, GElf_Rela *rela, GElf_Addr start,
+ GElf_Addr adjust)
+{
+ Elf32_Addr data;
+
+ switch (GELF_R_TYPE (rela->r_info))
+ {
+ case R_CRIS_RELATIVE:
+ if ((Elf32_Addr) rela->r_addend >= start)
+ rela->r_addend += (Elf32_Sword) adjust;
+ break;
+ case R_CRIS_JUMP_SLOT:
+ data = read_ule32 (dso, rela->r_offset);
+ if (data >= start)
+ write_le32 (dso, rela->r_offset, data + adjust);
+ break;
+ break;
+ }
+ return 0;
+}
+
+static int
+cris_prelink_rel (struct prelink_info *info, GElf_Rel *rel, GElf_Addr reladdr)
+{
+ error (0, 0, "%s: CRIS doesn't support REL relocs", info->dso->filename);
+ return 1;
+}
+
+static int
+cris_prelink_rela (struct prelink_info *info, GElf_Rela *rela,
+ GElf_Addr relaaddr)
+{
+ DSO *dso;
+ GElf_Addr value;
+
+ dso = info->dso;
+ if (GELF_R_TYPE (rela->r_info) == R_CRIS_NONE)
+ /* Fast path: nothing to do. */
+ return 0;
+ else if (GELF_R_TYPE (rela->r_info) == R_CRIS_RELATIVE)
+ {
+ write_le32 (dso, rela->r_offset, rela->r_addend);
+ return 0;
+ }
+ value = info->resolve (info, GELF_R_SYM (rela->r_info),
+ GELF_R_TYPE (rela->r_info));
+ value += rela->r_addend;
+ switch (GELF_R_TYPE (rela->r_info))
+ {
+ case R_CRIS_GLOB_DAT:
+ case R_CRIS_JUMP_SLOT:
+ case R_CRIS_32:
+ write_le32 (dso, rela->r_offset, value);
+ break;
+ case R_CRIS_16:
+ write_le16 (dso, rela->r_offset, value);
+ break;
+ case R_CRIS_8:
+ write_8 (dso, rela->r_offset, value);
+ break;
+ case R_CRIS_32_PCREL:
+ write_le32 (dso, rela->r_offset, value - rela->r_offset - 4);
+ break;
+ case R_CRIS_16_PCREL:
+ write_le16 (dso, rela->r_offset, value - rela->r_offset - 2);
+ break;
+ case R_CRIS_8_PCREL:
+ write_8 (dso, rela->r_offset, value - rela->r_offset - 1);
+ break;
+ case R_CRIS_COPY:
+ if (dso->ehdr.e_type == ET_EXEC)
+ /* COPY relocs are handled specially in generic code. */
+ return 0;
+ error (0, 0, "%s: R_CRIS_COPY reloc in shared library?", dso->filename);
+ return 1;
+ default:
+ error (0, 0, "%s: Unknown cris relocation type %d", dso->filename,
+ (int) GELF_R_TYPE (rela->r_info));
+ return 1;
+ }
+ return 0;
+}
+
+static int
+cris_apply_conflict_rela (struct prelink_info *info, GElf_Rela *rela,
+ char *buf, GElf_Addr dest_addr)
+{
+ switch (GELF_R_TYPE (rela->r_info))
+ {
+ case R_CRIS_GLOB_DAT:
+ case R_CRIS_JUMP_SLOT:
+ case R_CRIS_32:
+ buf_write_le32 (buf, rela->r_addend);
+ break;
+ case R_CRIS_16:
+ buf_write_le16 (buf, rela->r_addend);
+ break;
+ case R_CRIS_8:
+ buf_write_8 (buf, rela->r_addend);
+ break;
+ default:
+ abort ();
+ }
+ return 0;
+}
+
+static int
+cris_apply_rel (struct prelink_info *info, GElf_Rel *rel, char *buf)
+{
+ error (0, 0, "%s: CRIS doesn't support REL relocs", info->dso->filename);
+ return 1;
+}
+
+static int
+cris_apply_rela (struct prelink_info *info, GElf_Rela *rela, char *buf)
+{
+ GElf_Addr value;
+
+ value = info->resolve (info, GELF_R_SYM (rela->r_info),
+ GELF_R_TYPE (rela->r_info));
+ value += rela->r_addend;
+ switch (GELF_R_TYPE (rela->r_info))
+ {
+ case R_CRIS_NONE:
+ break;
+ case R_CRIS_GLOB_DAT:
+ case R_CRIS_JUMP_SLOT:
+ case R_CRIS_32:
+ buf_write_le32 (buf, value);
+ break;
+ case R_CRIS_16:
+ buf_write_le16 (buf, value);
+ break;
+ case R_CRIS_8:
+ buf_write_8 (buf, value);
+ break;
+ case R_CRIS_32_PCREL:
+ buf_write_le32 (buf, value - rela->r_offset - 4);
+ break;
+ case R_CRIS_16_PCREL:
+ buf_write_le16 (buf, value - rela->r_offset - 2);
+ break;
+ case R_CRIS_8:
+ buf_write_8 (buf, value - rela->r_offset - 1);
+ break;
+ case R_CRIS_COPY:
+ abort ();
+ case R_CRIS_RELATIVE:
+ error (0, 0, "%s: R_CRIS_RELATIVE in ET_EXEC object?", info->dso->filename);
+ return 1;
+ default:
+ return 1;
+ }
+ return 0;
+}
+
+static int
+cris_prelink_conflict_rel (DSO *dso, struct prelink_info *info, GElf_Rel *rel,
+ GElf_Addr reladdr)
+{
+ error (0, 0, "%s: CRIS doesn't support REL relocs", dso->filename);
+ return 1;
+}
+
+static int
+cris_prelink_conflict_rela (DSO *dso, struct prelink_info *info,
+ GElf_Rela *rela, GElf_Addr relaaddr)
+{
+ GElf_Addr value;
+ struct prelink_conflict *conflict;
+ GElf_Rela *ret;
+
+ if (GELF_R_TYPE (rela->r_info) == R_CRIS_RELATIVE
+ || GELF_R_TYPE (rela->r_info) == R_CRIS_NONE
+ || info->dso == dso)
+ /* Fast path: nothing to do. */
+ return 0;
+ conflict = prelink_conflict (info, GELF_R_SYM (rela->r_info),
+ GELF_R_TYPE (rela->r_info));
+ if (conflict == NULL)
+ return 0;
+ else if (conflict->ifunc)
+ {
+ error (0, 0, "%s: STT_GNU_IFUNC not handled on CRIS yet",
+ dso->filename);
+ return 1;
+ }
+ value = conflict_lookup_value (conflict);
+ ret = prelink_conflict_add_rela (info);
+ if (ret == NULL)
+ return 1;
+ ret->r_offset = rela->r_offset;
+ ret->r_info = GELF_R_INFO (0, GELF_R_TYPE (rela->r_info));
+ value += rela->r_addend;
+ switch (GELF_R_TYPE (rela->r_info))
+ {
+ case R_CRIS_GLOB_DAT:
+ case R_CRIS_JUMP_SLOT:
+ case R_CRIS_32:
+ case R_CRIS_16:
+ case R_CRIS_8:
+ ret->r_addend = (Elf32_Sword) (value + rela->r_addend);
+ break;
+ case R_CRIS_32_PCREL:
+ ret->r_addend = (Elf32_Sword) (value + rela->r_addend
+ - rela->r_offset - 4);
+ ret->r_info = GELF_R_INFO (0, R_CRIS_32);
+ break;
+ case R_CRIS_16_PCREL:
+ ret->r_addend = (Elf32_Sword) (value + rela->r_addend
+ - rela->r_offset - 2);
+ ret->r_info = GELF_R_INFO (0, R_CRIS_16);
+ break;
+ case R_CRIS_8_PCREL:
+ ret->r_addend = (Elf32_Sword) (value + rela->r_addend
+ - rela->r_offset - 1);
+ ret->r_info = GELF_R_INFO (0, R_CRIS_8);
+ break;
+ case R_CRIS_COPY:
+ error (0, 0, "R_CRIS_COPY should not be present in shared libraries");
+ return 1;
+ default:
+ error (0, 0, "%s: Unknown cris relocation type %d", dso->filename,
+ (int) GELF_R_TYPE (rela->r_info));
+ return 1;
+ }
+ return 0;
+}
+
+static int
+cris_rel_to_rela (DSO *dso, GElf_Rel *rel, GElf_Rela *rela)
+{
+ return 0;
+}
+
+static int
+cris_need_rel_to_rela (DSO *dso, int first, int last)
+{
+ return 0;
+}
+
+static int
+cris_arch_prelink (struct prelink_info *info)
+{
+ DSO *dso;
+ int i;
+
+ dso = info->dso;
+ if (dso->info[DT_PLTGOT])
+ {
+ /* Write address of .plt + 28 into got[1].
+ .plt + 28 is what got[3] contains unless prelinking. */
+ int sec = addr_to_sec (dso, dso->info[DT_PLTGOT]);
+ Elf32_Addr data;
+
+ if (sec == -1)
+ return 1;
+
+ for (i = 1; i < dso->ehdr.e_shnum; i++)
+ if (dso->shdr[i].sh_type == SHT_PROGBITS
+ && ! strcmp (strptr (dso, dso->ehdr.e_shstrndx,
+ dso->shdr[i].sh_name),
+ ".plt"))
+ break;
+
+ assert (i < dso->ehdr.e_shnum);
+ data = dso->shdr[i].sh_addr + 28;
+ write_le32 (dso, dso->info[DT_PLTGOT] + 4, data);
+ }
+
+ return 0;
+}
+
+static int
+cris_reloc_size (int reloc_type)
+{
+ switch (reloc_type)
+ {
+ case R_CRIS_16:
+ case R_CRIS_16_PCREL:
+ return 2;
+ case R_CRIS_8:
+ case R_CRIS_8_PCREL:
+ return 1;
+ default:
+ return 4;
+ }
+}
+
+static int
+cris_reloc_class (int reloc_type)
+{
+ switch (reloc_type)
+ {
+ case R_CRIS_COPY: return RTYPE_CLASS_COPY;
+ case R_CRIS_JUMP_SLOT: return RTYPE_CLASS_PLT;
+ default: return RTYPE_CLASS_VALID;
+ }
+}
+
+PL_ARCH(cris) = {
+ .name = "CRIS",
+ .class = ELFCLASS32,
+ .machine = EM_CRIS,
+ .alternate_machine = { EM_NONE },
+ .R_JUMP_SLOT = R_CRIS_JUMP_SLOT,
+ .R_COPY = R_CRIS_COPY,
+ .R_RELATIVE = R_CRIS_RELATIVE,
+ .rtype_class_valid = RTYPE_CLASS_VALID,
+ .dynamic_linker = "/lib/ld.so.1",
+ .adjust_dyn = cris_adjust_dyn,
+ .adjust_rel = cris_adjust_rel,
+ .adjust_rela = cris_adjust_rela,
+ .prelink_rel = cris_prelink_rel,
+ .prelink_rela = cris_prelink_rela,
+ .prelink_conflict_rel = cris_prelink_conflict_rel,
+ .prelink_conflict_rela = cris_prelink_conflict_rela,
+ .apply_conflict_rela = cris_apply_conflict_rela,
+ .apply_rel = cris_apply_rel,
+ .apply_rela = cris_apply_rela,
+ .rel_to_rela = cris_rel_to_rela,
+ .need_rel_to_rela = cris_need_rel_to_rela,
+ .reloc_size = cris_reloc_size,
+ .reloc_class = cris_reloc_class,
+ .max_reloc_size = 4,
+ .arch_prelink = cris_arch_prelink,
+ /* Although TASK_UNMAPPED_BASE is 0x3aaaa000, we leave some
+ area so that mmap of /etc/ld.so.cache and ld.so's malloc
+ does not take some library's VA slot.
+ Also, if this guard area isn't too small, typically
+ even dlopened libraries will get the slots they desire. */
+ .mmap_base = 0x3c000000,
+ .mmap_end = 0x48000000,
+ .max_page_size = 0x2000,
+ .page_size = 0x2000
+};
diff --git a/src/arch-i386.c b/src/arch-i386.c
new file mode 100644
index 0000000..a1e0fcc
--- /dev/null
+++ b/src/arch-i386.c
@@ -0,0 +1,1133 @@
+/* Copyright (C) 2001, 2002, 2003, 2004, 2009, 2011 Red Hat, Inc.
+ Written by Jakub Jelinek <jakub@redhat.com>, 2001.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include <config.h>
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <locale.h>
+#include <error.h>
+#include <argp.h>
+#include <stdlib.h>
+
+#include "prelink.h"
+#include "layout.h"
+
+static int
+i386_adjust_dyn (DSO *dso, int n, GElf_Dyn *dyn, GElf_Addr start,
+ GElf_Addr adjust)
+{
+ if (dyn->d_tag == DT_PLTGOT)
+ {
+ int sec = addr_to_sec (dso, dyn->d_un.d_ptr);
+ Elf32_Addr data;
+
+ if (sec == -1)
+ return 0;
+
+ data = read_ule32 (dso, dyn->d_un.d_ptr);
+ /* If .got.plt[0] points to _DYNAMIC, it needs to be adjusted. */
+ if (data == dso->shdr[n].sh_addr && data >= start)
+ write_le32 (dso, dyn->d_un.d_ptr, data + adjust);
+
+ data = read_ule32 (dso, dyn->d_un.d_ptr + 4);
+ /* If .got.plt[1] points to .plt + 0x16, it needs to be adjusted. */
+ if (data && data >= start)
+ {
+ int i;
+
+ for (i = 1; i < dso->ehdr.e_shnum; i++)
+ if (data == dso->shdr[i].sh_addr + 0x16
+ && dso->shdr[i].sh_type == SHT_PROGBITS
+ && strcmp (strptr (dso, dso->ehdr.e_shstrndx,
+ dso->shdr[i].sh_name), ".plt") == 0)
+ {
+ write_le32 (dso, dyn->d_un.d_ptr + 4, data + adjust);
+ break;
+ }
+ }
+ }
+ return 0;
+}
+
+static int
+i386_adjust_rel (DSO *dso, GElf_Rel *rel, GElf_Addr start,
+ GElf_Addr adjust)
+{
+ Elf32_Addr data;
+ switch (GELF_R_TYPE (rel->r_info))
+ {
+ case R_386_RELATIVE:
+ case R_386_JMP_SLOT:
+ case R_386_IRELATIVE:
+ data = read_ule32 (dso, rel->r_offset);
+ if (data >= start)
+ write_le32 (dso, rel->r_offset, data + adjust);
+ break;
+ }
+ return 0;
+}
+
+static int
+i386_adjust_rela (DSO *dso, GElf_Rela *rela, GElf_Addr start,
+ GElf_Addr adjust)
+{
+ Elf32_Addr data;
+
+ switch (GELF_R_TYPE (rela->r_info))
+ {
+ case R_386_RELATIVE:
+ case R_386_IRELATIVE:
+ if ((Elf32_Addr) rela->r_addend >= start)
+ {
+ rela->r_addend += (Elf32_Sword) adjust;
+ /* Write it to the memory location as well.
+ Not necessary, but we can do it. */
+ write_le32 (dso, rela->r_offset, rela->r_addend);
+ }
+ break;
+ case R_386_JMP_SLOT:
+ data = read_ule32 (dso, rela->r_offset);
+ if (data >= start)
+ write_le32 (dso, rela->r_offset, data + adjust);
+ break;
+ break;
+ }
+ return 0;
+}
+
+static int
+i386_prelink_rel (struct prelink_info *info, GElf_Rel *rel, GElf_Addr reladdr)
+{
+ DSO *dso;
+ GElf_Addr value;
+
+ if (GELF_R_TYPE (rel->r_info) == R_386_RELATIVE
+ || GELF_R_TYPE (rel->r_info) == R_386_IRELATIVE
+ || GELF_R_TYPE (rel->r_info) == R_386_NONE)
+ /* Fast path: nothing to do. */
+ return 0;
+ dso = info->dso;
+ value = info->resolve (info, GELF_R_SYM (rel->r_info),
+ GELF_R_TYPE (rel->r_info));
+ switch (GELF_R_TYPE (rel->r_info))
+ {
+ case R_386_GLOB_DAT:
+ case R_386_JMP_SLOT:
+ write_le32 (dso, rel->r_offset, value);
+ break;
+ case R_386_32:
+ {
+ if (read_ule32 (dso, rel->r_offset))
+ {
+ error (0, 0, "%s: R_386_32 relocs with non-zero addend should not be present in prelinked REL sections",
+ dso->filename);
+ return 1;
+ }
+ rel->r_info = GELF_R_INFO (GELF_R_SYM (rel->r_info), R_386_GLOB_DAT);
+ write_le32 (dso, rel->r_offset, value);
+ /* Tell prelink_rel routine *rel has changed. */
+ return 2;
+ }
+ case R_386_PC32:
+ error (0, 0, "%s: R_386_PC32 relocs should not be present in prelinked REL sections",
+ dso->filename);
+ return 1;
+ case R_386_TLS_DTPOFF32:
+ write_le32 (dso, rel->r_offset, value);
+ break;
+ /* DTPMOD32 and TPOFF{32,} is impossible to predict unless prelink
+ sets the rules. Also for TPOFF{32,} there is REL->RELA problem. */
+ case R_386_TLS_DTPMOD32:
+ if (dso->ehdr.e_type == ET_EXEC)
+ {
+ error (0, 0, "%s: R_386_TLS_DTPMOD32 reloc in executable?",
+ dso->filename);
+ return 1;
+ }
+ break;
+ case R_386_TLS_TPOFF32:
+ case R_386_TLS_TPOFF:
+ if (dso->ehdr.e_type == ET_EXEC)
+ error (0, 0, "%s: R_386_TLS_TPOFF relocs should not be present in prelinked ET_EXEC REL sections",
+ dso->filename);
+ break;
+ case R_386_COPY:
+ if (dso->ehdr.e_type == ET_EXEC)
+ /* COPY relocs are handled specially in generic code. */
+ return 0;
+ error (0, 0, "%s: R_386_COPY reloc in shared library?", dso->filename);
+ return 1;
+ default:
+ error (0, 0, "%s: Unknown i386 relocation type %d", dso->filename,
+ (int) GELF_R_TYPE (rel->r_info));
+ return 1;
+ }
+ return 0;
+}
+
+static int
+i386_prelink_rela (struct prelink_info *info, GElf_Rela *rela,
+ GElf_Addr relaaddr)
+{
+ DSO *dso;
+ GElf_Addr value;
+
+ if (GELF_R_TYPE (rela->r_info) == R_386_RELATIVE
+ || GELF_R_TYPE (rela->r_info) == R_386_IRELATIVE
+ || GELF_R_TYPE (rela->r_info) == R_386_NONE)
+ /* Fast path: nothing to do. */
+ return 0;
+ dso = info->dso;
+ value = info->resolve (info, GELF_R_SYM (rela->r_info),
+ GELF_R_TYPE (rela->r_info));
+ switch (GELF_R_TYPE (rela->r_info))
+ {
+ case R_386_GLOB_DAT:
+ case R_386_JMP_SLOT:
+ write_le32 (dso, rela->r_offset, value + rela->r_addend);
+ break;
+ case R_386_32:
+ write_le32 (dso, rela->r_offset, value + rela->r_addend);
+ break;
+ case R_386_PC32:
+ write_le32 (dso, rela->r_offset, value + rela->r_addend - rela->r_offset);
+ break;
+ case R_386_TLS_DTPOFF32:
+ write_le32 (dso, rela->r_offset, value + rela->r_addend);
+ break;
+ /* DTPMOD32 and TPOFF{32,} is impossible to predict unless prelink
+ sets the rules. */
+ case R_386_TLS_DTPMOD32:
+ if (dso->ehdr.e_type == ET_EXEC)
+ {
+ error (0, 0, "%s: R_386_TLS_DTPMOD32 reloc in executable?",
+ dso->filename);
+ return 1;
+ }
+ break;
+ case R_386_TLS_TPOFF32:
+ if (dso->ehdr.e_type == ET_EXEC && info->resolvetls)
+ write_le32 (dso, rela->r_offset,
+ -(value + rela->r_addend - info->resolvetls->offset));
+ break;
+ case R_386_TLS_TPOFF:
+ if (dso->ehdr.e_type == ET_EXEC && info->resolvetls)
+ write_le32 (dso, rela->r_offset,
+ value + rela->r_addend - info->resolvetls->offset);
+ break;
+ case R_386_COPY:
+ if (dso->ehdr.e_type == ET_EXEC)
+ /* COPY relocs are handled specially in generic code. */
+ return 0;
+ error (0, 0, "%s: R_386_COPY reloc in shared library?", dso->filename);
+ return 1;
+ default:
+ error (0, 0, "%s: Unknown i386 relocation type %d", dso->filename,
+ (int) GELF_R_TYPE (rela->r_info));
+ return 1;
+ }
+ return 0;
+}
+
+static int
+i386_apply_conflict_rela (struct prelink_info *info, GElf_Rela *rela,
+ char *buf, GElf_Addr dest_addr)
+{
+ GElf_Rela *ret;
+
+ switch (GELF_R_TYPE (rela->r_info))
+ {
+ case R_386_GLOB_DAT:
+ case R_386_JMP_SLOT:
+ case R_386_32:
+ buf_write_le32 (buf, rela->r_addend);
+ break;
+ case R_386_IRELATIVE:
+ if (dest_addr == 0)
+ return 5;
+ ret = prelink_conflict_add_rela (info);
+ if (ret == NULL)
+ return 1;
+ ret->r_offset = dest_addr;
+ ret->r_info = GELF_R_INFO (0, R_386_IRELATIVE);
+ ret->r_addend = rela->r_addend;
+ break;
+ default:
+ abort ();
+ }
+ return 0;
+}
+
+static int
+i386_apply_rel (struct prelink_info *info, GElf_Rel *rel, char *buf)
+{
+ GElf_Addr value;
+
+ value = info->resolve (info, GELF_R_SYM (rel->r_info),
+ GELF_R_TYPE (rel->r_info));
+ switch (GELF_R_TYPE (rel->r_info))
+ {
+ case R_386_NONE:
+ break;
+ case R_386_GLOB_DAT:
+ case R_386_JMP_SLOT:
+ buf_write_le32 (buf, value);
+ break;
+ case R_386_32:
+ buf_write_le32 (buf, value + read_ule32 (info->dso, rel->r_offset));
+ break;
+ case R_386_PC32:
+ buf_write_le32 (buf, value + read_ule32 (info->dso, rel->r_offset)
+ - rel->r_offset);
+ break;
+ case R_386_COPY:
+ abort ();
+ case R_386_RELATIVE:
+ error (0, 0, "%s: R_386_RELATIVE in ET_EXEC object?", info->dso->filename);
+ return 1;
+ default:
+ return 1;
+ }
+ return 0;
+}
+
+static int
+i386_apply_rela (struct prelink_info *info, GElf_Rela *rela, char *buf)
+{
+ GElf_Addr value;
+
+ value = info->resolve (info, GELF_R_SYM (rela->r_info),
+ GELF_R_TYPE (rela->r_info));
+ switch (GELF_R_TYPE (rela->r_info))
+ {
+ case R_386_NONE:
+ break;
+ case R_386_GLOB_DAT:
+ case R_386_JMP_SLOT:
+ case R_386_32:
+ buf_write_le32 (buf, value + rela->r_addend);
+ break;
+ case R_386_PC32:
+ buf_write_le32 (buf, value + rela->r_addend - rela->r_offset);
+ break;
+ case R_386_COPY:
+ abort ();
+ case R_386_RELATIVE:
+ error (0, 0, "%s: R_386_RELATIVE in ET_EXEC object?", info->dso->filename);
+ return 1;
+ default:
+ return 1;
+ }
+ return 0;
+}
+
+static int
+i386_prelink_conflict_rel (DSO *dso, struct prelink_info *info, GElf_Rel *rel,
+ GElf_Addr reladdr)
+{
+ GElf_Addr value;
+ struct prelink_conflict *conflict;
+ struct prelink_tls *tls;
+ GElf_Rela *ret;
+
+ if (GELF_R_TYPE (rel->r_info) == R_386_RELATIVE
+ || GELF_R_TYPE (rel->r_info) == R_386_NONE)
+ /* Fast path: nothing to do. */
+ return 0;
+ conflict = prelink_conflict (info, GELF_R_SYM (rel->r_info),
+ GELF_R_TYPE (rel->r_info));
+ if (conflict == NULL)
+ {
+ switch (GELF_R_TYPE (rel->r_info))
+ {
+ /* Even local DTPMOD and TPOFF relocs need conflicts. */
+ case R_386_TLS_DTPMOD32:
+ case R_386_TLS_TPOFF32:
+ case R_386_TLS_TPOFF:
+ if (info->curtls == NULL || info->dso == dso)
+ return 0;
+ break;
+ /* Similarly IRELATIVE relocations always need conflicts. */
+ case R_386_IRELATIVE:
+ break;
+ default:
+ return 0;
+ }
+ value = 0;
+ }
+ else if (info->dso == dso && !conflict->ifunc)
+ return 0;
+ else
+ {
+ /* DTPOFF32 wants to see only real conflicts, not lookups
+ with reloc_class RTYPE_CLASS_TLS. */
+ if (GELF_R_TYPE (rel->r_info) == R_386_TLS_DTPOFF32
+ && conflict->lookup.tls == conflict->conflict.tls
+ && conflict->lookupval == conflict->conflictval)
+ return 0;
+
+ value = conflict_lookup_value (conflict);
+ }
+ ret = prelink_conflict_add_rela (info);
+ if (ret == NULL)
+ return 1;
+ ret->r_offset = rel->r_offset;
+ ret->r_info = GELF_R_INFO (0, GELF_R_TYPE (rel->r_info));
+ switch (GELF_R_TYPE (rel->r_info))
+ {
+ case R_386_GLOB_DAT:
+ ret->r_info = GELF_R_INFO (0, R_386_32);
+ /* FALLTHROUGH */
+ case R_386_JMP_SLOT:
+ ret->r_addend = (Elf32_Sword) value;
+ if (conflict != NULL && conflict->ifunc)
+ ret->r_info = GELF_R_INFO (0, R_386_IRELATIVE);
+ break;
+ case R_386_IRELATIVE:
+ ret->r_addend = (Elf32_Sword) read_ule32 (dso, rel->r_offset);
+ break;
+ case R_386_32:
+ case R_386_PC32:
+ error (0, 0, "%s: R_386_%s32 relocs should not be present in prelinked REL sections",
+ dso->filename, GELF_R_TYPE (rel->r_info) == R_386_32 ? "" : "PC");
+ return 1;
+ case R_386_TLS_DTPMOD32:
+ case R_386_TLS_DTPOFF32:
+ case R_386_TLS_TPOFF32:
+ case R_386_TLS_TPOFF:
+ if (conflict != NULL
+ && (conflict->reloc_class != RTYPE_CLASS_TLS
+ || conflict->lookup.tls == NULL))
+ {
+ error (0, 0, "%s: R_386_TLS not resolving to STT_TLS symbol",
+ dso->filename);
+ return 1;
+ }
+ tls = conflict ? conflict->lookup.tls : info->curtls;
+ ret->r_info = GELF_R_INFO (0, R_386_32);
+ switch (GELF_R_TYPE (rel->r_info))
+ {
+ case R_386_TLS_DTPMOD32:
+ ret->r_addend = tls->modid;
+ break;
+ case R_386_TLS_DTPOFF32:
+ ret->r_addend = value;
+ break;
+ case R_386_TLS_TPOFF32:
+ ret->r_addend = -(value + read_ule32 (dso, rel->r_offset)
+ - tls->offset);
+ break;
+ case R_386_TLS_TPOFF:
+ ret->r_addend = value + read_ule32 (dso, rel->r_offset)
+ - tls->offset;
+ }
+ break;
+ case R_386_COPY:
+ error (0, 0, "R_386_COPY should not be present in shared libraries");
+ return 1;
+ default:
+ error (0, 0, "%s: Unknown i386 relocation type %d", dso->filename,
+ (int) GELF_R_TYPE (rel->r_info));
+ return 1;
+ }
+ return 0;
+}
+
+static int
+i386_prelink_conflict_rela (DSO *dso, struct prelink_info *info,
+ GElf_Rela *rela, GElf_Addr relaaddr)
+{
+ GElf_Addr value;
+ struct prelink_conflict *conflict;
+ struct prelink_tls *tls;
+ GElf_Rela *ret;
+
+ if (GELF_R_TYPE (rela->r_info) == R_386_RELATIVE
+ || GELF_R_TYPE (rela->r_info) == R_386_NONE)
+ /* Fast path: nothing to do. */
+ return 0;
+ conflict = prelink_conflict (info, GELF_R_SYM (rela->r_info),
+ GELF_R_TYPE (rela->r_info));
+ if (conflict == NULL)
+ {
+ switch (GELF_R_TYPE (rela->r_info))
+ {
+ /* Even local DTPMOD and TPOFF relocs need conflicts. */
+ case R_386_TLS_DTPMOD32:
+ case R_386_TLS_TPOFF32:
+ case R_386_TLS_TPOFF:
+ if (info->curtls == NULL || info->dso == dso)
+ return 0;
+ break;
+ /* Similarly IRELATIVE relocations always need conflicts. */
+ case R_386_IRELATIVE:
+ break;
+ default:
+ return 0;
+ }
+ value = 0;
+ }
+ else if (info->dso == dso && !conflict->ifunc)
+ return 0;
+ else
+ {
+ /* DTPOFF32 wants to see only real conflicts, not lookups
+ with reloc_class RTYPE_CLASS_TLS. */
+ if (GELF_R_TYPE (rela->r_info) == R_386_TLS_DTPOFF32
+ && conflict->lookup.tls == conflict->conflict.tls
+ && conflict->lookupval == conflict->conflictval)
+ return 0;
+
+ value = conflict_lookup_value (conflict);
+ }
+ ret = prelink_conflict_add_rela (info);
+ if (ret == NULL)
+ return 1;
+ ret->r_offset = rela->r_offset;
+ ret->r_info = GELF_R_INFO (0, GELF_R_TYPE (rela->r_info));
+ switch (GELF_R_TYPE (rela->r_info))
+ {
+ case R_386_GLOB_DAT:
+ ret->r_info = GELF_R_INFO (0, R_386_32);
+ /* FALLTHROUGH */
+ case R_386_JMP_SLOT:
+ case R_386_IRELATIVE:
+ ret->r_addend = (Elf32_Sword) (value + rela->r_addend);
+ if (conflict != NULL && conflict->ifunc)
+ ret->r_info = GELF_R_INFO (0, R_386_IRELATIVE);
+ break;
+ case R_386_32:
+ value += rela->r_addend;
+ ret->r_addend = (Elf32_Sword) value;
+ if (conflict != NULL && conflict->ifunc)
+ ret->r_info = GELF_R_INFO (0, R_386_IRELATIVE);
+ break;
+ case R_386_PC32:
+ ret->r_addend = (Elf32_Sword) (value + rela->r_addend - rela->r_offset);
+ ret->r_info = GELF_R_INFO (0, R_386_32);
+ break;
+ case R_386_COPY:
+ error (0, 0, "R_386_COPY should not be present in shared libraries");
+ return 1;
+ case R_386_TLS_DTPMOD32:
+ case R_386_TLS_DTPOFF32:
+ case R_386_TLS_TPOFF32:
+ case R_386_TLS_TPOFF:
+ if (conflict != NULL
+ && (conflict->reloc_class != RTYPE_CLASS_TLS
+ || conflict->lookup.tls == NULL))
+ {
+ error (0, 0, "%s: R_386_TLS not resolving to STT_TLS symbol",
+ dso->filename);
+ return 1;
+ }
+ tls = conflict ? conflict->lookup.tls : info->curtls;
+ ret->r_info = GELF_R_INFO (0, R_386_32);
+ switch (GELF_R_TYPE (rela->r_info))
+ {
+ case R_386_TLS_DTPMOD32:
+ ret->r_addend = tls->modid;
+ break;
+ case R_386_TLS_DTPOFF32:
+ ret->r_addend += value;
+ break;
+ case R_386_TLS_TPOFF32:
+ ret->r_addend = -(value + rela->r_addend - tls->offset);
+ break;
+ case R_386_TLS_TPOFF:
+ ret->r_addend = value + rela->r_addend - tls->offset;
+ break;
+ }
+ break;
+ default:
+ error (0, 0, "%s: Unknown i386 relocation type %d", dso->filename,
+ (int) GELF_R_TYPE (rela->r_info));
+ return 1;
+ }
+ return 0;
+}
+
+static int
+i386_rel_to_rela (DSO *dso, GElf_Rel *rel, GElf_Rela *rela)
+{
+ rela->r_offset = rel->r_offset;
+ rela->r_info = rel->r_info;
+ switch (GELF_R_TYPE (rel->r_info))
+ {
+ case R_386_JMP_SLOT:
+ /* We should be never converting .rel.plt into .rela.plt. */
+ abort ();
+ case R_386_RELATIVE:
+ case R_386_IRELATIVE:
+ case R_386_32:
+ case R_386_PC32:
+ case R_386_TLS_TPOFF32:
+ case R_386_TLS_TPOFF:
+ rela->r_addend = (Elf32_Sword) read_ule32 (dso, rel->r_offset);
+ break;
+ case R_386_COPY:
+ case R_386_GLOB_DAT:
+ case R_386_TLS_DTPOFF32:
+ case R_386_TLS_DTPMOD32:
+ rela->r_addend = 0;
+ break;
+ }
+ return 0;
+}
+
+static int
+i386_need_rel_to_rela (DSO *dso, int first, int last)
+{
+ Elf_Data *data;
+ Elf_Scn *scn;
+ Elf32_Rel *rel, *relend;
+ unsigned int val;
+
+ while (first <= last)
+ {
+ data = NULL;
+ scn = dso->scn[first++];
+ while ((data = elf_getdata (scn, data)) != NULL)
+ {
+ rel = (Elf32_Rel *) data->d_buf;
+ relend = rel + data->d_size / sizeof (Elf32_Rel);
+ for (; rel < relend; rel++)
+ switch (ELF32_R_TYPE (rel->r_info))
+ {
+ case R_386_32:
+ val = read_ule32 (dso, rel->r_offset);
+ /* R_386_32 with addend 0 can be converted
+ to R_386_GLOB_DAT and we don't have to convert
+ to RELA because of that. */
+ if (val == 0)
+ break;
+ /* FALLTHROUGH */
+ case R_386_PC32:
+ return 1;
+ case R_386_TLS_TPOFF32:
+ case R_386_TLS_TPOFF:
+ /* In shared libraries TPOFF is changed always into
+ conflicts, for executables we need to preserve
+ original addend. */
+ if (dso->ehdr.e_type == ET_EXEC)
+ return 1;
+ break;
+ }
+ }
+ }
+ return 0;
+}
+
+static int
+i386_arch_prelink (struct prelink_info *info)
+{
+ DSO *dso;
+ int i;
+
+ dso = info->dso;
+ if (dso->info[DT_PLTGOT])
+ {
+ /* Write address of .plt + 0x16 into got[1].
+ .plt + 0x16 is what got[3] contains unless prelinking. */
+ int sec = addr_to_sec (dso, dso->info[DT_PLTGOT]);
+ Elf32_Addr data;
+
+ if (sec == -1)
+ return 1;
+
+ for (i = 1; i < dso->ehdr.e_shnum; i++)
+ if (dso->shdr[i].sh_type == SHT_PROGBITS
+ && ! strcmp (strptr (dso, dso->ehdr.e_shstrndx,
+ dso->shdr[i].sh_name),
+ ".plt"))
+ break;
+
+ if (i == dso->ehdr.e_shnum)
+ return 0;
+ data = dso->shdr[i].sh_addr + 0x16;
+ write_le32 (dso, dso->info[DT_PLTGOT] + 4, data);
+ }
+
+ return 0;
+}
+
+static int
+i386_arch_undo_prelink (DSO *dso)
+{
+ int i;
+
+ if (dso->info[DT_PLTGOT])
+ {
+ /* Clear got[1] if it contains address of .plt + 0x16. */
+ int sec = addr_to_sec (dso, dso->info[DT_PLTGOT]);
+ Elf32_Addr data;
+
+ if (sec == -1)
+ return 1;
+
+ for (i = 1; i < dso->ehdr.e_shnum; i++)
+ if (dso->shdr[i].sh_type == SHT_PROGBITS
+ && ! strcmp (strptr (dso, dso->ehdr.e_shstrndx,
+ dso->shdr[i].sh_name),
+ ".plt"))
+ break;
+
+ if (i == dso->ehdr.e_shnum)
+ return 0;
+ data = read_ule32 (dso, dso->info[DT_PLTGOT] + 4);
+ if (data == dso->shdr[i].sh_addr + 0x16)
+ write_le32 (dso, dso->info[DT_PLTGOT] + 4, 0);
+ }
+
+ return 0;
+}
+
+static int
+i386_undo_prelink_rel (DSO *dso, GElf_Rel *rel, GElf_Addr reladdr)
+{
+ int sec;
+ const char *name;
+
+ switch (GELF_R_TYPE (rel->r_info))
+ {
+ case R_386_NONE:
+ case R_386_RELATIVE:
+ case R_386_IRELATIVE:
+ break;
+ case R_386_JMP_SLOT:
+ sec = addr_to_sec (dso, rel->r_offset);
+ name = strptr (dso, dso->ehdr.e_shstrndx, dso->shdr[sec].sh_name);
+ if (sec == -1 || (strcmp (name, ".got") && strcmp (name, ".got.plt")))
+ {
+ error (0, 0, "%s: R_386_JMP_SLOT not pointing into .got section",
+ dso->filename);
+ return 1;
+ }
+ else
+ {
+ Elf32_Addr data = read_ule32 (dso, dso->shdr[sec].sh_addr + 4);
+
+ assert (rel->r_offset >= dso->shdr[sec].sh_addr + 12);
+ assert (((rel->r_offset - dso->shdr[sec].sh_addr) & 3) == 0);
+ write_le32 (dso, rel->r_offset,
+ 4 * (rel->r_offset - dso->shdr[sec].sh_addr - 12)
+ + data);
+ }
+ break;
+ case R_386_GLOB_DAT:
+ sec = addr_to_sec (dso, rel->r_offset);
+
+ write_le32 (dso, rel->r_offset, 0);
+ if (sec != -1)
+ {
+ if (strcmp (strptr (dso, dso->ehdr.e_shstrndx,
+ dso->shdr[sec].sh_name),
+ ".got"))
+ {
+ rel->r_info = GELF_R_INFO (GELF_R_SYM (rel->r_info), R_386_32);
+ return 2;
+ }
+ }
+ break;
+ case R_386_32:
+ case R_386_PC32:
+ error (0, 0, "%s: R_386_%s32 relocs should not be present in prelinked REL sections",
+ GELF_R_TYPE (rel->r_info) == R_386_32 ? "" : "PC", dso->filename);
+ return 1;
+ case R_386_COPY:
+ if (dso->ehdr.e_type == ET_EXEC)
+ /* COPY relocs are handled specially in generic code. */
+ return 0;
+ error (0, 0, "%s: R_386_COPY reloc in shared library?", dso->filename);
+ return 1;
+ case R_386_TLS_DTPMOD32:
+ case R_386_TLS_DTPOFF32:
+ write_le32 (dso, rel->r_offset, 0);
+ break;
+ case R_386_TLS_TPOFF32:
+ case R_386_TLS_TPOFF:
+ break;
+ default:
+ error (0, 0, "%s: Unknown i386 relocation type %d", dso->filename,
+ (int) GELF_R_TYPE (rel->r_info));
+ return 1;
+ }
+ return 0;
+}
+
+static int
+i386_rela_to_rel (DSO *dso, GElf_Rela *rela, GElf_Rel *rel)
+{
+ rel->r_offset = rela->r_offset;
+ rel->r_info = rela->r_info;
+ switch (GELF_R_TYPE (rel->r_info))
+ {
+ case R_386_JMP_SLOT:
+ /* We should be never converting .rel.plt into .rela.plt
+ and thus never .rela.plt back to .rel.plt. */
+ abort ();
+ case R_386_RELATIVE:
+ case R_386_IRELATIVE:
+ case R_386_32:
+ case R_386_PC32:
+ case R_386_TLS_TPOFF32:
+ case R_386_TLS_TPOFF:
+ write_le32 (dso, rela->r_offset, rela->r_addend);
+ break;
+ case R_386_COPY:
+ case R_386_GLOB_DAT:
+ case R_386_TLS_DTPMOD32:
+ case R_386_TLS_DTPOFF32:
+ write_le32 (dso, rela->r_offset, 0);
+ break;
+ }
+ return 0;
+}
+
+static int
+i386_reloc_size (int reloc_type)
+{
+ assert (reloc_type != R_386_COPY);
+ return 4;
+}
+
+static int
+i386_reloc_class (int reloc_type)
+{
+ switch (reloc_type)
+ {
+ case R_386_COPY: return RTYPE_CLASS_COPY;
+ case R_386_JMP_SLOT: return RTYPE_CLASS_PLT;
+ case R_386_TLS_DTPMOD32:
+ case R_386_TLS_DTPOFF32:
+ case R_386_TLS_TPOFF32:
+ case R_386_TLS_TPOFF:
+ return RTYPE_CLASS_TLS;
+ default: return RTYPE_CLASS_VALID;
+ }
+}
+
+/* Library memory regions if --exec-shield in order of precedence:
+ 0x00101000 + (rand % 0x00cff000) .. 0x00e00000 bottom to top
+ 0x00101000 .. 0x00101000 + (rand % 0x00cff000) bottom to top
+ 0x02000000 + (rand % 0x06000000) .. 0x08000000 bottom to top
+ 0x02000000 .. 0x02000000 + (rand % 0x06000000) bottom to top
+ 0x41000000 + (rand % 0x0f000000) .. 0x50000000 bottom to top
+ 0x41000000 .. 0x41000000 + (rand % 0x0f000000) bottom to top */
+
+#define REG0S 0x00101000
+#define REG0E 0x00e00000
+#define REG1S 0x02000000
+#define REG1E 0x08000000
+#define REG2S 0x41000000
+#define REG2E 0x50000000
+
+struct i386_layout_data
+{
+ struct prelink_entry e[6];
+ Elf32_Addr addrs[12];
+};
+
+static inline void
+list_append (struct prelink_entry *x, struct prelink_entry *e)
+{
+ x->prev->next = e;
+ e->prev = x->prev;
+ e->next = NULL;
+ x->prev = e;
+}
+
+static inline void
+list_merge (struct prelink_entry *x, struct prelink_entry *e)
+{
+ struct prelink_entry *end = e->prev;
+ x->prev->next = e;
+ e->prev = x->prev;
+ x->prev = end;
+}
+
+static int
+i386_layout_libs_init (struct layout_libs *l)
+{
+ if (exec_shield)
+ {
+ int i;
+ struct prelink_entry *e;
+ Elf32_Addr reg0s;
+
+ if (l->max_page_size > 0x200000)
+ error (EXIT_FAILURE, 0, "--layout-page-size too large");
+
+ reg0s = (REG0S + l->max_page_size - 1) & ~(l->max_page_size - 1);
+ l->mmap_base = reg0s;
+ l->mmap_end = REG2E;
+ /* Don't allow this to be overridden. */
+ mmap_reg_start = ~(GElf_Addr) 0;
+ mmap_reg_end = ~(GElf_Addr) 0;
+ for (i = 0; i < l->nlibs; ++i)
+ {
+ e = l->libs[i];
+ if (e->done == 0)
+ continue;
+ if (e->base < reg0s
+ || (e->base < REG1S && e->layend > REG0E)
+ || (e->base < REG2S && e->layend > REG1E)
+ || e->layend > REG2E)
+ e->done = 0;
+ }
+ }
+ else
+ {
+ l->mmap_base = REG2S;
+ l->mmap_end = REG2E;
+ }
+ return 0;
+}
+
+static void
+i386_find_free_addr (struct layout_libs *l, Elf32_Addr *ret,
+ Elf32_Addr beg, Elf32_Addr end, Elf32_Addr start)
+{
+ struct prelink_entry *e;
+ Elf32_Addr low, hi;
+
+ ret[0] = beg;
+ ret[3] = end;
+ for (e = l->list; e != NULL; e = e->next)
+ if (e->base >= start)
+ break;
+ if (e == l->list)
+ {
+ ret[1] = ret[2] = start;
+ return;
+ }
+
+ if (e == NULL)
+ e = l->list;
+ low = start;
+ for (e = e->prev; ; e = e->prev)
+ {
+ if (e->base < beg)
+ break;
+ if (e->layend > low)
+ low = e->base;
+ if (e == l->list)
+ break;
+ }
+
+ if (low == start)
+ {
+ ret[1] = ret[2] = start;
+ return;
+ }
+
+ hi = start;
+ for (; e; e = e->next)
+ {
+ if (e->base >= end)
+ break;
+ if (e->base >= hi)
+ break;
+ if (e->layend > hi)
+ hi = e->layend;
+ }
+
+ assert (low >= beg && hi <= end);
+
+ if (hi - start > start - low)
+ start = low;
+ else
+ start = hi;
+
+ ret[1] = ret[2] = start;
+}
+
+static int
+i386_layout_libs_pre (struct layout_libs *l)
+{
+ Elf32_Addr mmap_start, virt, reg0s;
+ struct prelink_entry *e, *next;
+ struct i386_layout_data *pld;
+ int i;
+
+ if (!exec_shield)
+ {
+ l->mmap_fin = l->mmap_end;
+ l->fake = NULL;
+ l->fakecnt = 0;
+ return 0;
+ }
+
+ pld = calloc (sizeof (*pld), 1);
+ if (pld == NULL)
+ error (EXIT_FAILURE, ENOMEM, "Cannot lay libraries out");
+
+ l->arch_data = pld;
+ reg0s = (REG0S + l->max_page_size - 1) & ~(l->max_page_size - 1);
+
+ mmap_start = l->mmap_start - reg0s;
+ /* Unless not randomizing, try not to make the first region
+ too small, because otherwise it is likely libc.so as first
+ big library would often end up at reg0s. */
+ virt = mmap_start % (REG0E - reg0s - 0x200000);
+ i386_find_free_addr (l, pld->addrs + 0, reg0s, REG0E, reg0s + virt);
+ virt = mmap_start % (REG1E - REG1S - 0x200000);
+ i386_find_free_addr (l, pld->addrs + 4, REG1S, REG1E, REG1S + virt);
+ virt = mmap_start % (REG2E - REG2S - 0x200000);
+ i386_find_free_addr (l, pld->addrs + 8, REG2S, REG2E, REG2S + virt);
+ i = 0;
+ virt = pld->addrs[3] - pld->addrs[2];
+ pld->e[0].u.tmp = -1;
+ pld->e[0].base = virt;
+ pld->e[0].end = pld->e[0].base;
+ pld->e[0].layend = pld->e[0].end;
+ pld->e[0].prev = &pld->e[0];
+ next = NULL;
+ for (e = l->list; e != NULL; e = next)
+ {
+ next = e->next;
+ while (i < 5
+ && (e->base >= pld->addrs[2 * i + 1]
+ || pld->addrs[2 * i] == pld->addrs[2 * i + 1]))
+ {
+ ++i;
+ pld->e[i].u.tmp = -1;
+ if (i & 1)
+ virt -= pld->addrs[2 * i + 1] - pld->addrs[2 * i];
+ else
+ {
+ virt += pld->addrs[2 * i - 1] - pld->addrs[2 * i - 4];
+ virt += pld->addrs[2 * i + 3] - pld->addrs[2 * i + 2];
+ }
+ pld->e[i].base = virt;
+ pld->e[i].end = pld->e[i].base;
+ pld->e[i].layend = pld->e[i].end;
+ pld->e[i].prev = &pld->e[i];
+ }
+ e->base += (Elf32_Sword) (virt - pld->addrs[2 * i]);
+ e->end += (Elf32_Sword) (virt - pld->addrs[2 * i]);
+ e->layend += (Elf32_Sword) (virt - pld->addrs[2 * i]);
+ list_append (&pld->e[i], e);
+ }
+ while (i < 5)
+ {
+ ++i;
+ pld->e[i].u.tmp = -1;
+ if (i & 1)
+ virt -= pld->addrs[2 * i + 1] - pld->addrs[2 * i];
+ else
+ {
+ virt += pld->addrs[2 * i - 1] - pld->addrs[2 * i - 4];
+ virt += pld->addrs[2 * i + 3] - pld->addrs[2 * i + 2];
+ }
+ pld->e[i].base = virt;
+ pld->e[i].end = pld->e[i].base;
+ pld->e[i].layend = pld->e[i].end;
+ pld->e[i].prev = &pld->e[i];
+ }
+ l->list = &pld->e[1];
+ list_merge (&pld->e[1], &pld->e[0]);
+ list_merge (&pld->e[1], &pld->e[3]);
+ list_merge (&pld->e[1], &pld->e[2]);
+ list_merge (&pld->e[1], &pld->e[5]);
+ list_merge (&pld->e[1], &pld->e[4]);
+
+ l->mmap_start = 0;
+ l->mmap_base = 0;
+ l->mmap_fin = virt + pld->addrs[2 * i + 1] - pld->addrs[2 * i];
+ l->mmap_end = l->mmap_fin;
+ l->fakecnt = 6;
+ l->fake = pld->e;
+
+ return 0;
+}
+
+static int
+i386_layout_libs_post (struct layout_libs *l)
+{
+ struct prelink_entry *e;
+ struct i386_layout_data *pld = (struct i386_layout_data *) l->arch_data;
+ Elf32_Sword adj = 0;
+ int i;
+
+ if (!exec_shield)
+ return 0;
+
+ for (i = 0, e = l->list; e != NULL; e = e->next)
+ {
+ if (e == &pld->e[i ^ 1])
+ {
+ adj = pld->addrs[2 * (i ^ 1)] - e->base;
+ ++i;
+ }
+ else
+ {
+ e->base += adj;
+ e->end += adj;
+ e->layend += adj;
+ }
+ }
+
+ free (l->arch_data);
+ return 0;
+}
+
+PL_ARCH(i386) = {
+ .name = "i386",
+ .class = ELFCLASS32,
+ .machine = EM_386,
+ .alternate_machine = { EM_NONE },
+ .R_JMP_SLOT = R_386_JMP_SLOT,
+ .R_COPY = R_386_COPY,
+ .R_RELATIVE = R_386_RELATIVE,
+ .rtype_class_valid = RTYPE_CLASS_VALID,
+ .dynamic_linker = "/lib/ld-linux.so.2",
+ .adjust_dyn = i386_adjust_dyn,
+ .adjust_rel = i386_adjust_rel,
+ .adjust_rela = i386_adjust_rela,
+ .prelink_rel = i386_prelink_rel,
+ .prelink_rela = i386_prelink_rela,
+ .prelink_conflict_rel = i386_prelink_conflict_rel,
+ .prelink_conflict_rela = i386_prelink_conflict_rela,
+ .apply_conflict_rela = i386_apply_conflict_rela,
+ .apply_rel = i386_apply_rel,
+ .apply_rela = i386_apply_rela,
+ .rel_to_rela = i386_rel_to_rela,
+ .rela_to_rel = i386_rela_to_rel,
+ .need_rel_to_rela = i386_need_rel_to_rela,
+ .reloc_size = i386_reloc_size,
+ .reloc_class = i386_reloc_class,
+ .max_reloc_size = 4,
+ .arch_prelink = i386_arch_prelink,
+ .arch_undo_prelink = i386_arch_undo_prelink,
+ .undo_prelink_rel = i386_undo_prelink_rel,
+ .layout_libs_init = i386_layout_libs_init,
+ .layout_libs_pre = i386_layout_libs_pre,
+ .layout_libs_post = i386_layout_libs_post,
+ /* Although TASK_UNMAPPED_BASE is 0x40000000, we leave some
+ area so that mmap of /etc/ld.so.cache and ld.so's malloc
+ does not take some library's VA slot.
+ Also, if this guard area isn't too small, typically
+ even dlopened libraries will get the slots they desire. */
+ .mmap_base = REG2S,
+ .mmap_end = REG2E,
+ .max_page_size = 0x1000,
+ .page_size = 0x1000
+};
diff --git a/src/arch-ia64.c b/src/arch-ia64.c
new file mode 100644
index 0000000..6039115
--- /dev/null
+++ b/src/arch-ia64.c
@@ -0,0 +1,533 @@
+/* Copyright (C) 2001, 2002, 2003, 2004, 2009 Red Hat, Inc.
+ Written by Jakub Jelinek <jakub@redhat.com>, 2001.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include <config.h>
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <locale.h>
+#include <error.h>
+#include <argp.h>
+#include <stdlib.h>
+
+#include "prelink.h"
+#include "fptr.h"
+
+static int
+ia64_adjust_dyn (DSO *dso, int n, GElf_Dyn *dyn, GElf_Addr start,
+ GElf_Addr adjust)
+{
+ if (dyn->d_tag == DT_IA_64_PLT_RESERVE)
+ {
+ int sec = addr_to_sec (dso, dyn->d_un.d_ptr);
+ Elf64_Addr data;
+
+ if (sec != -1)
+ {
+ data = read_ule64 (dso, dyn->d_un.d_ptr + 8);
+
+ /* If .got[1] points to .plt + 0x30, it needs to be adjusted. */
+ if (data && data >= start)
+ {
+ int i;
+
+ for (i = 1; i < dso->ehdr.e_shnum; i++)
+ if (data == dso->shdr[i].sh_addr + 0x30
+ && dso->shdr[i].sh_type == SHT_PROGBITS
+ && strcmp (strptr (dso, dso->ehdr.e_shstrndx,
+ dso->shdr[i].sh_name), ".plt") == 0)
+ {
+ write_le64 (dso, dyn->d_un.d_ptr + 8, data + adjust);
+ break;
+ }
+ }
+ }
+
+ if (dyn->d_un.d_ptr >= start)
+ dyn->d_un.d_ptr += adjust;
+ return 1;
+ }
+
+ return 0;
+}
+
+static int
+ia64_adjust_rel (DSO *dso, GElf_Rel *rel, GElf_Addr start,
+ GElf_Addr adjust)
+{
+ error (0, 0, "%s: IA-64 doesn't support REL relocs", dso->filename);
+ return 1;
+}
+
+static int
+ia64_adjust_rela (DSO *dso, GElf_Rela *rela, GElf_Addr start,
+ GElf_Addr adjust)
+{
+ if ((GELF_R_TYPE (rela->r_info) & ~3) == R_IA64_REL32MSB
+ && rela->r_addend >= start)
+ {
+ rela->r_addend += adjust;
+ switch (GELF_R_TYPE (rela->r_info) & 3)
+ {
+ case 0: write_be32 (dso, rela->r_offset, rela->r_addend); break;
+ case 1: write_le32 (dso, rela->r_offset, rela->r_addend); break;
+ case 2: write_be64 (dso, rela->r_offset, rela->r_addend); break;
+ case 3: write_le64 (dso, rela->r_offset, rela->r_addend); break;
+ }
+ }
+ else if ((GELF_R_TYPE (rela->r_info) & ~1) == R_IA64_IPLTMSB)
+ {
+ GElf_Addr val, gp;
+
+ if (GELF_R_TYPE (rela->r_info) & 1)
+ {
+ val = read_ule64 (dso, rela->r_offset);
+ gp = read_ule64 (dso, rela->r_offset + 8);
+ }
+ else
+ {
+ val = read_ube64 (dso, rela->r_offset);
+ gp = read_ube64 (dso, rela->r_offset + 8);
+ }
+ if (gp == dso->info[DT_PLTGOT])
+ {
+ if (val >= start)
+ val += adjust;
+ if (gp >= start)
+ gp += adjust;
+ }
+ if (GELF_R_TYPE (rela->r_info) & 1)
+ {
+ write_le64 (dso, rela->r_offset, val);
+ write_le64 (dso, rela->r_offset + 8, gp);
+ }
+ else
+ {
+ write_le64 (dso, rela->r_offset, val);
+ write_le64 (dso, rela->r_offset + 8, gp);
+ }
+ }
+ return 0;
+}
+
+static int
+ia64_prelink_rel (struct prelink_info *info, GElf_Rel *rel, GElf_Addr reladdr)
+{
+ error (0, 0, "%s: IA-64 doesn't support REL relocs", info->dso->filename);
+ return 1;
+}
+
+static int
+ia64_prelink_rela (struct prelink_info *info, GElf_Rela *rela,
+ GElf_Addr relaaddr)
+{
+ DSO *dso;
+ GElf_Addr value;
+
+ if ((GELF_R_TYPE (rela->r_info) & ~3) == R_IA64_REL32MSB
+ || GELF_R_TYPE (rela->r_info) == R_IA64_NONE)
+ /* Fast path: nothing to do. */
+ return 0;
+ dso = info->dso;
+ value = info->resolve (info, GELF_R_SYM (rela->r_info),
+ GELF_R_TYPE (rela->r_info));
+ value += rela->r_addend;
+ if ((GELF_R_TYPE (rela->r_info) & ~3) == R_IA64_DIR32MSB)
+ {
+ /* Nothing to do. */
+ }
+ else if ((GELF_R_TYPE (rela->r_info) & ~3) == R_IA64_PCREL32MSB)
+ {
+ value -= rela->r_offset & -16;
+ }
+ else if ((GELF_R_TYPE (rela->r_info) & ~3) == R_IA64_FPTR32MSB)
+ {
+ /* FIXME */
+ }
+ else if ((GELF_R_TYPE (rela->r_info) & ~1) == R_IA64_IPLTMSB)
+ {
+ GElf_Addr gp = info->resolveent->pltgot;
+
+ if (GELF_R_TYPE (rela->r_info) & 1)
+ {
+ write_le64 (dso, rela->r_offset, value);
+ write_le64 (dso, rela->r_offset + 8, gp);
+ }
+ else
+ {
+ write_be64 (dso, rela->r_offset, value);
+ write_be64 (dso, rela->r_offset + 8, gp);
+ }
+
+ return 0;
+ }
+ else
+ {
+ error (0, 0, "%s: Unknown ia64 relocation type %d", dso->filename,
+ (int) GELF_R_TYPE (rela->r_info));
+ return 1;
+ }
+
+ switch (GELF_R_TYPE (rela->r_info) & 3)
+ {
+ case 0: write_be32 (dso, rela->r_offset, value); break;
+ case 1: write_le32 (dso, rela->r_offset, value); break;
+ case 2: write_be64 (dso, rela->r_offset, value); break;
+ case 3: write_le64 (dso, rela->r_offset, value); break;
+ }
+ return 0;
+}
+
+static int
+ia64_apply_conflict_rela (struct prelink_info *info, GElf_Rela *rela,
+ char *buf, GElf_Addr dest_addr)
+{
+ if ((GELF_R_TYPE (rela->r_info) & ~1) == R_IA64_IPLTMSB)
+ {
+ GElf_Addr gp = 0;
+ int i;
+
+ for (i = 0; i < info->ent->ndepends; ++i)
+ if (info->ent->depends[i]->base <= rela->r_addend
+ && info->ent->depends[i]->end > rela->r_addend)
+ {
+ gp = info->ent->depends[i]->pltgot;
+ break;
+ }
+
+ if (i == info->ent->ndepends)
+ abort ();
+
+ if (GELF_R_TYPE (rela->r_info) & 1)
+ {
+ buf_write_le64 (buf, rela->r_addend);
+ buf_write_le64 (buf + 8, gp);
+ }
+ else
+ {
+ buf_write_be64 (buf, rela->r_addend);
+ buf_write_be64 (buf + 8, gp);
+ }
+ return 0;
+ }
+
+ switch (GELF_R_TYPE (rela->r_info))
+ {
+ case R_IA64_DIR32MSB: buf_write_be32 (buf, rela->r_addend); break;
+ case R_IA64_DIR32LSB: buf_write_le32 (buf, rela->r_addend); break;
+ case R_IA64_DIR64MSB: buf_write_be64 (buf, rela->r_addend); break;
+ case R_IA64_DIR64LSB: buf_write_le64 (buf, rela->r_addend); break;
+ default:
+ abort ();
+ }
+ return 0;
+}
+
+static int
+ia64_apply_rel (struct prelink_info *info, GElf_Rel *rel, char *buf)
+{
+ error (0, 0, "%s: IA-64 doesn't support REL relocs", info->dso->filename);
+ return 1;
+}
+
+static int
+ia64_apply_rela (struct prelink_info *info, GElf_Rela *rela, char *buf)
+{
+ GElf_Addr value;
+
+ value = info->resolve (info, GELF_R_SYM (rela->r_info),
+ GELF_R_TYPE (rela->r_info));
+ value += rela->r_addend;
+ if ((GELF_R_TYPE (rela->r_info) & ~3) == R_IA64_DIR32MSB)
+ {
+ /* Nothing to do. */
+ }
+ else if ((GELF_R_TYPE (rela->r_info) & ~3) == R_IA64_PCREL32MSB)
+ {
+ value -= rela->r_offset & -16;
+ }
+ else if ((GELF_R_TYPE (rela->r_info) & ~3) == R_IA64_FPTR32MSB)
+ {
+ /* FIXME */
+ }
+ else if ((GELF_R_TYPE (rela->r_info) & ~1) == R_IA64_IPLTMSB)
+ {
+ GElf_Addr gp = info->resolveent->pltgot;
+
+ if (GELF_R_TYPE (rela->r_info) & 1)
+ {
+ buf_write_le64 (buf, value);
+ buf_write_le64 (buf + 8, gp);
+ }
+ else
+ {
+ buf_write_be64 (buf, value);
+ buf_write_be64 (buf + 8, gp);
+ }
+ return 0;
+ }
+ else
+ return 1;
+
+ switch (GELF_R_TYPE (rela->r_info) & 3)
+ {
+ case 0: buf_write_be32 (buf, value); break;
+ case 1: buf_write_le32 (buf, value); break;
+ case 2: buf_write_be64 (buf, value); break;
+ case 3: buf_write_le64 (buf, value); break;
+ }
+ return 0;
+}
+
+static int
+ia64_prelink_conflict_rel (DSO *dso, struct prelink_info *info, GElf_Rel *rel,
+ GElf_Addr reladdr)
+{
+ error (0, 0, "%s: IA-64 doesn't support REL relocs", dso->filename);
+ return 1;
+}
+
+static int
+ia64_prelink_conflict_rela (DSO *dso, struct prelink_info *info,
+ GElf_Rela *rela, GElf_Addr relaaddr)
+{
+ GElf_Addr value;
+ struct prelink_conflict *conflict;
+ GElf_Rela *ret;
+
+ if ((GELF_R_TYPE (rela->r_info) & ~3) == R_IA64_REL32MSB
+ || GELF_R_TYPE (rela->r_info) == R_IA64_NONE
+ || info->dso == dso)
+ /* Fast path: nothing to do. */
+ return 0;
+ conflict = prelink_conflict (info, GELF_R_SYM (rela->r_info),
+ GELF_R_TYPE (rela->r_info));
+ if (conflict == NULL)
+ return 0;
+ else if (conflict->ifunc)
+ {
+ error (0, 0, "%s: STT_GNU_IFUNC not handled on IA-64 yet",
+ dso->filename);
+ return 1;
+ }
+ value = conflict_lookup_value (conflict);
+ ret = prelink_conflict_add_rela (info);
+ if (ret == NULL)
+ return 1;
+ ret->r_offset = rela->r_offset;
+ ret->r_info = GELF_R_INFO (0, GELF_R_TYPE (rela->r_info));
+ if ((GELF_R_TYPE (rela->r_info) & ~3) == R_IA64_DIR32MSB
+ || (GELF_R_TYPE (rela->r_info) & ~1) == R_IA64_IPLTMSB)
+ {
+ ret->r_addend = value + rela->r_addend;
+ return 0;
+ }
+ else if ((GELF_R_TYPE (rela->r_info) & ~3) == R_IA64_PCREL32MSB)
+ {
+ ret->r_addend = value + rela->r_addend - (rela->r_offset & -16);
+ ret->r_info = GELF_R_INFO (0, GELF_R_TYPE (rela->r_info)
+ + R_IA64_DIR32MSB - R_IA64_PCREL32MSB);
+ return 0;
+ }
+ else if (GELF_R_TYPE (rela->r_info) == R_IA64_COPY)
+ {
+ error (0, 0, "R_IA64_COPY should not be present in shared libraries");
+ return 1;
+ }
+ error (0, 0, "%s: Unknown ia64 relocation type %d", dso->filename,
+ (int) GELF_R_TYPE (rela->r_info));
+ return 1;
+}
+
+static int
+ia64_rel_to_rela (DSO *dso, GElf_Rel *rel, GElf_Rela *rela)
+{
+ error (0, 0, "%s: IA-64 doesn't support REL relocs", dso->filename);
+ return 1;
+}
+
+static int
+ia64_need_rel_to_rela (DSO *dso, int first, int last)
+{
+ return 0;
+}
+
+static GElf_Addr
+ia64_create_opd (struct prelink_info *info, int first, int last, int plt)
+{
+ Elf_Data *d;
+ Elf_Scn *scn;
+ Elf64_Rela *rela, *relaend;
+ DSO *dso = info->dso;
+ int sec;
+
+ if (opd_init (info))
+ return -1;
+
+ if (plt)
+ info->ent->opd->plt_start = dso->shdr[dso->shdr[plt].sh_info].sh_addr;
+ else
+ info->ent->opd->plt_start = dso->shdr[dso->dynamic].sh_addr;
+ sec = first;
+ while (sec <= last)
+ {
+ d = NULL;
+ scn = dso->scn[sec++];
+ while ((d = elf_getdata (scn, d)) != NULL)
+ {
+ rela = (Elf64_Rela *) d->d_buf;
+ relaend = rela + d->d_size / sizeof (Elf64_Rela);
+ for (; rela < relaend; rela++)
+ if ((ELF64_R_TYPE (rela->r_info) & ~3) == R_IA64_FPTR32MSB
+ && opd_add (info, ELF64_R_SYM (rela->r_info),
+ R_IA64_FPTR64LSB))
+ return -1;
+ }
+ }
+
+ sec = first;
+ while (sec)
+ {
+ d = NULL;
+ if (sec == plt)
+ break;
+ scn = dso->scn[sec++];
+ if (sec == last + 1)
+ sec = plt;
+ while ((d = elf_getdata (scn, d)) != NULL)
+ {
+ rela = (Elf64_Rela *) d->d_buf;
+ relaend = rela + d->d_size / sizeof (Elf64_Rela);
+ for (; rela < relaend; rela++)
+ if ((ELF64_R_TYPE (rela->r_info) & ~1) == R_IA64_IPLTMSB)
+ opd_note_plt (info, ELF64_R_SYM (rela->r_info), R_IA64_IPLTLSB,
+ rela->r_offset);
+ }
+ }
+
+ return opd_size (info, 16);
+}
+
+static int
+ia64_arch_prelink (struct prelink_info *info)
+{
+ DSO *dso;
+ int plt = -1, got = -1, i;
+ const char *name;
+
+ /* Write address of .plt + 0x30 into .got[1].
+ .plt + 0x30 is what .IA_64.pltoff[0] contains unless prelinking. */
+
+ dso = info->dso;
+ for (i = 1; i < dso->ehdr.e_shnum; i++)
+ if (dso->shdr[i].sh_type == SHT_PROGBITS)
+ {
+ name = strptr (dso, dso->ehdr.e_shstrndx, dso->shdr[i].sh_name);
+ if (! strcmp (name, ".got"))
+ {
+ if (got != -1)
+ {
+ error (0, 0, "%s: More than one .got section", dso->filename);
+ return 1;
+ }
+ got = i;
+ }
+ else if (! strcmp (name, ".plt"))
+ {
+ if (plt != -1)
+ {
+ error (0, 0, "%s: More than one .plt section", dso->filename);
+ return 1;
+ }
+ plt = i;
+ }
+ }
+
+ if (plt == -1)
+ return 0;
+
+ if (got == -1)
+ {
+ error (0, 0, "%s: Has .plt section but not .got section", dso->filename);
+ return 1;
+ }
+
+ write_le64 (dso, dso->shdr[got].sh_addr + 8, dso->shdr[plt].sh_addr + 0x30);
+ return 0;
+}
+
+static int
+ia64_reloc_size (int reloc_type)
+{
+ if ((reloc_type & ~1) == R_IA64_IPLTMSB)
+ return 16;
+ return (reloc_type & 2) ? 8 : 4;
+}
+
+static int
+ia64_reloc_class (int reloc_type)
+{
+ switch (reloc_type)
+ {
+ case R_IA64_IPLTLSB:
+ case R_IA64_IPLTMSB:
+ return RTYPE_CLASS_PLT;
+ default: return RTYPE_CLASS_VALID;
+ }
+}
+
+PL_ARCH(ia64) = {
+ .name = "IA-64",
+ .class = ELFCLASS64,
+ .machine = EM_IA_64,
+ .alternate_machine = { EM_NONE },
+ .R_JMP_SLOT = R_IA64_IPLTLSB,
+ .R_COPY = -1,
+ .R_RELATIVE = R_IA64_REL64LSB,
+ .rtype_class_valid = RTYPE_CLASS_VALID,
+ .dynamic_linker = "/lib/ld-linux-ia64.so.2",
+ .adjust_dyn = ia64_adjust_dyn,
+ .adjust_rel = ia64_adjust_rel,
+ .adjust_rela = ia64_adjust_rela,
+ .prelink_rel = ia64_prelink_rel,
+ .prelink_rela = ia64_prelink_rela,
+ .prelink_conflict_rel = ia64_prelink_conflict_rel,
+ .prelink_conflict_rela = ia64_prelink_conflict_rela,
+ .apply_conflict_rela = ia64_apply_conflict_rela,
+ .apply_rel = ia64_apply_rel,
+ .apply_rela = ia64_apply_rela,
+ .rel_to_rela = ia64_rel_to_rela,
+ .need_rel_to_rela = ia64_need_rel_to_rela,
+ .create_opd = ia64_create_opd,
+ .reloc_size = ia64_reloc_size,
+ .reloc_class = ia64_reloc_class,
+ .max_reloc_size = 16,
+ .arch_prelink = ia64_arch_prelink,
+ /* Although TASK_UNMAPPED_BASE is 0x2000000000000000, we leave some
+ area so that mmap of /etc/ld.so.cache and ld.so's malloc
+ does not take some library's VA slot.
+ Also, if this guard area isn't too small, typically
+ even dlopened libraries will get the slots they desire. */
+ .mmap_base = 0x2000000010000000LL,
+ .mmap_end = 0x4000000000000000LL,
+ .max_page_size = 0x10000,
+ /* The kernel can be configured for 4K, 8K, 16K and 64K,
+ but most kernels have at least 8K. */
+ .page_size = 0x02000
+};
diff --git a/src/arch-mips.c b/src/arch-mips.c
new file mode 100644
index 0000000..ccb1834
--- /dev/null
+++ b/src/arch-mips.c
@@ -0,0 +1,1444 @@
+/* Copyright (C) 2006, 2008 CodeSourcery.
+ Written by Richard Sandiford <richard@codesourcery.com>, 2006
+ Updated by Maciej W. Rozycki <macro@codesourcery.com>, 2008.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* GENERAL NOTES
+
+ The psABI defines R_MIPS_REL32 as A - EA + S, where the value of EA
+ depends on the symbol index. If the index is less than DT_MIPS_GOTSYM,
+ EA is the symbol's st_value "plus displacement". If the index is greater
+ than or equal to DT_MIPS_GOTSYM, EA is the original value of the
+ associated GOT entry.
+
+ However, glibc's dynamic linker implements a different definition.
+ If the index is less than DT_MIPS_GOTSYM, the dynamic linker adds the
+ symbol's st_value and the base address to the addend. If the index
+ is greater than or equal to DT_MIPS_GOTSYM, the dynamic linker adds
+ the final symbol value to the addend.
+
+ MIPS GOTs are divided into three parts:
+
+ - Reserved entries (of which GNU objects have 2)
+ - Local entries
+ - Global entries
+
+ DT_MIPS_LOCAL_GOTNO gives the total number of reserved and local
+ entries. The local entries all hold virtual addresses and the
+ dynamic linker will add the base address to each one.
+
+ Unlike most other architectures, the MIPS ABI does not use
+ relocations to initialize the global GOT entries. Instead, global
+ GOT entry X is mapped to dynamic symbol DT_MIPS_GOTSYM + X, and there
+ are a total of DT_MIPS_SYMTABNO - DT_MIPS_GOTSYM global GOT entries.
+
+ The interpretation of a global GOT entry depends on the symbol entry
+ and the initial GOT contents. The psABI lists the following cases:
+
+ st_shndx st_type st_value initial GOT value
+ -------- ------- -------- -----------------
+ A: SHN_UNDEF STT_FUNC 0 st_value (== 0) / QS
+ B: SHN_UNDEF STT_FUNC stub address st_value / QS
+ C: SHN_UNDEF all others 0 st_value (== 0) / QS
+ D: SHN_COMMON any alignment 0 / QS
+ E: all others STT_FUNC value st_value / stub address
+ F: all others all others value st_value
+
+ (wording slightly modified from the psABI table). Here, QS denotes
+ Quickstart values.
+
+ The dynamic linker treats each case as follows:
+
+ - [A, B when not binding lazily, C, D, E when not binding lazily, F]
+ Resolve the symbol and store its value in the GOT.
+
+ - [B when binding lazily] Set the GOT entry to the st_value plus
+ the base address.
+
+ - [E when binding lazily] If the GOT entry is different from the st_value,
+ add the base addreess to the GOT entry. Otherwise resolve the symbol
+ and store its value in the GOT (as for A, C, etc).
+
+ As the table shows, we can install Quickstart values for types A-D.
+ Installing Quickstart values for type F should be a no-op, because the
+ GOT should already hold the desired value. Installing Quickstart values
+ for type E would either be a no-op (if the GOT entry already contains
+ st_value) or would lose the address of the lazy binding stub. */
+
+#include <config.h>
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <locale.h>
+#include <error.h>
+#include <argp.h>
+#include <stdlib.h>
+
+#include "prelink.h"
+#include "layout.h"
+#include "reloc-info.h"
+
+/* The thread pointer points 0x7000 past the first static TLS block. */
+#define TLS_TP_OFFSET 0x7000
+
+/* Dynamic thread vector pointers point 0x8000 past the start of each
+ TLS block. */
+#define TLS_DTV_OFFSET 0x8000
+
+/* The number of reserved entries at the beginning of the GOT.
+ The dynamic linker points entry 0 to the resolver function
+ and entry 1 to the link_map. */
+#define RESERVED_GOTNO 2
+
+/* A structure for iterating over local GOT entries. */
+struct mips_local_got_iterator {
+ /* The DSO containing the GOT. */
+ DSO *dso;
+
+ /* The size of a GOT entry. */
+ GElf_Word entry_size;
+
+ /* The index of the current GOT entry. */
+ GElf_Word got_index;
+
+ /* A pointer to the current GOT entry. */
+ unsigned char *got_entry;
+
+ /* True if we failed to read an entry correctly. */
+ int failed;
+
+ /* Used internally to obtain GOT_ENTRY. */
+ struct data_iterator got_iterator;
+};
+
+/* Read native-endian address-type data. */
+
+static uint64_t
+mips_buf_read_addr (DSO *dso, unsigned char *data)
+{
+ if (dso->ehdr.e_ident[EI_CLASS] == ELFCLASS64)
+ return buf_read_une64 (dso, data);
+ else
+ return buf_read_une32 (dso, data);
+}
+
+/* Write native-endian address-type data. */
+
+static void
+mips_buf_write_addr (DSO *dso, unsigned char *data, uint64_t val)
+{
+ if (dso->ehdr.e_ident[EI_CLASS] == ELFCLASS64)
+ buf_write_ne64 (dso, data, val);
+ else
+ buf_write_ne32 (dso, data, val);
+}
+
+/* Set up LGI to iterate over DSO's local GOT. The caller should use
+ mips_get_local_got_entry to read the first entry. */
+
+static inline void
+mips_init_local_got_iterator (struct mips_local_got_iterator *lgi, DSO *dso)
+{
+ lgi->dso = dso;
+ lgi->entry_size = gelf_fsize (dso->elf, ELF_T_ADDR, 1, EV_CURRENT);
+ lgi->got_index = RESERVED_GOTNO - 1;
+ lgi->failed = 0;
+ init_data_iterator (&lgi->got_iterator, dso,
+ dso->info[DT_PLTGOT]
+ + (lgi->got_index + 1) * lgi->entry_size);
+}
+
+/* Return true if LGI has not reached the end of the GOT and if the next
+ entry can be accessed. When returning true, use LGI's fields to
+ describe the next entry. */
+
+static inline int
+mips_get_local_got_entry (struct mips_local_got_iterator *lgi)
+{
+ lgi->got_index++;
+ if (lgi->got_index >= lgi->dso->info_DT_MIPS_LOCAL_GOTNO)
+ return 0;
+
+ lgi->got_entry = get_data_from_iterator (&lgi->got_iterator,
+ lgi->entry_size);
+ if (lgi->got_entry == NULL)
+ {
+ error (0, 0, "%s: Malformed local GOT\n", lgi->dso->filename);
+ lgi->failed = 1;
+ return 0;
+ }
+
+ return 1;
+}
+
+/* A structure for iterating over global GOT entries. */
+struct mips_global_got_iterator {
+ /* The DSO containing the GOT. */
+ DSO *dso;
+
+ /* The size of a GOT entry. */
+ GElf_Word entry_size;
+
+ /* The virtual address of the current GOT entry. */
+ GElf_Addr got_addr;
+
+ /* The index of the associated entry in the dynamic symbol table. */
+ GElf_Word sym_index;
+
+ /* A pointer to the current GOT entry. */
+ unsigned char *got_entry;
+
+ /* The symbol associated with the current GOT entry. */
+ GElf_Sym sym;
+
+ /* True if we failed to read an entry correctly. */
+ int failed;
+
+ /* Used internally to obtain GOT_ENTRY and SYM. */
+ struct data_iterator got_iterator;
+ struct data_iterator sym_iterator;
+};
+
+/* Set up GGI to iterate over DSO's global GOT. The caller should use
+ mips_get_global_got_entry to read the first entry. */
+
+static inline void
+mips_init_global_got_iterator (struct mips_global_got_iterator *ggi, DSO *dso)
+{
+ GElf_Word sym_size;
+
+ ggi->dso = dso;
+ ggi->entry_size = gelf_fsize (dso->elf, ELF_T_ADDR, 1, EV_CURRENT);
+ ggi->got_addr = (dso->info[DT_PLTGOT]
+ + (dso->info_DT_MIPS_LOCAL_GOTNO - 1) * ggi->entry_size);
+ ggi->sym_index = dso->info_DT_MIPS_GOTSYM - 1;
+ ggi->failed = 0;
+
+ sym_size = gelf_fsize (dso->elf, ELF_T_SYM, 1, EV_CURRENT);
+ init_data_iterator (&ggi->got_iterator, dso,
+ ggi->got_addr + ggi->entry_size);
+ init_data_iterator (&ggi->sym_iterator, dso,
+ dso->info[DT_SYMTAB] + (ggi->sym_index + 1) * sym_size);
+}
+
+/* Return true if GGI has not reached the end of the GOT and if the next
+ entry can be accessed. When returning true, use GGI's fields to
+ describe the next entry. */
+
+static inline int
+mips_get_global_got_entry (struct mips_global_got_iterator *ggi)
+{
+ ggi->sym_index++;
+ ggi->got_addr += ggi->entry_size;
+ if (ggi->sym_index >= ggi->dso->info_DT_MIPS_SYMTABNO)
+ return 0;
+
+ ggi->got_entry = get_data_from_iterator (&ggi->got_iterator,
+ ggi->entry_size);
+ if (ggi->got_entry == NULL
+ || !get_sym_from_iterator (&ggi->sym_iterator, &ggi->sym))
+ {
+ error (0, 0, "%s: Malformed global GOT\n", ggi->dso->filename);
+ ggi->failed = 1;
+ return 0;
+ }
+
+ return 1;
+}
+
+static int
+mips_arch_adjust (DSO *dso, GElf_Addr start, GElf_Addr adjust)
+{
+ struct mips_local_got_iterator lgi;
+ struct mips_global_got_iterator ggi;
+ GElf_Addr value;
+
+ if (dso->info[DT_PLTGOT] == 0)
+ return 0;
+
+ /* Adjust every local GOT entry by ADJUST. Every adjustment moves
+ the code and data, so we do not need to check START here. */
+ mips_init_local_got_iterator (&lgi, dso);
+ while (mips_get_local_got_entry (&lgi))
+ {
+ value = mips_buf_read_addr (dso, lgi.got_entry);
+ mips_buf_write_addr (dso, lgi.got_entry, value + adjust);
+ }
+
+ /* Adjust every global GOT entry. Referring to the table above:
+
+ For [A, B, C]: Adjust the GOT entry if it contains st_value
+ and if the symbol's value will be adjusted.
+
+ For [D]: Do nothing. SHN_COMMON entries never need adjusting.
+
+ For [E, F]: Adjust the GOT entry if it does not contain st_value
+ -- in other words, if it is a type E entry that points to a lazy
+ binding stub -- or if the symbol's value will also be adjusted. */
+ mips_init_global_got_iterator (&ggi, dso);
+ while (mips_get_global_got_entry (&ggi))
+ {
+ value = mips_buf_read_addr (dso, ggi.got_entry);
+ if (ggi.sym.st_shndx != SHN_COMMON
+ && value >= start
+ && (value == ggi.sym.st_value
+ ? adjust_symbol_p (dso, &ggi.sym)
+ : ggi.sym.st_shndx != SHN_UNDEF))
+ mips_buf_write_addr (dso, ggi.got_entry, value + adjust);
+ }
+
+ return lgi.failed || ggi.failed;
+}
+
+static int
+mips_adjust_dyn (DSO *dso, int n, GElf_Dyn *dyn, GElf_Addr start,
+ GElf_Addr adjust)
+{
+ switch (dyn->d_tag)
+ {
+ case DT_MIPS_TIME_STAMP:
+ case DT_MIPS_ICHECKSUM:
+ case DT_MIPS_IVERSION:
+ case DT_MIPS_CONFLICT:
+ case DT_MIPS_CONFLICTNO:
+ case DT_MIPS_LIBLIST:
+ case DT_MIPS_LIBLISTNO:
+ error (0, 0, "%s: File contains QuickStart information", dso->filename);
+ return 1;
+
+ case DT_MIPS_BASE_ADDRESS:
+ case DT_MIPS_RLD_MAP:
+ case DT_MIPS_OPTIONS:
+ if (dyn->d_un.d_ptr >= start)
+ dyn->d_un.d_ptr += adjust;
+ return 1;
+
+ case DT_MIPS_LOCAL_GOTNO:
+ case DT_MIPS_UNREFEXTNO:
+ case DT_MIPS_SYMTABNO:
+ case DT_MIPS_HIPAGENO:
+ case DT_MIPS_GOTSYM:
+ /* We don't change the layout of the GOT or symbol table. */
+ return 1;
+
+ case DT_MIPS_RLD_VERSION:
+ case DT_MIPS_FLAGS:
+ /* We don't change these properties. */
+ return 1;
+ }
+ return 0;
+}
+
+/* Read the addend for a relocation in DSO. If RELA is nonnull,
+ use its r_addend, otherwise read a 32-bit in-place addend from
+ address R_OFFSET. */
+
+static inline uint32_t
+mips_read_32bit_addend (DSO *dso, GElf_Addr r_offset, GElf_Rela *rela)
+{
+ return rela ? rela->r_addend : read_une32 (dso, r_offset);
+}
+
+/* Like mips_read_32bit_addend, but change the addend to VALUE. */
+
+static inline void
+mips_write_32bit_addend (DSO *dso, GElf_Addr r_offset, GElf_Rela *rela,
+ uint32_t value)
+{
+ if (rela)
+ rela->r_addend = (int32_t) value;
+ else
+ write_ne32 (dso, r_offset, value);
+}
+
+/* Like mips_read_32bit_addend, but 64-bit. */
+
+static inline uint64_t
+mips_read_64bit_addend (DSO *dso, GElf_Addr r_offset, GElf_Rela *rela)
+{
+ return rela ? rela->r_addend : read_une64 (dso, r_offset);
+}
+
+/* Like mips_read_64bit_addend, but change the addend to VALUE. */
+
+static inline void
+mips_write_64bit_addend (DSO *dso, GElf_Addr r_offset, GElf_Rela *rela,
+ uint64_t value)
+{
+ if (rela)
+ rela->r_addend = value;
+ else
+ write_ne64 (dso, r_offset, value);
+}
+
+/* There is a relocation of type R_INFO against address R_OFFSET in DSO.
+ Adjust it so that virtual addresses >= START are increased by ADJUST
+ If the relocation is in a RELA section, RELA points to the relocation,
+ otherwise it is null. */
+
+static int
+mips_adjust_reloc (DSO *dso, GElf_Addr r_offset, GElf_Xword r_info,
+ GElf_Addr start, GElf_Addr adjust, GElf_Rela *rela)
+{
+ GElf_Addr value;
+ GElf_Word r_sym;
+
+ if (reloc_r_type (dso, r_info) == R_MIPS_REL32)
+ {
+ r_sym = reloc_r_sym (dso, r_info);
+ if (r_sym < dso->info_DT_MIPS_GOTSYM)
+ {
+ /* glibc's dynamic linker adds the symbol's st_value and the
+ base address to the addend. It therefore treats all symbols
+ as being relative, even if they would normally be considered
+ absolute. For example, the special null symbol should always
+ have the value zero, even when the base address is nonzero,
+ but R_MIPS_REL32 relocations against the null symbol must
+ nevertheles be adjusted as if that symbol were relative.
+ The same would apply to SHN_ABS symbols too.
+
+ Thus the result of the relocation calculation must always
+ be adjusted by ADJUST. (We do not need to check START because
+ every adjustment requested by the caller will affect all
+ legitimate local relocation values.) This means that we
+ should add ADJUST to the addend if and only if the symbol's
+ value is not being adjusted.
+
+ In general, we can only check whether a symbol's value is
+ being adjusted by reading its entry in the dynamic symbol
+ table and then querying adjust_symbol_p. However, this
+ generality is fortunately not needed. Modern versions
+ of binutils will never generate R_MIPS_REL32 relocations
+ against symbols in the range [1, DT_MIPS_GOTSYM), so we
+ only need to handle relocations against the null symbol. */
+ if (r_sym != 0)
+ {
+ error (0, 0, "%s: The prelinker does not support R_MIPS_REL32"
+ " relocs against local symbols", dso->filename);
+ return 1;
+ }
+ if (reloc_r_type2 (dso, r_info) == R_MIPS_64)
+ {
+ assert (reloc_r_type3 (dso, r_info) == R_MIPS_NONE);
+ assert (reloc_r_ssym (dso, r_info) == RSS_UNDEF);
+ value = mips_read_64bit_addend (dso, r_offset, rela);
+ mips_write_64bit_addend (dso, r_offset, rela, value + adjust);
+ }
+ else
+ {
+ value = mips_read_32bit_addend (dso, r_offset, rela);
+ mips_write_32bit_addend (dso, r_offset, rela, value + adjust);
+ }
+ }
+ }
+ return 0;
+}
+
+static int
+mips_adjust_rel (DSO *dso, GElf_Rel *rel, GElf_Addr start, GElf_Addr adjust)
+{
+ return mips_adjust_reloc (dso, rel->r_offset, rel->r_info,
+ start, adjust, NULL);
+}
+
+static int
+mips_adjust_rela (DSO *dso, GElf_Rela *rela, GElf_Addr start, GElf_Addr adjust)
+{
+ return mips_adjust_reloc (dso, rela->r_offset, rela->r_info,
+ start, adjust, rela);
+}
+
+/* Calculate relocation RELA as A + VALUE and store the result in DSO. */
+
+static void
+mips_prelink_32bit_reloc (DSO *dso, GElf_Rela *rela, GElf_Addr value)
+{
+ assert (rela != NULL);
+ write_ne32 (dso, rela->r_offset, value + rela->r_addend);
+}
+
+static void
+mips_prelink_64bit_reloc (DSO *dso, GElf_Rela *rela, GElf_Addr value)
+{
+ assert (rela != NULL);
+ write_ne64 (dso, rela->r_offset, value + rela->r_addend);
+}
+
+/* There is a relocation of type R_INFO against address R_OFFSET in DSO.
+ Prelink the relocation field, using INFO to look up symbol values.
+ If the relocation is in a RELA section, RELA points to the relocation,
+ otherwise it is null. */
+
+static int
+mips_prelink_reloc (struct prelink_info *info, GElf_Addr r_offset,
+ GElf_Xword r_info, GElf_Rela *rela)
+{
+ DSO *dso;
+ GElf_Addr value;
+ GElf_Word r_sym;
+ int r_type;
+
+ dso = info->dso;
+ r_sym = reloc_r_sym (dso, r_info);
+ r_type = reloc_r_type (dso, r_info);
+ switch (r_type)
+ {
+ case R_MIPS_NONE:
+ break;
+
+ case R_MIPS_REL32:
+ /* An in-place R_MIPS_REL32 relocation against symbol 0 needs no
+ adjustment. */
+ if (rela != NULL || r_sym != 0)
+ {
+ value = info->resolve (info, r_sym, r_type);
+ if (reloc_r_type2 (dso, r_info) == R_MIPS_64)
+ {
+ assert (reloc_r_type3 (dso, r_info) == R_MIPS_NONE);
+ assert (reloc_r_ssym (dso, r_info) == RSS_UNDEF);
+ mips_prelink_64bit_reloc (dso, rela, value);
+ }
+ else
+ mips_prelink_32bit_reloc (dso, rela, value);
+ }
+ break;
+
+ case R_MIPS_GLOB_DAT:
+ if (reloc_r_type2 (dso, r_info) == R_MIPS_64)
+ {
+ assert (reloc_r_type3 (dso, r_info) == R_MIPS_NONE);
+ assert (reloc_r_ssym (dso, r_info) == RSS_UNDEF);
+ write_ne64 (dso, r_offset, info->resolve (info, r_sym, r_type));
+ }
+ else
+ write_ne32 (dso, r_offset, info->resolve (info, r_sym, r_type));
+ break;
+
+ case R_MIPS_JUMP_SLOT:
+ write_ne32 (dso, r_offset, info->resolve (info, r_sym, r_type));
+ break;
+
+ case R_MIPS_TLS_DTPMOD32:
+ case R_MIPS_TLS_DTPMOD64:
+ /* Relocations in a shared library will be resolved using a conflict.
+ We need not change the relocation field here. */
+ if (dso->ehdr.e_type == ET_EXEC)
+ {
+ struct prelink_tls *tls = info->symbols[r_sym].u.tls;
+
+ if (tls == NULL)
+ break;
+ value = tls->modid;
+ if (r_type == R_MIPS_TLS_DTPMOD32)
+ mips_prelink_32bit_reloc (dso, rela, value);
+ else
+ mips_prelink_64bit_reloc (dso, rela, value);
+ }
+ break;
+
+ case R_MIPS_TLS_DTPREL32:
+ case R_MIPS_TLS_DTPREL64:
+ value = info->resolve (info, r_sym, r_type);
+ if (r_type == R_MIPS_TLS_DTPREL32)
+ mips_prelink_32bit_reloc (dso, rela, value - TLS_DTV_OFFSET);
+ else
+ mips_prelink_64bit_reloc (dso, rela, value - TLS_DTV_OFFSET);
+ break;
+
+ case R_MIPS_TLS_TPREL32:
+ case R_MIPS_TLS_TPREL64:
+ /* Relocations in a shared library will be resolved using a conflict.
+ We need not change the relocation field here. */
+ if (dso->ehdr.e_type == ET_EXEC)
+ {
+ value = info->resolve (info, r_sym, r_type);
+ value += info->resolvetls->offset - TLS_TP_OFFSET;
+ if (r_type == R_MIPS_TLS_TPREL32)
+ mips_prelink_32bit_reloc (dso, rela, value);
+ else
+ mips_prelink_64bit_reloc (dso, rela, value);
+ }
+ break;
+
+ case R_MIPS_COPY:
+ if (dso->ehdr.e_type == ET_EXEC)
+ /* COPY relocs are handled specially in generic code. */
+ return 0;
+ error (0, 0, "%s: R_MIPS_COPY reloc in shared library?", dso->filename);
+ return 1;
+
+ default:
+ error (0, 0, "%s: Unknown MIPS relocation type %d",
+ dso->filename, (int) reloc_r_type (dso, r_info));
+ return 1;
+ }
+ return 0;
+}
+
+static int
+mips_prelink_rel (struct prelink_info *info, GElf_Rel *rel, GElf_Addr reladdr)
+{
+ GElf_Xword r_info;
+ GElf_Word r_sym;
+ int r_type;
+ DSO *dso;
+
+ /* Convert R_MIPS_REL32 relocations against global symbols into
+ R_MIPS_GLOB_DAT if the addend is zero. */
+ dso = info->dso;
+ r_sym = reloc_r_sym (dso, rel->r_info);
+ r_type = reloc_r_type (dso, rel->r_info);
+ if (r_type == R_MIPS_REL32 && r_sym >= dso->info_DT_MIPS_GOTSYM)
+ {
+ r_type = R_MIPS_GLOB_DAT;
+ r_info = reloc_r_info_ext (dso, r_sym, reloc_r_ssym (dso, rel->r_info),
+ r_type,
+ reloc_r_type2 (dso, rel->r_info),
+ reloc_r_type3 (dso, rel->r_info));
+ if (reloc_r_type2 (dso, rel->r_info) == R_MIPS_64)
+ {
+ assert (reloc_r_type3 (dso, rel->r_info) == R_MIPS_NONE);
+ assert (reloc_r_ssym (dso, rel->r_info) == RSS_UNDEF);
+ if (read_une64 (dso, rel->r_offset) == 0)
+ {
+ rel->r_info = r_info;
+ write_ne64 (dso, rel->r_offset,
+ info->resolve (info, r_sym, r_type));
+ return 2;
+ }
+ }
+ else if (read_une32 (dso, rel->r_offset) == 0)
+ {
+ rel->r_info = r_info;
+ write_ne32 (dso, rel->r_offset, info->resolve (info, r_sym, r_type));
+ return 2;
+ }
+ }
+ return mips_prelink_reloc (info, rel->r_offset, rel->r_info, NULL);
+}
+
+static int
+mips_prelink_rela (struct prelink_info *info, GElf_Rela *rela,
+ GElf_Addr relaaddr)
+{
+ return mips_prelink_reloc (info, rela->r_offset, rela->r_info, rela);
+}
+
+/* CONFLICT is a conflict returned by prelink_conflict for a symbol
+ belonging to DSO. Set *TLS_OUT to the associated TLS information.
+ Return 1 on failure. */
+
+static int
+mips_get_tls (DSO *dso, struct prelink_conflict *conflict,
+ struct prelink_tls **tls_out)
+{
+ if (conflict->reloc_class != RTYPE_CLASS_TLS
+ || conflict->lookup.tls == NULL)
+ {
+ error (0, 0, "%s: R_MIPS_TLS not resolving to STT_TLS symbol",
+ dso->filename);
+ return 1;
+ }
+
+ *tls_out = conflict->lookup.tls;
+ return 0;
+}
+
+/* There is a relocation of type R_INFO against address R_OFFSET in DSO.
+ See if the relocation field must be adjusted by a conflict when DSO
+ is used in the context described by INFO. Add a conflict entry if so.
+ If the relocation is in a RELA section, RELA points to the relocation,
+ otherwise it is null. */
+
+static int
+mips_prelink_conflict_reloc (DSO *dso, struct prelink_info *info,
+ GElf_Addr r_offset, GElf_Xword r_info,
+ GElf_Rela *rela)
+{
+ GElf_Addr value;
+ struct prelink_conflict *conflict;
+ struct prelink_tls *tls = NULL;
+ GElf_Rela *entry;
+ GElf_Word r_sym;
+ int r_type;
+
+ if (info->dso == dso)
+ return 0;
+
+ r_sym = reloc_r_sym (dso, r_info);
+ r_type = reloc_r_type (dso, r_info);
+ conflict = prelink_conflict (info, r_sym, r_type);
+ if (conflict == NULL)
+ {
+ switch (r_type)
+ {
+ case R_MIPS_TLS_DTPMOD32:
+ case R_MIPS_TLS_DTPMOD64:
+ case R_MIPS_TLS_TPREL32:
+ case R_MIPS_TLS_TPREL64:
+ tls = info->curtls;
+ if (tls == NULL)
+ return 0;
+ /* A relocation against symbol 0. A shared library cannot
+ know what the final module IDs or TP-relative offsets are,
+ so the executable must always have a conflict for them. */
+ value = 0;
+ break;
+ default:
+ return 0;
+ }
+ }
+ else if (conflict->ifunc)
+ {
+ error (0, 0, "%s: STT_GNU_IFUNC not handled on MIPS yet",
+ dso->filename);
+ return 1;
+ }
+ else
+ {
+ /* DTPREL32/DTPREL64 relocations just involve the symbol value;
+ no other TLS information is needed. Ignore conflicts created
+ from a lookup of type RTYPE_CLASS_TLS if no real conflict
+ exists. */
+ if ((r_type == R_MIPS_TLS_DTPREL32 || r_type == R_MIPS_TLS_DTPREL64)
+ && conflict->lookup.tls == conflict->conflict.tls
+ && conflict->lookupval == conflict->conflictval)
+ return 0;
+
+ value = conflict_lookup_value (conflict);
+ }
+ /* VALUE now contains the final symbol value. Change it to the
+ value we want to store at R_OFFSET. */
+ switch (r_type)
+ {
+ case R_MIPS_REL32:
+ if (reloc_r_type2 (dso, r_info) == R_MIPS_64)
+ {
+ assert (reloc_r_type3 (dso, r_info) == R_MIPS_NONE);
+ assert (reloc_r_ssym (dso, r_info) == RSS_UNDEF);
+ value += mips_read_64bit_addend (dso, r_offset, rela);
+ }
+ else
+ value += mips_read_32bit_addend (dso, r_offset, rela);
+ break;
+
+ case R_MIPS_GLOB_DAT:
+ break;
+
+ case R_MIPS_COPY:
+ error (0, 0, "R_MIPS_COPY should not be present in shared libraries");
+ return 1;
+
+ case R_MIPS_TLS_DTPMOD32:
+ case R_MIPS_TLS_DTPMOD64:
+ if (conflict != NULL && mips_get_tls (dso, conflict, &tls) == 1)
+ return 1;
+ value = tls->modid;
+ break;
+
+ case R_MIPS_TLS_DTPREL32:
+ value += mips_read_32bit_addend (dso, r_offset, rela) - TLS_DTV_OFFSET;
+ break;
+ case R_MIPS_TLS_DTPREL64:
+ value += mips_read_64bit_addend (dso, r_offset, rela) - TLS_DTV_OFFSET;
+ break;
+
+ case R_MIPS_TLS_TPREL32:
+ case R_MIPS_TLS_TPREL64:
+ if (conflict != NULL && mips_get_tls (dso, conflict, &tls) == 1)
+ return 1;
+ if (r_type == R_MIPS_TLS_TPREL32)
+ value += mips_read_32bit_addend (dso, r_offset, rela);
+ else
+ value += mips_read_64bit_addend (dso, r_offset, rela);
+ value += tls->offset - TLS_TP_OFFSET;
+ break;
+
+ default:
+ error (0, 0, "%s: Unknown MIPS relocation type %d", dso->filename,
+ r_type);
+ return 1;
+ }
+ /* Create and initialize a conflict entry. */
+ entry = prelink_conflict_add_rela (info);
+ if (entry == NULL)
+ return 1;
+ entry->r_offset = r_offset;
+ entry->r_info = reloc_r_info_ext (dso, 0, RSS_UNDEF,
+ R_MIPS_REL32, R_MIPS_64, R_MIPS_NONE);
+ if (reloc_r_type2 (dso, entry->r_info) == R_MIPS_64)
+ entry->r_addend = value;
+ else
+ entry->r_addend = (int32_t) value;
+ return 0;
+}
+
+static int
+mips_prelink_conflict_rel (DSO *dso, struct prelink_info *info,
+ GElf_Rel *rel, GElf_Addr reladdr)
+{
+ return mips_prelink_conflict_reloc (dso, info, rel->r_offset,
+ rel->r_info, NULL);
+}
+
+static int
+mips_prelink_conflict_rela (DSO *dso, struct prelink_info *info,
+ GElf_Rela *rela, GElf_Addr relaaddr)
+{
+ return mips_prelink_conflict_reloc (dso, info, rela->r_offset,
+ rela->r_info, rela);
+}
+
+static int
+mips_arch_prelink_conflict (DSO *dso, struct prelink_info *info)
+{
+ struct mips_global_got_iterator ggi;
+ GElf_Addr value;
+ struct prelink_conflict *conflict;
+ GElf_Rela *entry;
+
+ if (info->dso == dso || dso->info[DT_PLTGOT] == 0)
+ return 0;
+
+ /* Add a conflict for every global GOT entry that does not hold the
+ right value, either because of a conflict, or because the DSO has
+ a lazy binding stub for a symbol that it also defines. */
+ mips_init_global_got_iterator (&ggi, dso);
+ while (mips_get_global_got_entry (&ggi))
+ {
+ conflict = prelink_conflict (info, ggi.sym_index, R_MIPS_REL32);
+ if (conflict != NULL)
+ value = conflict_lookup_value (conflict);
+ else if (ggi.sym.st_shndx != SHN_UNDEF
+ && ggi.sym.st_shndx != SHN_COMMON)
+ value = ggi.sym.st_value;
+ else
+ continue;
+ if (mips_buf_read_addr (dso, ggi.got_entry) != value)
+ {
+ entry = prelink_conflict_add_rela (info);
+ if (entry == NULL)
+ return 1;
+ entry->r_offset = ggi.got_addr;
+ entry->r_info = reloc_r_info_ext (dso, 0, RSS_UNDEF,
+ R_MIPS_REL32, R_MIPS_64,
+ R_MIPS_NONE);
+ if (reloc_r_type2 (dso, entry->r_info) == R_MIPS_64)
+ entry->r_addend = value;
+ else
+ entry->r_addend = (int32_t) value;
+ }
+ }
+
+ return ggi.failed;
+}
+
+static int
+mips_apply_conflict_rela (struct prelink_info *info, GElf_Rela *rela,
+ char *buf, GElf_Addr dest_addr)
+{
+ DSO *dso;
+
+ dso = info->dso;
+ switch (reloc_r_type (dso, rela->r_info))
+ {
+ case R_MIPS_REL32:
+ if (reloc_r_type2 (dso, rela->r_info) == R_MIPS_64)
+ {
+ assert (reloc_r_ssym (dso, rela->r_info) == RSS_UNDEF);
+ assert (reloc_r_type3 (dso, rela->r_info) == R_MIPS_NONE);
+ buf_write_ne64 (info->dso, buf, rela->r_addend);
+ }
+ else
+ buf_write_ne32 (info->dso, buf, rela->r_addend);
+ break;
+
+ case R_MIPS_JUMP_SLOT:
+ buf_write_ne32 (info->dso, buf, rela->r_addend);
+ break;
+
+ default:
+ abort ();
+ }
+ return 0;
+}
+
+/* BUF points to a 32-bit field in DSO that is subject to relocation.
+ If the relocation is in a RELA section, RELA points to the relocation,
+ otherwise it is null. Add the addend to ADJUSTMENT and install the
+ result. */
+
+static inline void
+mips_apply_adjustment (DSO *dso, GElf_Rela *rela, char *buf,
+ GElf_Addr adjustment)
+{
+ if (rela)
+ adjustment += rela->r_addend;
+ else
+ adjustment += mips_buf_read_addr (dso, buf);
+ mips_buf_write_addr (dso, buf, adjustment);
+}
+
+static int
+mips_apply_reloc (struct prelink_info *info, GElf_Xword r_info,
+ GElf_Rela *rela, char *buf)
+{
+ GElf_Addr value;
+ GElf_Word r_sym;
+ int r_type;
+ DSO *dso;
+
+ dso = info->dso;
+ r_sym = reloc_r_sym (dso, r_info);
+ r_type = reloc_r_type (dso, r_info);
+ value = info->resolve (info, r_sym, r_type);
+ switch (r_type)
+ {
+ case R_MIPS_NONE:
+ break;
+
+ case R_MIPS_JUMP_SLOT:
+ buf_write_ne32 (info->dso, buf, value);
+ break;
+
+ case R_MIPS_COPY:
+ abort ();
+
+ case R_MIPS_REL32:
+ if (reloc_r_type2 (dso, r_info) == R_MIPS_64)
+ {
+ assert (reloc_r_type3 (dso, r_info) == R_MIPS_NONE);
+ assert (reloc_r_ssym (dso, r_info) == RSS_UNDEF);
+ }
+ mips_apply_adjustment (dso, rela, buf, value);
+ break;
+
+ default:
+ return 1;
+ }
+ return 0;
+}
+
+static int
+mips_apply_rel (struct prelink_info *info, GElf_Rel *rel, char *buf)
+{
+ return mips_apply_reloc (info, rel->r_info, NULL, buf);
+}
+
+static int
+mips_apply_rela (struct prelink_info *info, GElf_Rela *rela, char *buf)
+{
+ return mips_apply_reloc (info, rela->r_info, rela, buf);
+}
+
+static int
+mips_rel_to_rela (DSO *dso, GElf_Rel *rel, GElf_Rela *rela)
+{
+ GElf_Word r_sym;
+ int r_type;
+
+ r_sym = reloc_r_sym (dso, rel->r_info);
+ r_type = reloc_r_type (dso, rel->r_info);
+ rela->r_offset = rel->r_offset;
+ rela->r_info = rel->r_info;
+ switch (r_type)
+ {
+ case R_MIPS_REL32:
+ /* This relocation has an in-place addend. */
+ if (reloc_r_type2 (dso, rel->r_info) == R_MIPS_64)
+ {
+ assert (reloc_r_type3 (dso, rel->r_info) == R_MIPS_NONE);
+ assert (reloc_r_ssym (dso, rel->r_info) == RSS_UNDEF);
+ rela->r_addend = read_une64 (dso, rel->r_offset);
+ }
+ else
+ rela->r_addend = (int32_t) read_une32 (dso, rel->r_offset);
+ break;
+
+ case R_MIPS_TLS_DTPREL32:
+ case R_MIPS_TLS_TPREL32:
+ /* These relocations have an in-place addend. */
+ rela->r_addend = (int32_t) read_une32 (dso, rel->r_offset);
+ break;
+ case R_MIPS_TLS_DTPREL64:
+ case R_MIPS_TLS_TPREL64:
+ /* These relocations have an in-place addend. */
+ rela->r_addend = read_une64 (dso, rel->r_offset);
+ break;
+
+ case R_MIPS_NONE:
+ case R_MIPS_COPY:
+ case R_MIPS_GLOB_DAT:
+ case R_MIPS_TLS_DTPMOD32:
+ case R_MIPS_TLS_DTPMOD64:
+ /* These relocations have no addend. */
+ rela->r_addend = 0;
+ break;
+
+ default:
+ error (0, 0, "%s: Unknown MIPS relocation type %d", dso->filename,
+ r_type);
+ return 1;
+ }
+ return 0;
+}
+
+static int
+mips_rela_to_rel (DSO *dso, GElf_Rela *rela, GElf_Rel *rel)
+{
+ GElf_Sxword r_addend;
+ GElf_Word r_sym;
+ int r_type;
+
+ r_sym = reloc_r_sym (dso, rela->r_info);
+ r_type = reloc_r_type (dso, rela->r_info);
+ r_addend = rela->r_addend;
+ rel->r_offset = rela->r_offset;
+ rel->r_info = rela->r_info;
+ switch (r_type)
+ {
+ case R_MIPS_NONE:
+ case R_MIPS_COPY:
+ break;
+
+ case R_MIPS_GLOB_DAT:
+ /* This relocation has no addend. */
+ r_addend = 0;
+ /* FALLTHROUGH */
+ case R_MIPS_REL32:
+ /* This relocation has an in-place addend. */
+ if (reloc_r_type2 (dso, rel->r_info) == R_MIPS_64)
+ {
+ assert (reloc_r_type3 (dso, rel->r_info) == R_MIPS_NONE);
+ assert (reloc_r_ssym (dso, rel->r_info) == RSS_UNDEF);
+ write_ne64 (dso, rela->r_offset, rela->r_addend);
+ }
+ else
+ write_ne32 (dso, rela->r_offset, rela->r_addend);
+ break;
+
+ case R_MIPS_TLS_DTPMOD32:
+ /* This relocation has no addend. */
+ r_addend = 0;
+ /* FALLTHROUGH */
+ case R_MIPS_TLS_DTPREL32:
+ case R_MIPS_TLS_TPREL32:
+ /* These relocations have an in-place addend. */
+ write_ne32 (dso, rela->r_offset, rela->r_addend);
+ break;
+ case R_MIPS_TLS_DTPMOD64:
+ /* This relocation has no addend. */
+ r_addend = 0;
+ /* FALLTHROUGH */
+ case R_MIPS_TLS_DTPREL64:
+ case R_MIPS_TLS_TPREL64:
+ /* These relocations have an in-place addend. */
+ write_ne64 (dso, rela->r_offset, rela->r_addend);
+ break;
+ break;
+
+ default:
+ error (0, 0, "%s: Unknown MIPS relocation type %d", dso->filename,
+ r_type);
+ return 1;
+ }
+ return 0;
+}
+
+static int
+mips_need_rel_to_rela (DSO *dso, int first, int last)
+{
+ Elf_Data *data;
+ Elf_Scn *scn;
+ GElf_Shdr shdr;
+ GElf_Rel rel;
+ GElf_Word r_sym;
+ int r_type;
+ int count;
+ int i;
+ int n;
+
+ for (n = first; n <= last; n++)
+ {
+ data = NULL;
+ scn = dso->scn[n];
+ gelfx_getshdr (dso->elf, scn, &shdr);
+ while ((data = elf_getdata (scn, data)) != NULL)
+ {
+ count = data->d_size / shdr.sh_entsize;
+ for (i = 0; i < count; i++)
+ {
+ gelfx_getrel (dso->elf, data, i, &rel);
+ r_type = reloc_r_type (dso, rel.r_info);
+ r_sym = reloc_r_sym (dso, rel.r_info);
+ switch (r_type)
+ {
+ case R_MIPS_NONE:
+ case R_MIPS_COPY:
+ case R_MIPS_JUMP_SLOT:
+ break;
+
+ case R_MIPS_REL32:
+ /* The SVR4 definition was designed to allow exactly the
+ sort of prelinking we want to do here, in combination
+ with Quickstart. Unfortunately, glibc's definition
+ makes it impossible for relocations against anything
+ other than the null symbol. We get around this for
+ zero addends by using a R_MIPS_GLOB_DAT relocation
+ instead, where R_MIPS_GLOB_DAT is a GNU extension
+ added specifically for this purpose. */
+ if (r_sym != 0)
+ {
+ if (r_sym < dso->info_DT_MIPS_GOTSYM)
+ return 1;
+ if (reloc_r_type2 (dso, rel.r_info) == R_MIPS_64)
+ {
+ assert (reloc_r_type3 (dso, rel.r_info)
+ == R_MIPS_NONE);
+ assert (reloc_r_ssym (dso, rel.r_info)
+ == RSS_UNDEF);
+ if (read_une64 (dso, rel.r_offset) != 0)
+ return 1;
+ }
+ else if (read_une32 (dso, rel.r_offset) != 0)
+ return 1;
+ }
+ break;
+
+ case R_MIPS_GLOB_DAT:
+ /* This relocation has no addend. */
+ break;
+
+ case R_MIPS_TLS_DTPMOD32:
+ case R_MIPS_TLS_DTPMOD64:
+ /* The relocation will be resolved using a conflict. */
+ break;
+
+ case R_MIPS_TLS_DTPREL32:
+ case R_MIPS_TLS_DTPREL64:
+ /* We can prelink these fields, and the addend is relative
+ to the symbol value. A RELA entry is needed. */
+ return 1;
+
+ case R_MIPS_TLS_TPREL32:
+ case R_MIPS_TLS_TPREL64:
+ /* Relocations in shared libraries will be resolved by a
+ conflict. Relocations in executables will not, and the
+ addend is relative to the symbol value. */
+ if (dso->ehdr.e_type == ET_EXEC)
+ return 1;
+ break;
+
+ default:
+ error (0, 0, "%s: Unknown MIPS relocation type %d",
+ dso->filename, r_type);
+ return 1;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+static int
+mips_reloc_size (int reloc_type)
+{
+ return 4;
+}
+
+static int
+mips_reloc_class (int reloc_type)
+{
+ switch (reloc_type)
+ {
+ case R_MIPS_COPY:
+ return RTYPE_CLASS_COPY;
+ case R_MIPS_JUMP_SLOT:
+ return RTYPE_CLASS_PLT;
+ case R_MIPS_TLS_DTPMOD32:
+ case R_MIPS_TLS_DTPMOD64:
+ case R_MIPS_TLS_DTPREL32:
+ case R_MIPS_TLS_DTPREL64:
+ case R_MIPS_TLS_TPREL32:
+ case R_MIPS_TLS_TPREL64:
+ return RTYPE_CLASS_TLS;
+ default:
+ return RTYPE_CLASS_VALID;
+ }
+}
+
+static int
+mips_arch_prelink (struct prelink_info *info)
+{
+ struct mips_global_got_iterator ggi;
+ DSO *dso;
+ GElf_Addr value;
+ int i;
+
+ dso = info->dso;
+
+ if (dso->info_DT_MIPS_PLTGOT)
+ {
+ /* Write address of .plt into gotplt[1]. This is in each
+ normal gotplt entry unless prelinking. */
+ int sec = addr_to_sec (dso, dso->info_DT_MIPS_PLTGOT);
+ Elf32_Addr data;
+
+ if (sec == -1)
+ return 1;
+
+ for (i = 1; i < dso->ehdr.e_shnum; i++)
+ if (dso->shdr[i].sh_type == SHT_PROGBITS
+ && ! strcmp (strptr (dso, dso->ehdr.e_shstrndx,
+ dso->shdr[i].sh_name),
+ ".plt"))
+ break;
+
+ if (i == dso->ehdr.e_shnum)
+ return 0;
+ data = dso->shdr[i].sh_addr;
+ write_ne32 (dso, dso->info_DT_MIPS_PLTGOT + 4, data);
+ }
+
+ if (dso->info[DT_PLTGOT] == 0)
+ return 0;
+
+ /* Install Quickstart values for all global GOT entries of type A-D
+ in the table above. */
+ mips_init_global_got_iterator (&ggi, dso);
+ while (mips_get_global_got_entry (&ggi))
+ {
+ value = info->resolve (info, ggi.sym_index, R_MIPS_REL32);
+ if (ggi.sym.st_shndx == SHN_UNDEF
+ || ggi.sym.st_shndx == SHN_COMMON)
+ mips_buf_write_addr (dso, ggi.got_entry, value);
+ else
+ {
+ /* Type E and F in the table above. We cannot install Quickstart
+ values for type E, but we should never need to in executables,
+ because an executable should not use lazy binding stubs for
+ symbols it defines itself. Although we could in theory just
+ discard any such stub address, it goes against the principle
+ that prelinking should be reversible.
+
+ When type E entries occur in shared libraries, we can fix
+ them up using conflicts.
+
+ Type F entries should never need a Quickstart value -- the
+ current value should already be correct. However, the conflict
+ code will cope correctly with malformed type F entries in
+ shared libraries, so we only complain about executables here. */
+ if (dso->ehdr.e_type == ET_EXEC
+ && value != mips_buf_read_addr (dso, ggi.got_entry))
+ {
+ error (0, 0, "%s: The global GOT entries for defined symbols"
+ " do not match their st_values\n", dso->filename);
+ return 1;
+ }
+ }
+ }
+ return ggi.failed;
+}
+
+static int
+mips_arch_undo_prelink (DSO *dso)
+{
+ struct mips_global_got_iterator ggi;
+ int i;
+
+ if (dso->info_DT_MIPS_PLTGOT)
+ {
+ /* Clear gotplt[1] if it contains the address of .plt. */
+ int sec = addr_to_sec (dso, dso->info_DT_MIPS_PLTGOT);
+ Elf32_Addr data;
+
+ if (sec == -1)
+ return 1;
+
+ for (i = 1; i < dso->ehdr.e_shnum; i++)
+ if (dso->shdr[i].sh_type == SHT_PROGBITS
+ && ! strcmp (strptr (dso, dso->ehdr.e_shstrndx,
+ dso->shdr[i].sh_name),
+ ".plt"))
+ break;
+
+ if (i == dso->ehdr.e_shnum)
+ return 0;
+ data = read_une32 (dso, dso->info_DT_MIPS_PLTGOT + 4);
+ if (data == dso->shdr[i].sh_addr)
+ write_ne32 (dso, dso->info_DT_MIPS_PLTGOT + 4, 0);
+ }
+
+ if (dso->info[DT_PLTGOT] == 0)
+ return 0;
+
+ mips_init_global_got_iterator (&ggi, dso);
+ while (mips_get_global_got_entry (&ggi))
+ if (ggi.sym.st_shndx == SHN_UNDEF)
+ /* Types A-C in the table above. */
+ mips_buf_write_addr (dso, ggi.got_entry, ggi.sym.st_value);
+ else if (ggi.sym.st_shndx == SHN_COMMON)
+ /* Type D in the table above. */
+ mips_buf_write_addr (dso, ggi.got_entry, 0);
+ return ggi.failed;
+}
+
+static int
+mips_undo_prelink_rel (DSO *dso, GElf_Rel *rel, GElf_Addr reladdr)
+{
+ int sec;
+ const char *name;
+ GElf_Word r_sym;
+ int r_type;
+
+ /* Convert R_MIPS_GLOB_DAT relocations back into R_MIPS_REL32
+ relocations. Ideally we'd have some mechanism for recording
+ these changes in the undo section, but in the absence of that,
+ it's better to assume that the original relocation was
+ R_MIPS_REL32; R_MIPS_GLOB_DAT was added specifically for the
+ prelinker and shouldn't be used in non-prelinked binaries. */
+ r_sym = reloc_r_sym (dso, rel->r_info);
+ r_type = reloc_r_type (dso, rel->r_info);
+ if (r_type == R_MIPS_GLOB_DAT)
+ {
+ if (reloc_r_type2 (dso, rel->r_info) == R_MIPS_64)
+ {
+ assert (reloc_r_type3 (dso, rel->r_info) == R_MIPS_NONE);
+ assert (reloc_r_ssym (dso, rel->r_info) == RSS_UNDEF);
+ write_ne64 (dso, rel->r_offset, 0);
+ }
+ else
+ write_ne32 (dso, rel->r_offset, 0);
+ rel->r_info = reloc_r_info_ext (dso,
+ r_sym, reloc_r_ssym (dso, rel->r_info),
+ R_MIPS_REL32,
+ reloc_r_type2 (dso, rel->r_info),
+ reloc_r_type3 (dso, rel->r_info));
+ return 2;
+ }
+ else if (r_type == R_MIPS_JUMP_SLOT)
+ {
+ sec = addr_to_sec (dso, rel->r_offset);
+ name = strptr (dso, dso->ehdr.e_shstrndx, dso->shdr[sec].sh_name);
+ if (sec == -1 || strcmp (name, ".got.plt"))
+ {
+ error (0, 0,
+ "%s: R_MIPS_JUMP_SLOT not pointing into .got.plt section",
+ dso->filename);
+ return 1;
+ }
+ else
+ {
+ Elf32_Addr data = read_une32 (dso, dso->shdr[sec].sh_addr + 4);
+
+ assert (rel->r_offset >= dso->shdr[sec].sh_addr + 8);
+ assert (((rel->r_offset - dso->shdr[sec].sh_addr) & 3) == 0);
+ write_ne32 (dso, rel->r_offset, data);
+ }
+ }
+
+ return 0;
+}
+
+PL_ARCH(mips) = {
+ .name = "MIPS",
+ .class = ELFCLASS32,
+ .machine = EM_MIPS,
+ .max_reloc_size = 4,
+ .dynamic_linker = "/lib/ld.so.1",
+ .dynamic_linker_alt = "/lib32/ld.so.1",
+ .R_COPY = R_MIPS_COPY,
+ .R_JMP_SLOT = R_MIPS_JUMP_SLOT,
+ /* R_MIPS_REL32 relocations against symbol 0 do act as relative relocs,
+ but those against other symbols don't. */
+ .R_RELATIVE = ~0U,
+ .rtype_class_valid = RTYPE_CLASS_VALID,
+ .arch_adjust = mips_arch_adjust,
+ .adjust_dyn = mips_adjust_dyn,
+ .adjust_rel = mips_adjust_rel,
+ .adjust_rela = mips_adjust_rela,
+ .prelink_rel = mips_prelink_rel,
+ .prelink_rela = mips_prelink_rela,
+ .prelink_conflict_rel = mips_prelink_conflict_rel,
+ .prelink_conflict_rela = mips_prelink_conflict_rela,
+ .arch_prelink_conflict = mips_arch_prelink_conflict,
+ .apply_conflict_rela = mips_apply_conflict_rela,
+ .apply_rel = mips_apply_rel,
+ .apply_rela = mips_apply_rela,
+ .rel_to_rela = mips_rel_to_rela,
+ .rela_to_rel = mips_rela_to_rel,
+ .need_rel_to_rela = mips_need_rel_to_rela,
+ .reloc_size = mips_reloc_size,
+ .reloc_class = mips_reloc_class,
+ .arch_prelink = mips_arch_prelink,
+ .arch_undo_prelink = mips_arch_undo_prelink,
+ .undo_prelink_rel = mips_undo_prelink_rel,
+ /* Although TASK_UNMAPPED_BASE is 0x2aaa8000, we leave some
+ area so that mmap of /etc/ld.so.cache and ld.so's malloc
+ does not take some library's VA slot.
+ Also, if this guard area isn't too small, typically
+ even dlopened libraries will get the slots they desire. */
+ .mmap_base = 0x2c000000,
+ .mmap_end = 0x3c000000,
+ .max_page_size = 0x10000,
+ .page_size = 0x1000
+};
+
+PL_ARCH(mips64) = {
+ .name = "MIPS64",
+ .class = ELFCLASS64,
+ .machine = EM_MIPS,
+ .max_reloc_size = 8,
+ .dynamic_linker = "/lib/ld.so.1",
+ .dynamic_linker_alt = "/lib64/ld.so.1",
+ .R_COPY = R_MIPS_COPY,
+ .R_JMP_SLOT = R_MIPS_JUMP_SLOT,
+ /* R_MIPS_REL32 relocations against symbol 0 do act as relative relocs,
+ but those against other symbols don't. */
+ .R_RELATIVE = ~0U,
+ .rtype_class_valid = RTYPE_CLASS_VALID,
+ .arch_adjust = mips_arch_adjust,
+ .adjust_dyn = mips_adjust_dyn,
+ .adjust_rel = mips_adjust_rel,
+ .adjust_rela = mips_adjust_rela,
+ .prelink_rel = mips_prelink_rel,
+ .prelink_rela = mips_prelink_rela,
+ .prelink_conflict_rel = mips_prelink_conflict_rel,
+ .prelink_conflict_rela = mips_prelink_conflict_rela,
+ .arch_prelink_conflict = mips_arch_prelink_conflict,
+ .apply_conflict_rela = mips_apply_conflict_rela,
+ .apply_rel = mips_apply_rel,
+ .apply_rela = mips_apply_rela,
+ .rel_to_rela = mips_rel_to_rela,
+ .rela_to_rel = mips_rela_to_rel,
+ .need_rel_to_rela = mips_need_rel_to_rela,
+ .reloc_size = mips_reloc_size,
+ .reloc_class = mips_reloc_class,
+ .arch_prelink = mips_arch_prelink,
+ .arch_undo_prelink = mips_arch_undo_prelink,
+ .undo_prelink_rel = mips_undo_prelink_rel,
+ /* Although TASK_UNMAPPED_BASE is 0x5555556000, we leave some
+ area so that mmap of /etc/ld.so.cache and ld.so's malloc
+ does not take some library's VA slot.
+ Also, if this guard area isn't too small, typically
+ even dlopened libraries will get the slots they desire. */
+ .mmap_base = 0x5800000000LL,
+ .mmap_end = 0x9800000000LL,
+ .max_page_size = 0x10000,
+ .page_size = 0x1000
+};
diff --git a/src/arch-ppc.c b/src/arch-ppc.c
new file mode 100644
index 0000000..e22e5d5
--- /dev/null
+++ b/src/arch-ppc.c
@@ -0,0 +1,1191 @@
+/* Copyright (C) 2001, 2002, 2003, 2004, 2005, 2009, 2011 Red Hat, Inc.
+ Written by Jakub Jelinek <jakub@redhat.com>, 2001.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include <config.h>
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <locale.h>
+#include <error.h>
+#include <argp.h>
+#include <stdlib.h>
+
+#include "prelink.h"
+#include "layout.h"
+
+#ifndef DT_PPC_GOT
+# define DT_PPC_GOT (DT_LOPROC + 0)
+#endif
+
+#define DT_PPC_GOT_BIT DT_LOPROC_BIT
+
+static int
+ppc_adjust_dyn (DSO *dso, int n, GElf_Dyn *dyn, GElf_Addr start,
+ GElf_Addr adjust)
+{
+ if (dyn->d_tag == DT_PPC_GOT)
+ {
+ Elf32_Addr data;
+
+ data = read_ube32 (dso, dyn->d_un.d_ptr);
+ /* DT_PPC_GOT[0] points to _DYNAMIC, it needs to be adjusted. */
+ if (data == dso->shdr[n].sh_addr && data >= start)
+ write_be32 (dso, dyn->d_un.d_ptr, data + adjust);
+
+ data = read_ube32 (dso, dyn->d_un.d_ptr + 4);
+ /* DT_PPC_GOT[1] points to .glink in prelinked libs. */
+ if (data && data >= start)
+ write_be32 (dso, dyn->d_un.d_ptr + 4, data + adjust);
+
+ if (dyn->d_un.d_ptr >= start)
+ {
+ dyn->d_un.d_ptr += adjust;
+ return 1;
+ }
+ }
+ else if (dyn->d_tag == DT_PLTGOT
+ && !dynamic_info_is_set (dso, DT_PPC_GOT_BIT))
+ {
+ int i;
+
+ for (i = 1; i < dso->ehdr.e_shnum; ++i)
+ if (! strcmp (strptr (dso, dso->ehdr.e_shstrndx,
+ dso->shdr[i].sh_name), ".got")
+ && dso->shdr[i].sh_size >= 16)
+ {
+ Elf32_Addr data, addr;
+ int step;
+
+ /* If .got[1] points to _DYNAMIC, it needs to be adjusted.
+ Other possible locations of the .got header are at the
+ end of .got or around offset 32768 in it. */
+ for (addr = dso->shdr[i].sh_addr, step = 0; step < 18; step++)
+ {
+ if (read_ube32 (dso, addr) == 0x4e800021
+ && (data = read_ube32 (dso, addr + 4))
+ == dso->shdr[n].sh_addr
+ && data >= start
+ && read_ube32 (dso, addr + 8) == 0
+ && read_ube32 (dso, addr + 12) == 0)
+ {
+ /* Probably should use here a check that neither of
+ the 4 addresses contains a dynamic relocation against
+ it. */
+ write_be32 (dso, addr + 4, data + adjust);
+ break;
+ }
+ if (step == 0)
+ addr = dso->shdr[i].sh_addr + dso->shdr[i].sh_size - 16;
+ else if (step == 1)
+ {
+ if (dso->shdr[i].sh_size >= 32768 - 32)
+ addr = dso->shdr[i].sh_addr + 32768 - 32 - 16;
+ else
+ break;
+ }
+ else
+ {
+ addr += 4;
+ if (addr + 16
+ > dso->shdr[i].sh_addr + dso->shdr[i].sh_size)
+ break;
+ }
+ }
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static int
+ppc_adjust_rel (DSO *dso, GElf_Rel *rel, GElf_Addr start,
+ GElf_Addr adjust)
+{
+ error (0, 0, "%s: PowerPC doesn't support REL relocs", dso->filename);
+ return 1;
+}
+
+static int
+ppc_adjust_rela (DSO *dso, GElf_Rela *rela, GElf_Addr start,
+ GElf_Addr adjust)
+{
+ if (GELF_R_TYPE (rela->r_info) == R_PPC_RELATIVE
+ || GELF_R_TYPE (rela->r_info) == R_PPC_IRELATIVE)
+ {
+ if ((Elf32_Word) rela->r_addend >= start)
+ rela->r_addend += (Elf32_Sword) adjust;
+ }
+ if (GELF_R_TYPE (rela->r_info) == R_PPC_JMP_SLOT
+ && dynamic_info_is_set (dso, DT_PPC_GOT_BIT))
+ {
+ Elf32_Addr data = read_ube32 (dso, rela->r_offset);
+ if (data >= start)
+ write_be32 (dso, rela->r_offset, data + adjust);
+ }
+ return 0;
+}
+
+static int
+ppc_prelink_rel (struct prelink_info *info, GElf_Rel *rel,
+ GElf_Addr reladdr)
+{
+ error (0, 0, "%s: PowerPC doesn't support REL relocs", info->dso->filename);
+ return 1;
+}
+
+static void
+ppc_fixup_plt (DSO *dso, GElf_Rela *rela, GElf_Addr value)
+{
+ Elf32_Sword disp = value - rela->r_offset;
+
+ if (disp >= -0x2000000 && disp < 0x2000000)
+ {
+ /* b value */
+ write_be32 (dso, rela->r_offset, 0x48000000 | (disp & 0x3fffffc));
+ }
+ else if ((Elf32_Addr) value >= -0x2000000 || value < 0x2000000)
+ {
+ /* ba value */
+ write_be32 (dso, rela->r_offset, 0x48000002 | (value & 0x3fffffc));
+ }
+ else
+ {
+ Elf32_Addr plt = dso->info[DT_PLTGOT];
+
+ if (rela->r_offset - plt < (8192 * 2 + 18) * 4)
+ {
+ Elf32_Word index = (rela->r_offset - plt - 18 * 4) / (4 * 2);
+ Elf32_Word count = dso->info[DT_PLTRELSZ] / sizeof (Elf32_Rela);
+ Elf32_Addr data;
+
+ data = plt + (18 + 2 * count
+ + (count > 8192 ? (count - 8192) * 2 : 0)) * 4;
+ write_be32 (dso, data + 4 * index, value);
+ /* li %r11, 4*index
+ b .plt+0 */
+ write_be32 (dso, rela->r_offset,
+ 0x39600000 | ((index * 4) & 0xffff));
+ write_be32 (dso, rela->r_offset + 4,
+ 0x48000000 | ((plt - rela->r_offset - 4) & 0x3fffffc));
+ }
+ else
+ {
+ /* lis %r12, %hi(finaladdr)
+ addi %r12, %r12, %lo(finaladdr)
+ mtctr %r12
+ bctr */
+ write_be32 (dso, rela->r_offset,
+ 0x39800000 | (((value + 0x8000) >> 16) & 0xffff));
+ write_be32 (dso, rela->r_offset + 4, 0x398c0000 | (value & 0xffff));
+ write_be32 (dso, rela->r_offset + 8, 0x7d8903a6);
+ write_be32 (dso, rela->r_offset + 12, 0x4e800420);
+ }
+ }
+}
+
+static int
+ppc_prelink_rela (struct prelink_info *info, GElf_Rela *rela,
+ GElf_Addr relaaddr)
+{
+ DSO *dso = info->dso;
+ GElf_Addr value;
+
+ if (GELF_R_TYPE (rela->r_info) == R_PPC_NONE
+ || GELF_R_TYPE (rela->r_info) == R_PPC_IRELATIVE)
+ return 0;
+ else if (GELF_R_TYPE (rela->r_info) == R_PPC_RELATIVE)
+ {
+ write_be32 (dso, rela->r_offset, rela->r_addend);
+ return 0;
+ }
+ value = info->resolve (info, GELF_R_SYM (rela->r_info),
+ GELF_R_TYPE (rela->r_info));
+ value += rela->r_addend;
+ switch (GELF_R_TYPE (rela->r_info))
+ {
+ case R_PPC_GLOB_DAT:
+ case R_PPC_ADDR32:
+ case R_PPC_UADDR32:
+ write_be32 (dso, rela->r_offset, value);
+ break;
+ case R_PPC_DTPREL32:
+ write_be32 (dso, rela->r_offset, value - 0x8000);
+ break;
+ case R_PPC_JMP_SLOT:
+ if (dynamic_info_is_set (dso, DT_PPC_GOT_BIT))
+ write_be32 (dso, rela->r_offset, value);
+ else
+ ppc_fixup_plt (dso, rela, value);
+ break;
+ case R_PPC_ADDR16:
+ case R_PPC_UADDR16:
+ case R_PPC_ADDR16_LO:
+ write_be16 (dso, rela->r_offset, value);
+ break;
+ case R_PPC_DTPREL16:
+ case R_PPC_DTPREL16_LO:
+ write_be16 (dso, rela->r_offset, value - 0x8000);
+ break;
+ case R_PPC_ADDR16_HI:
+ case R_PPC_DTPREL16_HA:
+ write_be16 (dso, rela->r_offset, value >> 16);
+ break;
+ case R_PPC_DTPREL16_HI:
+ write_be16 (dso, rela->r_offset, (value - 0x8000) >> 16);
+ break;
+ case R_PPC_ADDR16_HA:
+ write_be16 (dso, rela->r_offset, (value + 0x8000) >> 16);
+ break;
+ case R_PPC_ADDR24:
+ write_be32 (dso, rela->r_offset,
+ (value & 0x03fffffc)
+ | (read_ube32 (dso, rela->r_offset) & 0xfc000003));
+ break;
+ case R_PPC_ADDR14:
+ write_be32 (dso, rela->r_offset,
+ (value & 0xfffc)
+ | (read_ube32 (dso, rela->r_offset) & 0xffff0003));
+ break;
+ case R_PPC_ADDR14_BRTAKEN:
+ case R_PPC_ADDR14_BRNTAKEN:
+ write_be32 (dso, rela->r_offset,
+ (value & 0xfffc)
+ | (read_ube32 (dso, rela->r_offset) & 0xffdf0003)
+ | ((((GELF_R_TYPE (rela->r_info) == R_PPC_ADDR14_BRTAKEN)
+ << 21)
+ ^ (value >> 10)) & 0x00200000));
+ break;
+ case R_PPC_REL24:
+ write_be32 (dso, rela->r_offset,
+ ((value - rela->r_offset) & 0x03fffffc)
+ | (read_ube32 (dso, rela->r_offset) & 0xfc000003));
+ break;
+ case R_PPC_REL32:
+ write_be32 (dso, rela->r_offset, value - rela->r_offset);
+ break;
+ /* DTPMOD32 and TPREL* is impossible to predict in shared libraries
+ unless prelink sets the rules. */
+ case R_PPC_DTPMOD32:
+ if (dso->ehdr.e_type == ET_EXEC)
+ {
+ error (0, 0, "%s: R_PPC_DTPMOD32 reloc in executable?",
+ dso->filename);
+ return 1;
+ }
+ break;
+ case R_PPC_TPREL32:
+ case R_PPC_TPREL16:
+ case R_PPC_TPREL16_LO:
+ case R_PPC_TPREL16_HI:
+ case R_PPC_TPREL16_HA:
+ if (dso->ehdr.e_type == ET_EXEC && info->resolvetls)
+ {
+ value += info->resolvetls->offset - 0x7000;
+ switch (GELF_R_TYPE (rela->r_info))
+ {
+ case R_PPC_TPREL32:
+ write_be32 (dso, rela->r_offset, value);
+ break;
+ case R_PPC_TPREL16:
+ case R_PPC_TPREL16_LO:
+ write_be16 (dso, rela->r_offset, value);
+ break;
+ case R_PPC_TPREL16_HI:
+ write_be16 (dso, rela->r_offset, value >> 16);
+ break;
+ case R_PPC_TPREL16_HA:
+ write_be16 (dso, rela->r_offset, (value + 0x8000) >> 16);
+ break;
+ }
+ }
+ break;
+ case R_PPC_COPY:
+ if (dso->ehdr.e_type == ET_EXEC)
+ /* COPY relocs are handled specially in generic code. */
+ return 0;
+ error (0, 0, "%s: R_PPC_COPY reloc in shared library?", dso->filename);
+ return 1;
+ default:
+ error (0, 0, "%s: Unknown ppc relocation type %d", dso->filename,
+ (int) GELF_R_TYPE (rela->r_info));
+ return 1;
+ }
+ return 0;
+}
+
+static int
+ppc_apply_conflict_rela (struct prelink_info *info, GElf_Rela *rela,
+ char *buf, GElf_Addr dest_addr)
+{
+ GElf_Rela *ret;
+ switch (GELF_R_TYPE (rela->r_info))
+ {
+ case R_PPC_ADDR32:
+ case R_PPC_UADDR32:
+ buf_write_be32 (buf, rela->r_addend);
+ break;
+ case R_PPC_ADDR16:
+ case R_PPC_UADDR16:
+ buf_write_be16 (buf, rela->r_addend);
+ break;
+ case R_PPC_IRELATIVE:
+ if (dest_addr == 0)
+ return 5;
+ ret = prelink_conflict_add_rela (info);
+ if (ret == NULL)
+ return 1;
+ ret->r_offset = dest_addr;
+ ret->r_info = GELF_R_INFO (0, R_PPC_IRELATIVE);
+ ret->r_addend = rela->r_addend;
+ break;
+ default:
+ abort ();
+ }
+ return 0;
+}
+
+static int
+ppc_apply_rel (struct prelink_info *info, GElf_Rel *rel, char *buf)
+{
+ error (0, 0, "%s: PowerPC doesn't support REL relocs", info->dso->filename);
+ return 1;
+}
+
+static int
+ppc_apply_rela (struct prelink_info *info, GElf_Rela *rela, char *buf)
+{
+ GElf_Addr value;
+
+ value = info->resolve (info, GELF_R_SYM (rela->r_info),
+ GELF_R_TYPE (rela->r_info));
+ value += rela->r_addend;
+ switch (GELF_R_TYPE (rela->r_info))
+ {
+ case R_PPC_NONE:
+ break;
+ case R_PPC_GLOB_DAT:
+ case R_PPC_ADDR32:
+ case R_PPC_UADDR32:
+ buf_write_be32 (buf, value);
+ break;
+ case R_PPC_ADDR16_HA:
+ value += 0x8000;
+ /* FALLTHROUGH */
+ case R_PPC_ADDR16_HI:
+ value = value >> 16;
+ /* FALLTHROUGH */
+ case R_PPC_ADDR16:
+ case R_PPC_UADDR16:
+ case R_PPC_ADDR16_LO:
+ buf_write_be16 (buf, value);
+ break;
+ case R_PPC_ADDR24:
+ buf_write_be32 (buf, (value & 0x03fffffc)
+ | (buf_read_ube32 (buf) & 0xfc000003));
+ break;
+ case R_PPC_ADDR14:
+ buf_write_be32 (buf, (value & 0xfffc)
+ | (buf_read_ube32 (buf) & 0xffff0003));
+ break;
+ case R_PPC_ADDR14_BRTAKEN:
+ case R_PPC_ADDR14_BRNTAKEN:
+ buf_write_be32 (buf, (value & 0xfffc)
+ | (buf_read_ube32 (buf) & 0xffdf0003)
+ | ((((GELF_R_TYPE (rela->r_info)
+ == R_PPC_ADDR14_BRTAKEN) << 21)
+ ^ (value >> 10)) & 0x00200000));
+ break;
+ case R_PPC_REL24:
+ buf_write_be32 (buf, ((value - rela->r_offset) & 0x03fffffc)
+ | (buf_read_ube32 (buf) & 0xfc000003));
+ break;
+ case R_PPC_REL32:
+ buf_write_be32 (buf, value - rela->r_offset);
+ break;
+ case R_PPC_RELATIVE:
+ error (0, 0, "%s: R_PPC_RELATIVE in ET_EXEC object?",
+ info->dso->filename);
+ return 1;
+ default:
+ return 1;
+ }
+ return 0;
+}
+
+static int
+ppc_prelink_conflict_rel (DSO *dso, struct prelink_info *info,
+ GElf_Rel *rel, GElf_Addr reladdr)
+{
+ error (0, 0, "%s: PowerPC doesn't support REL relocs", dso->filename);
+ return 1;
+}
+
+static int
+ppc_prelink_conflict_rela (DSO *dso, struct prelink_info *info,
+ GElf_Rela *rela, GElf_Addr relaaddr)
+{
+ GElf_Addr value;
+ struct prelink_conflict *conflict;
+ struct prelink_tls *tls;
+ GElf_Rela *ret;
+ int r_type;
+
+ if (GELF_R_TYPE (rela->r_info) == R_PPC_RELATIVE
+ || GELF_R_TYPE (rela->r_info) == R_PPC_NONE)
+ /* Fast path: nothing to do. */
+ return 0;
+ conflict = prelink_conflict (info, GELF_R_SYM (rela->r_info),
+ GELF_R_TYPE (rela->r_info));
+ if (conflict == NULL)
+ {
+ switch (GELF_R_TYPE (rela->r_info))
+ {
+ /* Even local DTPMOD and TPREL relocs need conflicts. */
+ case R_PPC_DTPMOD32:
+ case R_PPC_TPREL32:
+ case R_PPC_TPREL16:
+ case R_PPC_TPREL16_LO:
+ case R_PPC_TPREL16_HI:
+ case R_PPC_TPREL16_HA:
+ if (info->curtls == NULL || info->dso == dso)
+ return 0;
+ break;
+ /* Similarly IRELATIVE relocations always need conflicts. */
+ case R_PPC_IRELATIVE:
+ break;
+ default:
+ return 0;
+ }
+ value = 0;
+ }
+ else if (info->dso == dso && !conflict->ifunc)
+ return 0;
+ else
+ {
+ /* DTPREL wants to see only real conflicts, not lookups
+ with reloc_class RTYPE_CLASS_TLS. */
+ if (conflict->lookup.tls == conflict->conflict.tls
+ && conflict->lookupval == conflict->conflictval)
+ switch (GELF_R_TYPE (rela->r_info))
+ {
+ case R_PPC_DTPREL32:
+ case R_PPC_DTPREL16:
+ case R_PPC_DTPREL16_LO:
+ case R_PPC_DTPREL16_HI:
+ case R_PPC_DTPREL16_HA:
+ return 0;
+ }
+
+ value = conflict_lookup_value (conflict);
+ }
+ ret = prelink_conflict_add_rela (info);
+ if (ret == NULL)
+ return 1;
+ ret->r_offset = rela->r_offset;
+ value += rela->r_addend;
+ r_type = GELF_R_TYPE (rela->r_info);
+ switch (r_type)
+ {
+ case R_PPC_GLOB_DAT:
+ r_type = R_PPC_ADDR32;
+ case R_PPC_ADDR32:
+ case R_PPC_UADDR32:
+ case R_PPC_IRELATIVE:
+ if (conflict != NULL && conflict->ifunc)
+ r_type = R_PPC_IRELATIVE;
+ break;
+ case R_PPC_JMP_SLOT:
+ if (dynamic_info_is_set (dso, DT_PPC_GOT_BIT))
+ {
+ r_type = R_PPC_ADDR32;
+ if (conflict != NULL && conflict->ifunc)
+ r_type = R_PPC_IRELATIVE;
+ }
+ break;
+ case R_PPC_ADDR16_HA:
+ value += 0x8000;
+ /* FALLTHROUGH */
+ case R_PPC_ADDR16_HI:
+ value = value >> 16;
+ /* FALLTHROUGH */
+ case R_PPC_ADDR16:
+ case R_PPC_UADDR16:
+ case R_PPC_ADDR16_LO:
+ if (r_type != R_PPC_UADDR16)
+ r_type = R_PPC_ADDR16;
+ value = ((value & 0xffff) ^ 0x8000) - 0x8000;
+ break;
+ case R_PPC_ADDR24:
+ r_type = R_PPC_ADDR32;
+ value = (value & 0x03fffffc)
+ | (read_ube32 (dso, rela->r_offset) & 0xfc000003);
+ break;
+ case R_PPC_ADDR14:
+ r_type = R_PPC_ADDR32;
+ value = (value & 0xfffc)
+ | (read_ube32 (dso, rela->r_offset) & 0xffff0003);
+ break;
+ case R_PPC_ADDR14_BRTAKEN:
+ case R_PPC_ADDR14_BRNTAKEN:
+ r_type = R_PPC_ADDR32;
+ value = (value & 0xfffc)
+ | (read_ube32 (dso, rela->r_offset) & 0xffdf0003)
+ | ((((r_type == R_PPC_ADDR14_BRTAKEN) << 21)
+ ^ (value >> 10)) & 0x00200000);
+ break;
+ case R_PPC_REL24:
+ r_type = R_PPC_ADDR32;
+ value = ((value - rela->r_offset) & 0x03fffffc)
+ | (read_ube32 (dso, rela->r_offset) & 0xfc000003);
+ break;
+ case R_PPC_REL32:
+ r_type = R_PPC_ADDR32;
+ value -= rela->r_offset;
+ break;
+ case R_PPC_DTPMOD32:
+ case R_PPC_DTPREL32:
+ case R_PPC_DTPREL16:
+ case R_PPC_DTPREL16_LO:
+ case R_PPC_DTPREL16_HI:
+ case R_PPC_DTPREL16_HA:
+ case R_PPC_TPREL32:
+ case R_PPC_TPREL16:
+ case R_PPC_TPREL16_LO:
+ case R_PPC_TPREL16_HI:
+ case R_PPC_TPREL16_HA:
+ if (conflict != NULL
+ && (conflict->reloc_class != RTYPE_CLASS_TLS
+ || conflict->lookup.tls == NULL))
+ {
+ error (0, 0, "%s: TLS reloc not resolving to STT_TLS symbol",
+ dso->filename);
+ return 1;
+ }
+ tls = conflict ? conflict->lookup.tls : info->curtls;
+ r_type = R_PPC_ADDR16;
+ switch (GELF_R_TYPE (rela->r_info))
+ {
+ case R_PPC_DTPMOD32:
+ r_type = R_PPC_ADDR32;
+ value = tls->modid;
+ break;
+ case R_PPC_DTPREL32:
+ r_type = R_PPC_ADDR32;
+ value -= 0x8000;
+ break;
+ case R_PPC_DTPREL16:
+ case R_PPC_DTPREL16_LO:
+ value -= 0x8000;
+ break;
+ case R_PPC_DTPREL16_HI:
+ value = (value - 0x8000) >> 16;
+ break;
+ case R_PPC_DTPREL16_HA:
+ value >>= 16;
+ break;
+ case R_PPC_TPREL32:
+ r_type = R_PPC_ADDR32;
+ value += tls->offset - 0x7000;
+ break;
+ case R_PPC_TPREL16:
+ case R_PPC_TPREL16_LO:
+ value += tls->offset - 0x7000;
+ break;
+ case R_PPC_TPREL16_HI:
+ value = (value + tls->offset - 0x7000) >> 16;
+ break;
+ case R_PPC_TPREL16_HA:
+ value = (value + tls->offset - 0x7000 + 0x8000) >> 16;
+ break;
+ }
+ if (r_type == R_PPC_ADDR16)
+ value = ((value & 0xffff) ^ 0x8000) - 0x8000;
+ break;
+ default:
+ error (0, 0, "%s: Unknown PowerPC relocation type %d", dso->filename,
+ r_type);
+ return 1;
+ }
+ if (conflict != NULL && conflict->ifunc && r_type != R_PPC_IRELATIVE)
+ {
+ error (0, 0, "%s: relocation %d against IFUNC symbol", dso->filename,
+ (int) GELF_R_TYPE (rela->r_info));
+ return 1;
+ }
+ ret->r_info = GELF_R_INFO (0, r_type);
+ ret->r_addend = (Elf32_Sword) value;
+ return 0;
+}
+
+static int
+ppc_rel_to_rela (DSO *dso, GElf_Rel *rel, GElf_Rela *rela)
+{
+ error (0, 0, "%s: PowerPC doesn't support REL relocs", dso->filename);
+ return 1;
+}
+
+static int
+ppc_need_rel_to_rela (DSO *dso, int first, int last)
+{
+ return 0;
+}
+
+static int
+ppc_arch_pre_prelink (DSO *dso)
+{
+ Elf_Data *data = NULL;
+ Elf_Scn *scn;
+ GElf_Dyn dyn;
+ Elf32_Addr val;
+ int i;
+
+ if (!dynamic_info_is_set (dso, DT_PPC_GOT_BIT))
+ return 0;
+
+ assert (dso->shdr[dso->dynamic].sh_type == SHT_DYNAMIC);
+
+ scn = dso->scn[dso->dynamic];
+ while ((data = elf_getdata (scn, data)) != NULL)
+ {
+ int ndx, maxndx;
+
+ maxndx = data->d_size / dso->shdr[dso->dynamic].sh_entsize;
+ for (ndx = 0; ndx < maxndx; ++ndx)
+ {
+ gelfx_getdyn (dso->elf, data, ndx, &dyn);
+ assert (dyn.d_tag != DT_NULL);
+ if (dyn.d_tag == DT_PPC_GOT)
+ break;
+ }
+ if (ndx < maxndx)
+ break;
+ }
+
+ /* DT_PPC_GOT[1] should point to .glink in prelinked libs. */
+ val = read_ube32 (dso, dyn.d_un.d_ptr + 4);
+ if (val)
+ return 0;
+
+ for (i = 1; i < dso->ehdr.e_shnum; ++i)
+ if (! strcmp (strptr (dso, dso->ehdr.e_shstrndx,
+ dso->shdr[i].sh_name), ".plt"))
+ break;
+
+ if (i == dso->ehdr.e_shnum)
+ return 0;
+
+ val = read_ube32 (dso, dso->shdr[i].sh_addr);
+ write_be32 (dso, dyn.d_un.d_ptr + 4, val);
+
+ return 0;
+}
+
+static int
+ppc_arch_prelink (struct prelink_info *info)
+{
+ DSO *dso = info->dso;
+ Elf32_Addr plt = dso->info[DT_PLTGOT];
+
+ if (plt && !dynamic_info_is_set (dso, DT_PPC_GOT_BIT))
+ {
+ Elf32_Word count = dso->info[DT_PLTRELSZ] / sizeof (Elf32_Rela);
+ Elf32_Addr data;
+
+ data = plt + (18 + 2 * count
+ + (count > 8192 ? (count - 8192) * 2 : 0)) * 4;
+
+ /* addis %r11, %r11, %hi(data)
+ lwz %r11, %r11, %lo(data)
+ mtctr %r11
+ bctr */
+ write_be32 (dso, plt, 0x3d6b0000 | (((data + 0x8000) >> 16) & 0xffff));
+ write_be32 (dso, plt + 4, 0x816b0000 | (data & 0xffff));
+ write_be32 (dso, plt + 8, 0x7d6903a6);
+ write_be32 (dso, plt + 12, 0x4e800420);
+ }
+ return 0;
+}
+
+static int
+ppc_arch_undo_prelink (DSO *dso)
+{
+ Elf_Data *data = NULL;
+ Elf_Scn *scn;
+ GElf_Dyn dyn;
+ Elf32_Addr val, addr, endaddr;
+ int i;
+
+ if (!dynamic_info_is_set (dso, DT_PPC_GOT_BIT))
+ return 0;
+
+ assert (dso->shdr[dso->dynamic].sh_type == SHT_DYNAMIC);
+
+ scn = dso->scn[dso->dynamic];
+ while ((data = elf_getdata (scn, data)) != NULL)
+ {
+ int ndx, maxndx;
+
+ maxndx = data->d_size / dso->shdr[dso->dynamic].sh_entsize;
+ for (ndx = 0; ndx < maxndx; ++ndx)
+ {
+ gelfx_getdyn (dso->elf, data, ndx, &dyn);
+ assert (dyn.d_tag != DT_NULL);
+ if (dyn.d_tag == DT_PPC_GOT)
+ break;
+ }
+ if (ndx < maxndx)
+ break;
+ }
+
+ /* DT_PPC_GOT[1] should point to .glink in prelinked libs. */
+ val = read_ube32 (dso, dyn.d_un.d_ptr + 4);
+ if (!val)
+ return 0;
+
+ for (i = 1; i < dso->ehdr.e_shnum; ++i)
+ if (! strcmp (strptr (dso, dso->ehdr.e_shstrndx,
+ dso->shdr[i].sh_name), ".plt"))
+ break;
+
+ if (i == dso->ehdr.e_shnum || (dso->shdr[i].sh_size & 3))
+ return 0;
+
+ addr = dso->shdr[i].sh_addr;
+ endaddr = addr + dso->shdr[i].sh_size;
+ for (; addr < endaddr; addr += 4, val += 4)
+ write_be32 (dso, addr, val);
+
+ write_be32 (dso, dyn.d_un.d_ptr + 4, 0);
+
+ return 0;
+}
+
+
+static int
+ppc_undo_prelink_rela (DSO *dso, GElf_Rela *rela, GElf_Addr relaaddr)
+{
+ switch (GELF_R_TYPE (rela->r_info))
+ {
+ case R_PPC_NONE:
+ return 0;
+ case R_PPC_RELATIVE:
+ case R_PPC_GLOB_DAT:
+ case R_PPC_ADDR32:
+ case R_PPC_UADDR32:
+ case R_PPC_REL32:
+ case R_PPC_DTPMOD32:
+ case R_PPC_DTPREL32:
+ case R_PPC_TPREL32:
+ write_be32 (dso, rela->r_offset, 0);
+ break;
+ case R_PPC_JMP_SLOT:
+ /* .plt section will become SHT_NOBITS if DT_PPC_GOT is not present,
+ otherwise .plt section will be unprelinked in
+ ppc_arch_undo_prelink. */
+ return 0;
+ case R_PPC_IRELATIVE:
+ /* .iplt section will become SHT_NOBITS. */
+ return 0;
+ case R_PPC_ADDR16:
+ case R_PPC_UADDR16:
+ case R_PPC_ADDR16_LO:
+ case R_PPC_ADDR16_HI:
+ case R_PPC_ADDR16_HA:
+ case R_PPC_DTPREL16:
+ case R_PPC_TPREL16:
+ case R_PPC_DTPREL16_LO:
+ case R_PPC_TPREL16_LO:
+ case R_PPC_DTPREL16_HI:
+ case R_PPC_TPREL16_HI:
+ case R_PPC_DTPREL16_HA:
+ case R_PPC_TPREL16_HA:
+ write_be16 (dso, rela->r_offset, 0);
+ break;
+ case R_PPC_ADDR24:
+ case R_PPC_REL24:
+ write_be32 (dso, rela->r_offset,
+ read_ube32 (dso, rela->r_offset) & 0xfc000003);
+ break;
+ case R_PPC_ADDR14:
+ write_be32 (dso, rela->r_offset,
+ read_ube32 (dso, rela->r_offset) & 0xffff0003);
+ break;
+ case R_PPC_ADDR14_BRTAKEN:
+ case R_PPC_ADDR14_BRNTAKEN:
+ write_be32 (dso, rela->r_offset,
+ read_ube32 (dso, rela->r_offset) & 0xffdf0003);
+ break;
+ case R_PPC_COPY:
+ if (dso->ehdr.e_type == ET_EXEC)
+ /* COPY relocs are handled specially in generic code. */
+ return 0;
+ error (0, 0, "%s: R_PPC_COPY reloc in shared library?", dso->filename);
+ return 1;
+ default:
+ error (0, 0, "%s: Unknown ppc relocation type %d", dso->filename,
+ (int) GELF_R_TYPE (rela->r_info));
+ return 1;
+ }
+ return 0;
+}
+
+static int
+ppc_reloc_size (int reloc_type)
+{
+ switch (reloc_type)
+ {
+ case R_PPC_ADDR16:
+ case R_PPC_UADDR16:
+ case R_PPC_ADDR16_LO:
+ case R_PPC_ADDR16_HI:
+ case R_PPC_ADDR16_HA:
+ case R_PPC_DTPREL16:
+ case R_PPC_DTPREL16_LO:
+ case R_PPC_DTPREL16_HI:
+ case R_PPC_DTPREL16_HA:
+ case R_PPC_TPREL16:
+ case R_PPC_TPREL16_LO:
+ case R_PPC_TPREL16_HI:
+ case R_PPC_TPREL16_HA:
+ return 2;
+ default:
+ break;
+ }
+ return 4;
+}
+
+static int
+ppc_reloc_class (int reloc_type)
+{
+ switch (reloc_type)
+ {
+ case R_PPC_COPY: return RTYPE_CLASS_COPY;
+ case R_PPC_JMP_SLOT: return RTYPE_CLASS_PLT;
+ default:
+ if (reloc_type >= R_PPC_DTPMOD32 && reloc_type <= R_PPC_DTPREL32)
+ return RTYPE_CLASS_TLS;
+ return RTYPE_CLASS_VALID;
+ }
+}
+
+/* Library memory regions in order of precedence:
+ 0xe800000 .. 0x10000000 top to bottom
+ 0x40000 .. 0xe800000 bottom to top
+ 0x18000000 .. 0x30000000 bottom to top */
+
+#define REG0S 0x0e800000
+#define REG0E 0x10000000
+#define REG1S 0x00040000
+#define REG1E REG0S
+#define REG2S 0x18000000
+#define REG2E 0x30000000
+
+struct ppc_layout_data
+{
+ int cnt;
+ struct prelink_entry e[3];
+ Elf32_Addr mmap_start, first_start, last_start;
+ struct
+ {
+ struct prelink_entry *e;
+ Elf32_Addr base, end, layend;
+ } ents[0];
+};
+
+static inline void
+list_append (struct prelink_entry *x, struct prelink_entry *e)
+{
+ x->prev->next = e;
+ e->prev = x->prev;
+ e->next = NULL;
+ x->prev = e;
+}
+
+static int
+addr_cmp (const void *A, const void *B)
+{
+ struct prelink_entry *a = * (struct prelink_entry **) A;
+ struct prelink_entry *b = * (struct prelink_entry **) B;
+
+ if (a->base < b->base)
+ return -1;
+ else if (a->base > b->base)
+ return 1;
+ if (a->layend < b->layend)
+ return -1;
+ else if (a->layend > b->layend)
+ return 1;
+ return 0;
+}
+
+static void
+list_sort (struct prelink_entry *x)
+{
+ int cnt, i;
+ struct prelink_entry *e;
+ struct prelink_entry **a;
+
+ if (x->next == NULL)
+ return;
+ for (cnt = 0, e = x->next; e != NULL; e = e->next)
+ ++cnt;
+ a = alloca (cnt * sizeof (*a));
+ for (i = 0, e = x->next; e != NULL; e = e->next)
+ a[i++] = e;
+ qsort (a, cnt, sizeof (*a), addr_cmp);
+ x->next = NULL;
+ x->prev = x;
+ for (i = 0; i < cnt; ++i)
+ list_append (x, a[i]);
+}
+
+static int
+ppc_layout_libs_pre (struct layout_libs *l)
+{
+ Elf32_Addr mmap_start = l->mmap_start - REG1S;
+ Elf32_Addr first_start = REG0S, last_start = REG2S;
+ struct prelink_entry *e, e0, *next = NULL;
+ struct ppc_layout_data *pld;
+ int cnt;
+
+ if (l->max_page_size > 0x10000)
+ error (EXIT_FAILURE, 0, "--layout-page-size too large");
+
+ mmap_start = REG0E - (mmap_start & 0xff0000);
+ for (cnt = 0, e = l->list; e != NULL; e = e->next, ++cnt)
+ {
+ if (e->base < mmap_start && e->layend > mmap_start)
+ mmap_start = (e->layend + 0xffff) & ~0xffff;
+ if (e->base < REG0S && e->layend > REG0S && first_start > e->base)
+ first_start = e->base;
+ if (e->base < REG0E && e->layend > REG2S && last_start < e->layend)
+ last_start = e->layend;
+ }
+ if (mmap_start > REG0E)
+ mmap_start = REG0E;
+
+ pld = calloc (sizeof (*pld) + cnt * sizeof (pld->ents[0]), 1);
+ if (pld == NULL)
+ error (EXIT_FAILURE, ENOMEM, "Cannot lay libraries out");
+
+ l->arch_data = pld;
+ memset (&e0, 0, sizeof (e0));
+ e0.prev = &e0;
+ pld->cnt = cnt;
+ pld->e[0].u.tmp = -1;
+ pld->e[0].base = REG1S + REG0E - mmap_start;
+ pld->e[0].end = pld->e[0].base;
+ pld->e[0].layend = pld->e[0].end;
+ pld->e[0].prev = &pld->e[0];
+ pld->e[1].u.tmp = -1;
+ pld->e[1].base = pld->e[0].end + mmap_start - REG0S;
+ pld->e[1].end = pld->e[1].base;
+ pld->e[1].layend = pld->e[1].end;
+ pld->e[1].prev = &pld->e[1];
+ pld->e[2].u.tmp = -1;
+ pld->e[2].base = pld->e[1].end + first_start - REG1S;
+ pld->e[2].end = pld->e[1].base;
+ pld->e[2].layend = pld->e[2].end;
+ pld->e[2].prev = &pld->e[2];
+ for (cnt = 0, e = l->list; e != NULL; e = next, ++cnt)
+ {
+ next = e->next;
+ pld->ents[cnt].e = e;
+ pld->ents[cnt].base = e->base;
+ pld->ents[cnt].end = e->end;
+ pld->ents[cnt].layend = e->layend;
+ if (e->layend <= REG0S)
+ {
+ if (e->base < REG1S)
+ e->base = REG1S;
+ else if (e->base > first_start)
+ e->base = first_start;
+ if (e->layend < REG1S)
+ e->layend = REG1S;
+ else if (e->layend > first_start)
+ e->layend = first_start;
+ e->base += pld->e[1].end - REG1S;
+ e->layend += pld->e[1].end - REG1S;
+ list_append (&pld->e[1], e);
+ }
+ else if (e->base < mmap_start)
+ {
+ if (e->base < REG0S)
+ e->base = REG0S;
+ if (e->layend > mmap_start)
+ e->layend = mmap_start;
+ e->base = pld->e[0].end + mmap_start - e->layend;
+ e->layend = pld->e[0].layend + mmap_start - pld->ents[cnt].base;
+ list_append (&pld->e[0], e);
+ }
+ else if (e->base < REG0E)
+ {
+ if (e->layend > REG0E)
+ e->layend = REG0E;
+ e->base = REG1S + REG0E - e->layend;
+ e->layend = REG1S + REG0E - pld->ents[cnt].base;
+ list_append (&e0, e);
+ }
+ else if (e->layend >= last_start)
+ {
+ if (e->base < last_start)
+ e->base = last_start;
+ e->base += pld->e[2].end - last_start;
+ e->layend += pld->e[2].end - last_start;
+ list_append (&pld->e[2], e);
+ }
+ e->end = e->layend;
+ }
+
+ list_sort (&pld->e[0]);
+ if (e0.next == NULL)
+ l->list = &pld->e[0];
+ else
+ {
+ list_sort (&e0);
+ l->list = e0.next;
+ l->list->prev = pld->e[0].prev;
+ e0.prev->next = &pld->e[0];
+ pld->e[0].prev = e0.prev;
+ }
+
+ e0.prev = l->list->prev;
+ l->list->prev = pld->e[1].prev;
+ e0.prev->next = &pld->e[1];
+ pld->e[1].prev = e0.prev;
+
+ e0.prev = l->list->prev;
+ l->list->prev = pld->e[2].prev;
+ e0.prev->next = &pld->e[2];
+ pld->e[2].prev = e0.prev;
+
+ pld->mmap_start = mmap_start;
+ pld->first_start = first_start;
+ pld->last_start = last_start;
+
+ l->mmap_start = REG1S;
+ l->mmap_fin = pld->e[2].end + REG2E - last_start;
+ l->mmap_end = l->mmap_fin;
+ l->fakecnt = 3;
+ l->fake = pld->e;
+
+ return 0;
+}
+
+static int
+ppc_layout_libs_post (struct layout_libs *l)
+{
+ struct prelink_entry *e;
+ struct ppc_layout_data *pld = (struct ppc_layout_data *) l->arch_data;
+ Elf32_Addr base, end;
+ int i;
+
+ /* First fix up base and end fields we saved. */
+ for (i = 0; i < pld->cnt; ++i)
+ {
+ pld->ents[i].e->base = pld->ents[i].base;
+ pld->ents[i].e->layend = pld->ents[i].layend;
+ pld->ents[i].e->end = pld->ents[i].end;
+ pld->ents[i].e->done |= 0x40;
+ }
+ pld->e[0].done |= 0x40;
+ pld->e[1].done |= 0x40;
+ pld->e[2].done |= 0x40;
+
+ /* Now fix up the newly created items. */
+ for (e = l->list; e != NULL; e = e->next)
+ if (e->done & 0x40)
+ e->done &= ~0x40;
+ else
+ {
+ base = e->base;
+ end = e->layend;
+ if (e->base < pld->e[0].base)
+ {
+ e->base = REG1S + REG0E - end;
+ e->end += e->base - base;
+ e->layend = REG1S + REG0E - base;
+ }
+ else if (e->base < pld->e[1].base)
+ {
+ e->base = pld->e[0].end + pld->mmap_start - end;
+ e->end += e->base - base;
+ e->layend = pld->e[0].end + pld->mmap_start - base;
+ }
+ else if (e->base < pld->e[2].base)
+ {
+ e->base -= pld->e[1].end - REG1S;
+ e->end -= pld->e[1].end - REG1S;
+ e->layend -= pld->e[1].end - REG1S;
+ }
+ else
+ {
+ e->base -= pld->e[2].end - pld->last_start;
+ e->end -= pld->e[2].end - pld->last_start;
+ e->layend -= pld->e[2].end - pld->last_start;
+ }
+ }
+
+ for (i = 0; i < pld->cnt; ++i)
+ pld->ents[i].e->done &= ~0x40;
+
+ free (l->arch_data);
+ return 0;
+}
+
+PL_ARCH(ppc) = {
+ .name = "PowerPC",
+ .class = ELFCLASS32,
+ .machine = EM_PPC,
+ .alternate_machine = { EM_NONE },
+ .R_JMP_SLOT = R_PPC_JMP_SLOT,
+ .R_COPY = R_PPC_COPY,
+ .R_RELATIVE = R_PPC_RELATIVE,
+ .rtype_class_valid = RTYPE_CLASS_VALID,
+ .dynamic_linker = "/lib/ld.so.1",
+ .adjust_dyn = ppc_adjust_dyn,
+ .adjust_rel = ppc_adjust_rel,
+ .adjust_rela = ppc_adjust_rela,
+ .prelink_rel = ppc_prelink_rel,
+ .prelink_rela = ppc_prelink_rela,
+ .prelink_conflict_rel = ppc_prelink_conflict_rel,
+ .prelink_conflict_rela = ppc_prelink_conflict_rela,
+ .apply_conflict_rela = ppc_apply_conflict_rela,
+ .apply_rel = ppc_apply_rel,
+ .apply_rela = ppc_apply_rela,
+ .rel_to_rela = ppc_rel_to_rela,
+ .need_rel_to_rela = ppc_need_rel_to_rela,
+ .reloc_size = ppc_reloc_size,
+ .reloc_class = ppc_reloc_class,
+ .max_reloc_size = 4,
+ .arch_pre_prelink = ppc_arch_pre_prelink,
+ .arch_prelink = ppc_arch_prelink,
+ .arch_undo_prelink = ppc_arch_undo_prelink,
+ .undo_prelink_rela = ppc_undo_prelink_rela,
+ .layout_libs_pre = ppc_layout_libs_pre,
+ .layout_libs_post = ppc_layout_libs_post,
+ /* This will need some changes in layout.c.
+ PowerPC prefers addresses right below REG0E
+ and can use the region above REG2S if libs don't fit. */
+ .mmap_base = REG1S,
+ .mmap_end = REG2E,
+ .max_page_size = 0x10000,
+ .page_size = 0x1000
+};
diff --git a/src/arch-ppc64.c b/src/arch-ppc64.c
new file mode 100644
index 0000000..a764b99
--- /dev/null
+++ b/src/arch-ppc64.c
@@ -0,0 +1,900 @@
+/* Copyright (C) 2002, 2003, 2004, 2009 Red Hat, Inc.
+ Written by Jakub Jelinek <jakub@redhat.com>, 2002.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include <config.h>
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <locale.h>
+#include <error.h>
+#include <argp.h>
+#include <stdlib.h>
+
+#include "prelink.h"
+#include "layout.h"
+
+struct opd_rec
+{
+ GElf_Addr fn, toc, chain;
+};
+
+struct opd_lib
+{
+ GElf_Addr start, size;
+ GElf_Addr table[1];
+};
+
+static int
+ppc64_adjust_section (DSO *dso, int n, GElf_Addr start, GElf_Addr adjust)
+{
+ if (dso->shdr[n].sh_type == SHT_PROGBITS
+ && ! strcmp (strptr (dso, dso->ehdr.e_shstrndx,
+ dso->shdr[n].sh_name), ".got"))
+ {
+ Elf64_Addr data;
+
+ /* .got[0]-0x8000 points to .got, it needs to be adjusted. */
+ data = read_ube64 (dso, dso->shdr[n].sh_addr);
+ if (addr_to_sec (dso, data - 0x8000) == n
+ && data - 0x8000 == dso->shdr[n].sh_addr)
+ write_be64 (dso, dso->shdr[n].sh_addr, data + adjust);
+ }
+ return 0;
+}
+
+static int
+ppc64_adjust_dyn (DSO *dso, int n, GElf_Dyn *dyn, GElf_Addr start,
+ GElf_Addr adjust)
+{
+ if (dyn->d_tag == DT_PPC64_GLINK && dyn->d_un.d_ptr >= start)
+ {
+ dyn->d_un.d_ptr += adjust;
+ return 1;
+ }
+
+ return 0;
+}
+
+static int
+ppc64_adjust_rel (DSO *dso, GElf_Rel *rel, GElf_Addr start,
+ GElf_Addr adjust)
+{
+ error (0, 0, "%s: PowerPC64 doesn't support REL relocs", dso->filename);
+ return 1;
+}
+
+static int
+ppc64_adjust_rela (DSO *dso, GElf_Rela *rela, GElf_Addr start,
+ GElf_Addr adjust)
+{
+ if (GELF_R_TYPE (rela->r_info) == R_PPC64_RELATIVE
+ || GELF_R_TYPE (rela->r_info) == R_PPC64_IRELATIVE)
+ {
+ GElf_Addr val = read_ube64 (dso, rela->r_offset);
+
+ if (val == rela->r_addend && val >= start)
+ write_be64 (dso, rela->r_offset, val + adjust);
+ if (rela->r_addend >= start)
+ rela->r_addend += adjust;
+ }
+ else if (GELF_R_TYPE (rela->r_info) == R_PPC64_JMP_IREL)
+ {
+ if (rela->r_addend >= start)
+ rela->r_addend += adjust;
+ }
+ return 0;
+}
+
+static int
+ppc64_prelink_rel (struct prelink_info *info, GElf_Rel *rel,
+ GElf_Addr reladdr)
+{
+ error (0, 0, "%s: PowerPC64 doesn't support REL relocs", info->dso->filename);
+ return 1;
+}
+
+static int
+ppc64_fixup_plt (struct prelink_info *info, GElf_Rela *rela, GElf_Addr value)
+{
+ DSO *dso = info->dso;
+ int sec, i;
+ size_t n;
+ struct opd_rec rec;
+
+ if (value == 0)
+ {
+ rec.fn = 0;
+ rec.toc = 0;
+ rec.chain = 0;
+ }
+ else if ((sec = addr_to_sec (dso, value)) != -1)
+ {
+ rec.fn = read_ube64 (dso, value);
+ rec.toc = read_ube64 (dso, value + 8);
+ rec.chain = read_ube64 (dso, value + 16);
+ }
+ else
+ {
+ for (i = 0; i < info->ent->ndepends; ++i)
+ if (info->ent->depends[i]->opd
+ && info->ent->depends[i]->opd->start <= value
+ && (info->ent->depends[i]->opd->start
+ + info->ent->depends[i]->opd->size) > value)
+ break;
+
+ if (i == info->ent->ndepends)
+ {
+ error (0, 0, "%s: R_PPC64_JMP_SLOT doesn't resolve to an .opd address",
+ dso->filename);
+ return 1;
+ }
+ if ((value - info->ent->depends[i]->opd->start) % 8)
+ {
+ error (0, 0, "%s: R_PPC64_JMP_SLOT doesn't resolve to valid .opd section location",
+ dso->filename);
+ return 1;
+ }
+ n = (value - info->ent->depends[i]->opd->start) / 8;
+ rec.fn = info->ent->depends[i]->opd->table[n];
+ rec.toc = info->ent->depends[i]->opd->table[n + 1];
+ rec.chain = info->ent->depends[i]->opd->table[n + 2];
+ }
+ write_be64 (dso, rela->r_offset, rec.fn);
+ write_be64 (dso, rela->r_offset + 8, rec.toc);
+ write_be64 (dso, rela->r_offset + 16, rec.chain);
+ return 0;
+}
+
+static int
+ppc64_prelink_rela (struct prelink_info *info, GElf_Rela *rela,
+ GElf_Addr relaaddr)
+{
+ DSO *dso = info->dso;
+ GElf_Addr value;
+
+ if (GELF_R_TYPE (rela->r_info) == R_PPC64_NONE
+ || GELF_R_TYPE (rela->r_info) == R_PPC64_IRELATIVE
+ || GELF_R_TYPE (rela->r_info) == R_PPC64_JMP_IREL)
+ return 0;
+ else if (GELF_R_TYPE (rela->r_info) == R_PPC64_RELATIVE)
+ {
+ write_be64 (dso, rela->r_offset, rela->r_addend);
+ return 0;
+ }
+ value = info->resolve (info, GELF_R_SYM (rela->r_info),
+ GELF_R_TYPE (rela->r_info));
+ value += rela->r_addend;
+ switch (GELF_R_TYPE (rela->r_info))
+ {
+ case R_PPC64_GLOB_DAT:
+ case R_PPC64_ADDR64:
+ case R_PPC64_UADDR64:
+ write_be64 (dso, rela->r_offset, value);
+ break;
+ case R_PPC64_DTPREL64:
+ write_be64 (dso, rela->r_offset, value - 0x8000);
+ break;
+ case R_PPC64_ADDR32:
+ case R_PPC64_UADDR32:
+ write_be32 (dso, rela->r_offset, value);
+ break;
+ case R_PPC64_JMP_SLOT:
+ return ppc64_fixup_plt (info, rela, value);
+ case R_PPC64_ADDR16:
+ case R_PPC64_UADDR16:
+ case R_PPC64_ADDR16_LO:
+ write_be16 (dso, rela->r_offset, value);
+ break;
+ case R_PPC64_DTPREL16:
+ case R_PPC64_DTPREL16_LO:
+ write_be16 (dso, rela->r_offset, value - 0x8000);
+ break;
+ case R_PPC64_ADDR16_HI:
+ case R_PPC64_DTPREL16_HA:
+ write_be16 (dso, rela->r_offset, value >> 16);
+ break;
+ case R_PPC64_DTPREL16_HI:
+ write_be16 (dso, rela->r_offset, (value - 0x8000) >> 16);
+ break;
+ case R_PPC64_ADDR16_HA:
+ write_be16 (dso, rela->r_offset, (value + 0x8000) >> 16);
+ break;
+ case R_PPC64_ADDR16_HIGHER:
+ write_be16 (dso, rela->r_offset, value >> 32);
+ break;
+ case R_PPC64_ADDR16_HIGHERA:
+ write_be16 (dso, rela->r_offset, (value + 0x8000) >> 32);
+ break;
+ case R_PPC64_ADDR16_HIGHEST:
+ write_be16 (dso, rela->r_offset, value >> 48);
+ break;
+ case R_PPC64_ADDR16_HIGHESTA:
+ write_be16 (dso, rela->r_offset, (value + 0x8000) >> 48);
+ break;
+ case R_PPC64_ADDR16_LO_DS:
+ case R_PPC64_ADDR16_DS:
+ write_be16 (dso, rela->r_offset,
+ (value & 0xfffc) | read_ube16 (dso, rela->r_offset & 3));
+ break;
+ case R_PPC64_ADDR24:
+ write_be32 (dso, rela->r_offset,
+ (value & 0x03fffffc)
+ | (read_ube32 (dso, rela->r_offset) & 0xfc000003));
+ break;
+ case R_PPC64_ADDR14:
+ write_be32 (dso, rela->r_offset,
+ (value & 0xfffc)
+ | (read_ube32 (dso, rela->r_offset) & 0xffff0003));
+ break;
+ case R_PPC64_ADDR14_BRTAKEN:
+ case R_PPC64_ADDR14_BRNTAKEN:
+ write_be32 (dso, rela->r_offset,
+ (value & 0xfffc)
+ | (read_ube32 (dso, rela->r_offset) & 0xffdf0003)
+ | ((((GELF_R_TYPE (rela->r_info) == R_PPC64_ADDR14_BRTAKEN)
+ << 21)
+ ^ (value >> 42)) & 0x00200000));
+ break;
+ case R_PPC64_REL24:
+ write_be32 (dso, rela->r_offset,
+ ((value - rela->r_offset) & 0x03fffffc)
+ | (read_ube32 (dso, rela->r_offset) & 0xfc000003));
+ break;
+ case R_PPC64_REL32:
+ write_be32 (dso, rela->r_offset, value - rela->r_offset);
+ break;
+ case R_PPC64_REL64:
+ write_be64 (dso, rela->r_offset, value - rela->r_offset);
+ break;
+ /* DTPMOD64 and TPREL* is impossible to predict in shared libraries
+ unless prelink sets the rules. */
+ case R_PPC64_DTPMOD64:
+ if (dso->ehdr.e_type == ET_EXEC)
+ {
+ error (0, 0, "%s: R_PPC64_DTPMOD64 reloc in executable?",
+ dso->filename);
+ return 1;
+ }
+ break;
+ case R_PPC64_TPREL64:
+ case R_PPC64_TPREL16:
+ case R_PPC64_TPREL16_LO:
+ case R_PPC64_TPREL16_HI:
+ case R_PPC64_TPREL16_HA:
+ if (dso->ehdr.e_type == ET_EXEC && info->resolvetls)
+ {
+ value += info->resolvetls->offset - 0x7000;
+ switch (GELF_R_TYPE (rela->r_info))
+ {
+ case R_PPC64_TPREL64:
+ write_be64 (dso, rela->r_offset, value);
+ break;
+ case R_PPC64_TPREL16:
+ case R_PPC64_TPREL16_LO:
+ write_be16 (dso, rela->r_offset, value);
+ break;
+ case R_PPC64_TPREL16_HI:
+ write_be16 (dso, rela->r_offset, value >> 16);
+ break;
+ case R_PPC64_TPREL16_HA:
+ write_be16 (dso, rela->r_offset, (value + 0x8000) >> 16);
+ break;
+ }
+ }
+ break;
+ case R_PPC64_COPY:
+ if (dso->ehdr.e_type == ET_EXEC)
+ /* COPY relocs are handled specially in generic code. */
+ return 0;
+ error (0, 0, "%s: R_PPC64_COPY reloc in shared library?", dso->filename);
+ return 1;
+ default:
+ error (0, 0, "%s: Unknown ppc relocation type %d", dso->filename,
+ (int) GELF_R_TYPE (rela->r_info));
+ return 1;
+ }
+ return 0;
+}
+
+static int
+ppc64_apply_conflict_rela (struct prelink_info *info, GElf_Rela *rela,
+ char *buf, GElf_Addr dest_addr)
+{
+ GElf_Rela *ret;
+ switch (GELF_R_TYPE (rela->r_info))
+ {
+ case R_PPC64_ADDR64:
+ case R_PPC64_UADDR64:
+ buf_write_be64 (buf, rela->r_addend);
+ break;
+ case R_PPC64_ADDR32:
+ case R_PPC64_UADDR32:
+ buf_write_be32 (buf, rela->r_addend);
+ break;
+ case R_PPC64_ADDR16:
+ case R_PPC64_UADDR16:
+ buf_write_be16 (buf, rela->r_addend);
+ break;
+ case R_PPC64_IRELATIVE:
+ if (dest_addr == 0)
+ return 5;
+ ret = prelink_conflict_add_rela (info);
+ if (ret == NULL)
+ return 1;
+ ret->r_offset = dest_addr;
+ ret->r_info = GELF_R_INFO (0, R_PPC64_IRELATIVE);
+ ret->r_addend = rela->r_addend;
+ break;
+ default:
+ abort ();
+ }
+ return 0;
+}
+
+static int
+ppc64_apply_rel (struct prelink_info *info, GElf_Rel *rel, char *buf)
+{
+ error (0, 0, "%s: PowerPC64 doesn't support REL relocs", info->dso->filename);
+ return 1;
+}
+
+static int
+ppc64_apply_rela (struct prelink_info *info, GElf_Rela *rela, char *buf)
+{
+ GElf_Addr value;
+
+ value = info->resolve (info, GELF_R_SYM (rela->r_info),
+ GELF_R_TYPE (rela->r_info));
+ value += rela->r_addend;
+ switch (GELF_R_TYPE (rela->r_info))
+ {
+ case R_PPC64_NONE:
+ break;
+ case R_PPC64_GLOB_DAT:
+ case R_PPC64_ADDR64:
+ case R_PPC64_UADDR64:
+ buf_write_be64 (buf, value);
+ break;
+ case R_PPC64_ADDR32:
+ case R_PPC64_UADDR32:
+ buf_write_be32 (buf, value);
+ break;
+ case R_PPC64_ADDR16_HA:
+ value += 0x8000;
+ /* FALLTHROUGH */
+ case R_PPC64_ADDR16_HI:
+ value = value >> 16;
+ /* FALLTHROUGH */
+ case R_PPC64_ADDR16:
+ case R_PPC64_UADDR16:
+ case R_PPC64_ADDR16_LO:
+ buf_write_be16 (buf, value);
+ break;
+ case R_PPC64_ADDR16_HIGHERA:
+ value += 0x8000;
+ /* FALLTHROUGH */
+ case R_PPC64_ADDR16_HIGHER:
+ buf_write_be16 (buf, value >> 32);
+ break;
+ case R_PPC64_ADDR16_HIGHESTA:
+ value += 0x8000;
+ /* FALLTHROUGH */
+ case R_PPC64_ADDR16_HIGHEST:
+ buf_write_be16 (buf, value >> 48);
+ break;
+ case R_PPC64_ADDR16_LO_DS:
+ case R_PPC64_ADDR16_DS:
+ buf_write_be16 (buf, (value & 0xfffc)
+ | (buf_read_ube16 (buf) & 3));
+ break;
+ case R_PPC64_ADDR24:
+ buf_write_be32 (buf, (value & 0x03fffffc)
+ | (buf_read_ube32 (buf) & 0xfc000003));
+ break;
+ case R_PPC64_ADDR14:
+ buf_write_be32 (buf, (value & 0xfffc)
+ | (buf_read_ube32 (buf) & 0xffff0003));
+ break;
+ case R_PPC64_ADDR14_BRTAKEN:
+ case R_PPC64_ADDR14_BRNTAKEN:
+ buf_write_be32 (buf, (value & 0xfffc)
+ | (buf_read_ube32 (buf) & 0xffdf0003)
+ | ((((GELF_R_TYPE (rela->r_info)
+ == R_PPC64_ADDR14_BRTAKEN) << 21)
+ ^ (value >> 42)) & 0x00200000));
+ break;
+ case R_PPC64_REL24:
+ buf_write_be32 (buf, ((value - rela->r_offset) & 0x03fffffc)
+ | (buf_read_ube32 (buf) & 0xfc000003));
+ break;
+ case R_PPC64_REL32:
+ buf_write_be32 (buf, value - rela->r_offset);
+ break;
+ case R_PPC64_REL64:
+ buf_write_be64 (buf, value - rela->r_offset);
+ break;
+ case R_PPC64_RELATIVE:
+ error (0, 0, "%s: R_PPC64_RELATIVE in ET_EXEC object?",
+ info->dso->filename);
+ return 1;
+ default:
+ return 1;
+ }
+ return 0;
+}
+
+static int
+ppc64_prelink_conflict_rel (DSO *dso, struct prelink_info *info,
+ GElf_Rel *rel, GElf_Addr reladdr)
+{
+ error (0, 0, "%s: PowerPC64 doesn't support REL relocs", dso->filename);
+ return 1;
+}
+
+static int
+ppc64_prelink_conflict_rela (DSO *dso, struct prelink_info *info,
+ GElf_Rela *rela, GElf_Addr relaaddr)
+{
+ GElf_Addr value;
+ struct prelink_conflict *conflict;
+ struct prelink_tls *tls;
+ GElf_Rela *ret;
+ int r_type;
+
+ if (GELF_R_TYPE (rela->r_info) == R_PPC64_RELATIVE
+ || GELF_R_TYPE (rela->r_info) == R_PPC64_NONE)
+ /* Fast path: nothing to do. */
+ return 0;
+ conflict = prelink_conflict (info, GELF_R_SYM (rela->r_info),
+ GELF_R_TYPE (rela->r_info));
+ if (conflict == NULL)
+ {
+ switch (GELF_R_TYPE (rela->r_info))
+ {
+ /* Even local DTPMOD and TPREL relocs need conflicts. */
+ case R_PPC64_DTPMOD64:
+ case R_PPC64_TPREL64:
+ case R_PPC64_TPREL16:
+ case R_PPC64_TPREL16_LO:
+ case R_PPC64_TPREL16_HI:
+ case R_PPC64_TPREL16_HA:
+ if (info->curtls == NULL || info->dso == dso)
+ return 0;
+ break;
+ /* Similarly IRELATIVE relocations always need conflicts. */
+ case R_PPC64_IRELATIVE:
+ case R_PPC64_JMP_IREL:
+ break;
+ default:
+ return 0;
+ }
+ value = 0;
+ }
+ else if (info->dso == dso && !conflict->ifunc)
+ return 0;
+ else
+ {
+ /* DTPREL wants to see only real conflicts, not lookups
+ with reloc_class RTYPE_CLASS_TLS. */
+ if (conflict->lookup.tls == conflict->conflict.tls
+ && conflict->lookupval == conflict->conflictval)
+ switch (GELF_R_TYPE (rela->r_info))
+ {
+ case R_PPC64_DTPREL64:
+ case R_PPC64_DTPREL16:
+ case R_PPC64_DTPREL16_LO:
+ case R_PPC64_DTPREL16_HI:
+ case R_PPC64_DTPREL16_HA:
+ return 0;
+ }
+
+ value = conflict_lookup_value (conflict);
+ }
+ ret = prelink_conflict_add_rela (info);
+ if (ret == NULL)
+ return 1;
+ ret->r_offset = rela->r_offset;
+ value += rela->r_addend;
+ r_type = GELF_R_TYPE (rela->r_info);
+ switch (r_type)
+ {
+ case R_PPC64_GLOB_DAT:
+ r_type = R_PPC64_ADDR64;
+ case R_PPC64_ADDR64:
+ case R_PPC64_UADDR64:
+ if (conflict != NULL && conflict->ifunc)
+ r_type = R_PPC64_IRELATIVE;
+ break;
+ case R_PPC64_IRELATIVE:
+ case R_PPC64_JMP_IREL:
+ break;
+ case R_PPC64_JMP_SLOT:
+ if (conflict != NULL && conflict->ifunc)
+ r_type = R_PPC64_JMP_IREL;
+ break;
+ case R_PPC64_ADDR32:
+ case R_PPC64_UADDR32:
+ value = (Elf32_Sword) value;
+ break;
+ case R_PPC64_ADDR16_HA:
+ value += 0x8000;
+ /* FALLTHROUGH */
+ case R_PPC64_ADDR16_HI:
+ value = value >> 16;
+ /* FALLTHROUGH */
+ case R_PPC64_ADDR16:
+ case R_PPC64_UADDR16:
+ case R_PPC64_ADDR16_LO:
+ if (r_type != R_PPC64_UADDR16)
+ r_type = R_PPC64_ADDR16;
+ value = ((value & 0xffff) ^ 0x8000) - 0x8000;
+ break;
+ case R_PPC64_ADDR16_HIGHERA:
+ value += 0x8000;
+ /* FALLTHROUGH */
+ case R_PPC64_ADDR16_HIGHER:
+ r_type = R_PPC64_ADDR16;
+ value = (((value >> 32) & 0xffff) ^ 0x8000) - 0x8000;
+ break;
+ case R_PPC64_ADDR16_HIGHESTA:
+ value += 0x8000;
+ /* FALLTHROUGH */
+ case R_PPC64_ADDR16_HIGHEST:
+ r_type = R_PPC64_ADDR16;
+ value = ((Elf64_Sxword) value) >> 48;
+ break;
+ case R_PPC64_ADDR16_LO_DS:
+ case R_PPC64_ADDR16_DS:
+ r_type = R_PPC64_ADDR16;
+ value = ((value & 0xffff) ^ 0x8000) - 0x8000;
+ value |= read_ube16 (dso, rela->r_offset) & 3;
+ break;
+ case R_PPC64_ADDR24:
+ r_type = R_PPC64_ADDR32;
+ value = (value & 0x03fffffc)
+ | (read_ube32 (dso, rela->r_offset) & 0xfc000003);
+ value = (Elf32_Sword) value;
+ break;
+ case R_PPC64_ADDR14:
+ r_type = R_PPC64_ADDR32;
+ value = (value & 0xfffc)
+ | (read_ube32 (dso, rela->r_offset) & 0xffff0003);
+ value = (Elf32_Sword) value;
+ break;
+ case R_PPC64_ADDR14_BRTAKEN:
+ case R_PPC64_ADDR14_BRNTAKEN:
+ r_type = R_PPC64_ADDR32;
+ value = (value & 0xfffc)
+ | (read_ube32 (dso, rela->r_offset) & 0xffdf0003)
+ | ((((r_type == R_PPC64_ADDR14_BRTAKEN) << 21)
+ ^ (value >> 42)) & 0x00200000);
+ value = (Elf32_Sword) value;
+ break;
+ case R_PPC64_REL24:
+ r_type = R_PPC64_ADDR32;
+ value = ((value - rela->r_offset) & 0x03fffffc)
+ | (read_ube32 (dso, rela->r_offset) & 0xfc000003);
+ value = (Elf32_Sword) value;
+ break;
+ case R_PPC64_REL32:
+ r_type = R_PPC64_ADDR32;
+ value -= rela->r_offset;
+ value = (Elf32_Sword) value;
+ break;
+ case R_PPC64_REL64:
+ r_type = R_PPC64_ADDR64;
+ value -= rela->r_offset;
+ break;
+ case R_PPC64_DTPMOD64:
+ case R_PPC64_DTPREL64:
+ case R_PPC64_DTPREL16:
+ case R_PPC64_DTPREL16_LO:
+ case R_PPC64_DTPREL16_HI:
+ case R_PPC64_DTPREL16_HA:
+ case R_PPC64_TPREL64:
+ case R_PPC64_TPREL16:
+ case R_PPC64_TPREL16_LO:
+ case R_PPC64_TPREL16_HI:
+ case R_PPC64_TPREL16_HA:
+ if (conflict != NULL
+ && (conflict->reloc_class != RTYPE_CLASS_TLS
+ || conflict->lookup.tls == NULL))
+ {
+ error (0, 0, "%s: TLS reloc not resolving to STT_TLS symbol",
+ dso->filename);
+ return 1;
+ }
+ tls = conflict ? conflict->lookup.tls : info->curtls;
+ r_type = R_PPC64_ADDR16;
+ switch (GELF_R_TYPE (rela->r_info))
+ {
+ case R_PPC64_DTPMOD64:
+ r_type = R_PPC64_ADDR64;
+ value = tls->modid;
+ break;
+ case R_PPC64_DTPREL64:
+ r_type = R_PPC64_ADDR64;
+ value -= 0x8000;
+ break;
+ case R_PPC64_DTPREL16:
+ case R_PPC64_DTPREL16_LO:
+ value -= 0x8000;
+ break;
+ case R_PPC64_DTPREL16_HI:
+ value = (value - 0x8000) >> 16;
+ break;
+ case R_PPC64_DTPREL16_HA:
+ value >>= 16;
+ break;
+ case R_PPC64_TPREL64:
+ r_type = R_PPC64_ADDR64;
+ value += tls->offset - 0x7000;
+ break;
+ case R_PPC64_TPREL16:
+ case R_PPC64_TPREL16_LO:
+ value += tls->offset - 0x7000;
+ break;
+ case R_PPC64_TPREL16_HI:
+ value = (value + tls->offset - 0x7000) >> 16;
+ break;
+ case R_PPC64_TPREL16_HA:
+ value = (value + tls->offset - 0x7000 + 0x8000) >> 16;
+ break;
+ }
+ if (r_type == R_PPC64_ADDR16)
+ value = ((value & 0xffff) ^ 0x8000) - 0x8000;
+ break;
+ default:
+ error (0, 0, "%s: Unknown PowerPC64 relocation type %d", dso->filename,
+ r_type);
+ return 1;
+ }
+ if (conflict != NULL && conflict->ifunc
+ && r_type != R_PPC64_IRELATIVE && r_type != R_PPC64_JMP_IREL)
+ {
+ error (0, 0, "%s: relocation %d against IFUNC symbol", dso->filename,
+ (int) GELF_R_TYPE (rela->r_info));
+ return 1;
+ }
+ ret->r_info = GELF_R_INFO (0, r_type);
+ ret->r_addend = value;
+ return 0;
+}
+
+static int
+ppc64_rel_to_rela (DSO *dso, GElf_Rel *rel, GElf_Rela *rela)
+{
+ error (0, 0, "%s: PowerPC64 doesn't support REL relocs", dso->filename);
+ return 1;
+}
+
+static int
+ppc64_need_rel_to_rela (DSO *dso, int first, int last)
+{
+ return 0;
+}
+
+static int
+ppc64_undo_prelink_rela (DSO *dso, GElf_Rela *rela, GElf_Addr relaaddr)
+{
+ switch (GELF_R_TYPE (rela->r_info))
+ {
+ case R_PPC64_NONE:
+ return 0;
+ case R_PPC64_JMP_SLOT:
+ /* .plt section will become SHT_NOBITS. */
+ return 0;
+ case R_PPC64_JMP_IREL:
+ /* .iplt section will become SHT_NOBITS. */
+ return 0;
+ case R_PPC64_RELATIVE:
+ case R_PPC64_ADDR64:
+ case R_PPC64_IRELATIVE:
+ write_be64 (dso, rela->r_offset, rela->r_addend);
+ break;
+ case R_PPC64_GLOB_DAT:
+ case R_PPC64_UADDR64:
+ case R_PPC64_DTPREL64:
+ case R_PPC64_TPREL64:
+ case R_PPC64_DTPMOD64:
+ case R_PPC64_REL64:
+ write_be64 (dso, rela->r_offset, 0);
+ break;
+ case R_PPC64_ADDR32:
+ case R_PPC64_UADDR32:
+ case R_PPC64_REL32:
+ write_be32 (dso, rela->r_offset, 0);
+ break;
+ case R_PPC64_ADDR16_HA:
+ case R_PPC64_DTPREL16_HA:
+ case R_PPC64_TPREL16_HA:
+ case R_PPC64_ADDR16_HI:
+ case R_PPC64_DTPREL16_HI:
+ case R_PPC64_TPREL16_HI:
+ case R_PPC64_ADDR16:
+ case R_PPC64_UADDR16:
+ case R_PPC64_ADDR16_LO:
+ case R_PPC64_DTPREL16:
+ case R_PPC64_TPREL16:
+ case R_PPC64_DTPREL16_LO:
+ case R_PPC64_TPREL16_LO:
+ case R_PPC64_ADDR16_HIGHERA:
+ case R_PPC64_ADDR16_HIGHER:
+ case R_PPC64_ADDR16_HIGHESTA:
+ case R_PPC64_ADDR16_HIGHEST:
+ case R_PPC64_ADDR16_LO_DS:
+ case R_PPC64_ADDR16_DS:
+ write_be16 (dso, rela->r_offset, 0);
+ break;
+ case R_PPC64_ADDR24:
+ case R_PPC64_REL24:
+ write_be32 (dso, rela->r_offset,
+ read_ube32 (dso, rela->r_offset) & 0xfc000003);
+ break;
+ case R_PPC64_ADDR14:
+ write_be32 (dso, rela->r_offset,
+ read_ube32 (dso, rela->r_offset) & 0xffff0003);
+ break;
+ case R_PPC64_ADDR14_BRTAKEN:
+ case R_PPC64_ADDR14_BRNTAKEN:
+ write_be32 (dso, rela->r_offset,
+ read_ube32 (dso, rela->r_offset) & 0xffdf0003);
+ break;
+ case R_PPC64_COPY:
+ if (dso->ehdr.e_type == ET_EXEC)
+ /* COPY relocs are handled specially in generic code. */
+ return 0;
+ error (0, 0, "%s: R_PPC64_COPY reloc in shared library?", dso->filename);
+ return 1;
+ default:
+ error (0, 0, "%s: Unknown ppc relocation type %d", dso->filename,
+ (int) GELF_R_TYPE (rela->r_info));
+ return 1;
+ }
+ return 0;
+}
+
+static int
+ppc64_reloc_size (int reloc_type)
+{
+ switch (reloc_type)
+ {
+ case R_PPC64_ADDR16:
+ case R_PPC64_UADDR16:
+ case R_PPC64_ADDR16_LO:
+ case R_PPC64_ADDR16_HA:
+ case R_PPC64_ADDR16_HI:
+ case R_PPC64_ADDR16_LO_DS:
+ case R_PPC64_ADDR16_DS:
+ case R_PPC64_ADDR16_HIGHER:
+ case R_PPC64_ADDR16_HIGHERA:
+ case R_PPC64_ADDR16_HIGHEST:
+ case R_PPC64_ADDR16_HIGHESTA:
+ case R_PPC64_DTPREL16:
+ case R_PPC64_DTPREL16_LO:
+ case R_PPC64_DTPREL16_HI:
+ case R_PPC64_DTPREL16_HA:
+ case R_PPC64_TPREL16:
+ case R_PPC64_TPREL16_LO:
+ case R_PPC64_TPREL16_HI:
+ case R_PPC64_TPREL16_HA:
+ return 2;
+ case R_PPC64_GLOB_DAT:
+ case R_PPC64_ADDR64:
+ case R_PPC64_UADDR64:
+ case R_PPC64_REL64:
+ case R_PPC64_DTPMOD64:
+ case R_PPC64_DTPREL64:
+ case R_PPC64_TPREL64:
+ case R_PPC64_IRELATIVE:
+ return 8;
+ default:
+ break;
+ }
+ return 4;
+}
+
+static int
+ppc64_reloc_class (int reloc_type)
+{
+ switch (reloc_type)
+ {
+ case R_PPC64_COPY: return RTYPE_CLASS_COPY | RTYPE_CLASS_PLT;
+ default:
+ if (reloc_type >= R_PPC64_DTPMOD64
+ && reloc_type <= R_PPC64_TPREL16_HIGHESTA)
+ return RTYPE_CLASS_TLS;
+ return RTYPE_CLASS_PLT;
+ }
+}
+
+static int
+ppc64_read_opd (DSO *dso, struct prelink_entry *ent)
+{
+ int opd;
+ GElf_Addr n, s;
+
+ free (ent->opd);
+ ent->opd = NULL;
+ for (opd = 1; opd < dso->ehdr.e_shnum; ++opd)
+ if (dso->shdr[opd].sh_type == SHT_PROGBITS
+ && ! strcmp (strptr (dso, dso->ehdr.e_shstrndx,
+ dso->shdr[opd].sh_name), ".opd"))
+ break;
+ if (opd == dso->ehdr.e_shnum)
+ return 0;
+ ent->opd = malloc (sizeof (struct opd_lib) + dso->shdr[opd].sh_size);
+ /* The error will happen only when we'll need the opd. */
+ if (ent->opd == NULL)
+ return 0;
+ s = dso->shdr[opd].sh_addr;
+ for (n = 0; n < dso->shdr[opd].sh_size / 8; ++n, s += 8)
+ ent->opd->table[n] = read_ube64 (dso, s);
+ ent->opd->start = dso->shdr[opd].sh_addr;
+ ent->opd->size = dso->shdr[opd].sh_size;
+ return 0;
+}
+
+static int
+ppc64_free_opd (struct prelink_entry *ent)
+{
+ free (ent->opd);
+ ent->opd = NULL;
+ return 0;
+}
+
+PL_ARCH(ppc64) = {
+ .name = "PowerPC",
+ .class = ELFCLASS64,
+ .machine = EM_PPC64,
+ .alternate_machine = { EM_NONE },
+ .R_JMP_SLOT = R_PPC64_JMP_SLOT,
+ .R_COPY = R_PPC64_COPY,
+ .R_RELATIVE = R_PPC64_RELATIVE,
+ .rtype_class_valid = RTYPE_CLASS_PLT,
+ .dynamic_linker = "/lib64/ld64.so.1",
+ .adjust_section = ppc64_adjust_section,
+ .adjust_dyn = ppc64_adjust_dyn,
+ .adjust_rel = ppc64_adjust_rel,
+ .adjust_rela = ppc64_adjust_rela,
+ .prelink_rel = ppc64_prelink_rel,
+ .prelink_rela = ppc64_prelink_rela,
+ .prelink_conflict_rel = ppc64_prelink_conflict_rel,
+ .prelink_conflict_rela = ppc64_prelink_conflict_rela,
+ .apply_conflict_rela = ppc64_apply_conflict_rela,
+ .apply_rel = ppc64_apply_rel,
+ .apply_rela = ppc64_apply_rela,
+ .rel_to_rela = ppc64_rel_to_rela,
+ .need_rel_to_rela = ppc64_need_rel_to_rela,
+ .reloc_size = ppc64_reloc_size,
+ .reloc_class = ppc64_reloc_class,
+ .read_opd = ppc64_read_opd,
+ .free_opd = ppc64_free_opd,
+ .max_reloc_size = 8,
+ .undo_prelink_rela = ppc64_undo_prelink_rela,
+ /* Although TASK_UNMAPPED_BASE is 0x8000000000, we leave some
+ area so that mmap of /etc/ld.so.cache and ld.so's malloc
+ does not take some library's VA slot.
+ Also, if this guard area isn't too small, typically
+ even dlopened libraries will get the slots they desire. */
+ .mmap_base = 0x8001000000LL,
+ .mmap_end = 0x8100000000LL,
+ .max_page_size = 0x10000,
+ .page_size = 0x1000
+};
diff --git a/src/arch-s390.c b/src/arch-s390.c
new file mode 100644
index 0000000..e5fe130
--- /dev/null
+++ b/src/arch-s390.c
@@ -0,0 +1,632 @@
+/* Copyright (C) 2001, 2002, 2003, 2004, 2009, 2010, 2013 Red Hat, Inc.
+ Written by Jakub Jelinek <jakub@redhat.com>, 2001.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include <config.h>
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <locale.h>
+#include <error.h>
+#include <argp.h>
+#include <stdlib.h>
+
+#include "prelink.h"
+
+static int
+s390_adjust_dyn (DSO *dso, int n, GElf_Dyn *dyn, GElf_Addr start,
+ GElf_Addr adjust)
+{
+ if (dyn->d_tag == DT_PLTGOT)
+ {
+ int sec = addr_to_sec (dso, dyn->d_un.d_ptr);
+ Elf64_Addr data;
+
+ if (sec == -1)
+ return 0;
+
+ data = read_ube32 (dso, dyn->d_un.d_ptr);
+ /* If .got.plt[0] points to _DYNAMIC, it needs to be adjusted. */
+ if (data == dso->shdr[n].sh_addr && data >= start)
+ write_be32 (dso, dyn->d_un.d_ptr, data + adjust);
+
+ data = read_ube32 (dso, dyn->d_un.d_ptr + 4);
+ /* If .got.plt[1] points to .plt + 0x2c, it needs to be adjusted. */
+ if (data && data >= start)
+ {
+ int i;
+
+ for (i = 1; i < dso->ehdr.e_shnum; i++)
+ if (data == dso->shdr[i].sh_addr + 0x2c
+ && dso->shdr[i].sh_type == SHT_PROGBITS
+ && strcmp (strptr (dso, dso->ehdr.e_shstrndx,
+ dso->shdr[i].sh_name), ".plt") == 0)
+ {
+ write_be32 (dso, dyn->d_un.d_ptr + 4, data + adjust);
+ break;
+ }
+ }
+ }
+ return 0;
+}
+
+static int
+s390_adjust_rel (DSO *dso, GElf_Rel *rel, GElf_Addr start,
+ GElf_Addr adjust)
+{
+ error (0, 0, "%s: S390 doesn't support REL relocs", dso->filename);
+ return 1;
+}
+
+static int
+s390_adjust_rela (DSO *dso, GElf_Rela *rela, GElf_Addr start,
+ GElf_Addr adjust)
+{
+ Elf32_Addr addr;
+
+ switch (GELF_R_TYPE (rela->r_info))
+ {
+ case R_390_RELATIVE:
+ if ((Elf32_Addr) rela->r_addend >= start)
+ {
+ addr = read_ube32 (dso, rela->r_offset);
+ if (addr == rela->r_addend)
+ write_be32 (dso, rela->r_offset, addr + adjust);
+ rela->r_addend += (Elf32_Sword) adjust;
+ }
+ break;
+ case R_390_IRELATIVE:
+ if (rela->r_addend >= start)
+ /* Adjust the resolver function address. */
+ rela->r_addend += adjust;
+ /* FALLTHROUGH */
+ case R_390_JMP_SLOT:
+ /* Adjust the address in the GOT slot. */
+ addr = read_ube32 (dso, rela->r_offset);
+ if (addr >= start)
+ write_be32 (dso, rela->r_offset, addr + adjust);
+ break;
+ }
+ return 0;
+}
+
+static int
+s390_prelink_rel (struct prelink_info *info, GElf_Rel *rel, GElf_Addr reladdr)
+{
+ error (0, 0, "%s: S390 doesn't support REL relocs", info->dso->filename);
+ return 1;
+}
+
+static int
+s390_prelink_rela (struct prelink_info *info, GElf_Rela *rela,
+ GElf_Addr relaaddr)
+{
+ DSO *dso = info->dso;
+ GElf_Addr value;
+
+ if (GELF_R_TYPE (rela->r_info) == R_390_NONE
+ || GELF_R_TYPE (rela->r_info) == R_390_IRELATIVE)
+ return 0;
+ else if (GELF_R_TYPE (rela->r_info) == R_390_RELATIVE)
+ {
+ write_be32 (dso, rela->r_offset, rela->r_addend);
+ return 0;
+ }
+ value = info->resolve (info, GELF_R_SYM (rela->r_info),
+ GELF_R_TYPE (rela->r_info));
+ value += rela->r_addend;
+ switch (GELF_R_TYPE (rela->r_info))
+ {
+ case R_390_GLOB_DAT:
+ case R_390_JMP_SLOT:
+ write_be32 (dso, rela->r_offset, value - rela->r_addend);
+ break;
+ case R_390_32:
+ write_be32 (dso, rela->r_offset, value);
+ break;
+ case R_390_PC32:
+ write_be32 (dso, rela->r_offset, value - rela->r_offset);
+ break;
+ case R_390_PC32DBL:
+ case R_390_PLT32DBL:
+ write_be32 (dso, rela->r_offset,
+ ((Elf32_Sword) (value - rela->r_offset)) >> 1);
+ break;
+ case R_390_16:
+ write_be16 (dso, rela->r_offset, value);
+ break;
+ case R_390_PC16:
+ write_be16 (dso, rela->r_offset, value - rela->r_offset);
+ break;
+ case R_390_PC16DBL:
+ case R_390_PLT16DBL:
+ write_be16 (dso, rela->r_offset,
+ ((int16_t) (value - rela->r_offset)) >> 1);
+ break;
+ case R_390_8:
+ write_8 (dso, rela->r_offset, value);
+ break;
+ case R_390_TLS_DTPOFF:
+ write_be32 (dso, rela->r_offset, value);
+ break;
+ /* DTPMOD and TPOFF is impossible to predict in shared libraries
+ unless prelink sets the rules. */
+ case R_390_TLS_DTPMOD:
+ if (dso->ehdr.e_type == ET_EXEC)
+ {
+ error (0, 0, "%s: R_390_TLS_DTPMOD reloc in executable?",
+ dso->filename);
+ return 1;
+ }
+ break;
+ case R_390_TLS_TPOFF:
+ if (dso->ehdr.e_type == ET_EXEC && info->resolvetls)
+ write_be32 (dso, rela->r_offset,
+ value - info->resolvetls->offset);
+ break;
+ case R_390_COPY:
+ if (dso->ehdr.e_type == ET_EXEC)
+ /* COPY relocs are handled specially in generic code. */
+ return 0;
+ error (0, 0, "%s: R_390_COPY reloc in shared library?", dso->filename);
+ return 1;
+ default:
+ error (0, 0, "%s: Unknown S390 relocation type %d", dso->filename,
+ (int) GELF_R_TYPE (rela->r_info));
+ return 1;
+ }
+ return 0;
+}
+
+static int
+s390_apply_conflict_rela (struct prelink_info *info, GElf_Rela *rela,
+ char *buf, GElf_Addr dest_addr)
+{
+ GElf_Rela *ret;
+ switch (GELF_R_TYPE (rela->r_info))
+ {
+ case R_390_32:
+ buf_write_be32 (buf, rela->r_addend);
+ break;
+ case R_390_16:
+ buf_write_be16 (buf, rela->r_addend);
+ break;
+ case R_390_8:
+ buf_write_8 (buf, rela->r_addend);
+ break;
+ case R_390_IRELATIVE:
+ if (dest_addr == 0)
+ return 5;
+ ret = prelink_conflict_add_rela (info);
+ if (ret == NULL)
+ return 1;
+ ret->r_offset = dest_addr;
+ ret->r_info = GELF_R_INFO (0, R_390_IRELATIVE);
+ ret->r_addend = rela->r_addend;
+ break;
+ default:
+ abort ();
+ }
+ return 0;
+}
+
+static int
+s390_apply_rel (struct prelink_info *info, GElf_Rel *rel, char *buf)
+{
+ error (0, 0, "%s: S390 doesn't support REL relocs", info->dso->filename);
+ return 1;
+}
+
+static int
+s390_apply_rela (struct prelink_info *info, GElf_Rela *rela, char *buf)
+{
+ GElf_Addr value;
+
+ value = info->resolve (info, GELF_R_SYM (rela->r_info),
+ GELF_R_TYPE (rela->r_info));
+ value += rela->r_addend;
+ switch (GELF_R_TYPE (rela->r_info))
+ {
+ case R_390_NONE:
+ break;
+ case R_390_GLOB_DAT:
+ case R_390_JMP_SLOT:
+ buf_write_be32 (buf, value - rela->r_addend);
+ break;
+ case R_390_32:
+ buf_write_be32 (buf, value);
+ break;
+ case R_390_PC32:
+ buf_write_be32 (buf, value - rela->r_offset);
+ break;
+ case R_390_PC32DBL:
+ case R_390_PLT32DBL:
+ buf_write_be32 (buf, ((Elf32_Sword) (value - rela->r_offset)) >> 1);
+ break;
+ case R_390_16:
+ buf_write_be16 (buf, value);
+ break;
+ case R_390_PC16:
+ buf_write_be16 (buf, value - rela->r_offset);
+ break;
+ case R_390_PC16DBL:
+ case R_390_PLT16DBL:
+ buf_write_be16 (buf, ((int16_t) (value - rela->r_offset)) >> 1);
+ break;
+ case R_390_8:
+ buf_write_8 (buf, value);
+ break;
+ case R_390_COPY:
+ abort ();
+ case R_390_RELATIVE:
+ error (0, 0, "%s: R_390_RELATIVE in ET_EXEC object?", info->dso->filename);
+ return 1;
+ default:
+ return 1;
+ }
+ return 0;
+}
+
+static int
+s390_prelink_conflict_rel (DSO *dso, struct prelink_info *info, GElf_Rel *rel,
+ GElf_Addr reladdr)
+{
+ error (0, 0, "%s: S390 doesn't support REL relocs", dso->filename);
+ return 1;
+}
+
+static int
+s390_prelink_conflict_rela (DSO *dso, struct prelink_info *info,
+ GElf_Rela *rela, GElf_Addr relaaddr)
+{
+ GElf_Addr value;
+ struct prelink_conflict *conflict;
+ struct prelink_tls *tls;
+ GElf_Rela *ret;
+
+ if (GELF_R_TYPE (rela->r_info) == R_390_RELATIVE
+ || GELF_R_TYPE (rela->r_info) == R_390_NONE)
+ /* Fast path: nothing to do. */
+ return 0;
+ conflict = prelink_conflict (info, GELF_R_SYM (rela->r_info),
+ GELF_R_TYPE (rela->r_info));
+ if (conflict == NULL)
+ {
+ switch (GELF_R_TYPE (rela->r_info))
+ {
+ /* Even local DTPMOD and TPOFF relocs need conflicts. */
+ case R_390_TLS_DTPMOD:
+ case R_390_TLS_TPOFF:
+ if (info->curtls == NULL || info->dso == dso)
+ return 0;
+ break;
+ /* IRELATIVE always need conflicts. */
+ case R_390_IRELATIVE:
+ break;
+ default:
+ return 0;
+ }
+ value = 0;
+ }
+ else if (info->dso == dso && !conflict->ifunc)
+ return 0;
+ else
+ {
+ /* DTPOFF wants to see only real conflicts, not lookups
+ with reloc_class RTYPE_CLASS_TLS. */
+ if (GELF_R_TYPE (rela->r_info) == R_390_TLS_DTPOFF
+ && conflict->lookup.tls == conflict->conflict.tls
+ && conflict->lookupval == conflict->conflictval)
+ return 0;
+
+ value = conflict_lookup_value (conflict);
+ }
+ ret = prelink_conflict_add_rela (info);
+ if (ret == NULL)
+ return 1;
+ ret->r_offset = rela->r_offset;
+ ret->r_info = GELF_R_INFO (0, R_390_32);
+ value += rela->r_addend;
+ switch (GELF_R_TYPE (rela->r_info))
+ {
+ case R_390_GLOB_DAT:
+ case R_390_JMP_SLOT:
+ ret->r_addend = (Elf32_Sword) (value - rela->r_addend);
+ if (conflict != NULL && conflict->ifunc)
+ ret->r_info = GELF_R_INFO (0, R_390_IRELATIVE);
+ break;
+ case R_390_32:
+ ret->r_addend = (Elf32_Sword) value;
+ if (conflict != NULL && conflict->ifunc)
+ ret->r_info = GELF_R_INFO (0, R_390_IRELATIVE);
+ break;
+ case R_390_IRELATIVE:
+ ret->r_addend = (Elf32_Sword) value;
+ ret->r_info = GELF_R_INFO (0, R_390_IRELATIVE);
+ break;
+ case R_390_PC32:
+ ret->r_addend = (Elf32_Sword) (value - rela->r_offset);
+ break;
+ case R_390_PC32DBL:
+ case R_390_PLT32DBL:
+ ret->r_addend = ((Elf32_Sword) (value - rela->r_offset)) >> 1;
+ break;
+ case R_390_PC16:
+ value -= rela->r_offset;
+ case R_390_16:
+ ret->r_addend = (Elf32_Half) value;
+ ret->r_info = GELF_R_INFO (0, R_390_16);
+ break;
+ case R_390_PC16DBL:
+ case R_390_PLT16DBL:
+ ret->r_addend = (Elf32_Half) (((int16_t) (value - rela->r_offset)) >> 1);
+ ret->r_info = GELF_R_INFO (0, R_390_16);
+ break;
+ case R_390_8:
+ ret->r_addend = value & 0xff;
+ ret->r_info = GELF_R_INFO (0, R_390_8);
+ break;
+ case R_390_COPY:
+ error (0, 0, "R_390_COPY should not be present in shared libraries");
+ return 1;
+ case R_390_TLS_DTPMOD:
+ case R_390_TLS_DTPOFF:
+ case R_390_TLS_TPOFF:
+ if (conflict != NULL
+ && (conflict->reloc_class != RTYPE_CLASS_TLS
+ || conflict->lookup.tls == NULL))
+ {
+ error (0, 0, "%s: TLS reloc not resolving to STT_TLS symbol",
+ dso->filename);
+ return 1;
+ }
+ tls = conflict ? conflict->lookup.tls : info->curtls;
+ switch (GELF_R_TYPE (rela->r_info))
+ {
+ case R_390_TLS_DTPMOD:
+ ret->r_addend = tls->modid;
+ break;
+ case R_390_TLS_DTPOFF:
+ ret->r_addend = value;
+ break;
+ case R_390_TLS_TPOFF:
+ ret->r_addend = value - tls->offset;
+ break;
+ }
+ break;
+
+ default:
+ error (0, 0, "%s: Unknown S390 relocation type %d", dso->filename,
+ (int) GELF_R_TYPE (rela->r_info));
+ return 1;
+ }
+ return 0;
+}
+
+static int
+s390_rel_to_rela (DSO *dso, GElf_Rel *rel, GElf_Rela *rela)
+{
+ error (0, 0, "%s: S390 doesn't support REL relocs", dso->filename);
+ return 1;
+}
+
+static int
+s390_need_rel_to_rela (DSO *dso, int first, int last)
+{
+ return 0;
+}
+
+static int
+s390_arch_prelink (struct prelink_info *info)
+{
+ DSO *dso;
+ int i;
+
+ dso = info->dso;
+ if (dso->info[DT_PLTGOT])
+ {
+ /* Write address of .plt + 0x2c into got[1].
+ .plt + 0x2c is what got[3] contains unless prelinking. */
+ int sec = addr_to_sec (dso, dso->info[DT_PLTGOT]);
+ Elf64_Addr data;
+
+ if (sec == -1)
+ return 1;
+
+ for (i = 1; i < dso->ehdr.e_shnum; i++)
+ if (dso->shdr[i].sh_type == SHT_PROGBITS
+ && ! strcmp (strptr (dso, dso->ehdr.e_shstrndx,
+ dso->shdr[i].sh_name),
+ ".plt"))
+ break;
+
+ if (i == dso->ehdr.e_shnum)
+ return 0;
+ data = dso->shdr[i].sh_addr + 0x2c;
+ write_be32 (dso, dso->info[DT_PLTGOT] + 4, data);
+ }
+
+ return 0;
+}
+
+static int
+s390_arch_undo_prelink (DSO *dso)
+{
+ int i;
+
+ if (dso->info[DT_PLTGOT])
+ {
+ /* Clear got[1] if it contains address of .plt + 0x2c. */
+ int sec = addr_to_sec (dso, dso->info[DT_PLTGOT]);
+ Elf32_Addr data;
+
+ if (sec == -1)
+ return 1;
+
+ for (i = 1; i < dso->ehdr.e_shnum; i++)
+ if (dso->shdr[i].sh_type == SHT_PROGBITS
+ && ! strcmp (strptr (dso, dso->ehdr.e_shstrndx,
+ dso->shdr[i].sh_name),
+ ".plt"))
+ break;
+
+ if (i == dso->ehdr.e_shnum)
+ return 0;
+ data = read_ube32 (dso, dso->info[DT_PLTGOT] + 4);
+ if (data == dso->shdr[i].sh_addr + 0x2c)
+ write_be32 (dso, dso->info[DT_PLTGOT] + 4, 0);
+ }
+
+ return 0;
+}
+
+static int
+s390_undo_prelink_rela (DSO *dso, GElf_Rela *rela, GElf_Addr relaaddr)
+{
+ int sec;
+ const char *name;
+
+ switch (GELF_R_TYPE (rela->r_info))
+ {
+ case R_390_NONE:
+ case R_390_RELATIVE:
+ case R_390_IRELATIVE:
+ break;
+ case R_390_JMP_SLOT:
+ sec = addr_to_sec (dso, rela->r_offset);
+ name = strptr (dso, dso->ehdr.e_shstrndx, dso->shdr[sec].sh_name);
+ if (sec == -1 || (strcmp (name, ".got") && strcmp (name, ".got.plt")))
+ {
+ error (0, 0, "%s: R_390_JMP_SLOT not pointing into .got section",
+ dso->filename);
+ return 1;
+ }
+ else
+ {
+ Elf32_Addr data = read_ube32 (dso, dso->shdr[sec].sh_addr + 4);
+
+ assert (rela->r_offset >= dso->shdr[sec].sh_addr + 12);
+ assert (((rela->r_offset - dso->shdr[sec].sh_addr) & 3) == 0);
+ write_be32 (dso, rela->r_offset,
+ 8 * (rela->r_offset - dso->shdr[sec].sh_addr - 12)
+ + data);
+ }
+ break;
+ case R_390_GLOB_DAT:
+ case R_390_32:
+ case R_390_PC32:
+ case R_390_PC32DBL:
+ case R_390_PLT32DBL:
+ case R_390_TLS_DTPMOD:
+ case R_390_TLS_DTPOFF:
+ case R_390_TLS_TPOFF:
+ write_be32 (dso, rela->r_offset, 0);
+ break;
+ case R_390_16:
+ case R_390_PC16:
+ case R_390_PC16DBL:
+ case R_390_PLT16DBL:
+ write_be16 (dso, rela->r_offset, 0);
+ break;
+ case R_390_8:
+ write_8 (dso, rela->r_offset, 0);
+ break;
+ case R_390_COPY:
+ if (dso->ehdr.e_type == ET_EXEC)
+ /* COPY relocs are handled specially in generic code. */
+ return 0;
+ error (0, 0, "%s: R_390_COPY reloc in shared library?", dso->filename);
+ return 1;
+ default:
+ error (0, 0, "%s: Unknown s390 relocation type %d", dso->filename,
+ (int) GELF_R_TYPE (rela->r_info));
+ return 1;
+ }
+ return 0;
+}
+
+static int
+s390_reloc_size (int reloc_type)
+{
+ switch (reloc_type)
+ {
+ case R_390_16:
+ case R_390_PC16:
+ case R_390_PC16DBL:
+ case R_390_PLT16DBL:
+ return 2;
+ case R_390_8:
+ return 1;
+ default:
+ return 4;
+ }
+}
+
+static int
+s390_reloc_class (int reloc_type)
+{
+ switch (reloc_type)
+ {
+ case R_390_COPY: return RTYPE_CLASS_COPY;
+ case R_390_JMP_SLOT: return RTYPE_CLASS_PLT;
+ case R_390_TLS_DTPMOD:
+ case R_390_TLS_DTPOFF:
+ case R_390_TLS_TPOFF:
+ return RTYPE_CLASS_TLS;
+ default: return RTYPE_CLASS_VALID;
+ }
+}
+
+PL_ARCH(s390) = {
+ .name = "S390",
+ .class = ELFCLASS32,
+ .machine = EM_S390,
+ .alternate_machine = { 0xA390 },
+ .R_JMP_SLOT = R_390_JMP_SLOT,
+ .R_COPY = R_390_COPY,
+ .R_RELATIVE = R_390_RELATIVE,
+ .rtype_class_valid = RTYPE_CLASS_VALID,
+ .dynamic_linker = "/lib/ld.so.1",
+ .adjust_dyn = s390_adjust_dyn,
+ .adjust_rel = s390_adjust_rel,
+ .adjust_rela = s390_adjust_rela,
+ .prelink_rel = s390_prelink_rel,
+ .prelink_rela = s390_prelink_rela,
+ .prelink_conflict_rel = s390_prelink_conflict_rel,
+ .prelink_conflict_rela = s390_prelink_conflict_rela,
+ .apply_conflict_rela = s390_apply_conflict_rela,
+ .apply_rel = s390_apply_rel,
+ .apply_rela = s390_apply_rela,
+ .rel_to_rela = s390_rel_to_rela,
+ .need_rel_to_rela = s390_need_rel_to_rela,
+ .reloc_size = s390_reloc_size,
+ .reloc_class = s390_reloc_class,
+ .max_reloc_size = 4,
+ .arch_prelink = s390_arch_prelink,
+ .arch_undo_prelink = s390_arch_undo_prelink,
+ .undo_prelink_rela = s390_undo_prelink_rela,
+ /* Although TASK_UNMAPPED_BASE is 0x40000000, we leave some
+ area so that mmap of /etc/ld.so.cache and ld.so's malloc
+ does not take some library's VA slot.
+ Also, if this guard area isn't too small, typically
+ even dlopened libraries will get the slots they desire. */
+ .mmap_base = 0x41000000,
+ .mmap_end = 0x50000000,
+ .max_page_size = 0x1000,
+ .page_size = 0x1000
+};
diff --git a/src/arch-s390x.c b/src/arch-s390x.c
new file mode 100644
index 0000000..e4d82f7
--- /dev/null
+++ b/src/arch-s390x.c
@@ -0,0 +1,658 @@
+/* Copyright (C) 2001, 2002, 2003, 2004, 2009, 2013 Red Hat, Inc.
+ Written by Jakub Jelinek <jakub@redhat.com>, 2001.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include <config.h>
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <locale.h>
+#include <error.h>
+#include <argp.h>
+#include <stdlib.h>
+
+#include "prelink.h"
+
+static int
+s390x_adjust_dyn (DSO *dso, int n, GElf_Dyn *dyn, GElf_Addr start,
+ GElf_Addr adjust)
+{
+ if (dyn->d_tag == DT_PLTGOT)
+ {
+ int sec = addr_to_sec (dso, dyn->d_un.d_ptr);
+ Elf64_Addr data;
+
+ if (sec == -1)
+ return 0;
+
+ data = read_ube64 (dso, dyn->d_un.d_ptr);
+ /* If .got.plt[0] points to _DYNAMIC, it needs to be adjusted. */
+ if (data == dso->shdr[n].sh_addr && data >= start)
+ write_be64 (dso, dyn->d_un.d_ptr, data + adjust);
+
+ data = read_ube64 (dso, dyn->d_un.d_ptr + 8);
+ /* If .got.plt[1] points to .plt + 0x2e, it needs to be adjusted. */
+ if (data && data >= start)
+ {
+ int i;
+
+ for (i = 1; i < dso->ehdr.e_shnum; i++)
+ if (data == dso->shdr[i].sh_addr + 0x2e
+ && dso->shdr[i].sh_type == SHT_PROGBITS
+ && strcmp (strptr (dso, dso->ehdr.e_shstrndx,
+ dso->shdr[i].sh_name), ".plt") == 0)
+ {
+ write_be64 (dso, dyn->d_un.d_ptr + 8, data + adjust);
+ break;
+ }
+ }
+ }
+ return 0;
+}
+
+static int
+s390x_adjust_rel (DSO *dso, GElf_Rel *rel, GElf_Addr start,
+ GElf_Addr adjust)
+{
+ error (0, 0, "%s: S390 doesn't support REL relocs", dso->filename);
+ return 1;
+}
+
+static int
+s390x_adjust_rela (DSO *dso, GElf_Rela *rela, GElf_Addr start,
+ GElf_Addr adjust)
+{
+ Elf64_Addr addr;
+
+ switch (GELF_R_TYPE (rela->r_info))
+ {
+ case R_390_RELATIVE:
+ if (rela->r_addend >= start)
+ {
+ addr = read_ube64 (dso, rela->r_offset);
+ if (addr == rela->r_addend)
+ write_be64 (dso, rela->r_offset, addr + adjust);
+ rela->r_addend += adjust;
+ }
+ break;
+ case R_390_IRELATIVE:
+ if (rela->r_addend >= start)
+ /* Adjust the resolver function address. */
+ rela->r_addend += adjust;
+ /* FALLTHROUGH */
+ case R_390_JMP_SLOT:
+ /* Adjust the address in the GOT slot. */
+ addr = read_ube64 (dso, rela->r_offset);
+ if (addr >= start)
+ write_be64 (dso, rela->r_offset, addr + adjust);
+ break;
+ }
+ return 0;
+}
+
+static int
+s390x_prelink_rel (struct prelink_info *info, GElf_Rel *rel, GElf_Addr reladdr)
+{
+ error (0, 0, "%s: S390 doesn't support REL relocs", info->dso->filename);
+ return 1;
+}
+
+static int
+s390x_prelink_rela (struct prelink_info *info, GElf_Rela *rela,
+ GElf_Addr relaaddr)
+{
+ DSO *dso = info->dso;
+ GElf_Addr value;
+
+ if (GELF_R_TYPE (rela->r_info) == R_390_NONE
+ || GELF_R_TYPE (rela->r_info) == R_390_IRELATIVE)
+ return 0;
+ else if (GELF_R_TYPE (rela->r_info) == R_390_RELATIVE)
+ {
+ write_be64 (dso, rela->r_offset, rela->r_addend);
+ return 0;
+ }
+ value = info->resolve (info, GELF_R_SYM (rela->r_info),
+ GELF_R_TYPE (rela->r_info));
+ value += rela->r_addend;
+ switch (GELF_R_TYPE (rela->r_info))
+ {
+ case R_390_GLOB_DAT:
+ case R_390_JMP_SLOT:
+ case R_390_64:
+ write_be64 (dso, rela->r_offset, value);
+ break;
+ case R_390_PC64:
+ write_be64 (dso, rela->r_offset, value - rela->r_offset);
+ break;
+ case R_390_32:
+ write_be32 (dso, rela->r_offset, value);
+ break;
+ case R_390_PC32:
+ write_be32 (dso, rela->r_offset, value - rela->r_offset);
+ break;
+ case R_390_PC32DBL:
+ case R_390_PLT32DBL:
+ write_be32 (dso, rela->r_offset,
+ ((Elf32_Sword) (value - rela->r_offset)) >> 1);
+ break;
+ case R_390_16:
+ write_be16 (dso, rela->r_offset, value);
+ break;
+ case R_390_PC16:
+ write_be16 (dso, rela->r_offset, value - rela->r_offset);
+ break;
+ case R_390_PC16DBL:
+ case R_390_PLT16DBL:
+ write_be16 (dso, rela->r_offset,
+ ((int16_t) (value - rela->r_offset)) >> 1);
+ break;
+ case R_390_8:
+ write_8 (dso, rela->r_offset, value);
+ break;
+ case R_390_TLS_DTPOFF:
+ write_be64 (dso, rela->r_offset, value);
+ break;
+ /* DTPMOD and TPOFF is impossible to predict in shared libraries
+ unless prelink sets the rules. */
+ case R_390_TLS_DTPMOD:
+ if (dso->ehdr.e_type == ET_EXEC)
+ {
+ error (0, 0, "%s: R_390_TLS_DTPMOD reloc in executable?",
+ dso->filename);
+ return 1;
+ }
+ break;
+ case R_390_TLS_TPOFF:
+ if (dso->ehdr.e_type == ET_EXEC && info->resolvetls)
+ write_be64 (dso, rela->r_offset, value - info->resolvetls->offset);
+ break;
+ case R_390_COPY:
+ if (dso->ehdr.e_type == ET_EXEC)
+ /* COPY relocs are handled specially in generic code. */
+ return 0;
+ error (0, 0, "%s: R_390_COPY reloc in shared library?", dso->filename);
+ return 1;
+ default:
+ error (0, 0, "%s: Unknown S390 relocation type %d", dso->filename,
+ (int) GELF_R_TYPE (rela->r_info));
+ return 1;
+ }
+ return 0;
+}
+
+static int
+s390x_apply_conflict_rela (struct prelink_info *info, GElf_Rela *rela,
+ char *buf, GElf_Addr dest_addr)
+{
+ GElf_Rela *ret;
+ switch (GELF_R_TYPE (rela->r_info))
+ {
+ case R_390_64:
+ buf_write_be64 (buf, rela->r_addend);
+ break;
+ case R_390_32:
+ buf_write_be32 (buf, rela->r_addend);
+ break;
+ case R_390_16:
+ buf_write_be16 (buf, rela->r_addend);
+ break;
+ case R_390_8:
+ buf_write_8 (buf, rela->r_addend);
+ break;
+ case R_390_IRELATIVE:
+ if (dest_addr == 0)
+ return 5;
+ ret = prelink_conflict_add_rela (info);
+ if (ret == NULL)
+ return 1;
+ ret->r_offset = dest_addr;
+ ret->r_info = GELF_R_INFO (0, R_390_IRELATIVE);
+ ret->r_addend = rela->r_addend;
+ break;
+ default:
+ abort ();
+ }
+ return 0;
+}
+
+static int
+s390x_apply_rel (struct prelink_info *info, GElf_Rel *rel, char *buf)
+{
+ error (0, 0, "%s: S390 doesn't support REL relocs", info->dso->filename);
+ return 1;
+}
+
+static int
+s390x_apply_rela (struct prelink_info *info, GElf_Rela *rela, char *buf)
+{
+ GElf_Addr value;
+
+ value = info->resolve (info, GELF_R_SYM (rela->r_info),
+ GELF_R_TYPE (rela->r_info));
+ value += rela->r_addend;
+ switch (GELF_R_TYPE (rela->r_info))
+ {
+ case R_390_NONE:
+ break;
+ case R_390_GLOB_DAT:
+ case R_390_JMP_SLOT:
+ case R_390_64:
+ buf_write_be64 (buf, value);
+ break;
+ case R_390_PC64:
+ buf_write_be64 (buf, value - rela->r_offset);
+ break;
+ case R_390_32:
+ buf_write_be32 (buf, value);
+ break;
+ case R_390_PC32:
+ buf_write_be32 (buf, value - rela->r_offset);
+ break;
+ case R_390_PC32DBL:
+ case R_390_PLT32DBL:
+ buf_write_be32 (buf, ((Elf32_Sword) (value - rela->r_offset)) >> 1);
+ break;
+ case R_390_16:
+ buf_write_be16 (buf, value);
+ break;
+ case R_390_PC16:
+ buf_write_be16 (buf, value - rela->r_offset);
+ break;
+ case R_390_PC16DBL:
+ case R_390_PLT16DBL:
+ buf_write_be16 (buf, ((int16_t) (value - rela->r_offset)) >> 1);
+ break;
+ case R_390_8:
+ buf_write_8 (buf, value);
+ break;
+ case R_390_COPY:
+ abort ();
+ case R_390_RELATIVE:
+ error (0, 0, "%s: R_390_RELATIVE in ET_EXEC object?", info->dso->filename);
+ return 1;
+ default:
+ return 1;
+ }
+ return 0;
+}
+
+static int
+s390x_prelink_conflict_rel (DSO *dso, struct prelink_info *info, GElf_Rel *rel,
+ GElf_Addr reladdr)
+{
+ error (0, 0, "%s: S390 doesn't support REL relocs", dso->filename);
+ return 1;
+}
+
+static int
+s390x_prelink_conflict_rela (DSO *dso, struct prelink_info *info,
+ GElf_Rela *rela, GElf_Addr relaaddr)
+{
+ GElf_Addr value;
+ struct prelink_conflict *conflict;
+ struct prelink_tls *tls;
+ GElf_Rela *ret;
+ int r_type;
+
+ if (GELF_R_TYPE (rela->r_info) == R_390_RELATIVE
+ || GELF_R_TYPE (rela->r_info) == R_390_NONE)
+ /* Fast path: nothing to do. */
+ return 0;
+ conflict = prelink_conflict (info, GELF_R_SYM (rela->r_info),
+ GELF_R_TYPE (rela->r_info));
+ if (conflict == NULL)
+ {
+ switch (GELF_R_TYPE (rela->r_info))
+ {
+ /* Even local DTPMOD and TPOFF relocs need conflicts. */
+ case R_390_TLS_DTPMOD:
+ case R_390_TLS_TPOFF:
+ if (info->curtls == NULL || info->dso == dso)
+ return 0;
+ break;
+ /* IRELATIVE always need conflicts. */
+ case R_390_IRELATIVE:
+ break;
+ default:
+ return 0;
+ }
+ value = 0;
+ }
+ else if (info->dso == dso && !conflict->ifunc)
+ return 0;
+ else
+ {
+ /* DTPOFF wants to see only real conflicts, not lookups
+ with reloc_class RTYPE_CLASS_TLS. */
+ if (GELF_R_TYPE (rela->r_info) == R_390_TLS_DTPOFF
+ && conflict->lookup.tls == conflict->conflict.tls
+ && conflict->lookupval == conflict->conflictval)
+ return 0;
+
+ value = conflict_lookup_value (conflict);
+ }
+ ret = prelink_conflict_add_rela (info);
+ if (ret == NULL)
+ return 1;
+ ret->r_offset = rela->r_offset;
+ r_type = GELF_R_TYPE (rela->r_info);
+ value += rela->r_addend;
+ switch (r_type)
+ {
+ case R_390_PC64:
+ value -= rela->r_offset;
+ case R_390_GLOB_DAT:
+ case R_390_JMP_SLOT:
+ r_type = R_390_64;
+ case R_390_64:
+ case R_390_IRELATIVE:
+ ret->r_addend = value;
+ if (conflict != NULL && conflict->ifunc)
+ r_type = R_390_IRELATIVE;
+ break;
+ case R_390_PC32:
+ value -= rela->r_offset;
+ case R_390_32:
+ ret->r_addend = (Elf32_Addr) value;
+ r_type = R_390_32;
+ break;
+ case R_390_PC32DBL:
+ case R_390_PLT32DBL:
+ ret->r_addend
+ = (Elf32_Addr) (((Elf32_Sword) (value - rela->r_offset)) >> 1);
+ r_type = R_390_32;
+ break;
+ case R_390_PC16:
+ value -= rela->r_offset;
+ case R_390_16:
+ ret->r_addend = (Elf32_Half) value;
+ r_type = R_390_16;
+ break;
+ case R_390_PC16DBL:
+ case R_390_PLT16DBL:
+ ret->r_addend = (Elf32_Half) (((int16_t) (value - rela->r_offset)) >> 1);
+ r_type = R_390_16;
+ break;
+ case R_390_8:
+ ret->r_addend = value & 0xff;
+ break;
+ case R_390_COPY:
+ error (0, 0, "R_390_COPY should not be present in shared libraries");
+ return 1;
+ case R_390_TLS_DTPMOD:
+ case R_390_TLS_DTPOFF:
+ case R_390_TLS_TPOFF:
+ if (conflict != NULL
+ && (conflict->reloc_class != RTYPE_CLASS_TLS
+ || conflict->lookup.tls == NULL))
+ {
+ error (0, 0, "%s: TLS reloc not resolving to STT_TLS symbol",
+ dso->filename);
+ return 1;
+ }
+ tls = conflict ? conflict->lookup.tls : info->curtls;
+ switch (r_type)
+ {
+ case R_390_TLS_DTPMOD:
+ ret->r_addend = tls->modid;
+ break;
+ case R_390_TLS_DTPOFF:
+ ret->r_addend = value;
+ break;
+ case R_390_TLS_TPOFF:
+ ret->r_addend = value - tls->offset;
+ break;
+ }
+ r_type = R_390_64;
+ break;
+ default:
+ error (0, 0, "%s: Unknown S390 relocation type %d", dso->filename,
+ (int) GELF_R_TYPE (rela->r_info));
+ return 1;
+ }
+ ret->r_info = GELF_R_INFO (0, r_type);
+ return 0;
+}
+
+static int
+s390x_rel_to_rela (DSO *dso, GElf_Rel *rel, GElf_Rela *rela)
+{
+ error (0, 0, "%s: S390 doesn't support REL relocs", dso->filename);
+ return 1;
+}
+
+static int
+s390x_need_rel_to_rela (DSO *dso, int first, int last)
+{
+ return 0;
+}
+
+static int
+s390x_arch_prelink (struct prelink_info *info)
+{
+ DSO *dso;
+ int i;
+
+ dso = info->dso;
+ if (dso->info[DT_PLTGOT])
+ {
+ /* Write address of .plt + 0x2e into got[1].
+ .plt + 0x2e is what got[3] contains unless prelinking. */
+ int sec = addr_to_sec (dso, dso->info[DT_PLTGOT]);
+ Elf64_Addr data;
+
+ if (sec == -1)
+ return 1;
+
+ for (i = 1; i < dso->ehdr.e_shnum; i++)
+ if (dso->shdr[i].sh_type == SHT_PROGBITS
+ && ! strcmp (strptr (dso, dso->ehdr.e_shstrndx,
+ dso->shdr[i].sh_name),
+ ".plt"))
+ break;
+
+ if (i == dso->ehdr.e_shnum)
+ return 0;
+ data = dso->shdr[i].sh_addr + 0x2e;
+ write_be64 (dso, dso->info[DT_PLTGOT] + 8, data);
+ }
+
+ return 0;
+}
+
+static int
+s390x_arch_undo_prelink (DSO *dso)
+{
+ int i;
+
+ if (dso->info[DT_PLTGOT])
+ {
+ /* Clear got[1] if it contains address of .plt + 0x2e. */
+ int sec = addr_to_sec (dso, dso->info[DT_PLTGOT]);
+ Elf64_Addr data;
+
+ if (sec == -1)
+ return 1;
+
+ for (i = 1; i < dso->ehdr.e_shnum; i++)
+ if (dso->shdr[i].sh_type == SHT_PROGBITS
+ && ! strcmp (strptr (dso, dso->ehdr.e_shstrndx,
+ dso->shdr[i].sh_name),
+ ".plt"))
+ break;
+
+ if (i == dso->ehdr.e_shnum)
+ return 0;
+ data = read_ube64 (dso, dso->info[DT_PLTGOT] + 8);
+ if (data == dso->shdr[i].sh_addr + 0x2e)
+ write_be64 (dso, dso->info[DT_PLTGOT] + 8, 0);
+ }
+
+ return 0;
+}
+
+static int
+s390x_undo_prelink_rela (DSO *dso, GElf_Rela *rela, GElf_Addr relaaddr)
+{
+ int sec;
+ const char *name;
+
+ switch (GELF_R_TYPE (rela->r_info))
+ {
+ case R_390_NONE:
+ case R_390_RELATIVE:
+ case R_390_IRELATIVE:
+ break;
+ case R_390_JMP_SLOT:
+ sec = addr_to_sec (dso, rela->r_offset);
+ name = strptr (dso, dso->ehdr.e_shstrndx, dso->shdr[sec].sh_name);
+ if (sec == -1 || (strcmp (name, ".got") && strcmp (name, ".got.plt")))
+ {
+ error (0, 0, "%s: R_390_JMP_SLOT not pointing into .got section",
+ dso->filename);
+ return 1;
+ }
+ else
+ {
+ Elf64_Addr data = read_ube64 (dso, dso->shdr[sec].sh_addr + 8);
+
+ assert (rela->r_offset >= dso->shdr[sec].sh_addr + 24);
+ assert (((rela->r_offset - dso->shdr[sec].sh_addr) & 7) == 0);
+ write_be64 (dso, rela->r_offset,
+ 4 * (rela->r_offset - dso->shdr[sec].sh_addr - 24)
+ + data);
+ }
+ break;
+ case R_390_GLOB_DAT:
+ case R_390_64:
+ case R_390_PC64:
+ case R_390_TLS_DTPMOD:
+ case R_390_TLS_DTPOFF:
+ case R_390_TLS_TPOFF:
+ write_be64 (dso, rela->r_offset, 0);
+ break;
+ case R_390_32:
+ case R_390_PC32:
+ case R_390_PC32DBL:
+ case R_390_PLT32DBL:
+ write_be32 (dso, rela->r_offset, 0);
+ break;
+ case R_390_16:
+ case R_390_PC16:
+ case R_390_PC16DBL:
+ case R_390_PLT16DBL:
+ write_be16 (dso, rela->r_offset, 0);
+ break;
+ case R_390_8:
+ write_8 (dso, rela->r_offset, 0);
+ break;
+ case R_390_COPY:
+ if (dso->ehdr.e_type == ET_EXEC)
+ /* COPY relocs are handled specially in generic code. */
+ return 0;
+ error (0, 0, "%s: R_390_COPY reloc in shared library?", dso->filename);
+ return 1;
+ default:
+ error (0, 0, "%s: Unknown s390x relocation type %d", dso->filename,
+ (int) GELF_R_TYPE (rela->r_info));
+ return 1;
+ }
+ return 0;
+}
+
+static int
+s390x_reloc_size (int reloc_type)
+{
+ switch (reloc_type)
+ {
+ case R_390_GLOB_DAT:
+ case R_390_JMP_SLOT:
+ case R_390_64:
+ case R_390_PC64:
+ case R_390_IRELATIVE:
+ return 8;
+ case R_390_32:
+ case R_390_PC32:
+ case R_390_PC32DBL:
+ case R_390_PLT32DBL:
+ default:
+ return 4;
+ case R_390_16:
+ case R_390_PC16:
+ case R_390_PC16DBL:
+ case R_390_PLT16DBL:
+ return 2;
+ case R_390_8:
+ return 1;
+ }
+}
+
+static int
+s390x_reloc_class (int reloc_type)
+{
+ switch (reloc_type)
+ {
+ case R_390_COPY: return RTYPE_CLASS_COPY;
+ case R_390_JMP_SLOT: return RTYPE_CLASS_PLT;
+ case R_390_TLS_DTPMOD:
+ case R_390_TLS_DTPOFF:
+ case R_390_TLS_TPOFF:
+ return RTYPE_CLASS_TLS;
+ default: return RTYPE_CLASS_VALID;
+ }
+}
+
+PL_ARCH(s390x) = {
+ .name = "S390",
+ .class = ELFCLASS64,
+ .machine = EM_S390,
+ .alternate_machine = { 0xA390 },
+ .R_JMP_SLOT = R_390_JMP_SLOT,
+ .R_COPY = R_390_COPY,
+ .R_RELATIVE = R_390_RELATIVE,
+ .rtype_class_valid = RTYPE_CLASS_VALID,
+ .dynamic_linker = "/lib/ld64.so.1",
+ .adjust_dyn = s390x_adjust_dyn,
+ .adjust_rel = s390x_adjust_rel,
+ .adjust_rela = s390x_adjust_rela,
+ .prelink_rel = s390x_prelink_rel,
+ .prelink_rela = s390x_prelink_rela,
+ .prelink_conflict_rel = s390x_prelink_conflict_rel,
+ .prelink_conflict_rela = s390x_prelink_conflict_rela,
+ .apply_conflict_rela = s390x_apply_conflict_rela,
+ .apply_rel = s390x_apply_rel,
+ .apply_rela = s390x_apply_rela,
+ .rel_to_rela = s390x_rel_to_rela,
+ .need_rel_to_rela = s390x_need_rel_to_rela,
+ .reloc_size = s390x_reloc_size,
+ .reloc_class = s390x_reloc_class,
+ .max_reloc_size = 8,
+ .arch_prelink = s390x_arch_prelink,
+ .arch_undo_prelink = s390x_arch_undo_prelink,
+ .undo_prelink_rela = s390x_undo_prelink_rela,
+ /* Although TASK_UNMAPPED_BASE is 0x4000000000, we leave some
+ area so that mmap of /etc/ld.so.cache and ld.so's malloc
+ does not take some library's VA slot.
+ Also, if this guard area isn't too small, typically
+ even dlopened libraries will get the slots they desire. */
+ .mmap_base = 0x4010000000LL,
+ .mmap_end = 0x5000000000LL,
+ .max_page_size = 0x1000,
+ .page_size = 0x1000
+};
diff --git a/src/arch-sh.c b/src/arch-sh.c
new file mode 100644
index 0000000..1b11312
--- /dev/null
+++ b/src/arch-sh.c
@@ -0,0 +1,453 @@
+/* Copyright (C) 2001, 2002, 2003, 2004, 2009 Red Hat, Inc.
+ Written by Jakub Jelinek <jakub@redhat.com>, 2001.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include <config.h>
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <locale.h>
+#include <error.h>
+#include <argp.h>
+#include <stdlib.h>
+
+#include "prelink.h"
+
+static int
+sh_adjust_dyn (DSO *dso, int n, GElf_Dyn *dyn, GElf_Addr start,
+ GElf_Addr adjust)
+{
+ if (dyn->d_tag == DT_PLTGOT)
+ {
+ int sec = addr_to_sec (dso, dyn->d_un.d_ptr);
+ Elf32_Addr data;
+
+ if (sec == -1)
+ return 0;
+
+ data = read_une32 (dso, dyn->d_un.d_ptr);
+ /* If .got.plt[0] points to _DYNAMIC, it needs to be adjusted. */
+ if (data == dso->shdr[n].sh_addr && data >= start)
+ write_ne32 (dso, dyn->d_un.d_ptr, data + adjust);
+
+ data = read_une32 (dso, dyn->d_un.d_ptr + 4);
+ /* If .got.plt[1] points to .plt + 36, it needs to be adjusted. */
+ if (data && data >= start)
+ {
+ int i;
+
+ for (i = 1; i < dso->ehdr.e_shnum; i++)
+ if (data == dso->shdr[i].sh_addr + 36
+ && dso->shdr[i].sh_type == SHT_PROGBITS
+ && strcmp (strptr (dso, dso->ehdr.e_shstrndx,
+ dso->shdr[i].sh_name), ".plt") == 0)
+ {
+ write_ne32 (dso, dyn->d_un.d_ptr + 4, data + adjust);
+ break;
+ }
+ }
+ }
+ return 0;
+}
+
+static int
+sh_adjust_rel (DSO *dso, GElf_Rel *rel, GElf_Addr start,
+ GElf_Addr adjust)
+{
+ error (0, 0, "%s: SH doesn't support REL relocs", dso->filename);
+ return 1;
+}
+
+static int
+sh_adjust_rela (DSO *dso, GElf_Rela *rela, GElf_Addr start,
+ GElf_Addr adjust)
+{
+ Elf32_Addr data;
+
+ switch (GELF_R_TYPE (rela->r_info))
+ {
+ case R_SH_RELATIVE:
+ if (rela->r_addend && (Elf32_Addr) rela->r_addend >= start)
+ {
+ rela->r_addend += (Elf32_Sword) adjust;
+ break;
+ }
+ /* FALLTHROUGH */
+ case R_SH_JMP_SLOT:
+ data = read_une32 (dso, rela->r_offset);
+ if (data >= start)
+ write_ne32 (dso, rela->r_offset, data + adjust);
+ break;
+ break;
+ }
+ return 0;
+}
+
+static int
+sh_prelink_rel (struct prelink_info *info, GElf_Rel *rel, GElf_Addr reladdr)
+{
+ error (0, 0, "%s: SH doesn't support REL relocs", info->dso->filename);
+ return 1;
+}
+
+static int
+sh_prelink_rela (struct prelink_info *info, GElf_Rela *rela,
+ GElf_Addr relaaddr)
+{
+ DSO *dso;
+ GElf_Addr value;
+
+ dso = info->dso;
+ if (GELF_R_TYPE (rela->r_info) == R_SH_NONE)
+ /* Fast path: nothing to do. */
+ return 0;
+ else if (GELF_R_TYPE (rela->r_info) == R_SH_RELATIVE)
+ {
+ if (rela->r_addend)
+ write_ne32 (dso, rela->r_offset, rela->r_addend);
+ return 0;
+ }
+ value = info->resolve (info, GELF_R_SYM (rela->r_info),
+ GELF_R_TYPE (rela->r_info));
+ value += rela->r_addend;
+ switch (GELF_R_TYPE (rela->r_info))
+ {
+ case R_SH_GLOB_DAT:
+ case R_SH_JMP_SLOT:
+ case R_SH_DIR32:
+ write_ne32 (dso, rela->r_offset, value);
+ break;
+ case R_SH_REL32:
+ write_ne32 (dso, rela->r_offset, value - rela->r_addend);
+ break;
+ case R_SH_COPY:
+ if (dso->ehdr.e_type == ET_EXEC)
+ /* COPY relocs are handled specially in generic code. */
+ return 0;
+ error (0, 0, "%s: R_SH_COPY reloc in shared library?", dso->filename);
+ return 1;
+ default:
+ error (0, 0, "%s: Unknown sh relocation type %d", dso->filename,
+ (int) GELF_R_TYPE (rela->r_info));
+ return 1;
+ }
+ return 0;
+}
+
+static int
+sh_apply_conflict_rela (struct prelink_info *info, GElf_Rela *rela,
+ char *buf, GElf_Addr dest_addr)
+{
+ switch (GELF_R_TYPE (rela->r_info))
+ {
+ case R_SH_GLOB_DAT:
+ case R_SH_JMP_SLOT:
+ case R_SH_DIR32:
+ buf_write_ne32 (info->dso, buf, rela->r_addend);
+ break;
+ default:
+ abort ();
+ }
+ return 0;
+}
+
+static int
+sh_apply_rel (struct prelink_info *info, GElf_Rel *rel, char *buf)
+{
+ error (0, 0, "%s: SH doesn't support REL relocs", info->dso->filename);
+ return 1;
+}
+
+static int
+sh_apply_rela (struct prelink_info *info, GElf_Rela *rela, char *buf)
+{
+ GElf_Addr value;
+
+ value = info->resolve (info, GELF_R_SYM (rela->r_info),
+ GELF_R_TYPE (rela->r_info));
+ value += rela->r_addend;
+ switch (GELF_R_TYPE (rela->r_info))
+ {
+ case R_SH_NONE:
+ break;
+ case R_SH_GLOB_DAT:
+ case R_SH_JMP_SLOT:
+ case R_SH_DIR32:
+ buf_write_ne32 (info->dso, buf, value);
+ break;
+ case R_SH_REL32:
+ buf_write_ne32 (info->dso, buf, value - rela->r_offset);
+ break;
+ case R_SH_COPY:
+ abort ();
+ case R_SH_RELATIVE:
+ error (0, 0, "%s: R_SH_RELATIVE in ET_EXEC object?", info->dso->filename);
+ return 1;
+ default:
+ return 1;
+ }
+ return 0;
+}
+
+static int
+sh_prelink_conflict_rel (DSO *dso, struct prelink_info *info, GElf_Rel *rel,
+ GElf_Addr reladdr)
+{
+ error (0, 0, "%s: SH doesn't support REL relocs", dso->filename);
+ return 1;
+}
+
+static int
+sh_prelink_conflict_rela (DSO *dso, struct prelink_info *info,
+ GElf_Rela *rela, GElf_Addr relaaddr)
+{
+ GElf_Addr value;
+ struct prelink_conflict *conflict;
+ GElf_Rela *ret;
+
+ if (GELF_R_TYPE (rela->r_info) == R_SH_RELATIVE
+ || GELF_R_TYPE (rela->r_info) == R_SH_NONE
+ || info->dso == dso)
+ /* Fast path: nothing to do. */
+ return 0;
+ conflict = prelink_conflict (info, GELF_R_SYM (rela->r_info),
+ GELF_R_TYPE (rela->r_info));
+ if (conflict == NULL)
+ return 0;
+ else if (conflict->ifunc)
+ {
+ error (0, 0, "%s: STT_GNU_IFUNC not handled on SuperH yet",
+ dso->filename);
+ return 1;
+ }
+ value = conflict_lookup_value (conflict);
+ ret = prelink_conflict_add_rela (info);
+ if (ret == NULL)
+ return 1;
+ ret->r_offset = rela->r_offset;
+ ret->r_info = GELF_R_INFO (0, GELF_R_TYPE (rela->r_info));
+ value += rela->r_addend;
+ switch (GELF_R_TYPE (rela->r_info))
+ {
+ case R_SH_REL32:
+ value -= rela->r_offset;
+ ret->r_info = GELF_R_INFO (0, R_SH_DIR32);
+ /* FALLTHROUGH */
+ case R_SH_DIR32:
+ if ((rela->r_offset & 3) == 0)
+ ret->r_info = GELF_R_INFO (0, R_SH_GLOB_DAT);
+ /* FALLTHROUGH */
+ case R_SH_GLOB_DAT:
+ case R_SH_JMP_SLOT:
+ ret->r_addend = (Elf32_Sword) (value + rela->r_addend);
+ break;
+ case R_SH_COPY:
+ error (0, 0, "R_SH_COPY should not be present in shared libraries");
+ return 1;
+ default:
+ error (0, 0, "%s: Unknown sh relocation type %d", dso->filename,
+ (int) GELF_R_TYPE (rela->r_info));
+ return 1;
+ }
+ return 0;
+}
+
+static int
+sh_rel_to_rela (DSO *dso, GElf_Rel *rel, GElf_Rela *rela)
+{
+ return 0;
+}
+
+static int
+sh_need_rel_to_rela (DSO *dso, int first, int last)
+{
+ return 0;
+}
+
+static int
+sh_arch_prelink (struct prelink_info *info)
+{
+ DSO *dso;
+ int i;
+
+ dso = info->dso;
+ if (dso->info[DT_PLTGOT])
+ {
+ /* Write address of .plt + 36 into got[1].
+ .plt + 36 is what got[3] contains unless prelinking. */
+ int sec = addr_to_sec (dso, dso->info[DT_PLTGOT]);
+ Elf32_Addr data;
+
+ if (sec == -1)
+ return 1;
+
+ for (i = 1; i < dso->ehdr.e_shnum; i++)
+ if (dso->shdr[i].sh_type == SHT_PROGBITS
+ && ! strcmp (strptr (dso, dso->ehdr.e_shstrndx,
+ dso->shdr[i].sh_name),
+ ".plt"))
+ break;
+
+ if (i == dso->ehdr.e_shnum)
+ return 0;
+ data = dso->shdr[i].sh_addr + 36;
+ write_ne32 (dso, dso->info[DT_PLTGOT] + 4, data);
+ }
+
+ return 0;
+}
+
+static int
+sh_arch_undo_prelink (DSO *dso)
+{
+ int i;
+
+ if (dso->info[DT_PLTGOT])
+ {
+ /* Clear got[1] if it contains address of .plt + 36. */
+ int sec = addr_to_sec (dso, dso->info[DT_PLTGOT]);
+ Elf32_Addr data;
+
+ if (sec == -1)
+ return 1;
+
+ for (i = 1; i < dso->ehdr.e_shnum; i++)
+ if (dso->shdr[i].sh_type == SHT_PROGBITS
+ && ! strcmp (strptr (dso, dso->ehdr.e_shstrndx,
+ dso->shdr[i].sh_name),
+ ".plt"))
+ break;
+
+ if (i == dso->ehdr.e_shnum)
+ return 0;
+ data = read_une32 (dso, dso->info[DT_PLTGOT] + 4);
+ if (data == dso->shdr[i].sh_addr + 36)
+ write_ne32 (dso, dso->info[DT_PLTGOT] + 4, 0);
+ }
+
+ return 0;
+}
+
+static int
+sh_undo_prelink_rela (DSO *dso, GElf_Rela *rela, GElf_Addr relaaddr)
+{
+ int sec;
+ const char *name;
+
+ switch (GELF_R_TYPE (rela->r_info))
+ {
+ case R_SH_NONE:
+ break;
+ case R_SH_RELATIVE:
+ if (rela->r_addend)
+ write_ne32 (dso, rela->r_offset, 0);
+ break;
+ case R_SH_JMP_SLOT:
+ sec = addr_to_sec (dso, rela->r_offset);
+ name = strptr (dso, dso->ehdr.e_shstrndx, dso->shdr[sec].sh_name);
+ if (sec == -1 || (strcmp (name, ".got") && strcmp (name, ".got.plt")))
+ {
+ error (0, 0, "%s: R_SH_JMP_SLOT not pointing into .got section",
+ dso->filename);
+ return 1;
+ }
+ else
+ {
+ Elf32_Addr data = read_une32 (dso, dso->shdr[sec].sh_addr + 4);
+
+ assert (rela->r_offset >= dso->shdr[sec].sh_addr + 12);
+ assert (((rela->r_offset - dso->shdr[sec].sh_addr) & 3) == 0);
+ write_ne32 (dso, rela->r_offset,
+ 7 * (rela->r_offset - dso->shdr[sec].sh_addr - 12)
+ + data);
+ }
+ break;
+ case R_SH_GLOB_DAT:
+ case R_SH_DIR32:
+ case R_SH_REL32:
+ write_ne32 (dso, rela->r_offset, 0);
+ break;
+ case R_SH_COPY:
+ if (dso->ehdr.e_type == ET_EXEC)
+ /* COPY relocs are handled specially in generic code. */
+ return 0;
+ error (0, 0, "%s: R_SH_COPY reloc in shared library?", dso->filename);
+ return 1;
+ default:
+ error (0, 0, "%s: Unknown sh relocation type %d", dso->filename,
+ (int) GELF_R_TYPE (rela->r_info));
+ return 1;
+ }
+ return 0;
+}
+
+static int
+sh_reloc_size (int reloc_type)
+{
+ return 4;
+}
+
+static int
+sh_reloc_class (int reloc_type)
+{
+ switch (reloc_type)
+ {
+ case R_SH_COPY: return RTYPE_CLASS_COPY;
+ case R_SH_JMP_SLOT: return RTYPE_CLASS_PLT;
+ default: return RTYPE_CLASS_VALID;
+ }
+}
+
+PL_ARCH(sh) = {
+ .name = "SuperH",
+ .class = ELFCLASS32,
+ .machine = EM_SH,
+ .alternate_machine = { EM_NONE },
+ .R_JMP_SLOT = R_SH_JMP_SLOT,
+ .R_COPY = R_SH_COPY,
+ .R_RELATIVE = R_SH_RELATIVE,
+ .rtype_class_valid = RTYPE_CLASS_VALID,
+ .dynamic_linker = "/lib/ld-linux.so.2",
+ .adjust_dyn = sh_adjust_dyn,
+ .adjust_rel = sh_adjust_rel,
+ .adjust_rela = sh_adjust_rela,
+ .prelink_rel = sh_prelink_rel,
+ .prelink_rela = sh_prelink_rela,
+ .prelink_conflict_rel = sh_prelink_conflict_rel,
+ .prelink_conflict_rela = sh_prelink_conflict_rela,
+ .apply_conflict_rela = sh_apply_conflict_rela,
+ .apply_rel = sh_apply_rel,
+ .apply_rela = sh_apply_rela,
+ .rel_to_rela = sh_rel_to_rela,
+ .need_rel_to_rela = sh_need_rel_to_rela,
+ .reloc_size = sh_reloc_size,
+ .reloc_class = sh_reloc_class,
+ .max_reloc_size = 4,
+ .arch_prelink = sh_arch_prelink,
+ .arch_undo_prelink = sh_arch_undo_prelink,
+ .undo_prelink_rela = sh_undo_prelink_rela,
+ /* Although TASK_UNMAPPED_BASE is 0x29555000, we leave some
+ area so that mmap of /etc/ld.so.cache and ld.so's malloc
+ does not take some library's VA slot.
+ Also, if this guard area isn't too small, typically
+ even dlopened libraries will get the slots they desire. */
+ .mmap_base = 0x30000000,
+ .mmap_end = 0x40000000,
+ .max_page_size = 0x10000,
+ .page_size = 0x1000
+};
diff --git a/src/arch-sparc.c b/src/arch-sparc.c
new file mode 100644
index 0000000..e016a79
--- /dev/null
+++ b/src/arch-sparc.c
@@ -0,0 +1,645 @@
+/* Copyright (C) 2001, 2002, 2004, 2009 Red Hat, Inc.
+ Written by Jakub Jelinek <jakub@redhat.com>, 2001.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include <config.h>
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <locale.h>
+#include <error.h>
+#include <argp.h>
+#include <stdlib.h>
+
+#include "prelink.h"
+
+static int
+sparc_adjust_dyn (DSO *dso, int n, GElf_Dyn *dyn, GElf_Addr start,
+ GElf_Addr adjust)
+{
+ if (dyn->d_tag == DT_PLTGOT)
+ {
+ int i;
+
+ for (i = 1; i < dso->ehdr.e_shnum; ++i)
+ if (! strcmp (strptr (dso, dso->ehdr.e_shstrndx,
+ dso->shdr[i].sh_name), ".got"))
+ {
+ Elf32_Addr data;
+
+ data = read_ube32 (dso, dso->shdr[i].sh_addr);
+ /* .got[0] points to _DYNAMIC, it needs to be adjusted. */
+ if (data == dso->shdr[n].sh_addr && data >= start)
+ write_be32 (dso, dso->shdr[i].sh_addr, data + adjust);
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static int
+sparc_adjust_rel (DSO *dso, GElf_Rel *rel, GElf_Addr start,
+ GElf_Addr adjust)
+{
+ error (0, 0, "%s: Sparc doesn't support REL relocs", dso->filename);
+ return 1;
+}
+
+static int
+sparc_adjust_rela (DSO *dso, GElf_Rela *rela, GElf_Addr start,
+ GElf_Addr adjust)
+{
+ if (GELF_R_TYPE (rela->r_info) == R_SPARC_RELATIVE)
+ {
+ if (rela->r_addend)
+ {
+ if ((Elf32_Addr) rela->r_addend >= start)
+ rela->r_addend += (Elf32_Sword) adjust;
+ }
+ else
+ {
+ GElf_Addr val = read_ube32 (dso, rela->r_offset);
+
+ if (val >= start)
+ write_be32 (dso, rela->r_offset, val + adjust);
+ }
+ }
+ return 0;
+}
+
+static int
+sparc_prelink_rel (struct prelink_info *info, GElf_Rel *rel,
+ GElf_Addr reladdr)
+{
+ error (0, 0, "%s: Sparc doesn't support REL relocs", info->dso->filename);
+ return 1;
+}
+
+static void
+sparc_fixup_plt (DSO *dso, GElf_Rela *rela, GElf_Addr value)
+{
+ Elf32_Sword disp = value - rela->r_offset;
+
+ if (disp >= -0x800000 && disp < 0x800000)
+ {
+ /* b,a value
+ nop
+ nop */
+ write_be32 (dso, rela->r_offset, 0x30800000 | ((disp >> 2) & 0x3fffff));
+ write_be32 (dso, rela->r_offset + 4, 0x01000000);
+ write_be32 (dso, rela->r_offset + 8, 0x01000000);
+ }
+ else
+ {
+ /* sethi %hi(value), %g1
+ jmpl %g1 + %lo(value), %g0
+ nop */
+ write_be32 (dso, rela->r_offset, 0x03000000 | ((value >> 10) & 0x3fffff));
+ write_be32 (dso, rela->r_offset + 4, 0x81c06000 | (value & 0x3ff));
+ write_be32 (dso, rela->r_offset + 8, 0x01000000);
+ }
+}
+
+static int
+sparc_prelink_rela (struct prelink_info *info, GElf_Rela *rela,
+ GElf_Addr relaaddr)
+{
+ DSO *dso = info->dso;
+ GElf_Addr value;
+
+ if (GELF_R_TYPE (rela->r_info) == R_SPARC_NONE)
+ return 0;
+ else if (GELF_R_TYPE (rela->r_info) == R_SPARC_RELATIVE)
+ {
+ /* 32-bit SPARC handles RELATIVE relocs as
+ *(int *)rela->r_offset += l_addr + rela->r_addend.
+ RELATIVE relocs against .got traditionally used to have the
+ addend in memory pointed by r_offset and 0 r_addend,
+ other RELATIVE relocs and more recent .got RELATIVE relocs
+ too have 0 in memory and non-zero r_addend. For prelinking,
+ we need the value in memory to be already relocated for
+ l_addr == 0 case, so we have to make sure r_addend will be 0. */
+ if (rela->r_addend == 0)
+ return 0;
+ value = read_ube32 (dso, rela->r_offset);
+ value += rela->r_addend;
+ rela->r_addend = 0;
+ write_be32 (dso, rela->r_offset, value);
+ /* Tell prelink_rela routine it should update the relocation. */
+ return 2;
+ }
+ value = info->resolve (info, GELF_R_SYM (rela->r_info),
+ GELF_R_TYPE (rela->r_info));
+ value += rela->r_addend;
+ switch (GELF_R_TYPE (rela->r_info))
+ {
+ case R_SPARC_GLOB_DAT:
+ case R_SPARC_32:
+ case R_SPARC_UA32:
+ write_be32 (dso, rela->r_offset, value);
+ break;
+ case R_SPARC_JMP_SLOT:
+ sparc_fixup_plt (dso, rela, value);
+ break;
+ case R_SPARC_8:
+ write_8 (dso, rela->r_offset, value);
+ break;
+ case R_SPARC_16:
+ case R_SPARC_UA16:
+ write_be16 (dso, rela->r_offset, value);
+ break;
+ case R_SPARC_LO10:
+ write_be32 (dso, rela->r_offset,
+ (value & 0x3ff) | (read_ube32 (dso, rela->r_offset) & ~0x3ff));
+ break;
+ case R_SPARC_HI22:
+ write_be32 (dso, rela->r_offset,
+ ((value >> 10) & 0x3fffff)
+ | (read_ube32 (dso, rela->r_offset) & 0xffc00000));
+ break;
+ case R_SPARC_DISP8:
+ write_8 (dso, rela->r_offset, value - rela->r_offset);
+ break;
+ case R_SPARC_DISP16:
+ write_be16 (dso, rela->r_offset, value - rela->r_offset);
+ break;
+ case R_SPARC_DISP32:
+ write_be32 (dso, rela->r_offset, value - rela->r_offset);
+ break;
+ case R_SPARC_WDISP30:
+ write_be32 (dso, rela->r_offset,
+ (((value - rela->r_offset) >> 2) & 0x3fffffff)
+ | (read_ube32 (dso, rela->r_offset) & 0xc0000000));
+ break;
+ case R_SPARC_TLS_DTPOFF32:
+ write_be32 (dso, rela->r_offset, value + rela->r_addend);
+ break;
+ /* DTPMOD32 and TPOFF32 is impossible to predict in shared libraries
+ unless prelink sets the rules. */
+ case R_SPARC_TLS_DTPMOD32:
+ if (dso->ehdr.e_type == ET_EXEC)
+ {
+ error (0, 0, "%s: R_SPARC_TLS_DTPMOD32 reloc in executable?",
+ dso->filename);
+ return 1;
+ }
+ break;
+ case R_SPARC_TLS_TPOFF32:
+ if (dso->ehdr.e_type == ET_EXEC && info->resolvetls)
+ write_be32 (dso, rela->r_offset,
+ value + rela->r_addend - info->resolvetls->offset);
+ break;
+ case R_SPARC_TLS_LE_HIX22:
+ if (dso->ehdr.e_type == ET_EXEC && info->resolvetls)
+ write_be32 (dso, rela->r_offset,
+ (read_ube32 (dso, rela->r_offset) & 0xffc00000)
+ | (((~(value + rela->r_addend - info->resolvetls->offset))
+ >> 10) & 0x3fffff));
+ break;
+ case R_SPARC_TLS_LE_LOX10:
+ if (dso->ehdr.e_type == ET_EXEC && info->resolvetls)
+ write_be32 (dso, rela->r_offset,
+ (read_ube32 (dso, rela->r_offset) & 0xffffe000) | 0x1c00
+ | ((value + rela->r_addend - info->resolvetls->offset)
+ & 0x3ff));
+ break;
+ case R_SPARC_COPY:
+ if (dso->ehdr.e_type == ET_EXEC)
+ /* COPY relocs are handled specially in generic code. */
+ return 0;
+ error (0, 0, "%s: R_SPARC_COPY reloc in shared library?", dso->filename);
+ return 1;
+ default:
+ error (0, 0, "%s: Unknown sparc relocation type %d", dso->filename,
+ (int) GELF_R_TYPE (rela->r_info));
+ return 1;
+ }
+ return 0;
+}
+
+static int
+sparc_apply_conflict_rela (struct prelink_info *info, GElf_Rela *rela,
+ char *buf, GElf_Addr dest_addr)
+{
+ switch (GELF_R_TYPE (rela->r_info))
+ {
+ case R_SPARC_32:
+ case R_SPARC_UA32:
+ buf_write_be32 (buf, rela->r_addend);
+ break;
+ case R_SPARC_16:
+ case R_SPARC_UA16:
+ buf_write_be16 (buf, rela->r_addend);
+ break;
+ case R_SPARC_8:
+ buf_write_8 (buf, rela->r_addend);
+ break;
+ default:
+ abort ();
+ }
+ return 0;
+}
+
+static int
+sparc_apply_rel (struct prelink_info *info, GElf_Rel *rel, char *buf)
+{
+ error (0, 0, "%s: Sparc doesn't support REL relocs", info->dso->filename);
+ return 1;
+}
+
+static int
+sparc_apply_rela (struct prelink_info *info, GElf_Rela *rela, char *buf)
+{
+ GElf_Addr value;
+
+ value = info->resolve (info, GELF_R_SYM (rela->r_info),
+ GELF_R_TYPE (rela->r_info));
+ value += rela->r_addend;
+ switch (GELF_R_TYPE (rela->r_info))
+ {
+ case R_SPARC_NONE:
+ break;
+ case R_SPARC_DISP32:
+ value -= rela->r_offset;
+ case R_SPARC_GLOB_DAT:
+ case R_SPARC_32:
+ case R_SPARC_UA32:
+ buf_write_be32 (buf, value);
+ break;
+ case R_SPARC_DISP16:
+ value -= rela->r_offset;
+ case R_SPARC_16:
+ case R_SPARC_UA16:
+ buf_write_be16 (buf, value);
+ break;
+ case R_SPARC_DISP8:
+ value -= rela->r_offset;
+ case R_SPARC_8:
+ buf_write_8 (buf, value);
+ break;
+ case R_SPARC_LO10:
+ buf_write_be32 (buf, (buf_read_ube32 (buf) & ~0x3ff) | (value & 0x3ff));
+ break;
+ case R_SPARC_HI22:
+ buf_write_be32 (buf, (buf_read_ube32 (buf) & 0xffc00000)
+ | ((value >> 10) & 0x3fffff));
+ break;
+ case R_SPARC_WDISP30:
+ buf_write_be32 (buf, (buf_read_ube32 (buf) & 0xc0000000)
+ | (((value - rela->r_offset) >> 2) & 0x3fffffff));
+ break;
+ case R_SPARC_RELATIVE:
+ error (0, 0, "%s: R_SPARC_RELATIVE in ET_EXEC object?",
+ info->dso->filename);
+ return 1;
+ default:
+ return 1;
+ }
+ return 0;
+}
+
+static int
+sparc_prelink_conflict_rel (DSO *dso, struct prelink_info *info,
+ GElf_Rel *rel, GElf_Addr reladdr)
+{
+ error (0, 0, "%s: Sparc doesn't support REL relocs", dso->filename);
+ return 1;
+}
+
+static int
+sparc_prelink_conflict_rela (DSO *dso, struct prelink_info *info,
+ GElf_Rela *rela, GElf_Addr relaaddr)
+{
+ GElf_Addr value;
+ struct prelink_conflict *conflict;
+ struct prelink_tls *tls;
+ GElf_Rela *ret;
+ int r_type;
+
+ if (GELF_R_TYPE (rela->r_info) == R_SPARC_RELATIVE
+ || GELF_R_TYPE (rela->r_info) == R_SPARC_NONE
+ || info->dso == dso)
+ /* Fast path: nothing to do. */
+ return 0;
+ conflict = prelink_conflict (info, GELF_R_SYM (rela->r_info),
+ GELF_R_TYPE (rela->r_info));
+ if (conflict == NULL)
+ {
+ if (info->curtls == NULL)
+ return 0;
+ switch (GELF_R_TYPE (rela->r_info))
+ {
+ /* Even local DTPMOD32 and TPOFF32 relocs need conflicts. */
+ case R_SPARC_TLS_DTPMOD32:
+ case R_SPARC_TLS_TPOFF32:
+ case R_SPARC_TLS_LE_HIX22:
+ case R_SPARC_TLS_LE_LOX10:
+ break;
+ default:
+ return 0;
+ }
+ value = 0;
+ }
+ else if (conflict->ifunc)
+ {
+ error (0, 0, "%s: STT_GNU_IFUNC not handled on SPARC yet",
+ dso->filename);
+ return 1;
+ }
+ else
+ {
+ /* DTPOFF32 wants to see only real conflicts, not lookups
+ with reloc_class RTYPE_CLASS_TLS. */
+ if (GELF_R_TYPE (rela->r_info) == R_SPARC_TLS_DTPOFF32
+ && conflict->lookup.tls == conflict->conflict.tls
+ && conflict->lookupval == conflict->conflictval)
+ return 0;
+
+ value = conflict_lookup_value (conflict);
+ }
+ ret = prelink_conflict_add_rela (info);
+ if (ret == NULL)
+ return 1;
+ ret->r_offset = rela->r_offset;
+ value += rela->r_addend;
+ r_type = GELF_R_TYPE (rela->r_info);
+ switch (r_type)
+ {
+ case R_SPARC_DISP32:
+ value -= rela->r_offset;
+ case R_SPARC_GLOB_DAT:
+ case R_SPARC_32:
+ r_type = R_SPARC_32;
+ break;
+ case R_SPARC_DISP16:
+ value -= rela->r_offset;
+ case R_SPARC_16:
+ r_type = R_SPARC_16;
+ break;
+ case R_SPARC_DISP8:
+ value -= rela->r_offset;
+ case R_SPARC_8:
+ r_type = R_SPARC_8;
+ break;
+ /* Attempt to transform all reloc which read-modify-write into
+ simple writes. */
+ case R_SPARC_LO10:
+ value = (read_ube32 (dso, rela->r_offset) & ~0x3ff) | (value & 0x3ff);
+ r_type = R_SPARC_32;
+ break;
+ case R_SPARC_HI22:
+ value = (read_ube32 (dso, rela->r_offset) & 0xffc00000)
+ | ((value >> 10) & 0x3fffff);
+ r_type = R_SPARC_32;
+ break;
+ case R_SPARC_WDISP30:
+ value = (read_ube32 (dso, rela->r_offset) & 0xc0000000)
+ | (((value - rela->r_offset) >> 2) & 0x3fffffff);
+ r_type = R_SPARC_32;
+ break;
+ case R_SPARC_UA16:
+ case R_SPARC_UA32:
+ case R_SPARC_JMP_SLOT:
+ break;
+ case R_SPARC_TLS_DTPMOD32:
+ case R_SPARC_TLS_DTPOFF32:
+ case R_SPARC_TLS_TPOFF32:
+ case R_SPARC_TLS_LE_HIX22:
+ case R_SPARC_TLS_LE_LOX10:
+ if (conflict != NULL
+ && (conflict->reloc_class != RTYPE_CLASS_TLS
+ || conflict->lookup.tls == NULL))
+ {
+ error (0, 0, "%s: TLS reloc not resolving to STT_TLS symbol",
+ dso->filename);
+ return 1;
+ }
+ r_type = R_SPARC_32;
+ tls = conflict ? conflict->lookup.tls : info->curtls;
+ switch (GELF_R_TYPE (rela->r_info))
+ {
+ case R_SPARC_TLS_DTPMOD32:
+ value = tls->modid;
+ break;
+ case R_SPARC_TLS_DTPOFF32:
+ break;
+ case R_SPARC_TLS_TPOFF32:
+ value -= tls->offset;
+ break;
+ case R_SPARC_TLS_LE_HIX22:
+ value -= tls->offset;
+ value = (read_ube32 (dso, rela->r_offset) & 0xffc00000)
+ | (((~value) >> 10) & 0x3fffff);
+ break;
+ case R_SPARC_TLS_LE_LOX10:
+ value -= tls->offset;
+ value = (read_ube32 (dso, rela->r_offset) & 0xffffe000) | 0x1c00
+ | (value & 0x3ff);
+ break;
+ }
+ break;
+ default:
+ error (0, 0, "%s: Unknown Sparc relocation type %d", dso->filename,
+ r_type);
+ return 1;
+ }
+ ret->r_info = GELF_R_INFO (0, r_type);
+ ret->r_addend = (Elf32_Sword) value;
+ return 0;
+}
+
+static int
+sparc_rel_to_rela (DSO *dso, GElf_Rel *rel, GElf_Rela *rela)
+{
+ error (0, 0, "%s: Sparc doesn't support REL relocs", dso->filename);
+ return 1;
+}
+
+static int
+sparc_need_rel_to_rela (DSO *dso, int first, int last)
+{
+ return 0;
+}
+
+static int
+sparc_arch_prelink (struct prelink_info *info)
+{
+ return 0;
+}
+
+static int
+sparc_undo_prelink_rela (DSO *dso, GElf_Rela *rela, GElf_Addr relaaddr)
+{
+ int sec;
+
+ switch (GELF_R_TYPE (rela->r_info))
+ {
+ case R_SPARC_NONE:
+ return 0;
+ case R_SPARC_RELATIVE:
+ /* 32-bit SPARC handles RELATIVE relocs as
+ *(int *)rela->r_offset += l_addr + rela->r_addend.
+ RELATIVE relocs against .got traditionally used to have the
+ addend in memory pointed by r_offset and 0 r_addend,
+ other RELATIVE relocs and more recent RELATIVE relocs have 0
+ in memory and non-zero r_addend.
+ Always store 0 to memory when doing undo. */
+ assert (rela->r_addend == 0);
+ rela->r_addend = (Elf32_Sword) read_ube32 (dso, rela->r_offset);
+ write_be32 (dso, rela->r_offset, 0);
+ /* Tell undo_prelink_rela routine it should update the
+ relocation. */
+ return 2;
+ case R_SPARC_GLOB_DAT:
+ case R_SPARC_32:
+ case R_SPARC_UA32:
+ case R_SPARC_DISP32:
+ case R_SPARC_TLS_DTPMOD32:
+ case R_SPARC_TLS_DTPOFF32:
+ case R_SPARC_TLS_TPOFF32:
+ write_be32 (dso, rela->r_offset, 0);
+ break;
+ case R_SPARC_JMP_SLOT:
+ sec = addr_to_sec (dso, rela->r_offset);
+ if (sec != -1)
+ {
+ /* sethi .-.plt, %g1
+ b,a .plt+0 */
+ write_be32 (dso, rela->r_offset,
+ 0x03000000
+ | ((rela->r_offset - dso->shdr[sec].sh_addr)
+ & 0x3fffff));
+ write_be32 (dso, rela->r_offset + 4,
+ 0x30800000
+ | (((dso->shdr[sec].sh_addr - rela->r_offset - 4) >> 2)
+ & 0x3fffff));
+ }
+ break;
+ case R_SPARC_8:
+ case R_SPARC_DISP8:
+ write_8 (dso, rela->r_offset, 0);
+ break;
+ case R_SPARC_16:
+ case R_SPARC_UA16:
+ case R_SPARC_DISP16:
+ write_be16 (dso, rela->r_offset, 0);
+ break;
+ case R_SPARC_LO10:
+ write_be32 (dso, rela->r_offset,
+ read_ube32 (dso, rela->r_offset) & ~0x3ff);
+ break;
+ case R_SPARC_TLS_LE_LOX10:
+ write_be32 (dso, rela->r_offset,
+ read_ube32 (dso, rela->r_offset) & 0xffffe000);
+ break;
+ case R_SPARC_HI22:
+ case R_SPARC_TLS_LE_HIX22:
+ write_be32 (dso, rela->r_offset,
+ read_ube32 (dso, rela->r_offset) & 0xffc00000);
+ break;
+ case R_SPARC_WDISP30:
+ write_be32 (dso, rela->r_offset,
+ read_ube32 (dso, rela->r_offset) & 0xc0000000);
+ break;
+ case R_SPARC_COPY:
+ if (dso->ehdr.e_type == ET_EXEC)
+ /* COPY relocs are handled specially in generic code. */
+ return 0;
+ error (0, 0, "%s: R_SPARC_COPY reloc in shared library?", dso->filename);
+ return 1;
+ default:
+ error (0, 0, "%s: Unknown sparc relocation type %d", dso->filename,
+ (int) GELF_R_TYPE (rela->r_info));
+ return 1;
+ }
+ return 0;
+}
+
+static int
+sparc_reloc_size (int reloc_type)
+{
+ switch (reloc_type)
+ {
+ case R_SPARC_8:
+ case R_SPARC_DISP8:
+ return 1;
+ case R_SPARC_16:
+ case R_SPARC_DISP16:
+ case R_SPARC_UA16:
+ return 2;
+ default:
+ break;
+ }
+ return 4;
+}
+
+static int
+sparc_reloc_class (int reloc_type)
+{
+ switch (reloc_type)
+ {
+ case R_SPARC_COPY: return RTYPE_CLASS_COPY;
+ case R_SPARC_JMP_SLOT: return RTYPE_CLASS_PLT;
+ case R_SPARC_TLS_DTPMOD32:
+ case R_SPARC_TLS_DTPOFF32:
+ case R_SPARC_TLS_TPOFF32:
+ case R_SPARC_TLS_LE_HIX22:
+ case R_SPARC_TLS_LE_LOX10:
+ return RTYPE_CLASS_TLS;
+ default: return RTYPE_CLASS_VALID;
+ }
+}
+
+PL_ARCH(sparc) = {
+ .name = "SPARC",
+ .class = ELFCLASS32,
+ .machine = EM_SPARC,
+ .alternate_machine = { EM_SPARC32PLUS },
+ .R_JMP_SLOT = R_SPARC_JMP_SLOT,
+ .R_COPY = R_SPARC_COPY,
+ .R_RELATIVE = R_SPARC_RELATIVE,
+ .rtype_class_valid = RTYPE_CLASS_VALID,
+ .dynamic_linker = "/lib/ld-linux.so.2",
+ .adjust_dyn = sparc_adjust_dyn,
+ .adjust_rel = sparc_adjust_rel,
+ .adjust_rela = sparc_adjust_rela,
+ .prelink_rel = sparc_prelink_rel,
+ .prelink_rela = sparc_prelink_rela,
+ .prelink_conflict_rel = sparc_prelink_conflict_rel,
+ .prelink_conflict_rela = sparc_prelink_conflict_rela,
+ .apply_conflict_rela = sparc_apply_conflict_rela,
+ .apply_rel = sparc_apply_rel,
+ .apply_rela = sparc_apply_rela,
+ .rel_to_rela = sparc_rel_to_rela,
+ .need_rel_to_rela = sparc_need_rel_to_rela,
+ .reloc_size = sparc_reloc_size,
+ .reloc_class = sparc_reloc_class,
+ .max_reloc_size = 4,
+ .arch_prelink = sparc_arch_prelink,
+ .undo_prelink_rela = sparc_undo_prelink_rela,
+ /* Although TASK_UNMAPPED_BASE is 0x70000000, we leave some
+ area so that mmap of /etc/ld.so.cache and ld.so's malloc
+ does not take some library's VA slot.
+ Also, if this guard area isn't too small, typically
+ even dlopened libraries will get the slots they desire. */
+ .mmap_base = 0x71000000LL,
+ .mmap_end = 0x80000000LL,
+ .max_page_size = 0x10000,
+ .page_size = 0x1000
+};
diff --git a/src/arch-sparc64.c b/src/arch-sparc64.c
new file mode 100644
index 0000000..aee4601
--- /dev/null
+++ b/src/arch-sparc64.c
@@ -0,0 +1,849 @@
+/* Copyright (C) 2001, 2002, 2004, 2009 Red Hat, Inc.
+ Written by Jakub Jelinek <jakub@redhat.com>, 2001.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include <config.h>
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <locale.h>
+#include <error.h>
+#include <argp.h>
+#include <stdlib.h>
+
+#include "prelink.h"
+
+#define SPARC64_R_TYPE(info) (GELF_R_TYPE (info) & 0xff)
+
+static int
+sparc64_adjust_dyn (DSO *dso, int n, GElf_Dyn *dyn, GElf_Addr start,
+ GElf_Addr adjust)
+{
+ if (dyn->d_tag == DT_PLTGOT)
+ {
+ int i;
+
+ for (i = 1; i < dso->ehdr.e_shnum; ++i)
+ if (! strcmp (strptr (dso, dso->ehdr.e_shstrndx,
+ dso->shdr[i].sh_name), ".got"))
+ {
+ Elf64_Addr data;
+
+ data = read_ube64 (dso, dso->shdr[i].sh_addr);
+ /* .got[0] points to _DYNAMIC, it needs to be adjusted. */
+ if (data == dso->shdr[n].sh_addr && data >= start)
+ write_be64 (dso, dso->shdr[i].sh_addr, data + adjust);
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static int
+sparc64_adjust_rel (DSO *dso, GElf_Rel *rel, GElf_Addr start,
+ GElf_Addr adjust)
+{
+ error (0, 0, "%s: Sparc doesn't support REL relocs", dso->filename);
+ return 1;
+}
+
+static int
+sparc64_adjust_rela (DSO *dso, GElf_Rela *rela, GElf_Addr start,
+ GElf_Addr adjust)
+{
+ if (SPARC64_R_TYPE (rela->r_info) == R_SPARC_RELATIVE)
+ {
+ if (rela->r_addend >= start)
+ rela->r_addend += adjust;
+ }
+ else if (SPARC64_R_TYPE (rela->r_info) == R_SPARC_JMP_SLOT
+ && rela->r_addend)
+ {
+ /* .plt[32768+] r_addends are -some_address_in_plt_section. */
+ if ((- rela->r_addend) >= start)
+ rela->r_addend -= adjust;
+ }
+ return 0;
+}
+
+static int
+sparc64_prelink_rel (struct prelink_info *info, GElf_Rel *rel,
+ GElf_Addr reladdr)
+{
+ error (0, 0, "%s: Sparc doesn't support REL relocs", info->dso->filename);
+ return 1;
+}
+
+static void
+sparc64_fixup_plt (DSO *dso, GElf_Rela *rela, GElf_Addr value)
+{
+ Elf64_Sxword disp = value - rela->r_offset;
+
+ if (rela->r_addend)
+ {
+ /* .plt[32768+] */
+ write_be64 (dso, rela->r_offset, value);
+ }
+ else if (disp >= -0x800000 && disp < 0x800000)
+ {
+ /* b,a value
+ nop
+ nop */
+ write_be32 (dso, rela->r_offset, 0x30800000 | ((disp >> 2) & 0x3fffff));
+ write_be32 (dso, rela->r_offset + 4, 0x01000000);
+ write_be32 (dso, rela->r_offset + 8, 0x01000000);
+ }
+ else if (! (value >> 32))
+ {
+ /* sethi %hi(value), %g1
+ jmpl %g1 + %lo(value), %g0
+ nop */
+ write_be32 (dso, rela->r_offset, 0x03000000 | ((value >> 10) & 0x3fffff));
+ write_be32 (dso, rela->r_offset + 4, 0x81c06000 | (value & 0x3ff));
+ write_be32 (dso, rela->r_offset + 8, 0x01000000);
+ }
+ else if ((rela->r_offset + 4 > value
+ && ((rela->r_offset - value) >> 31) == 0)
+ || (value > rela->r_offset + 4
+ && ((value - rela->r_offset - 4) >> 31) == 0))
+ {
+ /* mov %o7, %g1
+ call value
+ mov %g1, %o7 */
+ write_be32 (dso, rela->r_offset, 0x8210000f);
+ write_be32 (dso, rela->r_offset + 4, 0x40000000
+ | (((value - rela->r_offset - 4) >> 2) & 0x3fffffff));
+ write_be32 (dso, rela->r_offset + 8, 0x9e100001);
+ }
+ else
+ {
+ unsigned int csts[4];
+ int i = 0;
+
+ /* sethi %hh(value), %g1
+ sethi %lm(value), %g5
+ or %g1, %hm(value), %g1
+ or %g5, %lo(value), %g5
+ sllx %g1, 32, %g1
+ jmpl %g1 + %g5, %g0
+ nop */
+
+ csts[0] = value >> 42;
+ csts[1] = (value >> 32) & 0x3ff;
+ csts[2] = (value >> 10) & 0x3fffff;
+ csts[3] = value & 0x3ff;
+ write_be32 (dso, rela->r_offset, 0x03000000 | csts[0]);
+ write_be32 (dso, rela->r_offset + 4, 0x0b000000 | csts[2]);
+ /* Sparc64 shared libs are often 0xfffff800XXXXXXXX, so optimize
+ for this common case. */
+ if (csts[1] == 0)
+ write_be32 (dso, rela->r_offset + 8, 0x83287020);
+ else
+ write_be32 (dso, rela->r_offset + 8, 0x82106000 | csts[1]);
+ write_be32 (dso, rela->r_offset + 12, 0x8a116000 | csts[3]);
+ if (csts[1] != 0)
+ write_be32 (dso, rela->r_offset + 16, 0x83287020), i = 4;
+ write_be32 (dso, rela->r_offset + 16 + i, 0x81c04005);
+ write_be32 (dso, rela->r_offset + 20 + i, 0x01000000);
+ }
+}
+
+static int
+sparc64_prelink_rela (struct prelink_info *info, GElf_Rela *rela,
+ GElf_Addr relaaddr)
+{
+ DSO *dso = info->dso;
+ GElf_Addr value;
+
+ if (SPARC64_R_TYPE (rela->r_info) == R_SPARC_NONE)
+ return 0;
+ else if (SPARC64_R_TYPE (rela->r_info) == R_SPARC_RELATIVE)
+ {
+ /* 64-bit SPARC handles RELATIVE relocs as
+ *(long *)rela->r_offset = l_addr + rela->r_addend,
+ so we must update the memory. */
+ write_be64 (dso, rela->r_offset, rela->r_addend);
+ return 0;
+ }
+ value = info->resolve (info, GELF_R_SYM (rela->r_info),
+ SPARC64_R_TYPE (rela->r_info));
+ value += rela->r_addend;
+ switch (SPARC64_R_TYPE (rela->r_info))
+ {
+ case R_SPARC_GLOB_DAT:
+ case R_SPARC_64:
+ case R_SPARC_UA64:
+ write_be64 (dso, rela->r_offset, value);
+ break;
+ case R_SPARC_32:
+ case R_SPARC_UA32:
+ write_be32 (dso, rela->r_offset, value);
+ break;
+ case R_SPARC_JMP_SLOT:
+ sparc64_fixup_plt (dso, rela, value);
+ break;
+ case R_SPARC_8:
+ write_8 (dso, rela->r_offset, value);
+ break;
+ case R_SPARC_16:
+ case R_SPARC_UA16:
+ write_be16 (dso, rela->r_offset, value);
+ break;
+ case R_SPARC_LO10:
+ write_be32 (dso, rela->r_offset,
+ (value & 0x3ff) | (read_ube32 (dso, rela->r_offset) & ~0x3ff));
+ break;
+ case R_SPARC_LM22:
+ case R_SPARC_HI22:
+ write_be32 (dso, rela->r_offset,
+ ((value >> 10) & 0x3fffff)
+ | (read_ube32 (dso, rela->r_offset) & 0xffc00000));
+ break;
+ case R_SPARC_DISP8:
+ write_8 (dso, rela->r_offset, value - rela->r_offset);
+ break;
+ case R_SPARC_DISP16:
+ write_be16 (dso, rela->r_offset, value - rela->r_offset);
+ break;
+ case R_SPARC_DISP32:
+ write_be32 (dso, rela->r_offset, value - rela->r_offset);
+ break;
+ case R_SPARC_DISP64:
+ write_be64 (dso, rela->r_offset, value - rela->r_offset);
+ break;
+ case R_SPARC_WDISP30:
+ write_be32 (dso, rela->r_offset,
+ (((value - rela->r_offset) >> 2) & 0x3fffffff)
+ | (read_ube32 (dso, rela->r_offset) & 0xc0000000));
+ break;
+ case R_SPARC_TLS_DTPOFF64:
+ write_be64 (dso, rela->r_offset, value + rela->r_addend);
+ break;
+ /* DTPMOD64 and TPOFF64 is impossible to predict in shared libraries
+ unless prelink sets the rules. */
+ case R_SPARC_TLS_DTPMOD64:
+ if (dso->ehdr.e_type == ET_EXEC)
+ {
+ error (0, 0, "%s: R_SPARC_TLS_DTPMOD64 reloc in executable?",
+ dso->filename);
+ return 1;
+ }
+ break;
+ case R_SPARC_TLS_TPOFF64:
+ if (dso->ehdr.e_type == ET_EXEC && info->resolvetls)
+ write_be64 (dso, rela->r_offset,
+ value + rela->r_addend - info->resolvetls->offset);
+ break;
+ case R_SPARC_TLS_LE_HIX22:
+ if (dso->ehdr.e_type == ET_EXEC && info->resolvetls)
+ write_be32 (dso, rela->r_offset,
+ (read_ube32 (dso, rela->r_offset) & 0xffc00000)
+ | (((~(value + rela->r_addend - info->resolvetls->offset))
+ >> 10) & 0x3fffff));
+ break;
+ case R_SPARC_TLS_LE_LOX10:
+ if (dso->ehdr.e_type == ET_EXEC && info->resolvetls)
+ write_be32 (dso, rela->r_offset,
+ (read_ube32 (dso, rela->r_offset) & 0xffffe000) | 0x1c00
+ | ((value + rela->r_addend - info->resolvetls->offset)
+ & 0x3ff));
+ break;
+ case R_SPARC_H44:
+ write_be32 (dso, rela->r_offset,
+ ((value >> 22) & 0x3fffff)
+ | (read_ube32 (dso, rela->r_offset) & 0xffc00000));
+ break;
+ case R_SPARC_M44:
+ write_be32 (dso, rela->r_offset,
+ ((value >> 12) & 0x3ff)
+ | (read_ube32 (dso, rela->r_offset) & ~0x3ff));
+ break;
+ case R_SPARC_L44:
+ write_be32 (dso, rela->r_offset,
+ (value & 0xfff) | (read_ube32 (dso, rela->r_offset) & ~0xfff));
+ break;
+ case R_SPARC_HH22:
+ write_be32 (dso, rela->r_offset,
+ ((value >> 42) & 0x3fffff)
+ | (read_ube32 (dso, rela->r_offset) & 0xffc00000));
+ break;
+ case R_SPARC_HM10:
+ write_be32 (dso, rela->r_offset,
+ ((value >> 32) & 0x3ff)
+ | (read_ube32 (dso, rela->r_offset) & ~0x3ff));
+ break;
+ case R_SPARC_OLO10:
+ write_be32 (dso, rela->r_offset,
+ (((value & 0x3ff) + (GELF_R_TYPE (rela->r_info) >> 8)) & 0x1fff)
+ | (read_ube32 (dso, rela->r_offset) & ~0x1fff));
+ break;
+ case R_SPARC_COPY:
+ if (dso->ehdr.e_type == ET_EXEC)
+ /* COPY relocs are handled specially in generic code. */
+ return 0;
+ error (0, 0, "%s: R_SPARC_COPY reloc in shared library?", dso->filename);
+ return 1;
+ default:
+ error (0, 0, "%s: Unknown sparc relocation type %d", dso->filename,
+ (int) SPARC64_R_TYPE (rela->r_info));
+ return 1;
+ }
+ return 0;
+}
+
+static int
+sparc64_apply_conflict_rela (struct prelink_info *info, GElf_Rela *rela,
+ char *buf, GElf_Addr dest_addr)
+{
+ switch (SPARC64_R_TYPE (rela->r_info))
+ {
+ case R_SPARC_64:
+ case R_SPARC_UA64:
+ buf_write_be64 (buf, rela->r_addend);
+ break;
+ case R_SPARC_32:
+ case R_SPARC_UA32:
+ buf_write_be32 (buf, rela->r_addend);
+ break;
+ case R_SPARC_16:
+ case R_SPARC_UA16:
+ buf_write_be16 (buf, rela->r_addend);
+ break;
+ case R_SPARC_8:
+ buf_write_8 (buf, rela->r_addend);
+ break;
+ default:
+ abort ();
+ }
+ return 0;
+}
+
+static int
+sparc64_apply_rel (struct prelink_info *info, GElf_Rel *rel, char *buf)
+{
+ error (0, 0, "%s: Sparc doesn't support REL relocs", info->dso->filename);
+ return 1;
+}
+
+static int
+sparc64_apply_rela (struct prelink_info *info, GElf_Rela *rela, char *buf)
+{
+ GElf_Addr value;
+
+ value = info->resolve (info, GELF_R_SYM (rela->r_info),
+ SPARC64_R_TYPE (rela->r_info));
+ value += rela->r_addend;
+ switch (SPARC64_R_TYPE (rela->r_info))
+ {
+ case R_SPARC_NONE:
+ break;
+ case R_SPARC_DISP64:
+ value -= rela->r_offset;
+ case R_SPARC_GLOB_DAT:
+ case R_SPARC_64:
+ case R_SPARC_UA64:
+ buf_write_be64 (buf, value);
+ break;
+ case R_SPARC_DISP32:
+ value -= rela->r_offset;
+ case R_SPARC_32:
+ case R_SPARC_UA32:
+ buf_write_be32 (buf, value);
+ break;
+ case R_SPARC_DISP16:
+ value -= rela->r_offset;
+ case R_SPARC_16:
+ case R_SPARC_UA16:
+ buf_write_be16 (buf, value);
+ break;
+ case R_SPARC_DISP8:
+ value -= rela->r_offset;
+ case R_SPARC_8:
+ buf_write_8 (buf, value);
+ break;
+ case R_SPARC_LO10:
+ buf_write_be32 (buf, (buf_read_ube32 (buf) & ~0x3ff) | (value & 0x3ff));
+ break;
+ case R_SPARC_LM22:
+ case R_SPARC_HI22:
+ buf_write_be32 (buf, (buf_read_ube32 (buf) & 0xffc00000)
+ | ((value >> 10) & 0x3fffff));
+ break;
+ case R_SPARC_WDISP30:
+ buf_write_be32 (buf, (buf_read_ube32 (buf) & 0xc0000000)
+ | (((value - rela->r_offset) >> 2) & 0x3fffffff));
+ break;
+ case R_SPARC_H44:
+ buf_write_be32 (buf, (buf_read_ube32 (buf) & 0xffc00000)
+ | ((value >> 22) & 0x3fffff));
+ break;
+ case R_SPARC_M44:
+ buf_write_be32 (buf, (buf_read_ube32 (buf) & ~0x3ff)
+ | ((value >> 12) & 0x3ff));
+ break;
+ case R_SPARC_L44:
+ buf_write_be32 (buf, (buf_read_ube32 (buf) & ~0xfff) | (value & 0xfff));
+ break;
+ case R_SPARC_HH22:
+ buf_write_be32 (buf, (buf_read_ube32 (buf) & 0xffc00000)
+ | ((value >> 42) & 0x3fffff));
+ break;
+ case R_SPARC_HM10:
+ buf_write_be32 (buf, (buf_read_ube32 (buf) & ~0x3ff)
+ | ((value >> 32) & 0x3ff));
+ break;
+ case R_SPARC_OLO10:
+ buf_write_be32 (buf, (buf_read_ube32 (buf) & ~0x1fff)
+ | (((value & 0x3ff)
+ + (GELF_R_TYPE (rela->r_info) >> 8)) & 0x1fff));
+ break;
+ case R_SPARC_RELATIVE:
+ error (0, 0, "%s: R_SPARC_RELATIVE in ET_EXEC object?",
+ info->dso->filename);
+ return 1;
+ default:
+ return 1;
+ }
+ return 0;
+}
+
+static int
+sparc64_prelink_conflict_rel (DSO *dso, struct prelink_info *info,
+ GElf_Rel *rel, GElf_Addr reladdr)
+{
+ error (0, 0, "%s: Sparc doesn't support REL relocs", dso->filename);
+ return 1;
+}
+
+static int
+sparc64_prelink_conflict_rela (DSO *dso, struct prelink_info *info,
+ GElf_Rela *rela, GElf_Addr relaaddr)
+{
+ GElf_Addr value;
+ struct prelink_conflict *conflict;
+ struct prelink_tls *tls;
+ GElf_Rela *ret;
+ int r_type;
+
+ if (SPARC64_R_TYPE (rela->r_info) == R_SPARC_RELATIVE
+ || SPARC64_R_TYPE (rela->r_info) == R_SPARC_NONE
+ || info->dso == dso)
+ /* Fast path: nothing to do. */
+ return 0;
+ conflict = prelink_conflict (info, GELF_R_SYM (rela->r_info),
+ SPARC64_R_TYPE (rela->r_info));
+ if (conflict == NULL)
+ {
+ if (info->curtls == NULL)
+ return 0;
+ switch (SPARC64_R_TYPE (rela->r_info))
+ {
+ /* Even local DTPMOD64 and TPOFF64 relocs need conflicts. */
+ case R_SPARC_TLS_DTPMOD64:
+ case R_SPARC_TLS_TPOFF64:
+ case R_SPARC_TLS_LE_HIX22:
+ case R_SPARC_TLS_LE_LOX10:
+ break;
+ default:
+ return 0;
+ }
+ value = 0;
+ }
+ else if (conflict->ifunc)
+ {
+ error (0, 0, "%s: STT_GNU_IFUNC not handled on SPARC64 yet",
+ dso->filename);
+ return 1;
+ }
+ else
+ {
+ /* DTPOFF64 wants to see only real conflicts, not lookups
+ with reloc_class RTYPE_CLASS_TLS. */
+ if (SPARC64_R_TYPE (rela->r_info) == R_SPARC_TLS_DTPOFF64
+ && conflict->lookup.tls == conflict->conflict.tls
+ && conflict->lookupval == conflict->conflictval)
+ return 0;
+
+ value = conflict_lookup_value (conflict);
+ }
+ ret = prelink_conflict_add_rela (info);
+ if (ret == NULL)
+ return 1;
+ ret->r_offset = rela->r_offset;
+ value += rela->r_addend;
+ r_type = SPARC64_R_TYPE (rela->r_info);
+ switch (r_type)
+ {
+ case R_SPARC_DISP64:
+ value -= rela->r_offset;
+ case R_SPARC_GLOB_DAT:
+ case R_SPARC_64:
+ r_type = R_SPARC_64;
+ break;
+ case R_SPARC_DISP32:
+ value -= rela->r_offset;
+ case R_SPARC_32:
+ r_type = R_SPARC_32;
+ break;
+ case R_SPARC_DISP16:
+ value -= rela->r_offset;
+ case R_SPARC_16:
+ r_type = R_SPARC_16;
+ break;
+ case R_SPARC_DISP8:
+ value -= rela->r_offset;
+ case R_SPARC_8:
+ r_type = R_SPARC_8;
+ break;
+ /* Attempt to transform all reloc which read-modify-write into
+ simple writes. */
+ case R_SPARC_LO10:
+ value = (read_ube32 (dso, rela->r_offset) & ~0x3ff) | (value & 0x3ff);
+ r_type = R_SPARC_32;
+ break;
+ case R_SPARC_LM22:
+ case R_SPARC_HI22:
+ value = (read_ube32 (dso, rela->r_offset) & 0xffc00000)
+ | ((value >> 10) & 0x3fffff);
+ r_type = R_SPARC_32;
+ break;
+ case R_SPARC_WDISP30:
+ value = (read_ube32 (dso, rela->r_offset) & 0xc0000000)
+ | (((value - rela->r_offset) >> 2) & 0x3fffffff);
+ r_type = R_SPARC_32;
+ break;
+ case R_SPARC_H44:
+ value = (read_ube32 (dso, rela->r_offset) & 0xffc00000)
+ | ((value >> 22) & 0x3fffff);
+ r_type = R_SPARC_32;
+ break;
+ case R_SPARC_M44:
+ value = (read_ube32 (dso, rela->r_offset) & ~0x3ff)
+ | ((value >> 12) & 0x3ff);
+ r_type = R_SPARC_32;
+ break;
+ case R_SPARC_L44:
+ value = (read_ube32 (dso, rela->r_offset) & ~0xfff) | (value & 0xfff);
+ r_type = R_SPARC_32;
+ break;
+ case R_SPARC_HH22:
+ value = (read_ube32 (dso, rela->r_offset) & 0xffc00000)
+ | ((value >> 42) & 0x3fffff);
+ r_type = R_SPARC_32;
+ break;
+ case R_SPARC_HM10:
+ value = (read_ube32 (dso, rela->r_offset) & ~0x3ff)
+ | ((value >> 32) & 0x3ff);
+ r_type = R_SPARC_32;
+ break;
+ case R_SPARC_OLO10:
+ value = (read_ube32 (dso, rela->r_offset) & ~0x1fff)
+ | (((value & 0x3ff) + (GELF_R_TYPE (rela->r_info) >> 8)) & 0x1fff);
+ r_type = R_SPARC_32;
+ break;
+ case R_SPARC_JMP_SLOT:
+ if (rela->r_addend)
+ r_type = R_SPARC_64;
+ break;
+ case R_SPARC_UA16:
+ case R_SPARC_UA32:
+ case R_SPARC_UA64:
+ break;
+ case R_SPARC_TLS_DTPMOD64:
+ case R_SPARC_TLS_DTPOFF64:
+ case R_SPARC_TLS_TPOFF64:
+ case R_SPARC_TLS_LE_HIX22:
+ case R_SPARC_TLS_LE_LOX10:
+ if (conflict != NULL
+ && (conflict->reloc_class != RTYPE_CLASS_TLS
+ || conflict->lookup.tls == NULL))
+ {
+ error (0, 0, "%s: TLS reloc not resolving to STT_TLS symbol",
+ dso->filename);
+ return 1;
+ }
+ tls = conflict ? conflict->lookup.tls : info->curtls;
+ switch (r_type)
+ {
+ case R_SPARC_TLS_DTPMOD64:
+ r_type = R_SPARC_64;
+ value = tls->modid;
+ break;
+ case R_SPARC_TLS_DTPOFF64:
+ r_type = R_SPARC_64;
+ break;
+ case R_SPARC_TLS_TPOFF64:
+ r_type = R_SPARC_64;
+ value -= tls->offset;
+ break;
+ case R_SPARC_TLS_LE_HIX22:
+ r_type = R_SPARC_32;
+ value -= tls->offset;
+ value = (read_ube32 (dso, rela->r_offset) & 0xffc00000)
+ | (((~value) >> 10) & 0x3fffff);
+ break;
+ case R_SPARC_TLS_LE_LOX10:
+ r_type = R_SPARC_32;
+ value -= tls->offset;
+ value = (read_ube32 (dso, rela->r_offset) & 0xffffe000) | 0x1c00
+ | (value & 0x3ff);
+ break;
+ }
+ break;
+ default:
+ error (0, 0, "%s: Unknown Sparc relocation type %d", dso->filename,
+ r_type);
+ return 1;
+ }
+ ret->r_info = GELF_R_INFO (0, r_type);
+ ret->r_addend = value;
+ return 0;
+}
+
+static int
+sparc64_rel_to_rela (DSO *dso, GElf_Rel *rel, GElf_Rela *rela)
+{
+ error (0, 0, "%s: Sparc doesn't support REL relocs", dso->filename);
+ return 1;
+}
+
+static int
+sparc64_need_rel_to_rela (DSO *dso, int first, int last)
+{
+ return 0;
+}
+
+static int
+sparc64_arch_prelink (struct prelink_info *info)
+{
+ return 0;
+}
+
+static int
+sparc64_undo_prelink_rela (DSO *dso, GElf_Rela *rela, GElf_Addr relaaddr)
+{
+ int sec;
+
+ switch (GELF_R_TYPE (rela->r_info))
+ {
+ case R_SPARC_NONE:
+ break;
+ case R_SPARC_JMP_SLOT:
+ sec = addr_to_sec (dso, rela->r_offset);
+ if (sec != -1)
+ {
+ if (rela->r_addend == 0)
+ {
+ /* sethi .-.plt, %g1
+ b,a %xcc, .plt+0x20 */
+ write_be32 (dso, rela->r_offset,
+ 0x03000000
+ | ((rela->r_offset - dso->shdr[sec].sh_addr)
+ & 0x3fffff));
+ write_be32 (dso, rela->r_offset + 4,
+ 0x30680000
+ | (((dso->shdr[sec].sh_addr + 32
+ - rela->r_offset - 4) >> 2)
+ & 0x7ffff));
+ write_be32 (dso, rela->r_offset + 8, 0x01000000);
+ write_be32 (dso, rela->r_offset + 12, 0x01000000);
+ write_be32 (dso, rela->r_offset + 16, 0x01000000);
+ write_be32 (dso, rela->r_offset + 20, 0x01000000);
+ write_be32 (dso, rela->r_offset + 24, 0x01000000);
+ write_be32 (dso, rela->r_offset + 28, 0x01000000);
+ }
+ else
+ {
+ GElf_Addr slot = ((rela->r_offset + 0x400
+ - dso->shdr[sec].sh_addr)
+ / 0x1400) * 0x1400
+ + dso->shdr[sec].sh_addr - 0x400;
+ /* slot+12 contains: ldx [%o7 + X], %g1 */
+ GElf_Addr ptr = slot + (read_ube32 (dso, slot + 12) & 0xfff) + 4;
+
+ write_be64 (dso, rela->r_offset,
+ dso->shdr[sec].sh_addr
+ - (slot + ((rela->r_offset - ptr) / 8) * 24 + 4));
+ }
+ }
+ break;
+ case R_SPARC_RELATIVE:
+ case R_SPARC_GLOB_DAT:
+ case R_SPARC_64:
+ case R_SPARC_UA64:
+ case R_SPARC_DISP64:
+ case R_SPARC_TLS_DTPMOD64:
+ case R_SPARC_TLS_DTPOFF64:
+ case R_SPARC_TLS_TPOFF64:
+ write_be64 (dso, rela->r_offset, 0);
+ break;
+ case R_SPARC_32:
+ case R_SPARC_UA32:
+ case R_SPARC_DISP32:
+ write_be32 (dso, rela->r_offset, 0);
+ break;
+ case R_SPARC_8:
+ case R_SPARC_DISP8:
+ write_8 (dso, rela->r_offset, 0);
+ break;
+ case R_SPARC_16:
+ case R_SPARC_UA16:
+ case R_SPARC_DISP16:
+ write_be16 (dso, rela->r_offset, 0);
+ break;
+ case R_SPARC_LO10:
+ write_be32 (dso, rela->r_offset,
+ read_ube32 (dso, rela->r_offset) & ~0x3ff);
+ break;
+ case R_SPARC_LM22:
+ case R_SPARC_HI22:
+ write_be32 (dso, rela->r_offset,
+ read_ube32 (dso, rela->r_offset) & 0xffc00000);
+ break;
+ case R_SPARC_WDISP30:
+ write_be32 (dso, rela->r_offset,
+ read_ube32 (dso, rela->r_offset) & 0xc0000000);
+ break;
+ case R_SPARC_H44:
+ write_be32 (dso, rela->r_offset,
+ read_ube32 (dso, rela->r_offset) & 0xffc00000);
+ break;
+ case R_SPARC_M44:
+ write_be32 (dso, rela->r_offset,
+ read_ube32 (dso, rela->r_offset) & ~0x3ff);
+ break;
+ case R_SPARC_L44:
+ write_be32 (dso, rela->r_offset,
+ read_ube32 (dso, rela->r_offset) & ~0xfff);
+ break;
+ case R_SPARC_HH22:
+ write_be32 (dso, rela->r_offset,
+ read_ube32 (dso, rela->r_offset) & 0xffc00000);
+ break;
+ case R_SPARC_HM10:
+ write_be32 (dso, rela->r_offset,
+ read_ube32 (dso, rela->r_offset) & ~0x3ff);
+ break;
+ case R_SPARC_OLO10:
+ write_be32 (dso, rela->r_offset,
+ read_ube32 (dso, rela->r_offset) & ~0x1fff);
+ break;
+ case R_SPARC_TLS_LE_LOX10:
+ write_be32 (dso, rela->r_offset,
+ read_ube32 (dso, rela->r_offset) & 0xffffe000);
+ break;
+ case R_SPARC_TLS_LE_HIX22:
+ write_be32 (dso, rela->r_offset,
+ read_ube32 (dso, rela->r_offset) & 0xffc00000);
+ break;
+ case R_SPARC_COPY:
+ if (dso->ehdr.e_type == ET_EXEC)
+ /* COPY relocs are handled specially in generic code. */
+ return 0;
+ error (0, 0, "%s: R_SPARC_COPY reloc in shared library?", dso->filename);
+ return 1;
+ default:
+ error (0, 0, "%s: Unknown sparc relocation type %d", dso->filename,
+ (int) GELF_R_TYPE (rela->r_info));
+ return 1;
+ }
+ return 0;
+}
+
+static int
+sparc64_reloc_size (int reloc_type)
+{
+ switch (reloc_type)
+ {
+ case R_SPARC_8:
+ case R_SPARC_DISP8:
+ return 1;
+ case R_SPARC_16:
+ case R_SPARC_DISP16:
+ case R_SPARC_UA16:
+ return 2;
+ case R_SPARC_RELATIVE:
+ case R_SPARC_64:
+ case R_SPARC_UA64:
+ case R_SPARC_GLOB_DAT:
+ return 8;
+ default:
+ break;
+ }
+ return 4;
+}
+
+static int
+sparc64_reloc_class (int reloc_type)
+{
+ switch (reloc_type)
+ {
+ case R_SPARC_COPY: return RTYPE_CLASS_COPY;
+ case R_SPARC_JMP_SLOT: return RTYPE_CLASS_PLT;
+ case R_SPARC_TLS_DTPMOD64:
+ case R_SPARC_TLS_DTPOFF64:
+ case R_SPARC_TLS_TPOFF64:
+ case R_SPARC_TLS_LE_HIX22:
+ case R_SPARC_TLS_LE_LOX10:
+ return RTYPE_CLASS_TLS;
+ default: return RTYPE_CLASS_VALID;
+ }
+}
+
+PL_ARCH(sparc64) = {
+ .name = "SPARC",
+ .class = ELFCLASS64,
+ .machine = EM_SPARCV9,
+ .alternate_machine = { EM_NONE },
+ .R_JMP_SLOT = R_SPARC_JMP_SLOT,
+ .R_COPY = R_SPARC_COPY,
+ .R_RELATIVE = R_SPARC_RELATIVE,
+ .rtype_class_valid = RTYPE_CLASS_VALID,
+ .dynamic_linker = "/lib64/ld-linux.so.2",
+ .adjust_dyn = sparc64_adjust_dyn,
+ .adjust_rel = sparc64_adjust_rel,
+ .adjust_rela = sparc64_adjust_rela,
+ .prelink_rel = sparc64_prelink_rel,
+ .prelink_rela = sparc64_prelink_rela,
+ .prelink_conflict_rel = sparc64_prelink_conflict_rel,
+ .prelink_conflict_rela = sparc64_prelink_conflict_rela,
+ .apply_conflict_rela = sparc64_apply_conflict_rela,
+ .apply_rel = sparc64_apply_rel,
+ .apply_rela = sparc64_apply_rela,
+ .rel_to_rela = sparc64_rel_to_rela,
+ .need_rel_to_rela = sparc64_need_rel_to_rela,
+ .reloc_size = sparc64_reloc_size,
+ .reloc_class = sparc64_reloc_class,
+ .max_reloc_size = 8,
+ .arch_prelink = sparc64_arch_prelink,
+ .undo_prelink_rela = sparc64_undo_prelink_rela,
+ /* Although TASK_UNMAPPED_BASE is 0xfffff80100000000, we leave some
+ area so that mmap of /etc/ld.so.cache and ld.so's malloc
+ does not take some library's VA slot.
+ Also, if this guard area isn't too small, typically
+ even dlopened libraries will get the slots they desire. */
+ .mmap_base = 0xfffff80101000000LL,
+ /* If we need yet more space for shared libraries, we can of course
+ expand, but limiting all DSOs into 4 GB means stack overflows
+ jumping to shared library functions is much harder (there is
+ '\0' byte in the address before the bytes that matter). */
+ .mmap_end = 0xfffff80200000000LL,
+ .max_page_size = 0x100000,
+ .page_size = 0x2000
+};
diff --git a/src/arch-x86_64.c b/src/arch-x86_64.c
new file mode 100644
index 0000000..dae66cd
--- /dev/null
+++ b/src/arch-x86_64.c
@@ -0,0 +1,643 @@
+/* Copyright (C) 2001, 2002, 2003, 2004, 2006, 2009 Red Hat, Inc.
+ Written by Jakub Jelinek <jakub@redhat.com>, 2001.
+ Copyright (C) 2011 Wind River Systems, Inc.
+ x32 support by Mark Hatle <mark.hatle@windriver.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include <config.h>
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <locale.h>
+#include <error.h>
+#include <argp.h>
+#include <stdlib.h>
+
+#include "prelink.h"
+
+/* The x32 ABI: https://sites.google.com/site/x32abi/documents/abi.pdf
+ * documents a "class" value for specific reads and writes. All this
+ * indicates is that we should be using the ELFCLASS to determine if
+ * this should be a 32/64 bit read/write. (See table 4.9)
+ *
+ * We emulate this behavior below...
+ */
+#define read_uleclass(DSO, ADDR) \
+( gelf_getclass(DSO->elf) == ELFCLASS32 ? read_ule32(DSO, ADDR) : read_ule64(DSO, ADDR) )
+
+#define write_leclass(DSO, ADDR, VAL) \
+( gelf_getclass(DSO->elf) == ELFCLASS32 ? write_le32(DSO, ADDR, VAL) : write_le64(DSO, ADDR, VAL) )
+
+#define buf_write_leclass(DSO, BUF, VAL) \
+( gelf_getclass(DSO->elf) == ELFCLASS32 ? buf_write_le32(BUF, VAL) : buf_write_le64(BUF, VAL) )
+
+static int
+x86_64_adjust_dyn (DSO *dso, int n, GElf_Dyn *dyn, GElf_Addr start,
+ GElf_Addr adjust)
+{
+ if (dyn->d_tag == DT_PLTGOT)
+ {
+ int sec = addr_to_sec (dso, dyn->d_un.d_ptr);
+ Elf64_Addr data;
+
+ if (sec == -1)
+ return 0;
+
+ data = read_ule64 (dso, dyn->d_un.d_ptr);
+ /* If .got.plt[0] points to _DYNAMIC, it needs to be adjusted. */
+ if (data == dso->shdr[n].sh_addr && data >= start)
+ write_le64 (dso, dyn->d_un.d_ptr, data + adjust);
+
+ data = read_ule64 (dso, dyn->d_un.d_ptr + 8);
+ /* If .got.plt[1] points to .plt + 0x16, it needs to be adjusted. */
+ if (data && data >= start)
+ {
+ int i;
+
+ for (i = 1; i < dso->ehdr.e_shnum; i++)
+ if (data == dso->shdr[i].sh_addr + 0x16
+ && dso->shdr[i].sh_type == SHT_PROGBITS
+ && strcmp (strptr (dso, dso->ehdr.e_shstrndx,
+ dso->shdr[i].sh_name), ".plt") == 0)
+ {
+ write_le64 (dso, dyn->d_un.d_ptr + 8, data + adjust);
+ break;
+ }
+ }
+ }
+ return 0;
+}
+
+static int
+x86_64_adjust_rel (DSO *dso, GElf_Rel *rel, GElf_Addr start,
+ GElf_Addr adjust)
+{
+ error (0, 0, "%s: X86-64 doesn't support REL relocs", dso->filename);
+ return 1;
+}
+
+static int
+x86_64_adjust_rela (DSO *dso, GElf_Rela *rela, GElf_Addr start,
+ GElf_Addr adjust)
+{
+ Elf64_Addr addr;
+
+ switch (GELF_R_TYPE (rela->r_info))
+ {
+ case R_X86_64_RELATIVE:
+ if (rela->r_addend >= start)
+ {
+ if (read_uleclass (dso, rela->r_offset) == rela->r_addend)
+ write_leclass (dso, rela->r_offset, rela->r_addend + adjust);
+ rela->r_addend += adjust;
+ }
+ break;
+ case R_X86_64_IRELATIVE:
+ if (rela->r_addend >= start)
+ rela->r_addend += adjust;
+ /* FALLTHROUGH */
+ case R_X86_64_JUMP_SLOT:
+ addr = read_uleclass (dso, rela->r_offset);
+ if (addr >= start)
+ write_leclass (dso, rela->r_offset, addr + adjust);
+ break;
+ }
+ return 0;
+}
+
+static int
+x86_64_prelink_rel (struct prelink_info *info, GElf_Rel *rel, GElf_Addr reladdr)
+{
+ error (0, 0, "%s: X86-64 doesn't support REL relocs", info->dso->filename);
+ return 1;
+}
+
+static int
+x86_64_prelink_rela (struct prelink_info *info, GElf_Rela *rela,
+ GElf_Addr relaaddr)
+{
+ DSO *dso;
+ GElf_Addr value;
+
+ dso = info->dso;
+ if (GELF_R_TYPE (rela->r_info) == R_X86_64_NONE
+ || GELF_R_TYPE (rela->r_info) == R_X86_64_IRELATIVE)
+ return 0;
+ else if (GELF_R_TYPE (rela->r_info) == R_X86_64_RELATIVE)
+ {
+ write_leclass (dso, rela->r_offset, rela->r_addend);
+ return 0;
+ }
+ value = info->resolve (info, GELF_R_SYM (rela->r_info),
+ GELF_R_TYPE (rela->r_info));
+ switch (GELF_R_TYPE (rela->r_info))
+ {
+ case R_X86_64_GLOB_DAT:
+ case R_X86_64_JUMP_SLOT:
+ write_leclass (dso, rela->r_offset, value + rela->r_addend);
+ break;
+ case R_X86_64_64:
+ write_le64 (dso, rela->r_offset, value + rela->r_addend);
+ break;
+ case R_X86_64_32:
+ write_le32 (dso, rela->r_offset, value + rela->r_addend);
+ break;
+ case R_X86_64_PC32:
+ write_le32 (dso, rela->r_offset, value + rela->r_addend - rela->r_offset);
+ break;
+ case R_X86_64_DTPOFF64:
+ write_le64 (dso, rela->r_offset, value + rela->r_addend);
+ break;
+ /* DTPMOD64 and TPOFF64 is impossible to predict in shared libraries
+ unless prelink sets the rules. */
+ case R_X86_64_DTPMOD64:
+ if (dso->ehdr.e_type == ET_EXEC)
+ {
+ error (0, 0, "%s: R_X86_64_DTPMOD64 reloc in executable?",
+ dso->filename);
+ return 1;
+ }
+ break;
+ case R_X86_64_TPOFF64:
+ if (dso->ehdr.e_type == ET_EXEC && info->resolvetls)
+ write_le64 (dso, rela->r_offset,
+ value + rela->r_addend - info->resolvetls->offset);
+ break;
+ case R_X86_64_COPY:
+ if (dso->ehdr.e_type == ET_EXEC)
+ /* COPY relocs are handled specially in generic code. */
+ return 0;
+ error (0, 0, "%s: R_X86_64_COPY reloc in shared library?", dso->filename);
+ return 1;
+ default:
+ error (0, 0, "%s: Unknown X86-64 relocation type %d", dso->filename,
+ (int) GELF_R_TYPE (rela->r_info));
+ return 1;
+ }
+ return 0;
+}
+
+static int
+x86_64_apply_conflict_rela (struct prelink_info *info, GElf_Rela *rela,
+ char *buf, GElf_Addr dest_addr)
+{
+ GElf_Rela *ret;
+ switch (GELF_R_TYPE (rela->r_info))
+ {
+ case R_X86_64_GLOB_DAT:
+ case R_X86_64_JUMP_SLOT:
+ buf_write_leclass (info->dso, buf, rela->r_addend);
+ break;
+ case R_X86_64_64:
+ buf_write_le64 (buf, rela->r_addend);
+ break;
+ case R_X86_64_IRELATIVE:
+ if (dest_addr == 0)
+ return 5;
+ ret = prelink_conflict_add_rela (info);
+ if (ret == NULL)
+ return 1;
+ ret->r_offset = dest_addr;
+ ret->r_info = GELF_R_INFO (0, R_X86_64_IRELATIVE);
+ ret->r_addend = rela->r_addend;
+ break;
+ case R_X86_64_32:
+ buf_write_le32 (buf, rela->r_addend);
+ break;
+ default:
+ abort ();
+ }
+ return 0;
+}
+
+static int
+x86_64_apply_rel (struct prelink_info *info, GElf_Rel *rel, char *buf)
+{
+ error (0, 0, "%s: X86-64 doesn't support REL relocs", info->dso->filename);
+ return 1;
+}
+
+static int
+x86_64_apply_rela (struct prelink_info *info, GElf_Rela *rela, char *buf)
+{
+ GElf_Addr value;
+
+ value = info->resolve (info, GELF_R_SYM (rela->r_info),
+ GELF_R_TYPE (rela->r_info));
+ switch (GELF_R_TYPE (rela->r_info))
+ {
+ case R_X86_64_NONE:
+ break;
+ case R_X86_64_GLOB_DAT:
+ case R_X86_64_JUMP_SLOT:
+ buf_write_leclass (info->dso, buf, value + rela->r_addend);
+ break;
+ case R_X86_64_64:
+ buf_write_le64 (buf, value + rela->r_addend);
+ break;
+ case R_X86_64_32:
+ buf_write_le32 (buf, value + rela->r_addend);
+ break;
+ case R_X86_64_PC32:
+ buf_write_le32 (buf, value + rela->r_addend - rela->r_offset);
+ break;
+ case R_X86_64_COPY:
+ abort ();
+ case R_X86_64_RELATIVE:
+ error (0, 0, "%s: R_X86_64_RELATIVE in ET_EXEC object?", info->dso->filename);
+ return 1;
+ default:
+ return 1;
+ }
+ return 0;
+}
+
+static int
+x86_64_prelink_conflict_rel (DSO *dso, struct prelink_info *info, GElf_Rel *rel,
+ GElf_Addr reladdr)
+{
+ error (0, 0, "%s: X86-64 doesn't support REL relocs", dso->filename);
+ return 1;
+}
+
+static int
+x86_64_prelink_conflict_rela (DSO *dso, struct prelink_info *info,
+ GElf_Rela *rela, GElf_Addr relaaddr)
+{
+ GElf_Addr value;
+ struct prelink_conflict *conflict;
+ struct prelink_tls *tls;
+ GElf_Rela *ret;
+
+ if (GELF_R_TYPE (rela->r_info) == R_X86_64_RELATIVE
+ || GELF_R_TYPE (rela->r_info) == R_X86_64_NONE)
+ /* Fast path: nothing to do. */
+ return 0;
+ conflict = prelink_conflict (info, GELF_R_SYM (rela->r_info),
+ GELF_R_TYPE (rela->r_info));
+ if (conflict == NULL)
+ {
+ switch (GELF_R_TYPE (rela->r_info))
+ {
+ /* Even local DTPMOD and TPOFF relocs need conflicts. */
+ case R_X86_64_DTPMOD64:
+ case R_X86_64_TPOFF64:
+ if (info->curtls == NULL || info->dso == dso)
+ return 0;
+ break;
+ /* Similarly IRELATIVE relocations always need conflicts. */
+ case R_X86_64_IRELATIVE:
+ break;
+ default:
+ return 0;
+ }
+ value = 0;
+ }
+ else if (info->dso == dso && !conflict->ifunc)
+ return 0;
+ else
+ {
+ /* DTPOFF wants to see only real conflicts, not lookups
+ with reloc_class RTYPE_CLASS_TLS. */
+ if (GELF_R_TYPE (rela->r_info) == R_X86_64_DTPOFF64
+ && conflict->lookup.tls == conflict->conflict.tls
+ && conflict->lookupval == conflict->conflictval)
+ return 0;
+
+ value = conflict_lookup_value (conflict);
+ }
+ ret = prelink_conflict_add_rela (info);
+ if (ret == NULL)
+ return 1;
+ ret->r_offset = rela->r_offset;
+ ret->r_info = GELF_R_INFO (0, GELF_R_TYPE (rela->r_info));
+ switch (GELF_R_TYPE (rela->r_info))
+ {
+ case R_X86_64_GLOB_DAT:
+ ret->r_info = GELF_R_INFO (0, (gelf_getclass (dso->elf) == ELFCLASS32 ? R_X86_64_32 : R_X86_64_64));
+ /* FALLTHROUGH */
+ case R_X86_64_JUMP_SLOT:
+ case R_X86_64_64:
+ case R_X86_64_IRELATIVE:
+ ret->r_addend = value + rela->r_addend;
+ if (conflict != NULL && conflict->ifunc)
+ ret->r_info = GELF_R_INFO (0, R_X86_64_IRELATIVE);
+ break;
+ case R_X86_64_32:
+ value += rela->r_addend;
+ ret->r_addend = value;
+ break;
+ case R_X86_64_PC32:
+ ret->r_addend = value + rela->r_addend - rela->r_offset;
+ ret->r_info = GELF_R_INFO (0, R_X86_64_32);
+ break;
+ case R_X86_64_COPY:
+ error (0, 0, "R_X86_64_COPY should not be present in shared libraries");
+ return 1;
+ case R_X86_64_DTPMOD64:
+ case R_X86_64_DTPOFF64:
+ case R_X86_64_TPOFF64:
+ if (conflict != NULL
+ && (conflict->reloc_class != RTYPE_CLASS_TLS
+ || conflict->lookup.tls == NULL))
+ {
+ error (0, 0, "%s: TLS reloc not resolving to STT_TLS symbol",
+ dso->filename);
+ return 1;
+ }
+ tls = conflict ? conflict->lookup.tls : info->curtls;
+ ret->r_info = GELF_R_INFO (0, R_X86_64_64);
+ switch (GELF_R_TYPE (rela->r_info))
+ {
+ case R_X86_64_DTPMOD64:
+ ret->r_addend = tls->modid;
+ break;
+ case R_X86_64_DTPOFF64:
+ ret->r_addend = value + rela->r_addend;
+ break;
+ case R_X86_64_TPOFF64:
+ ret->r_addend = value + rela->r_addend - tls->offset;
+ break;
+ }
+ break;
+
+ default:
+ error (0, 0, "%s: Unknown X86-64 relocation type %d", dso->filename,
+ (int) GELF_R_TYPE (rela->r_info));
+ return 1;
+ }
+ return 0;
+}
+
+static int
+x86_64_rel_to_rela (DSO *dso, GElf_Rel *rel, GElf_Rela *rela)
+{
+ error (0, 0, "%s: X86-64 doesn't support REL relocs", dso->filename);
+ return 1;
+}
+
+static int
+x86_64_need_rel_to_rela (DSO *dso, int first, int last)
+{
+ return 0;
+}
+
+static int
+x86_64_arch_prelink (struct prelink_info *info)
+{
+ DSO *dso;
+ int i;
+
+ dso = info->dso;
+ if (dso->info[DT_PLTGOT])
+ {
+ /* Write address of .plt + 0x16 into got[1].
+ .plt + 0x16 is what got[3] contains unless prelinking. */
+ int sec = addr_to_sec (dso, dso->info[DT_PLTGOT]);
+ Elf64_Addr data;
+
+ if (sec == -1)
+ return 1;
+
+ for (i = 1; i < dso->ehdr.e_shnum; i++)
+ if (dso->shdr[i].sh_type == SHT_PROGBITS
+ && ! strcmp (strptr (dso, dso->ehdr.e_shstrndx,
+ dso->shdr[i].sh_name),
+ ".plt"))
+ break;
+
+ assert (i < dso->ehdr.e_shnum);
+ data = dso->shdr[i].sh_addr + 0x16;
+ write_le64 (dso, dso->info[DT_PLTGOT] + 8, data);
+ }
+
+ return 0;
+}
+
+static int
+x86_64_arch_undo_prelink (DSO *dso)
+{
+ int i;
+
+ if (dso->info[DT_PLTGOT])
+ {
+ /* Clear got[1] if it contains address of .plt + 0x16. */
+ int sec = addr_to_sec (dso, dso->info[DT_PLTGOT]);
+ Elf64_Addr data;
+
+ if (sec == -1)
+ return 1;
+
+ for (i = 1; i < dso->ehdr.e_shnum; i++)
+ if (dso->shdr[i].sh_type == SHT_PROGBITS
+ && ! strcmp (strptr (dso, dso->ehdr.e_shstrndx,
+ dso->shdr[i].sh_name),
+ ".plt"))
+ break;
+
+ if (i == dso->ehdr.e_shnum)
+ return 0;
+ data = read_ule64 (dso, dso->info[DT_PLTGOT] + 8);
+ if (data == dso->shdr[i].sh_addr + 0x16)
+ write_le64 (dso, dso->info[DT_PLTGOT] + 8, 0);
+ }
+
+ return 0;
+}
+
+static int
+x86_64_undo_prelink_rela (DSO *dso, GElf_Rela *rela, GElf_Addr relaaddr)
+{
+ int sec;
+ const char *name;
+
+ switch (GELF_R_TYPE (rela->r_info))
+ {
+ case R_X86_64_NONE:
+ case R_X86_64_RELATIVE:
+ case R_X86_64_IRELATIVE:
+ break;
+ case R_X86_64_JUMP_SLOT:
+ sec = addr_to_sec (dso, rela->r_offset);
+ name = strptr (dso, dso->ehdr.e_shstrndx, dso->shdr[sec].sh_name);
+ if (sec == -1 || (strcmp (name, ".got") && strcmp (name, ".got.plt")))
+ {
+ error (0, 0, "%s: R_X86_64_JUMP_SLOT not pointing into .got section",
+ dso->filename);
+ return 1;
+ }
+ else
+ {
+ Elf64_Addr data = read_uleclass (dso, dso->shdr[sec].sh_addr + 8);
+
+ assert (rela->r_offset >= dso->shdr[sec].sh_addr + 24);
+ assert (((rela->r_offset - dso->shdr[sec].sh_addr) & 7) == 0);
+ write_leclass (dso, rela->r_offset,
+ 2 * (rela->r_offset - dso->shdr[sec].sh_addr - 24)
+ + data);
+ }
+ break;
+ case R_X86_64_GLOB_DAT:
+ write_leclass (dso, rela->r_offset, 0);
+ break;
+ case R_X86_64_64:
+ case R_X86_64_DTPMOD64:
+ case R_X86_64_DTPOFF64:
+ case R_X86_64_TPOFF64:
+ write_le64 (dso, rela->r_offset, 0);
+ break;
+ case R_X86_64_32:
+ case R_X86_64_PC32:
+ write_le32 (dso, rela->r_offset, 0);
+ break;
+ case R_X86_64_COPY:
+ if (dso->ehdr.e_type == ET_EXEC)
+ /* COPY relocs are handled specially in generic code. */
+ return 0;
+ error (0, 0, "%s: R_X86_64_COPY reloc in shared library?", dso->filename);
+ return 1;
+ default:
+ error (0, 0, "%s: Unknown X86-64 relocation type %d", dso->filename,
+ (int) GELF_R_TYPE (rela->r_info));
+ return 1;
+ }
+ return 0;
+}
+
+static int
+x86_64_reloc_size (int reloc_type)
+{
+ switch (reloc_type)
+ {
+ case R_X86_64_GLOB_DAT:
+ case R_X86_64_JUMP_SLOT:
+ case R_X86_64_64:
+ case R_X86_64_IRELATIVE:
+ return 8;
+ default:
+ return 4;
+ }
+}
+
+static int
+x86_64_x32_reloc_size (int reloc_type)
+{
+ switch (reloc_type)
+ {
+ case R_X86_64_64:
+ return 8;
+ case R_X86_64_GLOB_DAT:
+ case R_X86_64_JUMP_SLOT:
+ case R_X86_64_IRELATIVE:
+ default:
+ return 4;
+ }
+}
+
+static int
+x86_64_reloc_class (int reloc_type)
+{
+ switch (reloc_type)
+ {
+ case R_X86_64_COPY: return RTYPE_CLASS_COPY;
+ case R_X86_64_JUMP_SLOT: return RTYPE_CLASS_PLT;
+ case R_X86_64_DTPMOD64:
+ case R_X86_64_DTPOFF64:
+ case R_X86_64_TPOFF64:
+ return RTYPE_CLASS_TLS;
+ default: return RTYPE_CLASS_VALID;
+ }
+}
+
+PL_ARCH(x32) = {
+ .name = "x32",
+ .class = ELFCLASS32,
+ .machine = EM_X86_64,
+ .alternate_machine = { EM_NONE },
+ .R_JMP_SLOT = R_X86_64_JUMP_SLOT,
+ .R_COPY = R_X86_64_COPY,
+ .R_RELATIVE = R_X86_64_RELATIVE,
+ .rtype_class_valid = RTYPE_CLASS_VALID,
+ .dynamic_linker = "/libx32/ld-linux-x32.so.2",
+ .adjust_dyn = x86_64_adjust_dyn,
+ .adjust_rel = x86_64_adjust_rel,
+ .adjust_rela = x86_64_adjust_rela,
+ .prelink_rel = x86_64_prelink_rel,
+ .prelink_rela = x86_64_prelink_rela,
+ .prelink_conflict_rel = x86_64_prelink_conflict_rel,
+ .prelink_conflict_rela = x86_64_prelink_conflict_rela,
+ .apply_conflict_rela = x86_64_apply_conflict_rela,
+ .apply_rel = x86_64_apply_rel,
+ .apply_rela = x86_64_apply_rela,
+ .rel_to_rela = x86_64_rel_to_rela,
+ .need_rel_to_rela = x86_64_need_rel_to_rela,
+ .reloc_size = x86_64_x32_reloc_size,
+ .reloc_class = x86_64_reloc_class,
+ .max_reloc_size = 8,
+ .arch_prelink = x86_64_arch_prelink,
+ .arch_undo_prelink = x86_64_arch_undo_prelink,
+ .undo_prelink_rela = x86_64_undo_prelink_rela,
+ /* Although TASK_UNMAPPED_BASE is 0x40000000, we leave some
+ area so that mmap of /etc/ld.so.cache and ld.so's malloc
+ does not take some library's VA slot.
+ Also, if this guard area isn't too small, typically
+ even dlopened libraries will get the slots they desire. */
+ .mmap_base = 0x41000000,
+ .mmap_end = 0x50000000,
+ .max_page_size = 0x200000,
+ .page_size = 0x1000
+};
+
+PL_ARCH(x86_64) = {
+ .name = "x86-64",
+ .class = ELFCLASS64,
+ .machine = EM_X86_64,
+ .alternate_machine = { EM_NONE },
+ .R_JMP_SLOT = R_X86_64_JUMP_SLOT,
+ .R_COPY = R_X86_64_COPY,
+ .R_RELATIVE = R_X86_64_RELATIVE,
+ .rtype_class_valid = RTYPE_CLASS_VALID,
+ .dynamic_linker = "/lib64/ld-linux-x86-64.so.2",
+ .adjust_dyn = x86_64_adjust_dyn,
+ .adjust_rel = x86_64_adjust_rel,
+ .adjust_rela = x86_64_adjust_rela,
+ .prelink_rel = x86_64_prelink_rel,
+ .prelink_rela = x86_64_prelink_rela,
+ .prelink_conflict_rel = x86_64_prelink_conflict_rel,
+ .prelink_conflict_rela = x86_64_prelink_conflict_rela,
+ .apply_conflict_rela = x86_64_apply_conflict_rela,
+ .apply_rel = x86_64_apply_rel,
+ .apply_rela = x86_64_apply_rela,
+ .rel_to_rela = x86_64_rel_to_rela,
+ .need_rel_to_rela = x86_64_need_rel_to_rela,
+ .reloc_size = x86_64_reloc_size,
+ .reloc_class = x86_64_reloc_class,
+ .max_reloc_size = 8,
+ .arch_prelink = x86_64_arch_prelink,
+ .arch_undo_prelink = x86_64_arch_undo_prelink,
+ .undo_prelink_rela = x86_64_undo_prelink_rela,
+ /* Although TASK_UNMAPPED_BASE is 0x2a95555555, we leave some
+ area so that mmap of /etc/ld.so.cache and ld.so's malloc
+ does not take some library's VA slot.
+ Also, if this guard area isn't too small, typically
+ even dlopened libraries will get the slots they desire. */
+ .mmap_base = 0x3000000000LL,
+ .mmap_end = 0x4000000000LL,
+ .max_page_size = 0x200000,
+ .page_size = 0x1000
+};
diff --git a/src/cache.c b/src/cache.c
new file mode 100644
index 0000000..abcec27
--- /dev/null
+++ b/src/cache.c
@@ -0,0 +1,861 @@
+/* Copyright (C) 2001, 2002, 2003, 2004, 2006, 2013 Red Hat, Inc.
+ Written by Jakub Jelinek <jakub@redhat.com>, 2001.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include <config.h>
+#include <assert.h>
+#include <errno.h>
+#include <error.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <sys/mman.h>
+#include "prelinktab.h"
+
+htab_t prelink_devino_htab, prelink_filename_htab;
+
+int prelink_entry_count;
+
+static hashval_t
+devino_hash (const void *p)
+{
+ struct prelink_entry *e = (struct prelink_entry *)p;
+
+ return (e->dev << 2) ^ (e->ino) ^ (e->ino >> 20);
+}
+
+static int
+devino_eq (const void *p, const void *q)
+{
+ struct prelink_entry *e = (struct prelink_entry *)p;
+ struct prelink_entry *f = (struct prelink_entry *)q;
+
+ return e->ino == f->ino && e->dev == f->dev;
+}
+
+static hashval_t
+filename_hash (const void *p)
+{
+ struct prelink_entry *e = (struct prelink_entry *)p;
+ const unsigned char *s = (const unsigned char *)e->filename;
+ hashval_t h = 0;
+ unsigned char c;
+ size_t len = 0;
+
+ while ((c = *s++) != '\0')
+ {
+ h += c + (c << 17);
+ h ^= h >> 2;
+ ++len;
+ }
+ return h + len + (len << 17);
+}
+
+static int
+filename_eq (const void *p, const void *q)
+{
+ struct prelink_entry *e = (struct prelink_entry *)p;
+ struct prelink_entry *f = (struct prelink_entry *)q;
+
+ return strcmp (e->filename, f->filename) == 0;
+}
+
+int
+prelink_init_cache (void)
+{
+ prelink_devino_htab = htab_try_create (100, devino_hash, devino_eq, NULL);
+ prelink_filename_htab = htab_try_create (100, filename_hash, filename_eq,
+ NULL);
+ if (prelink_devino_htab == NULL || prelink_filename_htab == NULL)
+ error (EXIT_FAILURE, ENOMEM, "Could not create hash table");
+ return 0;
+}
+
+struct prelink_entry *
+prelink_find_entry (const char *filename, const struct stat64 *stp,
+ int insert)
+{
+ struct prelink_entry e, *ent = NULL;
+ void **filename_slot, *dummy = NULL;
+ void **devino_slot = NULL;
+ struct stat64 st;
+ char *canon_filename = NULL;
+
+ e.filename = filename;
+ filename_slot = htab_find_slot (prelink_filename_htab, &e,
+ insert ? INSERT : NO_INSERT);
+ if (filename_slot == NULL)
+ {
+ if (insert)
+ goto error_out;
+ filename_slot = &dummy;
+ }
+
+ if (*filename_slot != NULL)
+ return (struct prelink_entry *) *filename_slot;
+
+ if (! stp)
+ {
+ canon_filename = prelink_canonicalize (filename, &st);
+ if (canon_filename == NULL && wrap_stat64 (filename, &st) < 0)
+ {
+ error (0, errno, "Could not stat %s", filename);
+ if (insert)
+ {
+ *filename_slot = &dummy;
+ htab_clear_slot (prelink_filename_htab, filename_slot);
+ }
+ return NULL;
+ }
+ stp = &st;
+ }
+
+ e.dev = stp->st_dev;
+ e.ino = stp->st_ino;
+ devino_slot = htab_find_slot (prelink_devino_htab, &e,
+ insert ? INSERT : NO_INSERT);
+ if (devino_slot == NULL)
+ {
+ if (insert)
+ goto error_out;
+ free (canon_filename);
+ return NULL;
+ }
+
+ if (*devino_slot != NULL)
+ {
+ ent = (struct prelink_entry *) *devino_slot;
+ if (canon_filename == NULL)
+ canon_filename = prelink_canonicalize (filename, NULL);
+ if (canon_filename == NULL)
+ {
+ error (0, 0, "Could not canonicalize filename %s", filename);
+ goto error_out2;
+ }
+
+ if (strcmp (canon_filename, ent->canon_filename) != 0)
+ {
+ struct prelink_link *hardlink;
+
+ hardlink = (struct prelink_link *)
+ malloc (sizeof (struct prelink_link));
+ if (hardlink == NULL)
+ {
+ error (0, ENOMEM, "Could not record hardlink %s to %s",
+ canon_filename, ent->canon_filename);
+ goto error_out2;
+ }
+
+ hardlink->canon_filename = canon_filename;
+ hardlink->next = ent->hardlink;
+ ent->hardlink = hardlink;
+ }
+ else
+ free (canon_filename);
+ return ent;
+ }
+
+ if (! insert)
+ {
+ if (canon_filename != NULL)
+ free (canon_filename);
+ return NULL;
+ }
+
+ ent = (struct prelink_entry *) calloc (sizeof (struct prelink_entry), 1);
+ if (ent == NULL)
+ goto error_out;
+
+ ent->filename = strdup (filename);
+ if (ent->filename == NULL)
+ goto error_out;
+
+ if (canon_filename != NULL)
+ ent->canon_filename = canon_filename;
+ else
+ ent->canon_filename = prelink_canonicalize (filename, NULL);
+ if (ent->canon_filename == NULL)
+ {
+ error (0, 0, "Could not canonicalize filename %s", filename);
+ free ((char *) ent->filename);
+ free (ent);
+ goto error_out2;
+ }
+
+ ent->dev = stp->st_dev;
+ ent->ino = stp->st_ino;
+ ent->ctime = stp->st_ctime;
+ ent->mtime = stp->st_mtime;
+
+ *filename_slot = ent;
+ *devino_slot = ent;
+ ++prelink_entry_count;
+ return ent;
+
+error_out:
+ free (ent);
+ error (0, ENOMEM, "Could not insert %s into hash table", filename);
+error_out2:
+ if (insert)
+ {
+ if (filename_slot != NULL)
+ {
+ assert (*filename_slot == NULL);
+ *filename_slot = &dummy;
+ htab_clear_slot (prelink_filename_htab, filename_slot);
+ }
+ if (devino_slot != NULL && *devino_slot == NULL)
+ {
+ *devino_slot = &dummy;
+ htab_clear_slot (prelink_devino_htab, devino_slot);
+ }
+ }
+ free (canon_filename);
+ return NULL;
+}
+
+static struct prelink_entry *
+prelink_load_entry (const char *filename)
+{
+ struct prelink_entry e, *ent = NULL;
+ void **filename_slot, *dummy = NULL;
+ void **devino_slot = &dummy;
+ struct stat64 st;
+ uint32_t ctime = 0, mtime = 0;
+ char *canon_filename = NULL;
+
+ e.filename = filename;
+ filename_slot = htab_find_slot (prelink_filename_htab, &e, INSERT);
+ if (filename_slot == NULL)
+ goto error_out;
+
+ if (*filename_slot != NULL)
+ return (struct prelink_entry *) *filename_slot;
+
+ canon_filename = prelink_canonicalize (filename, &st);
+ if (canon_filename == NULL)
+ goto error_out2;
+ if (strcmp (canon_filename, filename) != 0)
+ {
+ *filename_slot = &dummy;
+ htab_clear_slot (prelink_filename_htab, filename_slot);
+
+ e.filename = canon_filename;
+ filename_slot = htab_find_slot (prelink_filename_htab, &e, INSERT);
+ if (filename_slot == NULL)
+ goto error_out;
+
+ if (*filename_slot != NULL)
+ {
+ free (canon_filename);
+ return (struct prelink_entry *) *filename_slot;
+ }
+ }
+
+ if (! S_ISREG (st.st_mode))
+ {
+ free (canon_filename);
+ *filename_slot = &dummy;
+ htab_clear_slot (prelink_filename_htab, filename_slot);
+ return NULL;
+ }
+ else
+ {
+ e.dev = st.st_dev;
+ e.ino = st.st_ino;
+ ctime = (uint32_t) st.st_ctime;
+ mtime = (uint32_t) st.st_mtime;
+ devino_slot = htab_find_slot (prelink_devino_htab, &e, INSERT);
+ if (devino_slot == NULL)
+ goto error_out;
+ }
+
+ if (*devino_slot != NULL)
+ {
+ free (canon_filename);
+ *filename_slot = &dummy;
+ htab_clear_slot (prelink_filename_htab, filename_slot);
+ return (struct prelink_entry *) *devino_slot;
+ }
+
+ ent = (struct prelink_entry *) calloc (sizeof (struct prelink_entry), 1);
+ if (ent == NULL)
+ goto error_out;
+
+ ent->filename = strdup (filename);
+ if (ent->filename == NULL)
+ goto error_out;
+
+ ent->canon_filename = canon_filename;
+ ent->dev = e.dev;
+ ent->ino = e.ino;
+ ent->ctime = ctime;
+ ent->mtime = mtime;
+ *filename_slot = ent;
+ *devino_slot = ent;
+ ++prelink_entry_count;
+ return ent;
+
+error_out:
+ free (ent);
+ error (0, ENOMEM, "Could not insert %s into hash table", filename);
+error_out2:
+ if (filename_slot != NULL)
+ {
+ *filename_slot = &dummy;
+ htab_clear_slot (prelink_filename_htab, filename_slot);
+ }
+ if (devino_slot != NULL && devino_slot != &dummy)
+ {
+ *devino_slot = &dummy;
+ htab_clear_slot (prelink_devino_htab, devino_slot);
+ }
+ free (canon_filename);
+ return NULL;
+}
+
+static int
+deps_cmp (const void *A, const void *B)
+{
+ struct prelink_entry *a = * (struct prelink_entry **) A;
+ struct prelink_entry *b = * (struct prelink_entry **) B;
+
+ if (a == NULL)
+ return (b != NULL);
+ if (a != NULL && b == NULL)
+ return -1;
+
+ if (a->type == ET_NONE && b->type != ET_NONE)
+ return 1;
+ if (a->type != ET_NONE && b->type == ET_NONE)
+ return -1;
+
+ /* Libraries with fewest dependencies first. */
+ if (a->ndepends < b->ndepends)
+ return -1;
+ if (a->ndepends > b->ndepends)
+ return 1;
+ return 0;
+}
+
+int
+prelink_load_cache (void)
+{
+ int fd, i, j;
+ struct stat64 st;
+ struct prelink_cache *cache;
+ struct prelink_entry **ents;
+ size_t cache_size;
+ uint32_t string_start, *dep;
+
+ fd = wrap_open (prelink_cache, O_RDONLY);
+ if (fd < 0)
+ return 0; /* The cache does not exist yet. */
+
+ if (fstat64 (fd, &st) < 0
+ || st.st_size == 0)
+ {
+ close (fd);
+ return 0;
+ }
+
+ cache = mmap (0, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
+ if (cache == MAP_FAILED)
+ error (EXIT_FAILURE, errno, "mmap of prelink cache file failed.");
+ cache_size = st.st_size;
+ if (memcmp (cache->magic, PRELINK_CACHE_MAGIC,
+ sizeof (PRELINK_CACHE_MAGIC) - 1))
+ {
+ if (memcmp (cache->magic, PRELINK_CACHE_NAME,
+ sizeof (PRELINK_CACHE_NAME) - 1))
+ error (EXIT_FAILURE, 0, "%s: is not prelink cache file",
+ prelink_cache);
+ munmap (cache, cache_size);
+ return 0;
+ }
+ dep = (uint32_t *) & cache->entry[cache->nlibs];
+ string_start = ((long) dep) - ((long) cache)
+ + cache->ndeps * sizeof (uint32_t);
+ ents = (struct prelink_entry **)
+ alloca (cache->nlibs * sizeof (struct prelink_entry *));
+ memset (ents, 0, cache->nlibs * sizeof (struct prelink_entry *));
+ for (i = 0; i < cache->nlibs; i++)
+ {
+ /* Sanity checks. */
+ if (cache->entry[i].filename < string_start
+ || cache->entry[i].filename >= string_start + cache->len_strings
+ || cache->entry[i].depends >= cache->ndeps)
+ error (EXIT_FAILURE, 0, "%s: bogus prelink cache file",
+ prelink_cache);
+
+ ents[i] = prelink_load_entry (((char *) cache)
+ + cache->entry[i].filename);
+ }
+
+ for (i = 0; i < cache->nlibs; i++)
+ {
+ if (ents[i] == NULL)
+ continue;
+
+ if (ents[i]->type != ET_NONE)
+ continue;
+
+ ents[i]->checksum = cache->entry[i].checksum;
+ ents[i]->base = cache->entry[i].base;
+ ents[i]->end = cache->entry[i].end;
+ ents[i]->type = (ents[i]->base == 0 && ents[i]->end == 0)
+ ? ET_CACHE_EXEC : ET_CACHE_DYN;
+ ents[i]->flags = cache->entry[i].flags;
+
+ if (ents[i]->flags == PCF_UNPRELINKABLE)
+ ents[i]->type = (quick || print_cache) ? ET_UNPRELINKABLE : ET_NONE;
+
+ /* If mtime is equal to ctime, assume the filesystem does not store
+ ctime. */
+ if (quick
+ && ((ents[i]->ctime == ents[i]->mtime
+ && ents[i]->type != ET_UNPRELINKABLE)
+ || ents[i]->ctime != cache->entry[i].ctime
+ || ents[i]->mtime != cache->entry[i].mtime))
+ ents[i]->type = ET_NONE;
+
+ for (j = cache->entry[i].depends; dep[j] != i; ++j)
+ if (dep[j] >= cache->nlibs)
+ error (EXIT_FAILURE, 0, "%s: bogus prelink cache file",
+ prelink_cache);
+ else if (ents[dep[j]] == NULL)
+ ents[i]->type = ET_NONE;
+
+ if (ents[i]->type == ET_NONE)
+ continue;
+
+ ents[i]->ndepends = j - cache->entry[i].depends;
+ if (ents[i]->ndepends)
+ {
+ ents[i]->depends =
+ (struct prelink_entry **)
+ malloc (ents[i]->ndepends * sizeof (struct prelink_entry *));
+ if (ents[i]->depends == NULL)
+ error (EXIT_FAILURE, ENOMEM, "Cannot read cache file %s",
+ prelink_cache);
+
+ for (j = 0; j < ents[i]->ndepends; ++j)
+ ents[i]->depends[j] = ents[dep[cache->entry[i].depends + j]];
+ }
+ }
+
+ if (quick)
+ {
+ qsort (ents, cache->nlibs, sizeof (struct prelink_entry *), deps_cmp);
+ for (i = 0; i < cache->nlibs; ++i)
+ {
+ if (ents[i] == NULL || ents[i]->type == ET_NONE)
+ continue;
+
+ for (j = 0; j < ents[i]->ndepends; ++j)
+ if (ents[i]->depends[j]->type == ET_NONE)
+ {
+ ents[i]->type = ET_NONE;
+ free (ents[i]->depends);
+ ents[i]->depends = NULL;
+ ents[i]->ndepends = 0;
+ break;
+ }
+ }
+ }
+
+ munmap (cache, cache_size);
+ close (fd);
+ return 0;
+}
+
+static int
+prelink_print_cache_size (void **p, void *info)
+{
+ struct prelink_entry *e = * (struct prelink_entry **) p;
+ int *psize = (int *) info;
+
+ if ((e->base & 0xffffffff) != e->base
+ || (e->end & 0xffffffff) != e->end)
+ {
+ *psize = 16;
+ return 0;
+ }
+
+ return 1;
+}
+
+static int
+prelink_print_cache_object (void **p, void *info)
+{
+ struct prelink_entry *e = * (struct prelink_entry **) p;
+ int *psize = (int *) info, i;
+
+ if (e->type == ET_UNPRELINKABLE)
+ {
+ printf ("%s (not prelinkable)%s\n", e->filename, e->ndepends ? ":" : "");
+ for (i = 0; i < e->ndepends; i++)
+ if (e->depends[i]->type == ET_UNPRELINKABLE)
+ printf (" %s (not prelinkable)\n", e->depends[i]->filename);
+ else
+ printf (" %s [0x%08x]\n", e->depends[i]->filename,
+ e->depends[i]->checksum);
+ return 1;
+ }
+
+ if (e->type == ET_CACHE_DYN)
+ printf ("%s [0x%08x] 0x%0*llx-0x%0*llx%s\n", e->filename, e->checksum,
+ *psize, (long long) e->base, *psize, (long long) e->end,
+ e->ndepends ? ":" : "");
+ else
+ printf ("%s%s\n", e->filename, e->ndepends ? ":" : "");
+ for (i = 0; i < e->ndepends; i++)
+ printf (" %s [0x%08x]\n", e->depends[i]->filename,
+ e->depends[i]->checksum);
+ return 1;
+}
+
+int
+prelink_print_cache (void)
+{
+ int size = 8;
+
+ printf ("%d objects found in prelink cache `%s'\n", prelink_entry_count,
+ prelink_cache);
+
+ htab_traverse (prelink_filename_htab, prelink_print_cache_size, &size);
+ htab_traverse (prelink_filename_htab, prelink_print_cache_object, &size);
+ return 0;
+}
+
+struct collect_ents
+{
+ struct prelink_entry **ents;
+ size_t len_strings;
+ int nents;
+ int ndeps;
+};
+
+static int
+prelink_save_cache_check (struct prelink_entry *ent)
+{
+ int i;
+
+ for (i = 0; i < ent->ndepends; ++i)
+ switch (ent->depends[i]->type)
+ {
+ case ET_DYN:
+ if (ent->depends[i]->done < 2
+ || (quick && (ent->depends[i]->flags & PCF_PRELINKED)))
+ return 1;
+ break;
+ case ET_CACHE_DYN:
+ if (prelink_save_cache_check (ent->depends[i]))
+ return 1;
+ break;
+ case ET_UNPRELINKABLE:
+ if (ent->type != ET_UNPRELINKABLE)
+ return 1;
+ if (prelink_save_cache_check (ent->depends[i]))
+ return 1;
+ break;
+ default:
+ return 1;
+ }
+
+ return 0;
+}
+
+static int
+find_ents (void **p, void *info)
+{
+ struct collect_ents *l = (struct collect_ents *) info;
+ struct prelink_entry *e = * (struct prelink_entry **) p;
+
+ if (((e->type == ET_DYN || e->type == ET_EXEC) && e->done == 2)
+ || ((e->type == ET_CACHE_DYN || e->type == ET_CACHE_EXEC
+ || e->type == ET_UNPRELINKABLE)
+ && ! prelink_save_cache_check (e)))
+ {
+ l->ents[l->nents++] = e;
+ l->ndeps += e->ndepends + 1;
+ l->len_strings += strlen (e->canon_filename) + 1;
+ }
+ return 1;
+}
+
+int
+prelink_save_cache (int do_warn)
+{
+ struct prelink_cache cache;
+ struct collect_ents l;
+ struct prelink_cache_entry *data;
+ uint32_t *deps, ndeps = 0, i, j, k;
+ char *strings;
+ int fd, len;
+ struct prelink_entry *ents_array[prelink_entry_count];
+
+ memset (&cache, 0, sizeof (cache));
+ memcpy ((char *) & cache, PRELINK_CACHE_MAGIC,
+ sizeof (PRELINK_CACHE_MAGIC) - 1);
+ l.ents = ents_array;
+ l.nents = 0;
+ l.ndeps = 0;
+ l.len_strings = 0;
+ htab_traverse (prelink_filename_htab, find_ents, &l);
+ cache.nlibs = l.nents;
+ cache.ndeps = l.ndeps;
+ cache.len_strings = l.len_strings;
+
+ len = cache.nlibs * sizeof (struct prelink_cache_entry)
+ + cache.ndeps * sizeof (uint32_t) + cache.len_strings;
+ char data_buf[len];
+ data = (struct prelink_cache_entry *) data_buf;
+ deps = (uint32_t *) & data[cache.nlibs];
+ strings = (char *) & deps[cache.ndeps];
+
+ for (i = 0; i < l.nents; ++i)
+ {
+ data[i].filename = (strings - (char *) data) + sizeof (cache);
+ strings = stpcpy (strings, l.ents[i]->canon_filename) + 1;
+ data[i].checksum = l.ents[i]->checksum;
+ data[i].flags = l.ents[i]->flags & ~PCF_PRELINKED;
+ data[i].ctime = l.ents[i]->ctime;
+ data[i].mtime = l.ents[i]->mtime;
+ if (l.ents[i]->type == ET_EXEC || l.ents[i]->type == ET_CACHE_EXEC)
+ {
+ data[i].base = 0;
+ data[i].end = 0;
+ }
+ else if (l.ents[i]->type == ET_UNPRELINKABLE)
+ {
+ data[i].base = 0;
+ data[i].end = 0;
+ data[i].checksum = 0;
+ data[i].flags = PCF_UNPRELINKABLE;
+ }
+ else
+ {
+ data[i].base = l.ents[i]->base;
+ data[i].end = l.ents[i]->end;
+ }
+ }
+
+ for (i = 0; i < cache.nlibs; i++)
+ {
+ data[i].depends = ndeps;
+ for (j = 0; j < l.ents[i]->ndepends; j++)
+ {
+ for (k = 0; k < cache.nlibs; k++)
+ if (l.ents[k] == l.ents[i]->depends[j])
+ break;
+ if (k == cache.nlibs)
+ abort ();
+ deps[ndeps++] = k;
+ }
+ deps[ndeps++] = i;
+ }
+
+ size_t prelink_cache_len = strlen (prelink_cache);
+ char prelink_cache_tmp [prelink_cache_len + sizeof (".XXXXXX")];
+ memcpy (mempcpy (prelink_cache_tmp, prelink_cache, prelink_cache_len),
+ ".XXXXXX", sizeof (".XXXXXX"));
+ fd = wrap_mkstemp (prelink_cache_tmp);
+ if (fd < 0)
+ {
+ error (0, errno, "Could not write prelink cache");
+ return 1;
+ }
+
+ if (write (fd, &cache, sizeof (cache)) != sizeof (cache)
+ || write (fd, data, len) != len
+ || fchmod (fd, 0644)
+ || fsync (fd)
+ || close (fd)
+ || wrap_rename (prelink_cache_tmp, prelink_cache))
+ {
+ error (0, errno, "Could not write prelink cache");
+ wrap_unlink (prelink_cache_tmp);
+ return 1;
+ }
+ return 0;
+}
+
+#ifndef NDEBUG
+static void
+prelink_entry_dumpfn (FILE *f, const void *ptr)
+{
+ struct prelink_entry *e = (struct prelink_entry *) ptr;
+ struct prelink_link *l;
+ int i;
+
+ fprintf (f, "%s|%s|%s|%x|%x|%llx|%llx|%llx|%llx|%llx|%d|%d|%d|%d|%d|%d|%d|",
+ e->filename,
+ strcmp (e->canon_filename, e->filename) ? e->canon_filename : "",
+ e->soname && strcmp (e->soname, e->filename) ? e->soname : "",
+ e->timestamp, e->checksum,
+ (long long) e->base, (long long) e->end, (long long) e->pltgot,
+ (long long) e->dev, (long long) e->ino,
+ e->type, e->done, e->ndepends, e->refs, e->flags,
+ e->prev ? e->prev->u.tmp : -1, e->next ? e->next->u.tmp : -1);
+ for (i = 0; i < e->ndepends; ++i)
+ fprintf (f, "%d-", e->depends [i]->u.tmp);
+ fputc ('|', f);
+ for (l = e->hardlink; l; l = l->next)
+ fprintf (f, "%s|", l->canon_filename);
+ fputs ("\n", f);
+}
+
+void
+prelink_entry_dump (htab_t htab, const char *filename)
+{
+ size_t i;
+
+ for (i = 0; i < htab->size; ++i)
+ if (htab->entries [i] && htab->entries [i] != (void *) 1)
+ ((struct prelink_entry *) htab->entries [i])->u.tmp = i;
+ htab_dump (htab, filename, prelink_entry_dumpfn);
+}
+
+static char *restore_line;
+static size_t restore_size;
+
+static void *
+prelink_entry_restorefn (FILE *f)
+{
+ struct prelink_entry *e;
+ struct prelink_link **plink;
+ char *p, *q, *s;
+ long long ll[5];
+ int ii[5];
+ int i;
+
+ if (getline (&restore_line, &restore_size, f) < 0)
+ abort ();
+ e = (struct prelink_entry *) calloc (1, sizeof (struct prelink_entry));
+ if (e == NULL)
+ abort ();
+ p = restore_line;
+ q = strchr (p, '|');
+ s = malloc (q - p + 1);
+ memcpy (s, p, q - p);
+ s [q - p] = '\0';
+ e->filename = s;
+ ++q;
+ p = q;
+ if (*p == '|')
+ e->canon_filename = strdup (e->filename);
+ else
+ {
+ q = strchr (p, '|');
+ s = malloc (q - p + 1);
+ memcpy (s, p, q - p);
+ s [q - p] = '\0';
+ e->canon_filename = s;
+ }
+ ++q;
+ p = q;
+ if (*p == '|')
+ e->soname = strdup (e->filename);
+ else
+ {
+ q = strchr (p, '|');
+ s = malloc (q - p + 1);
+ memcpy (s, p, q - p);
+ s [q - p] = '\0';
+ e->soname = s;
+ }
+ p = q + 1;
+ if (sscanf (p, "%x|%x|%llx|%llx|%llx|%llx|%llx|%d|%d|%d|%d|%d|%d|%d|%n",
+ ii, ii + 1, ll, ll + 1, ll + 2, ll + 3, ll + 4,
+ &e->type, &e->done, &e->ndepends, &e->refs, &e->flags,
+ ii + 2, ii + 3, ii + 4) < 14)
+ abort ();
+ e->timestamp = ii[0];
+ e->checksum = ii[1];
+ e->base = ll[0];
+ e->end = ll[1];
+ e->pltgot = ll[2];
+ e->dev = ll[3];
+ e->ino = ll[4];
+ e->prev = (void *) (long) ii[2];
+ e->next = (void *) (long) ii[3];
+ e->depends = (struct prelink_entry **)
+ malloc (e->ndepends * sizeof (struct prelink_entry *));
+ p += ii[4];
+ for (i = 0; i < e->ndepends; ++i)
+ {
+ e->depends [i] = (void *) strtol (p, &q, 0);
+ if (p == q || *q != '-')
+ abort ();
+ p = q + 1;
+ }
+ if (*p++ != '|')
+ abort ();
+ plink = &e->hardlink;
+ while (*p != '\n')
+ {
+ struct prelink_link *link = (struct prelink_link *)
+ malloc (sizeof (struct prelink_link));
+ q = strchr (p, '|');
+ *plink = link;
+ plink = &link->next;
+ s = malloc (q - p + 1);
+ memcpy (s, p, q - p);
+ s [q - p] = '\0';
+ e->soname = s;
+ link->canon_filename = s;
+ p = q + 1;
+ }
+ *plink = NULL;
+ ++prelink_entry_count;
+ return e;
+}
+
+void
+prelink_entry_restore (htab_t htab, const char *filename)
+{
+ size_t i, j;
+ struct prelink_entry *e;
+
+ prelink_entry_count = 0;
+ htab_restore (htab, filename, prelink_entry_restorefn);
+ free (restore_line);
+ for (i = 0; i < htab->size; ++i)
+ if (htab->entries [i] && htab->entries [i] != (void *) 1)
+ {
+ e = (struct prelink_entry *) htab->entries [i];
+ if (e->prev == (void *) -1)
+ e->prev = NULL;
+ else
+ e->prev = (struct prelink_entry *)
+ htab->entries [(long) e->prev];
+ if (e->next == (void *) -1)
+ e->next = NULL;
+ else
+ e->next = (struct prelink_entry *)
+ htab->entries [(long) e->next];
+ for (j = 0; j < e->ndepends; ++j)
+ {
+ e->depends [j] = (struct prelink_entry *)
+ htab->entries [(long) e->depends [j]];
+ }
+ }
+}
+#endif
diff --git a/src/canonicalize.c b/src/canonicalize.c
new file mode 100644
index 0000000..717e991
--- /dev/null
+++ b/src/canonicalize.c
@@ -0,0 +1,374 @@
+/* Return the canonical absolute name of a given file.
+ Copyright (C) 1996-2002, 2004, 2005, 2006 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <limits.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <stddef.h>
+
+#include "hashtab.h"
+#include "prelink.h"
+
+htab_t prelink_dirname_htab;
+
+struct dirname_entry
+{
+ const char *dirname;
+ size_t dirname_len;
+ const char *canon_dirname;
+ size_t canon_dirname_len;
+};
+
+static hashval_t
+dirname_hash (const void *p)
+{
+ struct dirname_entry *e = (struct dirname_entry *)p;
+ const unsigned char *s = (const unsigned char *)e->dirname;
+ hashval_t h = 0;
+ unsigned char c;
+ size_t len = e->dirname_len;
+
+ while (len--)
+ {
+ c = *s++;
+ h += c + (c << 17);
+ h ^= h >> 2;
+ }
+ return h + e->dirname_len + (e->dirname_len << 17);
+}
+
+static int
+dirname_eq (const void *p, const void *q)
+{
+ struct dirname_entry *e = (struct dirname_entry *)p;
+ struct dirname_entry *f = (struct dirname_entry *)q;
+
+ return (e->dirname_len == f->dirname_len
+ && memcmp (e->dirname, f->dirname, e->dirname_len) == 0);
+}
+
+/* Return the canonical absolute name of file NAME. A canonical name
+ does not contain any `.', `..' components nor any repeated path
+ separators ('/') or symlinks. All path components must exist.
+ The result is malloc'd. */
+
+char *
+canon_filename (const char *name, int nested, struct stat64 *stp,
+ const char *chroot, int allow_last_link,
+ int allow_missing)
+{
+ char *rpath, *dest, *extra_buf = NULL, *rpath_root;
+ const char *start, *end, *rpath_limit;
+ long int path_max;
+ int num_links = 0;
+ int stp_initialized = 0;
+ int chroot_len;
+
+ if (name == NULL)
+ {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ if (name[0] == '\0')
+ {
+ errno = ENOENT;
+ return NULL;
+ }
+ chroot_len = strlen (chroot);
+ if (chroot_len > 0 && chroot[chroot_len - 1] == '/')
+ chroot_len--;
+
+#ifdef PATH_MAX
+ path_max = PATH_MAX;
+#else
+ path_max = pathconf (name, _PC_PATH_MAX);
+ if (path_max <= 0)
+ path_max = 1024;
+#endif
+
+ rpath = malloc (path_max + chroot_len + 1);
+ if (rpath == NULL)
+ return NULL;
+ rpath_limit = rpath + path_max;
+
+ if (name[0] != '/')
+ {
+ if (!getcwd (rpath, path_max))
+ {
+ rpath[0] = '\0';
+ goto error;
+ }
+ if (chroot_len > 0)
+ {
+ struct stat64 st;
+ char *cwd = canon_filename (rpath, 1, &st, chroot, 0, 0);
+ if (cwd == NULL)
+ goto error;
+ if (memcmp (cwd, chroot, chroot_len) != 0)
+ goto error;
+ strcpy (rpath, cwd);
+ free (cwd);
+ rpath_root = rpath + chroot_len;
+ }
+ else
+ rpath_root = rpath;
+
+ dest = strchr (rpath_root, '\0');
+ }
+ else
+ {
+ if (chroot_len > 0)
+ rpath_root = (char *) mempcpy (rpath, chroot, chroot_len);
+ else
+ rpath_root = rpath;
+
+ rpath_root[0] = '/';
+ dest = rpath_root + 1;
+
+ if (!nested)
+ {
+ if (prelink_dirname_htab == NULL)
+ prelink_dirname_htab = htab_try_create (100, dirname_hash,
+ dirname_eq, NULL);
+ if (prelink_dirname_htab == NULL)
+ nested = 1;
+ }
+ if (!nested)
+ {
+ struct dirname_entry e;
+ void **dirname_slot;
+
+ end = strrchr (name, '/');
+
+ e.dirname = name;
+ e.dirname_len = end - name;
+ dirname_slot = htab_find_slot (prelink_dirname_htab, &e, INSERT);
+ if (*dirname_slot == NULL)
+ {
+ struct dirname_entry *ep = malloc (sizeof (struct dirname_entry)
+ + e.dirname_len + 1);
+ if (ep != NULL)
+ {
+ char *dirname = (char *) (ep + 1);
+ struct stat64 st;
+
+ ep->dirname = (const char *) dirname;
+ ep->dirname_len = e.dirname_len;
+ memcpy (dirname, name, ep->dirname_len);
+ dirname[ep->dirname_len] = '\0';
+ ep->canon_dirname = canon_filename (ep->dirname, 1, &st,
+ chroot, 0, 0);
+ if (ep->canon_dirname == NULL || !S_ISDIR (st.st_mode))
+ free (ep);
+ else
+ {
+ ep->canon_dirname_len = strlen (ep->canon_dirname);
+ *dirname_slot = ep;
+ }
+ }
+ }
+
+ if (*dirname_slot != NULL)
+ {
+ struct dirname_entry *ep = *dirname_slot;
+
+ if (rpath + ep->canon_dirname_len + 1 >= rpath_limit)
+ {
+ size_t new_size, root_size;
+ char *new_rpath;
+
+ new_size = rpath_limit - rpath;
+ root_size = rpath_root - rpath;
+ if (ep->canon_dirname_len + 1 > path_max)
+ new_size += ep->canon_dirname_len + 1;
+ else
+ new_size += path_max;
+ new_rpath = (char *) realloc (rpath, new_size);
+ if (new_rpath == NULL)
+ goto error;
+ rpath = new_rpath;
+ rpath_limit = rpath + new_size;
+ rpath_root = rpath + root_size;
+ }
+ dest = mempcpy (rpath, ep->canon_dirname, ep->canon_dirname_len);
+ *dest = '\0';
+ name = end + 1;
+ }
+ }
+ }
+
+ for (start = end = name; *start; start = end)
+ {
+ int n;
+
+ /* Skip sequence of multiple path-separators. */
+ while (*start == '/')
+ ++start;
+
+ /* Find end of path component. */
+ for (end = start; *end && *end != '/'; ++end)
+ /* Nothing. */;
+
+ if (end - start == 0)
+ break;
+ else if (end - start == 1 && start[0] == '.')
+ /* nothing */;
+ else if (end - start == 2 && start[0] == '.' && start[1] == '.')
+ {
+ /* Back up to previous component, ignore if at root already. */
+ if (dest > rpath_root + 1)
+ while ((--dest)[-1] != '/');
+ stp_initialized = 0;
+ }
+ else
+ {
+ size_t new_size;
+
+ if (dest[-1] != '/')
+ *dest++ = '/';
+
+ if (dest + (end - start) >= rpath_limit)
+ {
+ ptrdiff_t dest_offset = dest - rpath;
+ size_t root_size = rpath_root - rpath;
+ char *new_rpath;
+
+ new_size = rpath_limit - rpath;
+ if (end - start + 1 > path_max)
+ new_size += end - start + 1;
+ else
+ new_size += path_max;
+ new_rpath = (char *) realloc (rpath, new_size);
+ if (new_rpath == NULL)
+ goto error;
+ rpath = new_rpath;
+ rpath_limit = rpath + new_size;
+ rpath_root = rpath + root_size;
+
+ dest = rpath + dest_offset;
+ }
+
+ dest = mempcpy (dest, start, end - start);
+ *dest = '\0';
+
+ if (allow_last_link && *end == '\0')
+ break;
+
+ if (lstat64 (rpath, stp) < 0)
+ {
+ if (allow_missing && *end == '\0')
+ break;
+ goto error;
+ }
+
+ stp_initialized = 1;
+
+ if (S_ISLNK (stp->st_mode))
+ {
+ char *buf = alloca (path_max);
+ size_t len;
+
+ if (++num_links > MAXSYMLINKS)
+ {
+ errno = ELOOP;
+ goto error;
+ }
+
+ n = readlink (rpath, buf, path_max);
+ if (n < 0)
+ {
+ if (allow_missing && *end == '\0')
+ break;
+ goto error;
+ }
+ buf[n] = '\0';
+
+ if (!extra_buf)
+ extra_buf = alloca (path_max);
+
+ len = strlen (end);
+ if ((long int) (n + len) >= path_max)
+ {
+ errno = ENAMETOOLONG;
+ goto error;
+ }
+
+ /* Careful here, end may be a pointer into extra_buf... */
+ memmove (&extra_buf[n], end, len + 1);
+ name = end = memcpy (extra_buf, buf, n);
+
+ if (buf[0] == '/')
+ dest = rpath_root + 1; /* It's an absolute symlink */
+ else
+ /* Back up to previous component, ignore if at root already: */
+ if (dest > rpath_root + 1)
+ while ((--dest)[-1] != '/');
+ }
+ else if (!S_ISDIR (stp->st_mode) && *end != '\0')
+ {
+ errno = ENOTDIR;
+ goto error;
+ }
+ }
+ }
+ if (dest > rpath + 1 && dest[-1] == '/')
+ --dest;
+ *dest = '\0';
+
+ if (!stp_initialized && !allow_missing && !allow_last_link
+ && lstat64 (rpath, stp) < 0)
+ goto error;
+
+ if (dest + 1 - rpath <= (rpath_limit - rpath) / 2)
+ {
+ char *new_rpath = realloc (rpath, dest + 1 - rpath);
+
+ if (new_rpath != NULL)
+ return new_rpath;
+ }
+ return rpath;
+
+error:
+ free (rpath);
+ return NULL;
+}
+
+char *unsysroot_file_name (const char *name);
+
+char *
+prelink_canonicalize (const char *name, struct stat64 *stp)
+{
+ struct stat64 st;
+ char *canon, *final;
+
+ canon = canon_filename (name, 0, stp ? stp : &st,
+ sysroot ? sysroot : "", 0, 0);
+ if (canon == NULL)
+ return NULL;
+ final = unsysroot_file_name (canon);
+ if (final != canon)
+ free (canon);
+ return final;
+}
diff --git a/src/checksum.c b/src/checksum.c
new file mode 100644
index 0000000..20a23a0
--- /dev/null
+++ b/src/checksum.c
@@ -0,0 +1,89 @@
+/* Copyright (C) 2001, 2002, 2003 Red Hat, Inc.
+ Written by Jakub Jelinek <jakub@redhat.com>, 2001.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include <config.h>
+#include <assert.h>
+#include <endian.h>
+#include <errno.h>
+#include <error.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include "prelink.h"
+
+int
+prelink_set_checksum (DSO *dso)
+{
+ extern uint32_t crc32 (uint32_t crc, unsigned char *buf, size_t len);
+ uint32_t crc;
+ int i, cvt;
+
+ if (set_dynamic (dso, DT_CHECKSUM, 0, 1))
+ return 1;
+
+ if (dso->info_DT_GNU_PRELINKED
+ && set_dynamic (dso, DT_GNU_PRELINKED, 0, 1))
+ return 1;
+
+ /* Ensure any pending .mdebug/.dynsym/.dynstr etc. modifications
+ write_dso would do happen before checksumming. */
+ if (prepare_write_dso (dso))
+ return 1;
+
+ cvt = ! ((__BYTE_ORDER == __LITTLE_ENDIAN
+ && dso->ehdr.e_ident[EI_DATA] == ELFDATA2LSB)
+ || (__BYTE_ORDER == __BIG_ENDIAN
+ && dso->ehdr.e_ident[EI_DATA] == ELFDATA2MSB));
+ crc = 0;
+ for (i = 1; i < dso->ehdr.e_shnum; ++i)
+ {
+ if (! (dso->shdr[i].sh_flags & (SHF_ALLOC | SHF_WRITE | SHF_EXECINSTR)))
+ continue;
+ if (dso->shdr[i].sh_type != SHT_NOBITS && dso->shdr[i].sh_size)
+ {
+ Elf_Scn *scn = dso->scn[i];
+ Elf_Data *d = NULL;
+
+ /* Cannot use elf_rawdata here, since the image is not written
+ yet. */
+ while ((d = elf_getdata (scn, d)) != NULL)
+ {
+ if (cvt && d->d_type != ELF_T_BYTE)
+ {
+ gelf_xlatetof (dso->elf, d, d,
+ dso->ehdr.e_ident[EI_DATA]);
+ crc = crc32 (crc, d->d_buf, d->d_size);
+ gelf_xlatetom (dso->elf, d, d,
+ dso->ehdr.e_ident[EI_DATA]);
+ }
+ else
+ crc = crc32 (crc, d->d_buf, d->d_size);
+ }
+ }
+ }
+
+ if (set_dynamic (dso, DT_CHECKSUM, crc, 1))
+ abort ();
+ if (dso->info_DT_GNU_PRELINKED
+ && set_dynamic (dso, DT_GNU_PRELINKED, dso->info_DT_GNU_PRELINKED, 1))
+ abort ();
+ dso->info_DT_CHECKSUM = crc;
+
+ return 0;
+}
diff --git a/src/conflict.c b/src/conflict.c
new file mode 100644
index 0000000..9ae2ddb
--- /dev/null
+++ b/src/conflict.c
@@ -0,0 +1,832 @@
+/* Copyright (C) 2001, 2002, 2003, 2004, 2007, 2009 Red Hat, Inc.
+ Copyright (C) 2008 CodeSourcery.
+ Written by Jakub Jelinek <jakub@redhat.com>, 2001.
+ Updated by Maciej W. Rozycki <macro@codesourcery.com>, 2008.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include <config.h>
+#include <assert.h>
+#include <errno.h>
+#include <error.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include "prelink.h"
+#include "reloc.h"
+#include "reloc-info.h"
+
+struct prelink_conflict *
+prelink_conflict (struct prelink_info *info, GElf_Word r_sym,
+ int reloc_type)
+{
+ GElf_Word symoff = info->symtab_start + r_sym * info->symtab_entsize;
+ struct prelink_conflict *conflict;
+ int reloc_class = info->dso->arch->reloc_class (reloc_type);
+ size_t idx = 0;
+
+ if (info->curconflicts->hash != &info->curconflicts->first)
+ idx = symoff % 251;
+ for (conflict = info->curconflicts->hash[idx]; conflict;
+ conflict = conflict->next)
+ if (conflict->symoff == symoff && conflict->reloc_class == reloc_class)
+ {
+ conflict->used = 1;
+ return conflict;
+ }
+
+ return NULL;
+}
+
+GElf_Rela *
+prelink_conflict_add_rela (struct prelink_info *info)
+{
+ GElf_Rela *ret;
+
+ if (info->conflict_rela_alloced == info->conflict_rela_size)
+ {
+ info->conflict_rela_alloced += 10;
+ info->conflict_rela = realloc (info->conflict_rela,
+ info->conflict_rela_alloced
+ * sizeof (GElf_Rela));
+ if (info->conflict_rela == NULL)
+ {
+ error (0, ENOMEM, "Could not build .gnu.conflict section memory image");
+ return NULL;
+ }
+ }
+ ret = info->conflict_rela + info->conflict_rela_size++;
+ ret->r_offset = 0;
+ ret->r_info = 0;
+ ret->r_addend = 0;
+ return ret;
+}
+
+static int
+prelink_conflict_rel (DSO *dso, int n, struct prelink_info *info)
+{
+ Elf_Data *data = NULL;
+ Elf_Scn *scn = dso->scn[n];
+ GElf_Rel rel;
+ int sec, ndx, maxndx;
+
+ while ((data = elf_getdata (scn, data)) != NULL)
+ {
+ GElf_Addr addr = dso->shdr[n].sh_addr + data->d_off;
+
+ maxndx = data->d_size / dso->shdr[n].sh_entsize;
+ for (ndx = 0; ndx < maxndx;
+ ++ndx, addr += dso->shdr[n].sh_entsize)
+ {
+ gelfx_getrel (dso->elf, data, ndx, &rel);
+ sec = addr_to_sec (dso, rel.r_offset);
+ if (sec == -1)
+ continue;
+
+ if (dso->arch->prelink_conflict_rel (dso, info, &rel, addr))
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int
+prelink_conflict_rela (DSO *dso, int n, struct prelink_info *info)
+{
+ Elf_Data *data = NULL;
+ Elf_Scn *scn = dso->scn[n];
+ GElf_Rela rela;
+ int sec, ndx, maxndx;
+
+ while ((data = elf_getdata (scn, data)) != NULL)
+ {
+ GElf_Addr addr = dso->shdr[n].sh_addr + data->d_off;
+
+ maxndx = data->d_size / dso->shdr[n].sh_entsize;
+ for (ndx = 0; ndx < maxndx;
+ ++ndx, addr += dso->shdr[n].sh_entsize)
+ {
+ gelfx_getrela (dso->elf, data, ndx, &rela);
+ sec = addr_to_sec (dso, rela.r_offset);
+ if (sec == -1)
+ continue;
+
+ if (dso->arch->prelink_conflict_rela (dso, info, &rela, addr))
+ return 1;
+ }
+ }
+ return 0;
+}
+
+struct copy_relocs
+{
+ GElf_Rela *rela;
+ int alloced;
+ int count;
+};
+
+static int
+prelink_add_copy_rel (DSO *dso, int n, GElf_Rel *rel, struct copy_relocs *cr)
+{
+ Elf_Data *data = NULL;
+ int symsec = dso->shdr[n].sh_link;
+ Elf_Scn *scn = dso->scn[symsec];
+ GElf_Sym sym;
+ size_t entsize = dso->shdr[symsec].sh_entsize;
+ off_t off = reloc_r_sym (dso, rel->r_info) * entsize;
+
+ while ((data = elf_getdata (scn, data)) != NULL)
+ {
+ if (data->d_off <= off &&
+ data->d_off + data->d_size >= off + entsize)
+ {
+ gelfx_getsym (dso->elf, data, (off - data->d_off) / entsize, &sym);
+ if (sym.st_size == 0)
+ {
+ error (0, 0, "%s: Copy reloc against symbol with zero size",
+ dso->filename);
+ return 1;
+ }
+
+ if (cr->alloced == cr->count)
+ {
+ cr->alloced += 10;
+ cr->rela = realloc (cr->rela, cr->alloced * sizeof (GElf_Rela));
+ if (cr->rela == NULL)
+ {
+ error (0, ENOMEM, "%s: Could not build list of COPY relocs",
+ dso->filename);
+ return 1;
+ }
+ }
+ cr->rela[cr->count].r_offset = rel->r_offset;
+ cr->rela[cr->count].r_info = rel->r_info;
+ cr->rela[cr->count].r_addend = sym.st_size;
+ ++cr->count;
+ return 0;
+ }
+ }
+
+ error (0, 0, "%s: Copy reloc against unknown symbol", dso->filename);
+ return 1;
+}
+
+static int
+prelink_find_copy_rel (DSO *dso, int n, struct copy_relocs *cr)
+{
+ Elf_Data *data = NULL;
+ Elf_Scn *scn = dso->scn[n];
+ GElf_Rel rel;
+ int sec, ndx, maxndx;
+
+ while ((data = elf_getdata (scn, data)) != NULL)
+ {
+ maxndx = data->d_size / dso->shdr[n].sh_entsize;
+ for (ndx = 0; ndx < maxndx; ++ndx)
+ {
+ gelfx_getrel (dso->elf, data, ndx, &rel);
+ sec = addr_to_sec (dso, rel.r_offset);
+ if (sec == -1)
+ continue;
+
+ if (reloc_r_type (dso, rel.r_info) == dso->arch->R_COPY
+ && prelink_add_copy_rel (dso, n, &rel, cr))
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int
+prelink_find_copy_rela (DSO *dso, int n, struct copy_relocs *cr)
+{
+ Elf_Data *data = NULL;
+ Elf_Scn *scn = dso->scn[n];
+ union {
+ GElf_Rel rel;
+ GElf_Rela rela;
+ } u;
+ int sec, ndx, maxndx;
+
+ while ((data = elf_getdata (scn, data)) != NULL)
+ {
+ maxndx = data->d_size / dso->shdr[n].sh_entsize;
+ for (ndx = 0; ndx < maxndx; ++ndx)
+ {
+ gelfx_getrela (dso->elf, data, ndx, &u.rela);
+ sec = addr_to_sec (dso, u.rela.r_offset);
+ if (sec == -1)
+ continue;
+
+ if (reloc_r_type (dso, u.rela.r_info) == dso->arch->R_COPY)
+ {
+ if (u.rela.r_addend != 0)
+ {
+ error (0, 0, "%s: COPY reloc with non-zero addend?",
+ dso->filename);
+ return 1;
+ }
+ if (prelink_add_copy_rel (dso, n, &u.rel, cr))
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+static int
+rela_cmp (const void *A, const void *B)
+{
+ GElf_Rela *a = (GElf_Rela *)A;
+ GElf_Rela *b = (GElf_Rela *)B;
+
+ if (a->r_offset < b->r_offset)
+ return -1;
+ if (a->r_offset > b->r_offset)
+ return 1;
+ return 0;
+}
+
+static DSO *conflict_rela_cmp_dso;
+
+static int
+conflict_rela_cmp (const void *A, const void *B)
+{
+ DSO *dso = conflict_rela_cmp_dso;
+ GElf_Rela *a = (GElf_Rela *)A;
+ GElf_Rela *b = (GElf_Rela *)B;
+
+ if (reloc_r_sym (dso, a->r_info) < reloc_r_sym (dso, b->r_info))
+ return -1;
+ if (reloc_r_sym (dso, a->r_info) > reloc_r_sym (dso, b->r_info))
+ return 1;
+ if (a->r_offset < b->r_offset)
+ return -1;
+ if (a->r_offset > b->r_offset)
+ return 1;
+ return 0;
+}
+
+int
+get_relocated_mem (struct prelink_info *info, DSO *dso, GElf_Addr addr,
+ char *buf, GElf_Word size, GElf_Addr dest_addr)
+{
+ int sec = addr_to_sec (dso, addr), j;
+ Elf_Scn *scn;
+ Elf_Data *data;
+ off_t off;
+
+ if (sec == -1)
+ return 1;
+
+ memset (buf, 0, size);
+ if (dso->shdr[sec].sh_type != SHT_NOBITS)
+ {
+ scn = dso->scn[sec];
+ data = NULL;
+ off = addr - dso->shdr[sec].sh_addr;
+ while ((data = elf_rawdata (scn, data)) != NULL)
+ {
+ if (data->d_off < off + size
+ && data->d_off + data->d_size > off)
+ {
+ off_t off2 = off - data->d_off;
+ size_t len = size;
+
+ if (off2 < 0)
+ {
+ len += off2;
+ off2 = 0;
+ }
+ if (off2 + len > data->d_size)
+ len = data->d_size - off2;
+ assert (off2 + len <= data->d_size);
+ assert (len <= size);
+ memcpy (buf + off2 - off, data->d_buf + off2, len);
+ }
+ }
+ }
+
+ if (info->dso != dso)
+ {
+ /* This is tricky. We need to apply any conflicts
+ against memory area which we've copied to the COPY
+ reloc offset. */
+ for (j = 0; j < info->conflict_rela_size; ++j)
+ {
+ int reloc_type, reloc_size, ret;
+ off_t off;
+
+ if (info->conflict_rela[j].r_offset >= addr + size)
+ continue;
+ if (info->conflict_rela[j].r_offset + dso->arch->max_reloc_size
+ <= addr)
+ continue;
+
+ reloc_type = reloc_r_type (dso, info->conflict_rela[j].r_info);
+ reloc_size = dso->arch->reloc_size (reloc_type);
+ if (info->conflict_rela[j].r_offset + reloc_size <= addr)
+ continue;
+
+ off = info->conflict_rela[j].r_offset - addr;
+
+ /* Check if whole relocation fits into the area.
+ Punt if not. */
+ if (off < 0 || size - off < reloc_size)
+ return 2;
+ /* Note that apply_conflict_rela shouldn't rely on R_SYM
+ field of conflict to be 0. */
+ ret
+ = dso->arch->apply_conflict_rela (info, info->conflict_rela + j,
+ buf + off,
+ dest_addr ? dest_addr + off : 0);
+ if (ret)
+ return ret;
+ }
+ }
+ else
+ {
+ int i, ndx, maxndx;
+ int reloc_type, reloc_size;
+ union { GElf_Rel rel; GElf_Rela rela; } u;
+ off_t off;
+
+ if (addr + size > info->dynbss_base
+ && addr < info->dynbss_base + info->dynbss_size)
+ {
+ if (addr < info->dynbss_base
+ || addr + size > info->dynbss_base + info->dynbss_size)
+ return 4;
+
+ memcpy (buf, info->dynbss + (addr - info->dynbss_base), size);
+ return 0;
+ }
+
+ if (addr + size > info->sdynbss_base
+ && addr < info->sdynbss_base + info->sdynbss_size)
+ {
+ if (addr < info->sdynbss_base
+ || addr + size > info->sdynbss_base + info->sdynbss_size)
+ return 4;
+
+ memcpy (buf, info->sdynbss + (addr - info->sdynbss_base), size);
+ return 0;
+ }
+
+ for (i = 1; i < dso->ehdr.e_shnum; ++i)
+ {
+
+ if (! (dso->shdr[i].sh_flags & SHF_ALLOC))
+ continue;
+ if (! strcmp (strptr (dso, dso->ehdr.e_shstrndx,
+ dso->shdr[i].sh_name),
+ ".gnu.conflict"))
+ continue;
+ switch (dso->shdr[i].sh_type)
+ {
+ case SHT_REL:
+ case SHT_RELA:
+ break;
+ default:
+ continue;
+ }
+ scn = dso->scn[i];
+ data = NULL;
+ while ((data = elf_getdata (scn, data)) != NULL)
+ {
+ maxndx = data->d_size / dso->shdr[i].sh_entsize;
+ for (ndx = 0; ndx < maxndx; ++ndx)
+ {
+ if (dso->shdr[i].sh_type == SHT_REL)
+ gelfx_getrel (dso->elf, data, ndx, &u.rel);
+ else
+ gelfx_getrela (dso->elf, data, ndx, &u.rela);
+
+ if (u.rel.r_offset >= addr + size)
+ continue;
+ if (u.rel.r_offset + dso->arch->max_reloc_size <= addr)
+ continue;
+
+ reloc_type = reloc_r_type (dso, u.rel.r_info);
+ reloc_size = dso->arch->reloc_size (reloc_type);
+ if (u.rel.r_offset + reloc_size <= addr)
+ continue;
+
+ if (reloc_type == dso->arch->R_COPY)
+ return 3;
+
+ off = u.rel.r_offset - addr;
+
+ /* Check if whole relocation fits into the area.
+ Punt if not. */
+ if (off < 0 || size - off < reloc_size)
+ return 2;
+
+ if (dso->shdr[i].sh_type == SHT_REL)
+ dso->arch->apply_rel (info, &u.rel, buf + off);
+ else
+ dso->arch->apply_rela (info, &u.rela, buf + off);
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+int
+prelink_build_conflicts (struct prelink_info *info)
+{
+ int i, ndeps = info->ent->ndepends + 1;
+ struct prelink_entry *ent;
+ int ret = 0;
+ DSO *dso;
+ struct copy_relocs cr;
+
+ info->dsos = alloca (sizeof (struct DSO *) * ndeps);
+ memset (info->dsos, 0, sizeof (struct DSO *) * ndeps);
+ memset (&cr, 0, sizeof (cr));
+ info->dsos[0] = info->dso;
+ for (i = 1; i < ndeps; ++i)
+ {
+ ent = info->ent->depends[i - 1];
+ if ((dso = open_dso (ent->filename)) == NULL)
+ goto error_out;
+ info->dsos[i] = dso;
+ /* Now check that the DSO matches what we recorded about it. */
+ if (ent->timestamp != dso->info_DT_GNU_PRELINKED
+ || ent->checksum != dso->info_DT_CHECKSUM
+ || ent->base != dso->base)
+ {
+ error (0, 0, "%s: Library %s has changed since it has been prelinked",
+ info->dso->filename, ent->filename);
+ goto error_out;
+ }
+ }
+
+ for (i = 0; i < ndeps; ++i)
+ {
+ int j, sec, first_conflict, maxidx;
+ struct prelink_conflict *conflict;
+
+ dso = info->dsos[i];
+ ent = i ? info->ent->depends[i - 1] : info->ent;
+
+ /* Verify .gnu.liblist sections of all dependent libraries. */
+ if (i && ent->ndepends > 0)
+ {
+ const char *name;
+ int nliblist;
+ Elf32_Lib *liblist;
+ Elf_Scn *scn;
+ Elf_Data *data;
+
+ for (j = 1; j < dso->ehdr.e_shnum; ++j)
+ if (dso->shdr[j].sh_type == SHT_GNU_LIBLIST
+ && (name = strptr (dso, dso->ehdr.e_shstrndx,
+ dso->shdr[j].sh_name))
+ && ! strcmp (name, ".gnu.liblist")
+ && (dso->shdr[j].sh_size % sizeof (Elf32_Lib)) == 0)
+ break;
+
+ if (j == dso->ehdr.e_shnum)
+ {
+ error (0, 0, "%s: Library %s has dependencies, but doesn't contain .gnu.liblist section",
+ info->dso->filename, ent->filename);
+ goto error_out;
+ }
+
+ nliblist = dso->shdr[j].sh_size / sizeof (Elf32_Lib);
+ scn = dso->scn[j];
+ data = elf_getdata (scn, NULL);
+ if (data == NULL || elf_getdata (scn, data)
+ || data->d_buf == NULL || data->d_off
+ || data->d_size != dso->shdr[j].sh_size)
+ {
+ error (0, 0, "%s: Could not read .gnu.liblist section from %s",
+ info->dso->filename, ent->filename);
+ goto error_out;
+ }
+
+ if (nliblist != ent->ndepends)
+ {
+ error (0, 0, "%s: Library %s has different number of libs in .gnu.liblist than expected",
+ info->dso->filename, ent->filename);
+ goto error_out;
+ }
+ liblist = (Elf32_Lib *) data->d_buf;
+ for (j = 0; j < nliblist; ++j)
+ if (liblist[j].l_time_stamp != ent->depends[j]->timestamp
+ || liblist[j].l_checksum != ent->depends[j]->checksum)
+ {
+ error (0, 0, "%s: .gnu.liblist in library %s is inconsistent with recorded dependencies",
+ info->dso->filename, ent->filename);
+ goto error_out;
+ }
+
+ /* Extra check, maybe not needed. */
+ for (j = 0; j < nliblist; ++j)
+ {
+ int k;
+ for (k = 0; k < info->ent->ndepends; ++k)
+ if (liblist[j].l_time_stamp == info->ent->depends[k]->timestamp
+ && liblist[j].l_checksum == info->ent->depends[k]->checksum)
+ break;
+
+ if (k == info->ent->ndepends)
+ abort ();
+ }
+ }
+
+ info->curconflicts = &info->conflicts[i];
+ info->curtls = info->tls[i].modid ? info->tls + i : NULL;
+ first_conflict = info->conflict_rela_size;
+ sec = addr_to_sec (dso, dso->info[DT_SYMTAB]);
+ /* DT_SYMTAB should be found and should point to
+ start of .dynsym section. */
+ if (sec == -1 || dso->info[DT_SYMTAB] != dso->shdr[sec].sh_addr)
+ {
+ error (0, 0, "Bad symtab");
+ goto error_out;
+ }
+ info->symtab_start = dso->shdr[sec].sh_addr - dso->base;
+ info->symtab_end = info->symtab_start + dso->shdr[sec].sh_size;
+ for (j = 0; j < dso->ehdr.e_shnum; ++j)
+ {
+ if (! (dso->shdr[j].sh_flags & SHF_ALLOC))
+ continue;
+ switch (dso->shdr[j].sh_type)
+ {
+ case SHT_REL:
+ if (i == 0
+ && strcmp (strptr (dso, dso->ehdr.e_shstrndx,
+ dso->shdr[j].sh_name),
+ ".gnu.conflict") == 0)
+ break;
+ if (prelink_conflict_rel (dso, j, info))
+ goto error_out;
+ break;
+ case SHT_RELA:
+ if (i == 0
+ && strcmp (strptr (dso, dso->ehdr.e_shstrndx,
+ dso->shdr[j].sh_name),
+ ".gnu.conflict") == 0)
+ break;
+ if (prelink_conflict_rela (dso, j, info))
+ goto error_out;
+ break;
+ }
+ }
+
+ if (dso->arch->arch_prelink_conflict
+ && dso->arch->arch_prelink_conflict (dso, info))
+ goto error_out;
+
+ maxidx = 1;
+ if (info->curconflicts->hash != &info->curconflicts->first)
+ maxidx = 251;
+ for (j = 0; j < maxidx; j++)
+ for (conflict = info->curconflicts->hash[j]; conflict;
+ conflict = conflict->next)
+ if (! conflict->used && (i || conflict->ifunc))
+ {
+ error (0, 0, "%s: Conflict %08llx (%s) not found in any relocation",
+ dso->filename, (unsigned long long) conflict->symoff, conflict->symname);
+ ret = 1;
+ }
+
+ /* Record library's position in search scope into R_SYM field. */
+ for (j = first_conflict; j < info->conflict_rela_size; ++j)
+ info->conflict_rela[j].r_info
+ = reloc_r_info (dso, i,
+ reloc_r_type (dso, info->conflict_rela[j].r_info));
+
+ if (dynamic_info_is_set (dso, DT_TEXTREL)
+ && info->conflict_rela_size > first_conflict)
+ {
+ /* We allow prelinking against non-PIC libraries, as long as
+ no conflict is against read-only segment. */
+ int k;
+
+ for (j = first_conflict; j < info->conflict_rela_size; ++j)
+ for (k = 0; k < dso->ehdr.e_phnum; ++k)
+ if (dso->phdr[k].p_type == PT_LOAD
+ && (dso->phdr[k].p_flags & PF_W) == 0
+ && dso->phdr[k].p_vaddr
+ <= info->conflict_rela[j].r_offset
+ && dso->phdr[k].p_vaddr + dso->phdr[k].p_memsz
+ > info->conflict_rela[j].r_offset)
+ {
+ error (0, 0, "%s: Cannot prelink against non-PIC shared library %s",
+ info->dso->filename, dso->filename);
+ goto error_out;
+ }
+ }
+ }
+
+ dso = info->dso;
+ for (i = 0; i < dso->ehdr.e_shnum; ++i)
+ {
+ if (! (dso->shdr[i].sh_flags & SHF_ALLOC))
+ continue;
+ switch (dso->shdr[i].sh_type)
+ {
+ case SHT_REL:
+ if (prelink_find_copy_rel (dso, i, &cr))
+ goto error_out;
+ break;
+ case SHT_RELA:
+ if (prelink_find_copy_rela (dso, i, &cr))
+ goto error_out;
+ break;
+ }
+ }
+
+ if (cr.count)
+ {
+ int bss1, bss2, firstbss2 = 0;
+ const char *name;
+
+ qsort (cr.rela, cr.count, sizeof (GElf_Rela), rela_cmp);
+ bss1 = addr_to_sec (dso, cr.rela[0].r_offset);
+ bss2 = addr_to_sec (dso, cr.rela[cr.count - 1].r_offset);
+ if (bss1 != bss2)
+ {
+ for (i = 1; i < cr.count; ++i)
+ if (cr.rela[i].r_offset
+ >= dso->shdr[bss1].sh_addr + dso->shdr[bss1].sh_size)
+ break;
+ if (cr.rela[i].r_offset < dso->shdr[bss2].sh_addr)
+ {
+ error (0, 0, "%s: Copy relocs against 3 or more sections",
+ dso->filename);
+ goto error_out;
+ }
+ firstbss2 = i;
+ info->sdynbss_size = cr.rela[i - 1].r_offset - cr.rela[0].r_offset;
+ info->sdynbss_size += cr.rela[i - 1].r_addend;
+ info->sdynbss = calloc (info->sdynbss_size, 1);
+ info->sdynbss_base = cr.rela[0].r_offset;
+ if (info->sdynbss == NULL)
+ {
+ error (0, ENOMEM, "%s: Cannot build .sdynbss", dso->filename);
+ goto error_out;
+ }
+
+ for (i = 0; i < dso->ehdr.e_phnum; ++i)
+ if (dso->phdr[i].p_type == PT_LOAD
+ && dso->shdr[bss1].sh_addr >= dso->phdr[i].p_vaddr
+ && dso->shdr[bss1].sh_addr
+ < dso->phdr[i].p_vaddr + dso->phdr[i].p_memsz)
+ break;
+ if (i == dso->ehdr.e_phnum
+ || dso->shdr[bss2].sh_addr + dso->shdr[bss2].sh_size
+ > dso->phdr[i].p_vaddr + dso->phdr[i].p_memsz)
+ {
+ error (0, 0, "%s: Copy relocs against more than one segment",
+ dso->filename);
+ goto error_out;
+ }
+ }
+
+ info->dynbss_size = cr.rela[cr.count - 1].r_offset
+ - cr.rela[firstbss2].r_offset;
+ info->dynbss_size += cr.rela[cr.count - 1].r_addend;
+ info->dynbss = calloc (info->dynbss_size, 1);
+ info->dynbss_base = cr.rela[firstbss2].r_offset;
+ if (info->dynbss == NULL)
+ {
+ error (0, ENOMEM, "%s: Cannot build .dynbss", dso->filename);
+ goto error_out;
+ }
+
+ /* emacs apparently has .rel.bss relocations against .data section,
+ crap. */
+ if (dso->shdr[bss1].sh_type != SHT_NOBITS
+ && strcmp (name = strptr (dso, dso->ehdr.e_shstrndx,
+ dso->shdr[bss1].sh_name),
+ ".dynbss") != 0
+ && strcmp (name, ".sdynbss") != 0)
+ {
+ error (0, 0, "%s: COPY relocations don't point into .bss or .sbss section",
+ dso->filename);
+ goto error_out;
+ }
+ if (bss1 != bss2
+ && dso->shdr[bss2].sh_type != SHT_NOBITS
+ && strcmp (name = strptr (dso, dso->ehdr.e_shstrndx,
+ dso->shdr[bss2].sh_name),
+ ".dynbss") != 0
+ && strcmp (name, ".sdynbss") != 0)
+ {
+ error (0, 0, "%s: COPY relocations don't point into .bss or .sbss section",
+ dso->filename);
+ goto error_out;
+ }
+
+ for (i = 0; i < cr.count; ++i)
+ {
+ struct prelink_symbol *s;
+ DSO *ndso = NULL;
+ int j, reloc_class;
+
+ reloc_class
+ = dso->arch->reloc_class (reloc_r_type (dso, cr.rela[i].r_info));
+
+ assert (reloc_class != RTYPE_CLASS_TLS);
+
+ for (s = & info->symbols[reloc_r_sym (dso, cr.rela[i].r_info)]; s;
+ s = s->next)
+ if (s->reloc_class == reloc_class)
+ break;
+
+ if (s == NULL || s->u.ent == NULL)
+ {
+ error (0, 0, "%s: Could not find symbol copy reloc is against",
+ dso->filename);
+ goto error_out;
+ }
+
+ for (j = 1; j < ndeps; ++j)
+ if (info->ent->depends[j - 1] == s->u.ent)
+ {
+ ndso = info->dsos[j];
+ break;
+ }
+
+ assert (j < ndeps);
+ if (i < firstbss2)
+ j = get_relocated_mem (info, ndso, s->u.ent->base + s->value,
+ info->sdynbss + cr.rela[i].r_offset
+ - info->sdynbss_base, cr.rela[i].r_addend,
+ cr.rela[i].r_offset);
+ else
+ j = get_relocated_mem (info, ndso, s->u.ent->base + s->value,
+ info->dynbss + cr.rela[i].r_offset
+ - info->dynbss_base, cr.rela[i].r_addend,
+ cr.rela[i].r_offset);
+
+ switch (j)
+ {
+ case 1:
+ error (0, 0, "%s: Could not find variable copy reloc is against",
+ dso->filename);
+ goto error_out;
+ case 2:
+ error (0, 0, "%s: Conflict partly overlaps with %08llx-%08llx area",
+ dso->filename,
+ (long long) cr.rela[i].r_offset,
+ (long long) (cr.rela[i].r_offset + cr.rela[i].r_addend));
+ goto error_out;
+ }
+ }
+ }
+
+ if (info->conflict_rela_size)
+ {
+ conflict_rela_cmp_dso = dso;
+ qsort (info->conflict_rela, info->conflict_rela_size, sizeof (GElf_Rela),
+ conflict_rela_cmp);
+
+ /* Now make sure all conflict RELA's are against absolute 0 symbol. */
+ for (i = 0; i < info->conflict_rela_size; ++i)
+ info->conflict_rela[i].r_info
+ = reloc_r_info (dso, 0,
+ reloc_r_type (dso, info->conflict_rela[i].r_info));
+
+ if (enable_cxx_optimizations && remove_redundant_cxx_conflicts (info))
+ goto error_out;
+ }
+
+ for (i = 1; i < ndeps; ++i)
+ if (info->dsos[i])
+ close_dso (info->dsos[i]);
+
+ info->dsos = NULL;
+ free (cr.rela);
+ return ret;
+
+error_out:
+ free (cr.rela);
+ free (info->dynbss);
+ free (info->sdynbss);
+ info->dynbss = NULL;
+ info->sdynbss = NULL;
+ for (i = 1; i < ndeps; ++i)
+ if (info->dsos[i])
+ close_dso (info->dsos[i]);
+ return 1;
+}
diff --git a/src/crc32.c b/src/crc32.c
new file mode 100644
index 0000000..f36abb5
--- /dev/null
+++ b/src/crc32.c
@@ -0,0 +1,87 @@
+/* Copyright (C) 2001 Red Hat, Inc.
+ Written by Jakub Jelinek <jakub@redhat.com>, 2001.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include <config.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+/* Table computed with Mark Adler's makecrc.c utility. */
+static const uint32_t crc32_table[256] =
+{
+ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419,
+ 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4,
+ 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07,
+ 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
+ 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856,
+ 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
+ 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
+ 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
+ 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,
+ 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a,
+ 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599,
+ 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+ 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190,
+ 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
+ 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e,
+ 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
+ 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed,
+ 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
+ 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3,
+ 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
+ 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,
+ 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5,
+ 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010,
+ 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17,
+ 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6,
+ 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,
+ 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
+ 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344,
+ 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
+ 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a,
+ 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
+ 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1,
+ 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c,
+ 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,
+ 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+ 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe,
+ 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31,
+ 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c,
+ 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
+ 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b,
+ 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
+ 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1,
+ 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
+ 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,
+ 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7,
+ 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66,
+ 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
+ 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8,
+ 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b,
+ 0x2d02ef8d
+};
+
+uint32_t crc32 (uint32_t crc, unsigned char *buf, size_t len)
+{
+ unsigned char *end;
+
+ crc = ~crc;
+ for (end = buf + len; buf < end; ++buf)
+ crc = crc32_table[(crc ^ *buf) & 0xff] ^ (crc >> 8);
+ return ~crc;
+}
diff --git a/src/cxx.c b/src/cxx.c
new file mode 100644
index 0000000..4391ebe
--- /dev/null
+++ b/src/cxx.c
@@ -0,0 +1,643 @@
+/* Copyright (C) 2001, 2002, 2003, 2007, 2009 Red Hat, Inc.
+ Written by Jakub Jelinek <jakub@redhat.com>, 2001.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include <config.h>
+#include <alloca.h>
+#include <assert.h>
+#include <errno.h>
+#include <error.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include "prelink.h"
+#include "reloc-info.h"
+
+static struct
+ {
+ const char *prefix;
+ unsigned char prefix_len, st_info, check_pltref;
+ }
+specials[] =
+ {
+ /* G++ 3.0 ABI. */
+ /* Virtual table. */
+ { "_ZTV", 4, GELF_ST_INFO (STB_WEAK, STT_OBJECT), 1 },
+ /* Typeinfo. */
+ { "_ZTI", 4, GELF_ST_INFO (STB_WEAK, STT_OBJECT), 0 },
+ /* G++ 2.96-RH ABI. */
+ /* Virtual table. */
+ { "__vt_", 5, GELF_ST_INFO (STB_WEAK, STT_OBJECT), 0 },
+ { NULL, 0, 0, 0 }
+ };
+
+struct find_cxx_sym_valsize
+{
+ GElf_Addr start;
+ GElf_Addr end;
+ unsigned int idx;
+ unsigned char mark;
+};
+
+struct find_cxx_sym_cache
+{
+ Elf_Data *symtab, *strtab;
+ int symsec, strsec, count;
+ struct find_cxx_sym_valsize vals[];
+};
+
+struct find_cxx_sym
+{
+ DSO *dso;
+ int n;
+ struct find_cxx_sym_cache *cache;
+ struct prelink_entry *ent;
+ Elf_Data *symtab, *strtab;
+ int symsec, strsec;
+ int lastndx;
+ GElf_Sym sym;
+};
+
+static int
+cachecmp (const void *a, const void *b)
+{
+ GElf_Addr va = ((const struct find_cxx_sym_valsize *) a)->start;
+ GElf_Addr vb = ((const struct find_cxx_sym_valsize *) b)->start;
+
+ if (va < vb)
+ return -1;
+ if (va > vb)
+ return 1;
+
+ va = ((const struct find_cxx_sym_valsize *) a)->end;
+ vb = ((const struct find_cxx_sym_valsize *) b)->end;
+
+ if (va < vb)
+ return -1;
+
+ return va > vb;
+}
+
+static struct find_cxx_sym_cache *
+create_cache (DSO *dso, int plt)
+{
+ Elf_Data *symtab, *strtab;
+ Elf_Scn *scn;
+ int symsec, strsec, ndx, dndx, maxndx;
+ struct find_cxx_sym_cache *cache;
+ GElf_Addr top;
+
+ symsec = addr_to_sec (dso, dso->info[DT_SYMTAB]);
+ if (symsec == -1)
+ return (struct find_cxx_sym_cache *) -1UL;
+ scn = dso->scn[symsec];
+ symtab = elf_getdata (scn, NULL);
+ assert (elf_getdata (scn, symtab) == NULL);
+ strsec = addr_to_sec (dso, dso->info[DT_STRTAB]);
+ if (strsec == -1)
+ return (struct find_cxx_sym_cache *) -1UL;
+ scn = dso->scn[strsec];
+ strtab = elf_getdata (scn, NULL);
+ assert (elf_getdata (scn, strtab) == NULL);
+ maxndx = symtab->d_size / dso->shdr[symsec].sh_entsize;
+
+ cache = malloc (sizeof (*cache) + sizeof (cache->vals[0]) * maxndx);
+ if (cache == NULL)
+ {
+ error (0, ENOMEM, "%s: Could load symbol table", dso->filename);
+ return NULL;
+ }
+
+ cache->symsec = symsec;
+ cache->strsec = strsec;
+ cache->symtab = symtab;
+ cache->strtab = strtab;
+ for (ndx = 0, dndx = 0; ndx < maxndx; ++ndx)
+ {
+ GElf_Sym sym;
+ const char *name;
+ int k;
+
+ gelfx_getsym (dso->elf, symtab, ndx, &sym);
+ if (plt)
+ {
+ if (sym.st_shndx != SHN_UNDEF || sym.st_value == 0)
+ continue;
+ }
+ else if (sym.st_shndx == SHN_UNDEF)
+ continue;
+ cache->vals[dndx].start = sym.st_value;
+ cache->vals[dndx].end = sym.st_value + sym.st_size;
+ cache->vals[dndx].idx = ndx;
+ cache->vals[dndx].mark = 0;
+ name = (const char *) strtab->d_buf + sym.st_name;
+ if (!plt && ELF32_ST_VISIBILITY (sym.st_other) == STV_DEFAULT)
+ for (k = 0; specials[k].prefix; ++k)
+ if (sym.st_info == specials[k].st_info
+ && strncmp (name, specials[k].prefix,
+ specials[k].prefix_len) == 0)
+ {
+ cache->vals[dndx].mark = 1;
+ break;
+ }
+ ++dndx;
+ }
+
+ maxndx = dndx;
+ qsort (cache->vals, maxndx, sizeof (cache->vals[0]), cachecmp);
+
+ if (!plt)
+ {
+ for (top = 0, ndx = 0; ndx < maxndx; ++ndx)
+ {
+ if (cache->vals[ndx].start < top
+ || (ndx < maxndx - 1
+ && cache->vals[ndx].end > cache->vals[ndx + 1].start))
+ cache->vals[ndx].mark = 0;
+ if (cache->vals[ndx].end > top)
+ top = cache->vals[ndx].end;
+ }
+
+ for (ndx = dndx = 0; ndx < maxndx; ++ndx)
+ if (cache->vals[ndx].mark)
+ cache->vals[dndx++] = cache->vals[ndx];
+ }
+ cache->count = dndx;
+ return cache;
+}
+
+static int
+find_cxx_sym (struct prelink_info *info, GElf_Addr addr,
+ struct find_cxx_sym *fcs, int reloc_size,
+ struct find_cxx_sym_cache **cache)
+{
+ int n, ndeps = info->ent->ndepends + 1;
+ unsigned int hi, lo, mid;
+ DSO *dso = NULL;
+ struct find_cxx_sym_cache *c;
+
+ if (fcs->dso == NULL
+ || addr < fcs->dso->base
+ || addr >= fcs->dso->end)
+ {
+ for (n = 1; n < ndeps; ++n)
+ {
+ dso = info->dsos[n];
+ if (addr >= dso->base
+ && addr < dso->end)
+ break;
+ }
+
+ if (n == ndeps
+ && addr >= info->dso->base
+ && addr < info->dso->end)
+ {
+ n = 0;
+ dso = info->dso;
+ }
+
+ assert (n < ndeps);
+
+ if (cache[n] == NULL)
+ {
+ cache[n] = create_cache (dso, 0);
+ if (cache[n] == NULL)
+ return -2;
+ }
+ if (cache[n] == (struct find_cxx_sym_cache *) -1UL)
+ return -1;
+
+ fcs->n = n;
+ fcs->ent = n ? info->ent->depends[n - 1] : info->ent;
+ fcs->dso = dso;
+ fcs->cache = cache[n];
+ fcs->symsec = fcs->cache->symsec;
+ fcs->symtab = fcs->cache->symtab;
+ fcs->strsec = fcs->cache->strsec;
+ fcs->strtab = fcs->cache->strtab;
+ fcs->lastndx = -1;
+ }
+ else
+ dso = fcs->dso;
+
+ c = fcs->cache;
+ lo = 0;
+ hi = c->count;
+ if (fcs->lastndx != -1)
+ {
+ if (c->vals[fcs->lastndx].start <= addr)
+ {
+ lo = fcs->lastndx;
+ if (hi - lo >= 16)
+ {
+ if (c->vals[lo + 2].start > addr)
+ hi = lo + 2;
+ else if (c->vals[lo + 15].start > addr)
+ hi = lo + 15;
+ }
+ }
+ else
+ {
+ hi = fcs->lastndx;
+ if (hi >= 15)
+ {
+ if (c->vals[hi - 2].start <= addr)
+ lo = hi - 2;
+ else if (c->vals[hi - 15].start <= addr)
+ lo = hi - 15;
+ }
+ }
+ }
+ while (lo < hi)
+ {
+ mid = (lo + hi) / 2;
+ if (c->vals[mid].start <= addr)
+ {
+ if (c->vals[mid].end >= addr + reloc_size)
+ {
+ gelfx_getsym (dso->elf, fcs->symtab, c->vals[mid].idx,
+ &fcs->sym);
+ fcs->lastndx = mid;
+ return c->vals[mid].idx;
+ }
+ lo = mid + 1;
+ }
+ else
+ hi = mid;
+ }
+
+ return -1;
+}
+
+/* The idea here is that C++ virtual tables are always emitted
+ in .gnu.linkonce.d.* sections as WEAK symbols and they
+ need to be the same.
+ We check if they are and if yes, remove conflicts against
+ virtual tables which will not be used. */
+
+int
+remove_redundant_cxx_conflicts (struct prelink_info *info)
+{
+ int i, j, k, n, o, state, removed = 0;
+ int ndx, sec;
+ unsigned int hi, lo, mid;
+ int reloc_type, reloc_size;
+ struct find_cxx_sym fcs1, fcs2;
+ char *mem1, *mem2;
+ const char *name = NULL, *secname = NULL;
+ GElf_Addr symtab_start;
+ GElf_Word symoff;
+ Elf_Data *binsymtab = NULL;
+ int binsymtabsec;
+ struct prelink_conflict *conflict;
+ struct find_cxx_sym_cache **cache;
+ struct find_cxx_sym_cache *binsymcache = NULL;
+ int ret = 0;
+ int rtype_class_valid;
+
+ /* Don't bother doing this for non-C++ programs. */
+ for (i = 0; i < info->ent->ndepends; ++i)
+ if (strstr (info->ent->depends[i]->canon_filename, "libstdc++"))
+ break;
+ if (i == info->ent->ndepends)
+ return 0;
+
+ binsymtabsec = addr_to_sec (info->dso, info->dso->info[DT_SYMTAB]);
+ if (binsymtabsec != -1)
+ {
+ Elf_Scn *scn = info->dso->scn[binsymtabsec];
+
+ binsymtab = elf_getdata (scn, NULL);
+ assert (elf_getdata (scn, binsymtab) == NULL);
+ }
+
+ rtype_class_valid = info->dso->arch->rtype_class_valid;
+
+ state = 0;
+ memset (&fcs1, 0, sizeof (fcs1));
+ memset (&fcs2, 0, sizeof (fcs2));
+ cache = alloca (sizeof (struct find_cxx_sym_cache *)
+ * (info->ent->ndepends + 1));
+ memset (cache, '\0', sizeof (struct find_cxx_sym_cache *)
+ * (info->ent->ndepends + 1));
+ for (i = 0; i < info->conflict_rela_size; ++i)
+ {
+ size_t cidx;
+
+ reloc_type = reloc_r_type (info->dso, info->conflict_rela[i].r_info);
+ reloc_size = info->dso->arch->reloc_size (reloc_type);
+
+ if (reloc_r_sym (info->dso, info->conflict_rela[i].r_info) != 0)
+ continue;
+
+ if (state
+ && fcs1.sym.st_value <= info->conflict_rela[i].r_offset
+ && fcs1.sym.st_value + fcs1.sym.st_size
+ >= info->conflict_rela[i].r_offset + reloc_size)
+ {
+ if (state == 3)
+ goto remove_noref;
+ if (state == 2)
+ goto check_pltref;
+ continue;
+ }
+
+ n = find_cxx_sym (info, info->conflict_rela[i].r_offset,
+ &fcs1, reloc_size, cache);
+
+ state = 0;
+ if (n == -1)
+ continue;
+ if (n == -2)
+ {
+ ret = 1;
+ goto out_free_cache;
+ }
+ state = 1;
+ sec = addr_to_sec (fcs1.dso, fcs1.sym.st_value);
+ if (sec == -1)
+ continue;
+ secname = strptr (fcs1.dso, fcs1.dso->ehdr.e_shstrndx,
+ fcs1.dso->shdr[sec].sh_name);
+ if (secname == NULL)
+ continue;
+
+ name = (const char *) fcs1.strtab->d_buf + fcs1.sym.st_name;
+
+ for (k = 0; specials[k].prefix; ++k)
+ if (ELF32_ST_VISIBILITY (fcs1.sym.st_other) == STV_DEFAULT
+ && fcs1.sym.st_info == specials[k].st_info
+ && strncmp (name, specials[k].prefix, specials[k].prefix_len) == 0)
+ break;
+
+ if (specials[k].prefix == NULL)
+ continue;
+
+ if (strcmp (secname, ".data") != 0
+ && strcmp (secname, ".data.rel.ro") != 0
+ && strcmp (secname, ".sdata") != 0)
+ continue;
+
+ if (specials[k].check_pltref)
+ state = 2;
+
+ symtab_start = fcs1.dso->shdr[fcs1.symsec].sh_addr - fcs1.dso->base;
+ symoff = symtab_start + n * fcs1.dso->shdr[fcs1.symsec].sh_entsize;
+
+ cidx = 0;
+ if (info->conflicts[fcs1.n].hash != &info->conflicts[fcs1.n].first)
+ cidx = symoff % 251;
+ for (conflict = info->conflicts[fcs1.n].hash[cidx]; conflict;
+ conflict = conflict->next)
+ if (conflict->symoff == symoff
+ && conflict->reloc_class == rtype_class_valid)
+ break;
+
+ if (conflict == NULL)
+ goto check_pltref;
+
+ if (conflict->conflict.ent != fcs1.ent
+ || fcs1.dso->base + conflict->conflictval != fcs1.sym.st_value)
+ goto check_pltref;
+
+ if (verbose > 4)
+ error (0, 0, "Possible C++ conflict removal from unreferenced table at %s:%s+%d",
+ fcs1.dso->filename, name,
+ (int) (info->conflict_rela[i].r_offset - fcs1.sym.st_value));
+
+ /* Limit size slightly. */
+ if (fcs1.sym.st_size > 16384)
+ goto check_pltref;
+
+ o = find_cxx_sym (info, conflict->lookup.ent->base + conflict->lookupval,
+ &fcs2, fcs1.sym.st_size, cache);
+
+ if (o == -2)
+ {
+ ret = 1;
+ goto out_free_cache;
+ }
+
+ if (o == -1
+ || fcs1.sym.st_size != fcs2.sym.st_size
+ || fcs1.sym.st_info != fcs2.sym.st_info
+ || ELF32_ST_VISIBILITY (fcs2.sym.st_other) != STV_DEFAULT
+ || strcmp (name, (char *) fcs2.strtab->d_buf + fcs2.sym.st_name) != 0)
+ goto check_pltref;
+
+ mem1 = malloc (fcs1.sym.st_size * 2);
+ if (mem1 == NULL)
+ {
+ error (0, ENOMEM, "%s: Could not compare %s arrays",
+ info->dso->filename, name);
+ ret = 1;
+ goto out_free_cache;
+ }
+
+ mem2 = mem1 + fcs1.sym.st_size;
+
+ if (get_relocated_mem (info, fcs1.dso, fcs1.sym.st_value, mem1,
+ fcs1.sym.st_size, 0)
+ || get_relocated_mem (info, fcs2.dso, fcs2.sym.st_value, mem2,
+ fcs1.sym.st_size, 0)
+ || memcmp (mem1, mem2, fcs1.sym.st_size) != 0)
+ {
+ free (mem1);
+ goto check_pltref;
+ }
+
+ free (mem1);
+
+ state = 3;
+
+remove_noref:
+ if (verbose > 3)
+ error (0, 0, "Removing C++ conflict from unreferenced table at %s:%s+%d",
+ fcs1.dso->filename, name,
+ (int) (info->conflict_rela[i].r_offset - fcs1.sym.st_value));
+
+ info->conflict_rela[i].r_info =
+ reloc_r_info (info->dso, 1,
+ reloc_r_type (info->dso, info->conflict_rela[i].r_info));
+ ++removed;
+ continue;
+
+check_pltref:
+ /* If the binary calls directly (or takes its address) one of the
+ methods in a virtual table, but doesn't define it, there is no
+ need to leave conflicts in the virtual table which will only
+ slow down the code (as it has to hop through binary's .plt
+ back to the method). */
+ if (state != 2
+ || info->conflict_rela[i].r_addend < info->dso->base
+ || info->conflict_rela[i].r_addend >= info->dso->end
+ || binsymtab == NULL)
+ continue;
+
+ if (binsymcache == NULL)
+ {
+ binsymcache = create_cache (info->dso, 1);
+ if (binsymcache == NULL)
+ {
+ ret = 1;
+ goto out_free_cache;
+ }
+ }
+ if (binsymcache == (struct find_cxx_sym_cache *) -1UL)
+ continue;
+
+ lo = 0;
+ mid = 0;
+ hi = binsymcache->count;
+ while (lo < hi)
+ {
+ mid = (lo + hi) / 2;
+ if (binsymcache->vals[mid].start < info->conflict_rela[i].r_addend)
+ lo = mid + 1;
+ else if (binsymcache->vals[mid].start
+ > info->conflict_rela[i].r_addend)
+ hi = mid;
+ else
+ break;
+ }
+ if (lo >= hi)
+ continue;
+
+ while (mid > 0 && binsymcache->vals[mid - 1].start
+ == info->conflict_rela[i].r_addend)
+ --mid;
+
+ while (mid < binsymcache->count
+ && binsymcache->vals[mid].start
+ == info->conflict_rela[i].r_addend)
+ {
+ GElf_Sym sym;
+
+ ndx = binsymcache->vals[mid].idx;
+ mid++;
+ gelfx_getsym (info->dso->elf, binsymtab, ndx, &sym);
+ assert (sym.st_value == info->conflict_rela[i].r_addend);
+ if (sym.st_shndx == SHN_UNDEF && sym.st_value)
+ {
+ struct prelink_symbol *s;
+ size_t maxidx, l;
+
+ if (verbose > 4)
+ error (0, 0, "Possible C++ conflict removal due to reference to binary's .plt at %s:%s+%d",
+ fcs1.dso->filename, name,
+ (int) (info->conflict_rela[i].r_offset
+ - fcs1.sym.st_value));
+
+ for (s = &info->symbols[ndx]; s; s = s->next)
+ if (s->reloc_class == RTYPE_CLASS_PLT)
+ break;
+
+ if (s == NULL)
+ break;
+
+ maxidx = 1;
+ if (info->conflicts[fcs1.n].hash
+ != &info->conflicts[fcs1.n].first)
+ {
+ if (info->conflicts[fcs1.n].hash2 == NULL)
+ {
+ info->conflicts[fcs1.n].hash2
+ = calloc (sizeof (struct prelink_conflict *), 251);
+ if (info->conflicts[fcs1.n].hash2 != NULL)
+ {
+ for (l = 0; l < 251; l++)
+ for (conflict = info->conflicts[fcs1.n].hash[l];
+ conflict; conflict = conflict->next)
+ if (conflict->reloc_class == rtype_class_valid
+ && conflict->conflict.ent)
+ {
+ size_t ccidx
+ = (conflict->lookup.ent->base
+ + conflict->lookupval) % 251;
+ conflict->next2
+ = info->conflicts[fcs1.n].hash2[ccidx];
+ info->conflicts[fcs1.n].hash2[ccidx]
+ = conflict;
+ }
+ }
+ }
+ if (info->conflicts[fcs1.n].hash2 != NULL)
+ {
+ size_t ccidx = info->conflict_rela[i].r_addend % 251;
+ for (conflict = info->conflicts[fcs1.n].hash2[ccidx];
+ conflict; conflict = conflict->next2)
+ if (conflict->lookup.ent->base + conflict->lookupval
+ == info->conflict_rela[i].r_addend
+ && (conflict->conflict.ent->base
+ + conflict->conflictval
+ == s->u.ent->base + s->value))
+ goto pltref_remove;
+ break;
+ }
+ maxidx = 251;
+ }
+
+ for (l = 0; l < maxidx; l++)
+ for (conflict = info->conflicts[fcs1.n].hash[l];
+ conflict; conflict = conflict->next)
+ if (conflict->lookup.ent->base + conflict->lookupval
+ == info->conflict_rela[i].r_addend
+ && conflict->conflict.ent
+ && (conflict->conflict.ent->base
+ + conflict->conflictval == s->u.ent->base + s->value)
+ && conflict->reloc_class == rtype_class_valid)
+ {
+pltref_remove:
+ if (verbose > 3)
+ error (0, 0, "Removing C++ conflict due to reference to binary's .plt at %s:%s+%d",
+ fcs1.dso->filename, name,
+ (int) (info->conflict_rela[i].r_offset
+ - fcs1.sym.st_value));
+
+ info->conflict_rela[i].r_info =
+ reloc_r_info (info->dso, 1, reloc_r_type (info->dso, info->conflict_rela[i].r_info));
+ ++removed;
+ goto pltref_check_done;
+ }
+
+pltref_check_done:
+ break;
+ }
+ }
+ }
+
+ if (removed)
+ {
+ for (i = 0, j = 0; i < info->conflict_rela_size; ++i)
+ if (reloc_r_sym (info->dso, info->conflict_rela[i].r_info) == 0)
+ {
+ if (i != j)
+ info->conflict_rela[j] = info->conflict_rela[i];
+ ++j;
+ }
+ info->conflict_rela_size = j;
+ }
+
+out_free_cache:
+ for (i = 0; i < info->ent->ndepends + 1; i++)
+ if (cache[i] && cache[i] != (struct find_cxx_sym_cache *) -1UL)
+ free (cache[i]);
+ if (binsymcache && binsymcache != (struct find_cxx_sym_cache *) -1UL)
+ free (binsymcache);
+ return ret;
+}
diff --git a/src/data.c b/src/data.c
new file mode 100644
index 0000000..751f96f
--- /dev/null
+++ b/src/data.c
@@ -0,0 +1,339 @@
+/* Copyright (C) 2001, 2002 Red Hat, Inc.
+ Written by Jakub Jelinek <jakub@redhat.com>, 2001.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include <config.h>
+#include "prelink.h"
+
+#define UREAD(le,nn) \
+uint##nn##_t \
+read_u##le##nn (DSO *dso, GElf_Addr addr) \
+{ \
+ Elf_Type type; \
+ unsigned char *data = get_data (dso, addr, NULL, &type); \
+ \
+ if (data == NULL) \
+ return 0; \
+ \
+ if (type == ELF_T_BYTE) \
+ return buf_read_u##le##nn (data); \
+ else \
+ return *(uint##nn##_t *)data; \
+}
+
+#define WRITE(le,nn) \
+int \
+write_##le##nn (DSO *dso, GElf_Addr addr, uint##nn##_t val) \
+{ \
+ int sec; \
+ Elf_Type type; \
+ unsigned char *data = get_data (dso, addr, &sec, &type); \
+ \
+ if (data == NULL) \
+ return -1; \
+ \
+ if (type == ELF_T_BYTE) \
+ buf_write_##le##nn (data, val); \
+ else \
+ *(uint##nn##_t *)data = val; \
+ elf_flagscn (dso->scn[sec], ELF_C_SET, ELF_F_DIRTY); \
+ return 0; \
+}
+
+#define BUFREADUNE(nn) \
+uint##nn##_t \
+buf_read_une##nn (DSO *dso, unsigned char *buf) \
+{ \
+ if (dso->ehdr.e_ident[EI_DATA] == ELFDATA2LSB) \
+ return buf_read_ule##nn (buf); \
+ else \
+ return buf_read_ube##nn (buf); \
+}
+
+#define READUNE(nn) \
+uint##nn##_t \
+read_une##nn (DSO *dso, GElf_Addr addr) \
+{ \
+ if (dso->ehdr.e_ident[EI_DATA] == ELFDATA2LSB) \
+ return read_ule##nn (dso, addr); \
+ else \
+ return read_ube##nn (dso, addr); \
+}
+
+#define WRITENE(nn) \
+void \
+write_ne##nn (DSO *dso, GElf_Addr addr, uint##nn##_t val) \
+{ \
+ if (dso->ehdr.e_ident[EI_DATA] == ELFDATA2LSB) \
+ write_le##nn (dso, addr, val); \
+ else \
+ write_be##nn (dso, addr, val); \
+}
+
+#define BUFWRITENE(nn) \
+void \
+buf_write_ne##nn (DSO *dso, unsigned char *buf, \
+ uint##nn##_t val) \
+{ \
+ if (dso->ehdr.e_ident[EI_DATA] == ELFDATA2LSB) \
+ buf_write_le##nn (buf, val); \
+ else \
+ buf_write_be##nn (buf, val); \
+}
+
+#define READWRITE(le,nn) UREAD(le,nn) WRITE(le,nn)
+#define READWRITESIZE(nn) \
+ READWRITE(le,nn) READWRITE(be,nn) \
+ BUFREADUNE(nn) READUNE(nn) \
+ WRITENE(nn) BUFWRITENE(nn)
+
+unsigned char *
+get_data (DSO *dso, GElf_Addr addr, int *secp, Elf_Type *typep)
+{
+ int sec = addr_to_sec (dso, addr);
+ Elf_Data *data = NULL;
+
+ if (sec == -1)
+ return NULL;
+
+ if (secp)
+ *secp = sec;
+
+ addr -= dso->shdr[sec].sh_addr;
+ while ((data = elf_getdata (dso->scn[sec], data)) != NULL)
+ if (data->d_off <= addr && data->d_off + data->d_size > addr)
+ {
+ if (typep) *typep = data->d_type;
+ return (unsigned char *) data->d_buf + (addr - data->d_off);
+ }
+ return NULL;
+}
+
+/* Initialize IT so that the first byte it provides is address ADDR
+ of DSO. */
+
+void
+init_data_iterator (struct data_iterator *it, DSO *dso, GElf_Addr addr)
+{
+ it->dso = dso;
+ it->data = NULL;
+ it->addr = addr;
+}
+
+/* Return a pointer to the next SIZE bytes pointed to by IT, and move
+ IT to the end of the returned block. Return null if the data could
+ not be read for some reason. */
+
+unsigned char *
+get_data_from_iterator (struct data_iterator *it, GElf_Addr size)
+{
+ unsigned char *ptr;
+
+ /* If we're at the end of a data block, move onto the next. */
+ if (it->data && it->data->d_off + it->data->d_size == it->sec_offset)
+ it->data = elf_getdata (it->dso->scn[it->sec], it->data);
+
+ if (it->data == NULL)
+ {
+ /* Find out which section contains the next byte. */
+ it->sec = addr_to_sec (it->dso, it->addr);
+ if (it->sec < 0)
+ return NULL;
+
+ /* Fast-forward to the block that contains ADDR, if any. */
+ it->sec_offset = it->addr - it->dso->shdr[it->sec].sh_addr;
+ do
+ it->data = elf_getdata (it->dso->scn[it->sec], it->data);
+ while (it->data && it->data->d_off + it->data->d_size <= it->sec_offset);
+ }
+
+ /* Make sure that all the data we want is included in this block. */
+ if (it->data == NULL
+ || it->data->d_off > it->sec_offset
+ || it->data->d_off + it->data->d_size < it->sec_offset + size)
+ return NULL;
+
+ ptr = (unsigned char *) it->data->d_buf + (it->sec_offset - it->data->d_off);
+ it->sec_offset += size;
+ it->addr += size;
+ return ptr;
+}
+
+/* Read the symbol pointed to by IT into SYM and move IT onto the
+ next symbol. Return true on success. */
+
+int
+get_sym_from_iterator (struct data_iterator *it, GElf_Sym *sym)
+{
+ GElf_Addr offset, size;
+ unsigned char *ptr;
+
+ size = gelf_fsize (it->dso->elf, ELF_T_SYM, 1, EV_CURRENT);
+ ptr = get_data_from_iterator (it, size);
+ if (ptr != NULL)
+ {
+ offset = ptr - (unsigned char *) it->data->d_buf;
+ if (offset % size == 0)
+ {
+ gelfx_getsym (it->dso->elf, it->data, offset / size, sym);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+inline uint8_t
+buf_read_u8 (unsigned char *data)
+{
+ return *data;
+}
+
+inline uint16_t
+buf_read_ule16 (unsigned char *data)
+{
+ return data[0] | (data[1] << 8);
+}
+
+inline uint16_t
+buf_read_ube16 (unsigned char *data)
+{
+ return data[1] | (data[0] << 8);
+}
+
+inline uint32_t
+buf_read_ule32 (unsigned char *data)
+{
+ return data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
+}
+
+inline uint32_t
+buf_read_ube32 (unsigned char *data)
+{
+ return data[3] | (data[2] << 8) | (data[1] << 16) | (data[0] << 24);
+}
+
+inline uint64_t
+buf_read_ule64 (unsigned char *data)
+{
+ return (data[0] | (data[1] << 8) | (data[2] << 16))
+ | (((uint64_t)data[3]) << 24)
+ | (((uint64_t)data[4]) << 32)
+ | (((uint64_t)data[5]) << 40)
+ | (((uint64_t)data[6]) << 48)
+ | (((uint64_t)data[7]) << 56);
+}
+
+inline uint64_t
+buf_read_ube64 (unsigned char *data)
+{
+ return (data[7] | (data[6] << 8) | (data[5] << 16))
+ | (((uint64_t)data[4]) << 24)
+ | (((uint64_t)data[3]) << 32)
+ | (((uint64_t)data[2]) << 40)
+ | (((uint64_t)data[1]) << 48)
+ | (((uint64_t)data[0]) << 56);
+}
+
+inline void
+buf_write_8 (unsigned char *data, uint8_t val)
+{
+ *data = val;
+}
+
+inline void
+buf_write_le16 (unsigned char *data, uint16_t val)
+{
+ data[0] = val;
+ data[1] = val >> 8;
+}
+
+inline void
+buf_write_be16 (unsigned char *data, uint16_t val)
+{
+ data[1] = val;
+ data[0] = val >> 8;
+}
+
+inline void
+buf_write_le32 (unsigned char *data, uint32_t val)
+{
+ data[0] = val;
+ data[1] = val >> 8;
+ data[2] = val >> 16;
+ data[3] = val >> 24;
+}
+
+inline void
+buf_write_be32 (unsigned char *data, uint32_t val)
+{
+ data[3] = val;
+ data[2] = val >> 8;
+ data[1] = val >> 16;
+ data[0] = val >> 24;
+}
+
+inline void
+buf_write_le64 (unsigned char *data, uint64_t val)
+{
+ data[0] = val;
+ data[1] = val >> 8;
+ data[2] = val >> 16;
+ data[3] = val >> 24;
+ data[4] = val >> 32;
+ data[5] = val >> 40;
+ data[6] = val >> 48;
+ data[7] = val >> 56;
+}
+
+inline void
+buf_write_be64 (unsigned char *data, uint64_t val)
+{
+ data[7] = val;
+ data[6] = val >> 8;
+ data[5] = val >> 16;
+ data[4] = val >> 24;
+ data[3] = val >> 32;
+ data[2] = val >> 40;
+ data[1] = val >> 48;
+ data[0] = val >> 56;
+}
+
+READWRITE(,8)
+READWRITESIZE(16)
+READWRITESIZE(32)
+READWRITESIZE(64)
+
+const char *
+strptr (DSO *dso, int sec, off_t offset)
+{
+ Elf_Scn *scn;
+ Elf_Data *data;
+
+ scn = dso->scn[sec];
+ if (offset >= 0 && offset < dso->shdr[sec].sh_size)
+ {
+ data = NULL;
+ while ((data = elf_getdata (scn, data)) != NULL)
+ {
+ if (data->d_buf
+ && offset >= data->d_off
+ && offset < data->d_off + data->d_size)
+ return (const char *) data->d_buf + (offset - data->d_off);
+ }
+ }
+
+ return NULL;
+}
diff --git a/src/doit.c b/src/doit.c
new file mode 100644
index 0000000..6b07afb
--- /dev/null
+++ b/src/doit.c
@@ -0,0 +1,256 @@
+/* Copyright (C) 2001, 2003, 2004, 2005, 2007 Red Hat, Inc.
+ Written by Jakub Jelinek <jakub@redhat.com>, 2001.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include <config.h>
+#include <alloca.h>
+#include <errno.h>
+#include <error.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <unistd.h>
+#include "prelinktab.h"
+
+struct collect_ents
+ {
+ struct prelink_entry **ents;
+ int nents;
+ };
+
+static int
+find_ents (void **p, void *info)
+{
+ struct collect_ents *l = (struct collect_ents *) info;
+ struct prelink_entry *e = * (struct prelink_entry **) p;
+
+ e->u.tmp = 0;
+ if ((e->type == ET_DYN && e->done == 1)
+ || (e->type == ET_EXEC && e->done == 0 && ! libs_only))
+ l->ents[l->nents++] = e;
+
+ return 1;
+}
+
+static void
+prelink_ent (struct prelink_entry *ent)
+{
+ int i, j;
+ DSO *dso;
+ struct stat64 st;
+ struct prelink_link *hardlink;
+ char *move = NULL, *move_temp;
+ size_t movelen = 0;
+
+ for (i = 0; i < ent->ndepends; ++i)
+ if (ent->depends[i]->done == 1)
+ prelink_ent (ent->depends[i]);
+
+ for (i = 0; i < ent->ndepends; ++i)
+ if (ent->depends[i]->done != 2)
+ {
+ ent->done = 0;
+ if (! undo)
+ ent->type = ET_UNPRELINKABLE;
+ if (verbose)
+ error (0, 0, "Could not prelink %s because its dependency %s could not be prelinked",
+ ent->filename, ent->depends[i]->filename);
+ return;
+ }
+
+ ent->u.tmp = 1;
+ for (i = 0; i < ent->ndepends; ++i)
+ ent->depends[i]->u.tmp = 1;
+ for (i = 0; i < ent->ndepends; ++i)
+ {
+ struct prelink_entry *dent = ent->depends[i];
+ for (j = 0; j < dent->ndepends; ++j)
+ if (dent->depends[j]->u.tmp == 0)
+ {
+ ent->done = 0;
+ if (! undo)
+ ent->type = ET_UNPRELINKABLE;
+ if (verbose)
+ error (0, 0, "Could not prelink %s because it doesn't use %s, but one of its dependencies has been prelinked against it",
+ ent->filename, dent->depends[j]->filename);
+ ent->u.tmp = 0;
+ for (i = 0; i < ent->ndepends; ++i)
+ ent->depends[i]->u.tmp = 0;
+ return;
+ }
+ }
+ ent->u.tmp = 0;
+ for (i = 0; i < ent->ndepends; ++i)
+ ent->depends[i]->u.tmp = 0;
+
+ if (verbose)
+ {
+ if (dry_run)
+ printf ("Would prelink %s\n", ent->canon_filename);
+ else
+ printf ("Prelinking %s\n", ent->canon_filename);
+ }
+
+ dso = open_dso (ent->canon_filename);
+ if (dso == NULL)
+ goto error_out;
+
+ if (fstat64 (dso->fd, &st) < 0)
+ {
+ error (0, errno, "%s changed during prelinking", ent->filename);
+ goto error_out;
+ }
+
+ if (st.st_dev != ent->dev || st.st_ino != ent->ino)
+ {
+ error (0, 0, "%s changed during prelinking", ent->filename);
+ goto error_out;
+ }
+
+ if (dry_run)
+ close_dso (dso);
+ else
+ {
+ if (prelink_prepare (dso))
+ goto make_unprelinkable;
+ if (ent->type == ET_DYN && relocate_dso (dso, ent->base))
+ goto make_unprelinkable;
+ if (prelink (dso, ent))
+ goto make_unprelinkable;
+ if (update_dso (dso, NULL))
+ {
+ dso = NULL;
+ goto error_out;
+ }
+ }
+ ent->done = 2;
+ ent->flags |= PCF_PRELINKED;
+
+ /* Redo hardlinks. */
+ for (hardlink = ent->hardlink; hardlink; hardlink = hardlink->next)
+ {
+ size_t len;
+
+ if (wrap_lstat64 (hardlink->canon_filename, &st) < 0)
+ {
+ error (0, 0, "Could not stat %s (former hardlink to %s)",
+ hardlink->canon_filename, ent->canon_filename);
+ continue;
+ }
+
+ if (st.st_dev != ent->dev || st.st_ino != ent->ino)
+ {
+ error (0, 0, "%s is no longer hardlink to %s",
+ hardlink->canon_filename, ent->canon_filename);
+ continue;
+ }
+
+ if (verbose)
+ {
+ if (dry_run)
+ printf ("Would link %s to %s\n", hardlink->canon_filename,
+ ent->canon_filename);
+ else
+ printf ("Linking %s to %s\n", hardlink->canon_filename,
+ ent->canon_filename);
+ }
+
+ if (dry_run)
+ continue;
+
+ len = strlen (hardlink->canon_filename);
+ if (len + sizeof (".#prelink#") > movelen)
+ {
+ movelen = len + sizeof (".#prelink#");
+ move_temp = move;
+ move = realloc (move, movelen);
+ if (move == NULL)
+ {
+ free(move_temp);
+ error (0, ENOMEM, "Could not hardlink %s to %s",
+ hardlink->canon_filename, ent->canon_filename);
+ movelen = 0;
+ continue;
+ }
+ }
+
+ memcpy (mempcpy (move, hardlink->canon_filename, len), ".#prelink#",
+ sizeof (".#prelink#"));
+ if (wrap_rename (hardlink->canon_filename, move) < 0)
+ {
+ error (0, errno, "Could not hardlink %s to %s",
+ hardlink->canon_filename, ent->canon_filename);
+ continue;
+ }
+
+ if (wrap_link (ent->canon_filename, hardlink->canon_filename) < 0)
+ {
+ error (0, errno, "Could not hardlink %s to %s",
+ hardlink->canon_filename, ent->canon_filename);
+
+ if (wrap_rename (move, hardlink->canon_filename) < 0)
+ {
+ error (0, errno, "Could not rename %s back to %s",
+ move, hardlink->canon_filename);
+ }
+ continue;
+ }
+
+ if (wrap_unlink (move) < 0)
+ {
+ error (0, errno, "Could not unlink %s", move);
+ continue;
+ }
+ }
+ free (move);
+
+ if (! dry_run && wrap_stat64 (ent->canon_filename, &st) >= 0)
+ {
+ ent->dev = st.st_dev;
+ ent->ino = st.st_ino;
+ ent->ctime = st.st_ctime;
+ ent->mtime = st.st_mtime;
+ }
+ return;
+
+make_unprelinkable:
+ if (! undo)
+ ent->type = ET_UNPRELINKABLE;
+error_out:
+ ent->done = 0;
+ if (dso)
+ close_dso (dso);
+ return;
+}
+
+void
+prelink_all (void)
+{
+ struct collect_ents l;
+ int i;
+
+ l.ents =
+ (struct prelink_entry **) alloca (prelink_entry_count
+ * sizeof (struct prelink_entry *));
+ l.nents = 0;
+ htab_traverse (prelink_filename_htab, find_ents, &l);
+
+ for (i = 0; i < l.nents; ++i)
+ if (l.ents[i]->done == 1
+ || (l.ents[i]->done == 0 && l.ents[i]->type == ET_EXEC))
+ prelink_ent (l.ents[i]);
+}
diff --git a/src/dso.c b/src/dso.c
new file mode 100644
index 0000000..983f1d8
--- /dev/null
+++ b/src/dso.c
@@ -0,0 +1,2013 @@
+/* Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2010 Red Hat, Inc.
+ Written by Jakub Jelinek <jakub@redhat.com>, 2001.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include <config.h>
+#include <assert.h>
+#include <errno.h>
+#include <error.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <time.h>
+#include <unistd.h>
+#include <utime.h>
+#include "prelink.h"
+
+#if defined HAVE_LIBSELINUX && defined HAVE_SELINUX_SELINUX_H
+#include <selinux/selinux.h>
+#define USE_SELINUX
+#endif
+
+#include <sys/xattr.h>
+
+#define RELOCATE_SCN(shf) \
+ ((shf) & (SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR))
+
+#ifndef ELF_F_PERMISSIVE
+# define ELF_F_PERMISSIVE 0
+#endif
+
+void
+read_dynamic (DSO *dso)
+{
+ int i;
+
+ memset (dso->info, 0, sizeof(dso->info));
+ dso->info_set_mask = 0;
+ for (i = 0; i < dso->ehdr.e_shnum; i++)
+ if (dso->shdr[i].sh_type == SHT_DYNAMIC)
+ {
+ Elf_Data *data = NULL;
+ Elf_Scn *scn = dso->scn[i];
+ GElf_Dyn dyn;
+
+ dso->dynamic = i;
+ while ((data = elf_getdata (scn, data)) != NULL)
+ {
+ int ndx, maxndx;
+
+ maxndx = data->d_size / dso->shdr[i].sh_entsize;
+ for (ndx = 0; ndx < maxndx; ++ndx)
+ {
+ gelfx_getdyn (dso->elf, data, ndx, &dyn);
+ if (dyn.d_tag == DT_NULL)
+ break;
+ else if ((GElf_Xword) dyn.d_tag < DT_NUM)
+ {
+ dso->info[dyn.d_tag] = dyn.d_un.d_val;
+ if (dyn.d_tag < 50)
+ dso->info_set_mask |= (1ULL << dyn.d_tag);
+ }
+ else if (dyn.d_tag == DT_CHECKSUM)
+ {
+ dso->info_DT_CHECKSUM = dyn.d_un.d_val;
+ dso->info_set_mask |= (1ULL << DT_CHECKSUM_BIT);
+ }
+ else if (dyn.d_tag == DT_GNU_PRELINKED)
+ {
+ dso->info_DT_GNU_PRELINKED = dyn.d_un.d_val;
+ dso->info_set_mask |= (1ULL << DT_GNU_PRELINKED_BIT);
+ }
+ else if (dyn.d_tag == DT_VERDEF)
+ {
+ dso->info_DT_VERDEF = dyn.d_un.d_val;
+ dso->info_set_mask |= (1ULL << DT_VERDEF_BIT);
+ }
+ else if (dyn.d_tag == DT_VERNEED)
+ {
+ dso->info_DT_VERNEED = dyn.d_un.d_val;
+ dso->info_set_mask |= (1ULL << DT_VERNEED_BIT);
+ }
+ else if (dyn.d_tag == DT_VERSYM)
+ {
+ dso->info_DT_VERSYM = dyn.d_un.d_val;
+ dso->info_set_mask |= (1ULL << DT_VERSYM_BIT);
+ }
+ else if (dyn.d_tag == DT_FILTER)
+ dso->info_set_mask |= (1ULL << DT_FILTER_BIT);
+ else if (dyn.d_tag == DT_AUXILIARY)
+ dso->info_set_mask |= (1ULL << DT_AUXILIARY_BIT);
+ else if (dyn.d_tag == DT_LOPROC)
+ dso->info_set_mask |= (1ULL << DT_LOPROC_BIT);
+ else if (dyn.d_tag == DT_GNU_HASH)
+ {
+ dso->info_DT_GNU_HASH = dyn.d_un.d_val;
+ dso->info_set_mask |= (1ULL << DT_GNU_HASH_BIT);
+ }
+ else if (dyn.d_tag == DT_TLSDESC_PLT)
+ {
+ dso->info_DT_TLSDESC_PLT = dyn.d_un.d_val;
+ dso->info_set_mask |= (1ULL << DT_TLSDESC_PLT_BIT);
+ }
+ if (dso->ehdr.e_machine == EM_MIPS)
+ {
+ if (dyn.d_tag == DT_MIPS_LOCAL_GOTNO)
+ dso->info_DT_MIPS_LOCAL_GOTNO = dyn.d_un.d_val;
+ else if (dyn.d_tag == DT_MIPS_GOTSYM)
+ dso->info_DT_MIPS_GOTSYM = dyn.d_un.d_val;
+ else if (dyn.d_tag == DT_MIPS_SYMTABNO)
+ dso->info_DT_MIPS_SYMTABNO = dyn.d_un.d_val;
+ else if (dyn.d_tag == DT_MIPS_PLTGOT)
+ dso->info_DT_MIPS_PLTGOT = dyn.d_un.d_val;
+ }
+ }
+ if (ndx < maxndx)
+ break;
+ }
+ }
+}
+
+int
+set_dynamic (DSO *dso, GElf_Word tag, GElf_Addr value, int fatal)
+{
+ Elf_Data *data;
+ Elf_Scn *scn;
+ GElf_Dyn dyn;
+ int ndx, maxndx;
+ uint64_t mask = dso->info_set_mask;
+
+ assert (dso->shdr[dso->dynamic].sh_type == SHT_DYNAMIC);
+
+ scn = dso->scn[dso->dynamic];
+
+ data = elf_getdata (scn, NULL);
+ assert (elf_getdata (scn, data) == NULL);
+
+ switch (tag)
+ {
+ case DT_CHECKSUM:
+ mask |= (1ULL << DT_CHECKSUM_BIT); break;
+ case DT_GNU_PRELINKED:
+ mask |= (1ULL << DT_GNU_PRELINKED_BIT); break;
+ case DT_VERDEF:
+ mask |= (1ULL << DT_VERDEF_BIT); break;
+ case DT_VERNEED:
+ mask |= (1ULL << DT_VERNEED_BIT); break;
+ case DT_VERSYM:
+ mask |= (1ULL << DT_VERSYM_BIT); break;
+ default:
+ if (tag < DT_NUM && tag < 50)
+ mask |= (1ULL << tag);
+ break;
+ }
+
+ maxndx = data->d_size / dso->shdr[dso->dynamic].sh_entsize;
+ for (ndx = 0; ndx < maxndx; ndx++)
+ {
+ gelfx_getdyn (dso->elf, data, ndx, &dyn);
+ if (dyn.d_tag == DT_NULL)
+ break;
+ else if (dyn.d_tag == tag)
+ {
+ if (dyn.d_un.d_ptr != value)
+ {
+ dyn.d_un.d_ptr = value;
+ gelfx_update_dyn (dso->elf, data, ndx, &dyn);
+ elf_flagscn (scn, ELF_C_SET, ELF_F_DIRTY);
+ }
+
+ return 0;
+ }
+ }
+ assert (ndx < maxndx);
+
+ if (ndx + 1 < maxndx)
+ {
+ /* DT_NULL is not the last dynamic entry. */
+ gelfx_update_dyn (dso->elf, data, ndx + 1, &dyn);
+ dyn.d_tag = tag;
+ dyn.d_un.d_ptr = value;
+ gelfx_update_dyn (dso->elf, data, ndx, &dyn);
+ dso->info_set_mask = mask;
+ elf_flagscn (scn, ELF_C_SET, ELF_F_DIRTY);
+ return 0;
+ }
+
+ if (fatal)
+ error (0, 0, "%s: Not enough room to add .dynamic entry",
+ dso->filename);
+ return 1;
+}
+
+int
+check_dso (DSO *dso)
+{
+ int i, last = 1;
+
+ /* FIXME: Several routines in prelink and in libelf-0.7.0 too
+ rely on sh_offset's monotonically increasing. */
+ for (i = 2; i < dso->ehdr.e_shnum; ++i)
+ {
+ if (dso->shdr[last].sh_offset
+ + (dso->shdr[last].sh_type == SHT_NOBITS
+ ? 0 : dso->shdr[last].sh_size) > dso->shdr[i].sh_offset)
+ {
+ if (!dso->permissive
+ || RELOCATE_SCN (dso->shdr[last].sh_flags)
+ || RELOCATE_SCN (dso->shdr[i].sh_flags))
+ {
+ error (0, 0, "%s: section file offsets not monotonically increasing",
+ dso->filename);
+ return 1;
+ }
+ }
+ if (!dso->permissive
+ || (dso->shdr[i].sh_type != SHT_NOBITS && dso->shdr[i].sh_size != 0))
+ last = i;
+ }
+
+#ifndef DSO_READONLY
+ if (dso_has_bad_textrel (dso))
+ {
+ error (0, 0, "%s has text relocations", dso->filename);
+ return 1;
+ }
+#endif
+
+ return 0;
+}
+
+DSO *
+open_dso (const char *name)
+{
+ int fd;
+
+ fd = wrap_open (name, O_RDONLY);
+ if (fd == -1)
+ {
+ error (0, errno, "cannot open \"%s\"", name);
+ return NULL;
+ }
+ return fdopen_dso (fd, name);
+}
+
+/* WARNING: If prelink is ever multi-threaded, this will not work
+ Other alternatives are:
+ 1) make section_cmp nested function - trampolines
+ vs. non-exec stack needs to be resolved for it though
+ 2) make the variable __thread
+ 3) use locking around the qsort
+ */
+static DSO *section_cmp_dso;
+
+static int
+section_cmp (const void *A, const void *B)
+{
+ int *a = (int *) A;
+ int *b = (int *) B;
+ DSO *dso = section_cmp_dso;
+
+ if (dso->shdr[*a].sh_offset < dso->shdr[*b].sh_offset)
+ return -1;
+ if (dso->shdr[*a].sh_offset > dso->shdr[*b].sh_offset)
+ return 1;
+ if (*a < *b)
+ return -1;
+ return *a > *b;
+}
+
+DSO *
+fdopen_dso (int fd, const char *name)
+{
+ Elf *elf = NULL;
+ GElf_Ehdr ehdr;
+ GElf_Addr last_off;
+ int i, j, k, last, *sections, *invsections;
+ DSO *dso = NULL;
+#ifndef DSO_READONLY
+ struct PLArch *plarch;
+ extern struct PLArch __start_pl_arch[], __stop_pl_arch[];
+#endif /* DSO_READONLY */
+
+ elf = elf_begin (fd, ELF_C_READ, NULL);
+ if (elf == NULL)
+ {
+ error (0, 0, "cannot open ELF file: %s", elf_errmsg (-1));
+ goto error_out;
+ }
+
+ if (elf_kind (elf) != ELF_K_ELF)
+ {
+ error (0, 0, "\"%s\" is not an ELF file", name);
+ goto error_out;
+ }
+
+ if (gelf_getehdr (elf, &ehdr) == NULL)
+ {
+ error (0, 0, "cannot get the ELF header: %s",
+ elf_errmsg (-1));
+ goto error_out;
+ }
+
+ if (ehdr.e_type != ET_DYN && ehdr.e_type != ET_EXEC)
+ {
+ error (0, 0, "\"%s\" is not a shared library", name);
+ goto error_out;
+ }
+
+ if (ehdr.e_shnum == 0)
+ {
+ GElf_Phdr phdr;
+
+ /* Check for UPX compressed executables. */
+ if (ehdr.e_type == ET_EXEC
+ && ehdr.e_phnum > 0
+ && (gelf_getphdr (elf, 0, &phdr), phdr.p_type == PT_LOAD)
+ && phdr.p_filesz >= 256
+ && phdr.p_filesz <= 4096
+ && phdr.p_offset == 0
+ && ehdr.e_phoff + ehdr.e_phnum * ehdr.e_phentsize < phdr.p_filesz)
+ {
+ char *buf = alloca (phdr.p_filesz);
+ size_t start = ehdr.e_phoff + ehdr.e_phnum * ehdr.e_phentsize;
+
+ if (pread (fd, buf, phdr.p_filesz, 0) == phdr.p_filesz
+ && memmem (buf + start, phdr.p_filesz - start,
+ "UPX!", 4) != NULL)
+ {
+ error (0, 0, "\"%s\" is UPX compressed executable", name);
+ goto error_out;
+ }
+ }
+ error (0, 0, "\"%s\" has no section headers", name);
+ goto error_out;
+ }
+
+ /* Allocate DSO structure. Leave place for additional 20 new section
+ headers. */
+ dso = (DSO *)
+ malloc (sizeof(DSO) + (ehdr.e_shnum + 20) * sizeof(GElf_Shdr)
+ + (ehdr.e_phnum + 1) * sizeof(GElf_Phdr)
+ + (ehdr.e_shnum + 20) * sizeof(Elf_Scn *));
+ if (!dso)
+ {
+ error (0, ENOMEM, "Could not open DSO");
+ goto error_out;
+ }
+
+ elf_flagelf (elf, ELF_C_SET, ELF_F_LAYOUT | ELF_F_PERMISSIVE);
+
+ memset (dso, 0, sizeof(DSO));
+ dso->elf = elf;
+ dso->ehdr = ehdr;
+ dso->phdr = (GElf_Phdr *) &dso->shdr[ehdr.e_shnum + 20];
+ dso->scn = (Elf_Scn **) &dso->phdr[ehdr.e_phnum + 1];
+ switch (ehdr.e_ident[EI_CLASS])
+ {
+ case ELFCLASS32:
+ dso->mask = 0xffffffff; break;
+ case ELFCLASS64:
+ dso->mask = 0xffffffffffffffffULL; break;
+ }
+ for (i = 0; i < ehdr.e_phnum; ++i)
+ gelf_getphdr (elf, i, dso->phdr + i);
+ dso->fd = fd;
+
+ for (i = 0, j = 0; i < ehdr.e_shnum; ++i)
+ {
+ dso->scn[i] = elf_getscn (elf, i);
+ gelfx_getshdr (elf, dso->scn[i], dso->shdr + i);
+ if ((dso->shdr[i].sh_flags & SHF_ALLOC) && dso->shdr[i].sh_type != SHT_NOBITS)
+ j = 1;
+ }
+ if (j == 0)
+ {
+ /* If all ALLOC sections are SHT_NOBITS, then this is a
+ stripped-to-file debuginfo. Skip it silently. */
+ goto error_out;
+ }
+
+ sections = (int *) alloca (dso->ehdr.e_shnum * sizeof (int) * 2);
+ sections[0] = 0;
+ for (i = 1, j = 1, k = dso->ehdr.e_shnum, last = -1;
+ i < dso->ehdr.e_shnum; ++i)
+ if (RELOCATE_SCN (dso->shdr[i].sh_flags))
+ {
+ last = i;
+ sections[j++] = i;
+ }
+ else
+ sections[--k] = i;
+ assert (j == k);
+
+ section_cmp_dso = dso;
+ qsort (sections + k, dso->ehdr.e_shnum - k, sizeof (*sections), section_cmp);
+ invsections = sections + dso->ehdr.e_shnum;
+ invsections[0] = 0;
+ for (i = 1, j = 0; i < ehdr.e_shnum; ++i)
+ {
+ if (i != sections[i])
+ {
+ j = 1;
+ dso->scn[i] = elf_getscn (elf, sections[i]);
+ gelfx_getshdr (elf, dso->scn[i], dso->shdr + i);
+ }
+ invsections[sections[i]] = i;
+ }
+
+#ifndef DSO_READONLY
+ if (j)
+ {
+ dso->move = init_section_move (dso);
+ if (dso->move == NULL)
+ goto error_out;
+ memcpy (dso->move->old_to_new, invsections, dso->ehdr.e_shnum * sizeof (int));
+ memcpy (dso->move->new_to_old, sections, dso->ehdr.e_shnum * sizeof (int));
+ }
+#endif /* DSO_READONLY */
+
+ last_off = 0;
+ for (i = 1; i < ehdr.e_shnum; ++i)
+ {
+ if (dso->shdr[i].sh_link >= ehdr.e_shnum)
+ {
+ error (0, 0, "%s: bogus sh_link value %d", name,
+ dso->shdr[i].sh_link);
+ goto error_out;
+ }
+ dso->shdr[i].sh_link = invsections[dso->shdr[i].sh_link];
+ if (dso->shdr[i].sh_type == SHT_REL
+ || dso->shdr[i].sh_type == SHT_RELA
+ || (dso->shdr[i].sh_flags & SHF_INFO_LINK))
+ {
+ if (dso->shdr[i].sh_info >= ehdr.e_shnum)
+ {
+ error (0, 0, "%s: bogus sh_info value %d", name,
+ dso->shdr[i].sh_info);
+ goto error_out;
+ }
+ dso->shdr[i].sh_info = invsections[dso->shdr[i].sh_info];
+ }
+
+ /* Some linkers mess up sh_offset fields for empty or nobits
+ sections. */
+ if (RELOCATE_SCN (dso->shdr[i].sh_flags)
+ && (dso->shdr[i].sh_size == 0
+ || dso->shdr[i].sh_type == SHT_NOBITS))
+ {
+ for (j = i + 1; j < ehdr.e_shnum; ++j)
+ if (! RELOCATE_SCN (dso->shdr[j].sh_flags))
+ break;
+ else if (dso->shdr[j].sh_size != 0
+ && dso->shdr[j].sh_type != SHT_NOBITS)
+ break;
+ dso->shdr[i].sh_offset = (last_off + dso->shdr[i].sh_addralign - 1)
+ & ~(dso->shdr[i].sh_addralign - 1);
+ if (j < ehdr.e_shnum
+ && dso->shdr[i].sh_offset > dso->shdr[j].sh_offset)
+ {
+ GElf_Addr k;
+
+ for (k = dso->shdr[i].sh_addralign - 1; k; )
+ {
+ k >>= 1;
+ dso->shdr[i].sh_offset = (last_off + k) & ~k;
+ if (dso->shdr[i].sh_offset <= dso->shdr[j].sh_offset)
+ break;
+ }
+ }
+ last_off = dso->shdr[i].sh_offset;
+ }
+ else
+ last_off = dso->shdr[i].sh_offset + dso->shdr[i].sh_size;
+ }
+ dso->ehdr.e_shstrndx = invsections[dso->ehdr.e_shstrndx];
+
+#ifndef DSO_READONLY
+ for (plarch = __start_pl_arch; plarch < __stop_pl_arch; plarch++)
+ if (plarch->class == ehdr.e_ident[EI_CLASS]
+ && (plarch->machine == ehdr.e_machine
+ || plarch->alternate_machine[0] == ehdr.e_machine
+ || plarch->alternate_machine[1] == ehdr.e_machine
+ || plarch->alternate_machine[2] == ehdr.e_machine))
+ break;
+
+ if (plarch == __stop_pl_arch || ehdr.e_machine == EM_NONE)
+ {
+ error (0, 0, "\"%s\"'s architecture is not supported", name);
+ goto error_out;
+ }
+
+ dso->arch = plarch;
+#else
+ dso->arch = NULL;
+#endif /* DSO_READONLY */
+
+ dso->base = ~(GElf_Addr) 0;
+ dso->align = 0;
+ dso->end = 0;
+ for (i = 0; i < dso->ehdr.e_phnum; i++)
+ if (dso->phdr[i].p_type == PT_LOAD)
+ {
+ GElf_Addr base, end;
+
+ if (dso->phdr[i].p_align > dso->align)
+ dso->align = dso->phdr[i].p_align;
+ base = dso->phdr[i].p_vaddr & ~(dso->phdr[i].p_align - 1);
+ end = dso->phdr[i].p_vaddr + dso->phdr[i].p_memsz;
+ if (base < dso->base)
+ dso->base = base;
+ if (end > dso->end)
+ dso->end = end;
+ }
+
+ if (dso->base == ~(GElf_Addr) 0)
+ {
+ error (0, 0, "%s: cannot find loadable segment", name);
+ goto error_out;
+ }
+
+ read_dynamic (dso);
+
+ dso->filename = (const char *) strdup (name);
+ dso->soname = dso->filename;
+ if (dso->info[DT_STRTAB] && dso->info[DT_SONAME])
+ {
+ const char *soname;
+
+ soname = get_data (dso, dso->info[DT_STRTAB] + dso->info[DT_SONAME],
+ NULL, NULL);
+ if (soname && soname[0] != '\0')
+ dso->soname = (const char *) strdup (soname);
+ }
+
+#ifndef DSO_READONLY
+ if (dso->arch->machine == EM_ALPHA
+ || dso->arch->machine == EM_MIPS)
+ for (i = 1; i < ehdr.e_shnum; ++i)
+ {
+ if ((dso->shdr[i].sh_type == SHT_ALPHA_DEBUG
+ && dso->arch->machine == EM_ALPHA)
+ || (dso->shdr[i].sh_type == SHT_MIPS_DEBUG
+ && dso->arch->machine == EM_MIPS))
+ {
+ const char *name
+ = strptr (dso, dso->ehdr.e_shstrndx, dso->shdr[i].sh_name);
+ if (! strcmp (name, ".mdebug"))
+ dso->mdebug_orig_offset = dso->shdr[i].sh_offset;
+ break;
+ }
+ }
+#endif /* DSO_READONLY */
+
+ return dso;
+
+error_out:
+ if (dso)
+ {
+ free (dso->move);
+ if (dso->soname != dso->filename)
+ free ((char *) dso->soname);
+ free ((char *) dso->filename);
+ free (dso);
+ }
+ if (elf)
+ elf_end (elf);
+ if (fd != -1)
+ {
+ fsync (fd);
+ close (fd);
+ }
+ return NULL;
+}
+
+#ifndef DSO_READONLY
+static int
+adjust_symtab_section_indices (DSO *dso, int n, int old_shnum, int *old_to_new)
+{
+ Elf_Data *data = NULL;
+ Elf_Scn *scn = dso->scn[n];
+ GElf_Sym sym;
+ int changed = 0, ndx, maxndx;
+
+ while ((data = elf_getdata (scn, data)) != NULL)
+ {
+ maxndx = data->d_size / dso->shdr[n].sh_entsize;
+ for (ndx = 0; ndx < maxndx; ++ndx)
+ {
+ gelfx_getsym (dso->elf, data, ndx, &sym);
+ if (sym.st_shndx > SHN_UNDEF && sym.st_shndx < SHN_LORESERVE)
+ {
+ if (sym.st_shndx >= old_shnum
+ || old_to_new[sym.st_shndx] == -1)
+ {
+ if (! sym.st_size &&
+ sym.st_info == ELF32_ST_INFO (STB_LOCAL, STT_SECTION))
+ {
+ sym.st_value = 0;
+ sym.st_shndx = SHN_UNDEF;
+ gelfx_update_sym (dso->elf, data, ndx, &sym);
+ changed = 1;
+ continue;
+ }
+ else
+ {
+ if (sym.st_shndx >= old_shnum)
+ {
+ error (0, 0, "%s: Symbol section index outside of section numbers",
+ dso->filename);
+ return 1;
+ }
+ error (0, 0, "%s: Section symbol points into has been removed",
+ dso->filename);
+ return 1;
+ }
+ }
+ if (old_to_new[sym.st_shndx] != sym.st_shndx)
+ {
+ changed = 1;
+ sym.st_shndx = old_to_new[sym.st_shndx];
+ gelfx_update_sym (dso->elf, data, ndx, &sym);
+ }
+ }
+ }
+ }
+
+ if (changed)
+ elf_flagscn (scn, ELF_C_SET, ELF_F_DIRTY);
+
+ return 0;
+}
+
+static int
+set_stt_section_values (DSO *dso, int n)
+{
+ Elf_Data *data;
+ Elf_Scn *scn = dso->scn[n];
+ GElf_Sym sym;
+ int ndx, maxndx, sec;
+ char seen[dso->ehdr.e_shnum];
+
+ memset (seen, 0, dso->ehdr.e_shnum);
+ data = elf_getdata (scn, NULL);
+ assert (data != NULL);
+ assert (elf_getdata (scn, data) == NULL);
+ assert (data->d_off == 0);
+
+ maxndx = data->d_size / dso->shdr[n].sh_entsize;
+ gelfx_getsym (dso->elf, data, 0, &sym);
+ if (sym.st_info != ELF32_ST_INFO (STB_LOCAL, STT_NOTYPE)
+ || sym.st_size != 0 || sym.st_other != 0
+ || sym.st_value != 0 || sym.st_shndx != SHN_UNDEF
+ || sym.st_name != 0)
+ return 0;
+
+ for (ndx = 1; ndx < maxndx; ++ndx)
+ {
+ gelfx_getsym (dso->elf, data, ndx, &sym);
+ if (sym.st_info == ELF32_ST_INFO (STB_LOCAL, STT_SECTION)
+ && sym.st_size == 0 && sym.st_other == 0
+ && sym.st_name == 0)
+ {
+ if (sym.st_shndx > SHN_UNDEF && sym.st_shndx < SHN_LORESERVE)
+ {
+ seen[sym.st_shndx] = 1;
+ sym.st_value = dso->shdr[sym.st_shndx].sh_addr;
+ gelfx_update_sym (dso->elf, data, ndx, &sym);
+ }
+ }
+ else
+ break;
+ }
+
+ for (ndx = 1, sec = 1; ndx < maxndx; ++ndx)
+ {
+ gelfx_getsym (dso->elf, data, ndx, &sym);
+ if (sym.st_info == ELF32_ST_INFO (STB_LOCAL, STT_SECTION)
+ && sym.st_size == 0 && sym.st_other == 0
+ && sym.st_name == 0)
+ {
+ if (sym.st_shndx == SHN_UNDEF)
+ {
+ while (sec < dso->ehdr.e_shnum && seen[sec])
+ ++sec;
+
+ if (sec >= dso->ehdr.e_shnum)
+ sym.st_value = 0;
+ else
+ sym.st_value = dso->shdr[sec].sh_addr;
+ sym.st_shndx = sec++;
+ gelfx_update_sym (dso->elf, data, ndx, &sym);
+ }
+ }
+ else
+ break;
+ }
+
+ return 0;
+}
+
+struct section_move *
+init_section_move (DSO *dso)
+{
+ struct section_move *move;
+ int i;
+
+ move = malloc (sizeof (struct section_move)
+ + (dso->ehdr.e_shnum * 2 + 20) * sizeof (int));
+ if (move == NULL)
+ {
+ error (0, ENOMEM, "%s: Could not move sections", dso->filename);
+ return move;
+ }
+ move->old_shnum = dso->ehdr.e_shnum;
+ move->new_shnum = dso->ehdr.e_shnum;
+ move->old_to_new = (int *)(move + 1);
+ move->new_to_old = move->old_to_new + move->new_shnum;
+ for (i = 0; i < move->new_shnum; i++)
+ {
+ move->old_to_new[i] = i;
+ move->new_to_old[i] = i;
+ }
+ return move;
+}
+
+void
+add_section (struct section_move *move, int sec)
+{
+ int i;
+
+ assert (move->new_shnum < move->old_shnum + 20);
+ assert (sec <= move->new_shnum);
+
+ memmove (move->new_to_old + sec + 1, move->new_to_old + sec,
+ (move->new_shnum - sec) * sizeof (int));
+ ++move->new_shnum;
+ move->new_to_old[sec] = -1;
+ for (i = 1; i < move->old_shnum; i++)
+ if (move->old_to_new[i] >= sec)
+ ++move->old_to_new[i];
+}
+
+void
+remove_section (struct section_move *move, int sec)
+{
+ int i;
+
+ assert (sec < move->new_shnum);
+
+ memmove (move->new_to_old + sec, move->new_to_old + sec + 1,
+ (move->new_shnum - sec - 1) * sizeof (int));
+ --move->new_shnum;
+ for (i = 1; i < move->old_shnum; i++)
+ if (move->old_to_new[i] == sec)
+ move->old_to_new[i] = -1;
+ else if (move->old_to_new[i] > sec)
+ --move->old_to_new[i];
+}
+
+int
+reopen_dso (DSO *dso, struct section_move *move, const char *temp_base)
+{
+ char filename[strlen (temp_base ? temp_base : dso->filename)
+ + sizeof ("/dev/shm/.#prelink#.XXXXXX")];
+ int adddel = 0;
+ int free_move = 0;
+ Elf *elf = NULL;
+ GElf_Ehdr ehdr;
+ char *e_ident;
+ int fd, i, j;
+
+ if (move == NULL)
+ {
+ move = init_section_move (dso);
+ if (move == NULL)
+ return 1;
+ free_move = 1;
+ }
+ else
+ assert (dso->ehdr.e_shnum == move->old_shnum);
+
+ if (temp_base == NULL)
+ temp_base = dso->filename;
+ sprintf (filename, "%s.#prelink#.XXXXXX", temp_base);
+
+ fd = wrap_mkstemp (filename);
+ if (fd == -1)
+ {
+ strcpy (filename, "/tmp/#prelink#.XXXXXX");
+ fd = wrap_mkstemp (filename);
+ if (fd == -1)
+ {
+ strcpy (filename, "/dev/shm/#prelink#.XXXXXX");
+ fd = wrap_mkstemp (filename);
+ }
+ if (fd == -1)
+ {
+ error (0, errno, "Could not create temporary file %s", filename);
+ goto error_out;
+ }
+ }
+
+ elf = elf_begin (fd, ELF_C_WRITE, NULL);
+ if (elf == NULL)
+ {
+ error (0, 0, "cannot open ELF file: %s", elf_errmsg (-1));
+ goto error_out;
+
+ }
+
+ /* Some gelf_newehdr implementations don't return the resulting
+ ElfNN_Ehdr, so we have to do it the hard way instead of:
+ e_ident = (char *) gelf_newehdr (elf, gelf_getclass (dso->elf)); */
+ switch (gelf_getclass (dso->elf))
+ {
+ case ELFCLASS32:
+ e_ident = (char *) elf32_newehdr (elf);
+ break;
+ case ELFCLASS64:
+ e_ident = (char *) elf64_newehdr (elf);
+ break;
+ default:
+ e_ident = NULL;
+ break;
+ }
+
+ if (e_ident == NULL
+ /* This is here just for the gelfx wrapper, so that gelf_update_ehdr
+ already has the correct ELF class. */
+ || memcpy (e_ident, dso->ehdr.e_ident, EI_NIDENT) == NULL
+ || gelf_update_ehdr (elf, &dso->ehdr) == 0
+ || gelf_newphdr (elf, dso->ehdr.e_phnum) == 0)
+ {
+ error (0, 0, "Could not create new ELF headers");
+ goto error_out;
+ }
+ ehdr = dso->ehdr;
+ elf_flagelf (elf, ELF_C_SET, ELF_F_LAYOUT | ELF_F_PERMISSIVE);
+ for (i = 0; i < ehdr.e_phnum; ++i)
+ gelf_update_phdr (elf, i, dso->phdr + i);
+
+ for (i = 1; i < move->new_shnum; ++i)
+ {
+ Elf_Scn *scn;
+ Elf_Data data, *data1, *data2;
+
+ if (move->new_to_old[i] == -1)
+ {
+ scn = elf_newscn (elf);
+ elf_newdata (scn);
+ }
+ else
+ {
+ j = move->new_to_old[i];
+ scn = elf_newscn (elf);
+ gelfx_update_shdr (elf, scn, &dso->shdr[j]);
+ if (dso->shdr[j].sh_type == SHT_NOBITS)
+ {
+ data1 = elf_getdata (dso->scn[j], NULL);
+ data2 = elf_newdata (scn);
+ memcpy (data2, data1, sizeof (*data1));
+ }
+ else
+ {
+ memset (&data, 0, sizeof data);
+ data.d_type = ELF_T_NUM;
+ data1 = NULL;
+ while ((data1 = elf_getdata (dso->scn[j], data1))
+ != NULL)
+ {
+ if (data.d_type == ELF_T_NUM)
+ data = *data1;
+ else if (data.d_type != data1->d_type
+ || data.d_version != data1->d_version)
+ abort ();
+ else
+ {
+ if (data1->d_off < data.d_off)
+ {
+ data.d_size += data.d_off - data1->d_off;
+ data.d_off = data1->d_off;
+ }
+ if (data1->d_off + data1->d_size
+ > data.d_off + data.d_size)
+ data.d_size = data1->d_off + data1->d_size
+ - data.d_off;
+ if (data1->d_align > data.d_align)
+ data.d_align = data1->d_align;
+ }
+ }
+ if (data.d_type == ELF_T_NUM)
+ {
+ assert (dso->shdr[j].sh_size == 0);
+ continue;
+ }
+ if (data.d_size != 0)
+ {
+ data.d_buf = calloc (1, data.d_size);
+ if (data.d_buf == NULL)
+ {
+ error (0, ENOMEM, "%s: Could not copy section",
+ dso->filename);
+ goto error_out;
+ }
+ }
+ else
+ data.d_buf = NULL;
+ data1 = NULL;
+ while ((data1 = elf_getdata (dso->scn[j], data1))
+ != NULL)
+ memcpy (data.d_buf + data1->d_off - data.d_off, data1->d_buf,
+ data1->d_size);
+ data2 = elf_newdata (scn);
+ memcpy (data2, &data, sizeof (data));
+ }
+ }
+ }
+
+ ehdr.e_shnum = move->new_shnum;
+ dso->temp_filename = strdup (filename);
+ if (dso->temp_filename == NULL)
+ {
+ error (0, ENOMEM, "%s: Could not save temporary filename", dso->filename);
+ goto error_out;
+ }
+ dso->elfro = dso->elf;
+ dso->elf = elf;
+ dso->fdro = dso->fd;
+ dso->fd = fd;
+ dso->ehdr = ehdr;
+ dso->lastscn = 0;
+ elf = NULL;
+ fd = -1;
+ for (i = 1; i < move->old_shnum; i++)
+ if (move->old_to_new[i] != i)
+ {
+ adddel = 1;
+ break;
+ }
+ if (! adddel)
+ for (i = 1; i < move->new_shnum; i++)
+ if (move->new_to_old[i] != i)
+ {
+ adddel = 1;
+ break;
+ }
+
+ for (i = 1; i < move->new_shnum; i++)
+ {
+ dso->scn[i] = elf_getscn (dso->elf, i);
+ gelfx_getshdr (dso->elf, dso->scn[i], dso->shdr + i);
+ if (move->new_to_old[i] == -1)
+ continue;
+ if (dso->move
+ && (dso->shdr[i].sh_type == SHT_SYMTAB
+ || dso->shdr[i].sh_type == SHT_DYNSYM))
+ {
+ if (adjust_symtab_section_indices (dso, i, dso->move->old_shnum,
+ dso->move->old_to_new))
+ goto error_out;
+ }
+ if (adddel)
+ {
+ if (dso->shdr[i].sh_link)
+ {
+ if (dso->shdr[i].sh_link >= move->old_shnum)
+ {
+ error (0, 0, "%s: bogus sh_link value %d", dso->filename,
+ dso->shdr[i].sh_link);
+ goto error_out;
+ }
+ if (move->old_to_new[dso->shdr[i].sh_link] == -1)
+ {
+ error (0, 0, "Section sh_link points to has been removed");
+ goto error_out;
+ }
+ dso->shdr[i].sh_link = move->old_to_new[dso->shdr[i].sh_link];
+ }
+ /* Only some section types use sh_info for section index. */
+ if (dso->shdr[i].sh_info
+ && (dso->shdr[i].sh_type == SHT_REL
+ || dso->shdr[i].sh_type == SHT_RELA
+ || (dso->shdr[i].sh_flags & SHF_INFO_LINK)))
+ {
+ if (dso->shdr[i].sh_info >= move->old_shnum)
+ {
+ error (0, 0, "%s: bogus sh_info value %d", dso->filename,
+ dso->shdr[i].sh_info);
+ goto error_out;
+ }
+ if (move->old_to_new[dso->shdr[i].sh_info] == -1)
+ {
+ error (0, 0, "Section sh_info points to has been removed");
+ goto error_out;
+ }
+ dso->shdr[i].sh_info = move->old_to_new[dso->shdr[i].sh_info];
+ }
+ if (dso->shdr[i].sh_type == SHT_SYMTAB
+ || dso->shdr[i].sh_type == SHT_DYNSYM)
+ {
+ if (adjust_symtab_section_indices (dso, i, move->old_shnum,
+ move->old_to_new))
+ goto error_out;
+ }
+ }
+ }
+
+ free (dso->move);
+ dso->move = NULL;
+
+ dso->ehdr.e_shstrndx = move->old_to_new[dso->ehdr.e_shstrndx];
+ gelf_update_ehdr (dso->elf, &dso->ehdr);
+
+ read_dynamic (dso);
+
+ /* If shoff does not point after last section, we need to adjust the sections
+ after it if we added or removed some sections. */
+ if (move->old_shnum != move->new_shnum
+ && adjust_dso_nonalloc (dso, 0, dso->ehdr.e_shoff + 1,
+ ((long) move->new_shnum - (long) move->old_shnum)
+ * gelf_fsize (dso->elf, ELF_T_SHDR, 1,
+ EV_CURRENT)))
+ goto error_out;
+
+ if (free_move)
+ free (move);
+ return 0;
+
+error_out:
+ if (free_move)
+ free (move);
+ if (elf)
+ elf_end (elf);
+ if (fd != -1)
+ {
+ wrap_unlink (filename);
+ fsync (fd);
+ close (fd);
+ }
+ return 1;
+}
+
+/* Return true if the value of symbol SYM, which belongs to DSO,
+ should be treated as an address within the DSO, and should
+ therefore track DSO's relocations. */
+
+int
+adjust_symbol_p (DSO *dso, GElf_Sym *sym)
+{
+ if (sym->st_shndx == SHN_ABS
+ && sym->st_value != 0
+ && (GELF_ST_TYPE (sym->st_info) <= STT_FUNC
+ || (dso->ehdr.e_machine == EM_ARM
+ && GELF_ST_TYPE (sym->st_info) == STT_ARM_TFUNC)))
+ /* This is problematic. How do we find out if
+ we should relocate this? Assume we should. */
+ return 1;
+
+ /* If a MIPS object does not define a symbol, but has a lazy binding
+ stub for it, st_value will point to that stub. Note that unlike
+ other targets, these stub addresses never participate in symbol
+ lookup; the stubs can only be called by the object that defines them.
+ st_values are only used in this way so that the associated GOT entry
+ can store a Quickstart value without losing the original stub
+ address. */
+ if (dso->ehdr.e_machine == EM_MIPS
+ && sym->st_shndx == SHN_UNDEF
+ && sym->st_value != 0)
+ return 1;
+
+ return (sym->st_shndx > SHN_UNDEF
+ && sym->st_shndx < dso->ehdr.e_shnum
+ && ELF32_ST_TYPE (sym->st_info) != STT_TLS
+ && RELOCATE_SCN (dso->shdr[sym->st_shndx].sh_flags));
+}
+
+static int
+adjust_symtab (DSO *dso, int n, GElf_Addr start, GElf_Addr adjust)
+{
+ Elf_Data *data = NULL;
+ Elf_Scn *scn = dso->scn[n];
+ GElf_Sym sym;
+ int ndx, maxndx;
+
+ while ((data = elf_getdata (scn, data)) != NULL)
+ {
+ maxndx = data->d_size / dso->shdr[n].sh_entsize;
+ for (ndx = 0; ndx < maxndx; ++ndx)
+ {
+ gelfx_getsym (dso->elf, data, ndx, &sym);
+ if (adjust_symbol_p (dso, &sym) && sym.st_value >= start)
+ {
+ sym.st_value += adjust;
+ gelfx_update_sym (dso->elf, data, ndx, &sym);
+ }
+ }
+ }
+
+ elf_flagscn (scn, ELF_C_SET, ELF_F_DIRTY);
+ return 0;
+}
+#endif /* DSO_READONLY */
+
+int
+dso_is_rdwr (DSO *dso)
+{
+ return dso->elfro != NULL;
+}
+
+#ifndef DSO_READONLY
+GElf_Addr
+adjust_old_to_new (DSO *dso, GElf_Addr addr)
+{
+ int i;
+
+ if (dso->adjust == NULL)
+ return addr; /* Fast path. */
+
+ for (i = 0; i < dso->nadjust; i++)
+ if (addr >= dso->adjust[i].start)
+ {
+ addr += dso->adjust[i].adjust;
+ assert (dso->ehdr.e_ident[EI_CLASS] != ELFCLASS32
+ || addr == (Elf32_Addr) addr);
+ return addr;
+ }
+
+ return addr;
+}
+
+GElf_Addr
+adjust_new_to_old (DSO *dso, GElf_Addr addr)
+{
+ int i;
+
+ if (dso->adjust == NULL)
+ return addr; /* Fast path. */
+
+ for (i = 0; i < dso->nadjust; i++)
+ if (addr >= dso->adjust[i].start + dso->adjust[i].adjust)
+ {
+ addr -= dso->adjust[i].adjust;
+ assert (dso->ehdr.e_ident[EI_CLASS] != ELFCLASS32
+ || addr == (Elf32_Addr) addr);
+ return addr;
+ }
+
+ return addr;
+}
+
+static int
+adjust_dynamic (DSO *dso, int n, GElf_Addr start, GElf_Addr adjust)
+{
+ Elf_Data *data = NULL;
+ Elf_Scn *scn = dso->scn[n];
+ GElf_Dyn dyn;
+ int ndx, maxndx;
+
+ while ((data = elf_getdata (scn, data)) != NULL)
+ {
+ maxndx = data->d_size / dso->shdr[n].sh_entsize;
+ for (ndx = 0; ndx < maxndx; ++ndx)
+ {
+ gelfx_getdyn (dso->elf, data, ndx, &dyn);
+ if (dso->arch->adjust_dyn (dso, n, &dyn, start, adjust) == 0)
+ switch (dyn.d_tag)
+ {
+ case DT_REL:
+ case DT_RELA:
+ /* On some arches DT_REL* may be 0 indicating no relocations
+ (if DT_REL*SZ is also 0). Don't adjust it in that case. */
+ if (dyn.d_un.d_ptr && dyn.d_un.d_ptr >= start)
+ {
+ dyn.d_un.d_ptr += adjust;
+ gelfx_update_dyn (dso->elf, data, ndx, &dyn);
+ }
+ break;
+ default:
+ if (dyn.d_tag < DT_ADDRRNGLO || dyn.d_tag > DT_ADDRRNGHI)
+ break;
+ /* FALLTHROUGH */
+ case DT_INIT:
+ case DT_FINI:
+ case DT_HASH:
+ case DT_STRTAB:
+ case DT_SYMTAB:
+ case DT_JMPREL:
+ case DT_INIT_ARRAY:
+ case DT_FINI_ARRAY:
+ case DT_PREINIT_ARRAY:
+ case DT_VERDEF:
+ case DT_VERNEED:
+ case DT_VERSYM:
+ case DT_PLTGOT:
+ if (dyn.d_un.d_ptr >= start)
+ {
+ dyn.d_un.d_ptr += adjust;
+ gelfx_update_dyn (dso->elf, data, ndx, &dyn);
+ }
+ break;
+ }
+ else
+ gelfx_update_dyn (dso->elf, data, ndx, &dyn);
+ }
+ }
+
+ elf_flagscn (scn, ELF_C_SET, ELF_F_DIRTY);
+
+ /* Update the cached dynamic info as well. */
+ read_dynamic (dso);
+ return 0;
+}
+#endif /* DSO_READONLY */
+
+int
+addr_to_sec (DSO *dso, GElf_Addr addr)
+{
+ GElf_Shdr *shdr;
+ int i;
+
+ shdr = &dso->shdr[dso->lastscn];
+ for (i = -1; i < dso->ehdr.e_shnum; shdr = &dso->shdr[++i])
+ if (RELOCATE_SCN (shdr->sh_flags)
+ && shdr->sh_addr <= addr && shdr->sh_addr + shdr->sh_size > addr
+ && (shdr->sh_type != SHT_NOBITS || (shdr->sh_flags & SHF_TLS) == 0))
+ {
+ if (i != -1)
+ dso->lastscn = i;
+ return dso->lastscn;
+ }
+
+ return -1;
+}
+
+#ifndef DSO_READONLY
+static int
+adjust_rel (DSO *dso, int n, GElf_Addr start, GElf_Addr adjust)
+{
+ Elf_Data *data = NULL;
+ Elf_Scn *scn = dso->scn[n];
+ GElf_Rel rel;
+ int sec, ndx, maxndx;
+
+ while ((data = elf_getdata (scn, data)) != NULL)
+ {
+ maxndx = data->d_size / dso->shdr[n].sh_entsize;
+ for (ndx = 0; ndx < maxndx; ++ndx)
+ {
+ gelfx_getrel (dso->elf, data, ndx, &rel);
+ sec = addr_to_sec (dso, rel.r_offset);
+ if (sec == -1)
+ continue;
+
+ dso->arch->adjust_rel (dso, &rel, start, adjust);
+ addr_adjust (rel.r_offset, start, adjust);
+ gelfx_update_rel (dso->elf, data, ndx, &rel);
+ }
+ }
+
+ elf_flagscn (scn, ELF_C_SET, ELF_F_DIRTY);
+ return 0;
+}
+
+static int
+adjust_rela (DSO *dso, int n, GElf_Addr start, GElf_Addr adjust)
+{
+ Elf_Data *data = NULL;
+ Elf_Scn *scn = dso->scn[n];
+ GElf_Rela rela;
+ int sec, ndx, maxndx;
+
+ while ((data = elf_getdata (scn, data)) != NULL)
+ {
+ maxndx = data->d_size / dso->shdr[n].sh_entsize;
+ for (ndx = 0; ndx < maxndx; ++ndx)
+ {
+ gelfx_getrela (dso->elf, data, ndx, &rela);
+ sec = addr_to_sec (dso, rela.r_offset);
+ if (sec == -1)
+ continue;
+
+ dso->arch->adjust_rela (dso, &rela, start, adjust);
+ addr_adjust (rela.r_offset, start, adjust);
+ gelfx_update_rela (dso->elf, data, ndx, &rela);
+ }
+ }
+
+ elf_flagscn (scn, ELF_C_SET, ELF_F_DIRTY);
+ return 0;
+}
+
+int
+adjust_nonalloc (DSO *dso, GElf_Ehdr *ehdr, GElf_Shdr *shdr, int first,
+ GElf_Addr start, GElf_Addr adjust)
+{
+ int i;
+
+ for (i = 1; i < ehdr->e_shnum; i++)
+ {
+ if (RELOCATE_SCN (shdr[i].sh_flags) || shdr[i].sh_type == SHT_NULL)
+ continue;
+
+ if ((shdr[i].sh_offset > start
+ || (shdr[i].sh_offset == start && i >= first))
+ && (adjust & (shdr[i].sh_addralign - 1)))
+ adjust = (adjust + shdr[i].sh_addralign - 1)
+ & ~(shdr[i].sh_addralign - 1);
+ }
+
+ if (ehdr->e_shoff >= start)
+ {
+ GElf_Addr shdralign = gelf_fsize (dso->elf, ELF_T_ADDR, 1, EV_CURRENT);
+
+ if (adjust & (shdralign - 1))
+ adjust = (adjust + shdralign - 1) & ~(shdralign - 1);
+ ehdr->e_shoff += adjust;
+ }
+
+ for (i = 1; i < ehdr->e_shnum; i++)
+ {
+ if (RELOCATE_SCN (shdr[i].sh_flags) || shdr[i].sh_type == SHT_NULL)
+ continue;
+
+ if (shdr[i].sh_offset > start
+ || (shdr[i].sh_offset == start && i >= first))
+ shdr[i].sh_offset += adjust;
+ }
+ return 0;
+}
+
+int
+adjust_dso_nonalloc (DSO *dso, int first, GElf_Addr start, GElf_Addr adjust)
+{
+ return adjust_nonalloc (dso, &dso->ehdr, dso->shdr, first, start, adjust);
+}
+
+/* Add ADJUST to all addresses above START. */
+int
+adjust_dso (DSO *dso, GElf_Addr start, GElf_Addr adjust)
+{
+ int i;
+
+ if (dso->arch->arch_adjust
+ && dso->arch->arch_adjust (dso, start, adjust))
+ return 1;
+
+ if (dso->ehdr.e_entry >= start)
+ {
+ dso->ehdr.e_entry += adjust;
+ gelf_update_ehdr (dso->elf, &dso->ehdr);
+ elf_flagehdr (dso->elf, ELF_C_SET, ELF_F_DIRTY);
+ }
+
+ for (i = 0; i < dso->ehdr.e_phnum; i++)
+ {
+ /* Leave STACK segment alone, it has
+ p_vaddr == p_paddr == p_offset == p_filesz == p_memsz == 0. */
+ if (dso->phdr[i].p_type == PT_GNU_STACK)
+ continue;
+ if (! start)
+ {
+ dso->phdr[i].p_vaddr += adjust;
+ dso->phdr[i].p_paddr += adjust;
+ }
+ else if (start <= dso->phdr[i].p_vaddr)
+ {
+ dso->phdr[i].p_vaddr += adjust;
+ dso->phdr[i].p_paddr += adjust;
+ dso->phdr[i].p_offset += adjust;
+ }
+ else if (start < dso->phdr[i].p_vaddr + dso->phdr[i].p_filesz)
+ {
+ dso->phdr[i].p_filesz += adjust;
+ dso->phdr[i].p_memsz += adjust;
+ }
+ else if (start < dso->phdr[i].p_vaddr + dso->phdr[i].p_memsz)
+ dso->phdr[i].p_memsz += adjust;
+ else
+ continue;
+ if (dso->phdr[i].p_type == PT_LOAD
+ && (dso->phdr[i].p_vaddr - dso->phdr[i].p_offset)
+ % dso->phdr[i].p_align)
+ {
+ error (0, 0, "%s: PT_LOAD %08llx %08llx 0x%x would be not properly aligned",
+ dso->filename, (long long) dso->phdr[i].p_offset,
+ (long long) dso->phdr[i].p_vaddr, (int) dso->phdr[i].p_align);
+ return 1;
+ }
+ gelf_update_phdr (dso->elf, i, dso->phdr + i);
+ }
+ elf_flagphdr (dso->elf, ELF_C_SET, ELF_F_DIRTY);
+
+ for (i = 1; i < dso->ehdr.e_shnum; i++)
+ {
+ const char *name;
+
+ if (dso->arch->adjust_section)
+ {
+ int ret = dso->arch->adjust_section (dso, i, start, adjust);
+
+ if (ret == 1)
+ return 1;
+ else if (ret)
+ continue;
+ }
+ switch (dso->shdr[i].sh_type)
+ {
+ case SHT_PROGBITS:
+ case SHT_MIPS_DWARF:
+ name = strptr (dso, dso->ehdr.e_shstrndx, dso->shdr[i].sh_name);
+ if (strcmp (name, ".stab") == 0
+ && adjust_stabs (dso, i, start, adjust))
+ return 1;
+ if (strcmp (name, ".debug_info") == 0
+ && adjust_dwarf2 (dso, i, start, adjust))
+ return 1;
+ break;
+ case SHT_HASH:
+ case SHT_GNU_HASH:
+ case SHT_NOBITS:
+ case SHT_STRTAB:
+ break;
+ case SHT_SYMTAB:
+ case SHT_DYNSYM:
+ if (adjust_symtab (dso, i, start, adjust))
+ return 1;
+ break;
+ case SHT_DYNAMIC:
+ if (adjust_dynamic (dso, i, start, adjust))
+ return 1;
+ break;
+ case SHT_REL:
+ /* Don't adjust reloc sections for debug info. */
+ if (dso->shdr[i].sh_flags & SHF_ALLOC)
+ if (adjust_rel (dso, i, start, adjust))
+ return 1;
+ break;
+ case SHT_RELA:
+ if (dso->shdr[i].sh_flags & SHF_ALLOC)
+ if (adjust_rela (dso, i, start, adjust))
+ return 1;
+ break;
+ }
+ if ((dso->arch->machine == EM_ALPHA
+ && dso->shdr[i].sh_type == SHT_ALPHA_DEBUG)
+ || (dso->arch->machine == EM_MIPS
+ && dso->shdr[i].sh_type == SHT_MIPS_DEBUG))
+ if (adjust_mdebug (dso, i, start, adjust))
+ return 1;
+ }
+
+ for (i = 0; i < dso->ehdr.e_shnum; i++)
+ {
+ if (RELOCATE_SCN (dso->shdr[i].sh_flags))
+ {
+ if (dso->shdr[i].sh_addr >= start)
+ {
+ Elf_Scn *scn = dso->scn[i];
+
+ dso->shdr[i].sh_addr += adjust;
+ if (start)
+ dso->shdr[i].sh_offset += adjust;
+ gelfx_update_shdr (dso->elf, scn, dso->shdr + i);
+ elf_flagshdr (scn, ELF_C_SET, ELF_F_DIRTY);
+ }
+ }
+ }
+
+ addr_adjust (dso->base, start, adjust);
+ addr_adjust (dso->end, start, adjust);
+
+ if (start)
+ {
+ start = adjust_new_to_old (dso, start);
+ for (i = 0; i < dso->nadjust; i++)
+ if (start < dso->adjust[i].start)
+ dso->adjust[i].adjust += adjust;
+ else
+ break;
+ if (i < dso->nadjust && start == dso->adjust[i].start)
+ dso->adjust[i].adjust += adjust;
+ else
+ {
+ dso->adjust =
+ realloc (dso->adjust, (dso->nadjust + 1) * sizeof (*dso->adjust));
+ if (dso->adjust == NULL)
+ {
+ error (0, ENOMEM, "Cannot record the list of adjustements being made");
+ return 1;
+ }
+ memmove (dso->adjust + i + 1, dso->adjust + i, dso->nadjust - i);
+ dso->adjust[i].start = start;
+ dso->adjust[i].adjust = adjust;
+ ++dso->nadjust;
+ }
+ }
+
+ return start ? adjust_dso_nonalloc (dso, 0, 0, adjust) : 0;
+}
+
+int
+recompute_nonalloc_offsets (DSO *dso)
+{
+ int i, first_nonalloc, sec_before_shoff = 0;
+ GElf_Addr last_offset = 0;
+ GElf_Addr shdralign = gelf_fsize (dso->elf, ELF_T_ADDR, 1, EV_CURRENT);
+ GElf_Addr shdrsize = gelf_fsize (dso->elf, ELF_T_SHDR, 1, EV_CURRENT)
+ * dso->ehdr.e_shnum;
+
+ for (i = 1; i < dso->ehdr.e_shnum; ++i)
+ if (RELOCATE_SCN (dso->shdr[i].sh_flags))
+ {
+ if (dso->shdr[i].sh_type == SHT_NOBITS)
+ last_offset = dso->shdr[i].sh_offset;
+ else
+ last_offset = dso->shdr[i].sh_offset + dso->shdr[i].sh_size;
+ }
+ else
+ break;
+
+ first_nonalloc = i;
+ if (dso->ehdr.e_shoff < dso->shdr[i].sh_offset)
+ {
+ dso->ehdr.e_shoff = (last_offset + shdralign - 1) & ~(shdralign - 1);
+ last_offset = dso->ehdr.e_shoff + shdrsize;
+ }
+ else
+ for (; i < dso->ehdr.e_shnum; ++i)
+ if (dso->shdr[i].sh_offset < dso->ehdr.e_shoff
+ && (i == dso->ehdr.e_shnum - 1
+ || dso->shdr[i + 1].sh_offset > dso->ehdr.e_shoff))
+ {
+ sec_before_shoff = i;
+ break;
+ }
+
+ for (i = first_nonalloc; i < dso->ehdr.e_shnum; ++i)
+ {
+ assert (!RELOCATE_SCN (dso->shdr[i].sh_flags));
+ assert (dso->shdr[i].sh_type != SHT_NOBITS);
+ dso->shdr[i].sh_offset = (last_offset + dso->shdr[i].sh_addralign - 1)
+ & ~(dso->shdr[i].sh_addralign - 1);
+ last_offset = dso->shdr[i].sh_offset + dso->shdr[i].sh_size;
+ if (i == sec_before_shoff)
+ {
+ dso->ehdr.e_shoff = (last_offset + shdralign - 1) & ~(shdralign - 1);
+ last_offset = dso->ehdr.e_shoff + shdrsize;
+ }
+ }
+
+ return 0;
+}
+
+int
+strtabfind (DSO *dso, int strndx, const char *name)
+{
+ Elf_Scn *scn;
+ Elf_Data *data;
+ const char *p, *q, *r;
+ size_t len = strlen (name);
+
+ if (dso->shdr[strndx].sh_type != SHT_STRTAB)
+ return 0;
+
+ scn = dso->scn[strndx];
+ data = elf_getdata (scn, NULL);
+ assert (elf_getdata (scn, data) == NULL);
+ assert (data->d_off == 0);
+ assert (data->d_size == dso->shdr[strndx].sh_size);
+ q = data->d_buf + data->d_size;
+ for (p = data->d_buf; p < q; p = r + 1)
+ {
+ r = strchr (p, '\0');
+ if (r - p >= len && memcmp (r - len, name, len) == 0)
+ return (r - (const char *) data->d_buf) - len;
+ }
+
+ return 0;
+}
+
+int
+shstrtabadd (DSO *dso, const char *name)
+{
+ Elf_Scn *scn;
+ Elf_Data *data;
+ GElf_Addr adjust;
+ const char *p, *q, *r;
+ size_t len = strlen (name), align;
+ int ret;
+
+ scn = dso->scn[dso->ehdr.e_shstrndx];
+ data = elf_getdata (scn, NULL);
+ assert (elf_getdata (scn, data) == NULL);
+ assert (data->d_off == 0);
+ assert (data->d_size == dso->shdr[dso->ehdr.e_shstrndx].sh_size);
+ q = data->d_buf + data->d_size;
+ for (p = data->d_buf; p < q; p = r + 1)
+ {
+ r = strchr (p, '\0');
+ if (r - p >= len && memcmp (r - len, name, len) == 0)
+ return (r - (const char *) data->d_buf) - len;
+ }
+
+ data->d_buf = realloc (data->d_buf, data->d_size + len + 1);
+ if (data->d_buf == NULL)
+ {
+ error (0, ENOMEM, "Cannot add new section name %s", name);
+ return 0;
+ }
+
+ memcpy (data->d_buf + data->d_size, name, len + 1);
+ ret = data->d_size;
+ data->d_size += len + 1;
+ align = gelf_fsize (dso->elf, ELF_T_ADDR, 1, EV_CURRENT);
+ adjust = (len + 1 + align - 1) & ~(align - 1);
+ if (adjust_dso_nonalloc (dso, 0,
+ dso->shdr[dso->ehdr.e_shstrndx].sh_offset
+ + dso->shdr[dso->ehdr.e_shstrndx].sh_size,
+ adjust))
+ return 0;
+ dso->shdr[dso->ehdr.e_shstrndx].sh_size += len + 1;
+ return ret;
+}
+
+int
+relocate_dso (DSO *dso, GElf_Addr base)
+{
+ /* Check if it is already relocated. */
+ if (dso->base == base)
+ return 0;
+
+ if (! dso_is_rdwr (dso))
+ {
+ if (reopen_dso (dso, NULL, NULL))
+ return 1;
+ }
+
+ return adjust_dso (dso, 0, base - dso->base);
+}
+#endif /* DSO_READONLY */
+
+static int
+close_dso_1 (DSO *dso)
+{
+ if (dso_is_rdwr (dso))
+ {
+ int i;
+
+ for (i = 1; i < dso->ehdr.e_shnum; ++i)
+ {
+ Elf_Scn *scn = dso->scn[i];
+ Elf_Data *data = NULL;
+
+ while ((data = elf_getdata (scn, data)) != NULL)
+ {
+ free (data->d_buf);
+ data->d_buf = NULL;
+ }
+ }
+ }
+
+ elf_end (dso->elf);
+ fsync (dso->fd);
+ close (dso->fd);
+ if (dso->elfro)
+ {
+ elf_end (dso->elfro);
+ fsync (dso->fdro);
+ close (dso->fdro);
+ }
+ if (dso->filename != dso->soname)
+ free ((char *) dso->soname);
+ free ((char *) dso->filename);
+ free ((char *) dso->temp_filename);
+ free (dso->move);
+ free (dso->adjust);
+ free (dso->undo.d_buf);
+ free (dso);
+ return 0;
+}
+
+int
+close_dso (DSO *dso)
+{
+ int rdwr = dso_is_rdwr (dso);
+
+ if (rdwr && dso->temp_filename != NULL)
+ wrap_unlink (dso->temp_filename);
+ close_dso_1 (dso);
+ return 0;
+}
+
+#ifndef DSO_READONLY
+int
+prepare_write_dso (DSO *dso)
+{
+ int i;
+
+ if (check_dso (dso)
+ || (dso->mdebug_orig_offset && finalize_mdebug (dso)))
+ return 1;
+
+ gelf_update_ehdr (dso->elf, &dso->ehdr);
+ for (i = 0; i < dso->ehdr.e_phnum; ++i)
+ gelf_update_phdr (dso->elf, i, dso->phdr + i);
+ for (i = 0; i < dso->ehdr.e_shnum; ++i)
+ {
+ gelfx_update_shdr (dso->elf, dso->scn[i], dso->shdr + i);
+ if (dso->shdr[i].sh_type == SHT_SYMTAB
+ || dso->shdr[i].sh_type == SHT_DYNSYM)
+ set_stt_section_values (dso, i);
+ }
+ return 0;
+}
+
+int
+write_dso (DSO *dso)
+{
+ if (prepare_write_dso (dso))
+ return 1;
+
+ if (! dso->permissive && ELF_F_PERMISSIVE)
+ elf_flagelf (dso->elf, ELF_C_CLR, ELF_F_PERMISSIVE);
+
+ if (elf_update (dso->elf, ELF_C_WRITE) == -1)
+ return 2;
+ return 0;
+}
+
+static int
+copy_xattrs (const char *temp_name, const char *name, int ignore_errors)
+{
+ ssize_t sz = wrap_listxattr (name, NULL, 0), valsz = 0;
+ char *list = NULL, *end, *p, *val = NULL, *newval;
+
+ if (sz < 0)
+ {
+ if (errno == ENOSYS || errno == ENOTSUP)
+ return 0;
+ goto read_err;
+ }
+ list = malloc (sz + 1);
+ if (list == NULL)
+ goto read_err;
+ sz = wrap_listxattr (name, list, sz);
+ if (sz < 0)
+ goto read_err;
+ end = list + sz;
+ *end = '\0';
+ for (p = list; p != end; p = strchr (p, '\0') + 1)
+ if (*p == '\0' || strcmp (p, "security.selinux") == 0)
+ continue;
+ else
+ {
+ sz = wrap_getxattr (name, p, val, valsz);
+ if (sz < 0)
+ {
+ if (errno != ERANGE)
+ goto read_err;
+ sz = wrap_getxattr (name, p, NULL, 0);
+ if (sz < 0)
+ goto read_err;
+ }
+ if (sz > valsz)
+ {
+ valsz = sz * 2;
+ if (valsz < 64)
+ valsz = 64;
+ newval = realloc (val, valsz);
+ if (newval == NULL)
+ goto read_err;
+ val = newval;
+ sz = wrap_getxattr (name, p, val, valsz);
+ if (sz < 0)
+ goto read_err;
+ }
+ if (wrap_setxattr (temp_name, p, val, sz, 0) < 0)
+ {
+ if (errno == ENOSYS || errno == ENOTSUP)
+ continue;
+ if (!ignore_errors)
+ {
+ int err = errno;
+ ssize_t newsz;
+
+ newval = malloc (sz);
+ if (newval == NULL
+ || (newsz = wrap_getxattr (temp_name, p, newval, sz)) != sz
+ || memcmp (val, newval, sz) != 0)
+ {
+ error (0, err, "Could not set extended attributes for %s",
+ name);
+ free (newval);
+ free (val);
+ free (list);
+ return 1;
+ }
+ free (newval);
+ }
+ }
+ }
+ free (val);
+ free (list);
+ return 0;
+
+read_err:
+ error (0, errno, "Could not get extended attributes for %s", name);
+ free (val);
+ free (list);
+ return 1;
+}
+
+static int
+set_security_context (const char *temp_name, const char *name,
+ int ignore_errors)
+{
+#ifdef USE_SELINUX
+ static int selinux_enabled = -1;
+ if (selinux_enabled == -1)
+ selinux_enabled = is_selinux_enabled ();
+ if (selinux_enabled > 0)
+ {
+ security_context_t scontext;
+ if (getfilecon (name, &scontext) < 0)
+ {
+ /* If the filesystem doesn't support extended attributes,
+ the original had no special security context and the
+ target cannot have one either. */
+ if (errno == EOPNOTSUPP)
+ return 0;
+
+ error (0, errno, "Could not get security context for %s",
+ name);
+ return 1;
+ }
+ if (setfilecon (temp_name, scontext) < 0 && !ignore_errors)
+ {
+ error (0, errno, "Could not set security context for %s",
+ name);
+ freecon (scontext);
+ return 1;
+ }
+ freecon (scontext);
+ }
+#endif /* USE_SELINUX */
+ return copy_xattrs (temp_name, name, ignore_errors);
+}
+
+int
+copy_fd_to_file (int fdin, const char *name, struct stat64 *st)
+{
+ struct stat64 stt;
+ off_t off = 0;
+ int err, fdout;
+ struct utimbuf u;
+
+ if (strcmp (name, "-") == 0)
+ fdout = 1;
+ else
+ fdout = wrap_open (name, O_WRONLY | O_CREAT, 0600);
+ if (fdout != -1
+ && fstat64 (fdin, &stt) >= 0
+ && send_file (fdout, fdin, &off, stt.st_size) == stt.st_size)
+ {
+ if (fchown (fdout, st->st_uid, st->st_gid) >= 0)
+ fchmod (fdout, st->st_mode & 07777);
+ if (strcmp (name, "-") != 0)
+ {
+ set_security_context (name, name, 1);
+ u.actime = time (NULL);
+ u.modtime = st->st_mtime;
+ wrap_utime (name, &u);
+ close (fdout);
+ }
+ return 0;
+ }
+ else if (fdout != -1)
+ {
+ err = errno;
+ if (strcmp (name, "-") == 0)
+ close (fdout);
+ }
+ else
+ err = errno;
+ return err;
+}
+
+int
+update_dso (DSO *dso, const char *orig_name)
+{
+ int rdwr = dso_is_rdwr (dso);
+
+ if (rdwr)
+ {
+ char *name1, *name2;
+ struct utimbuf u;
+ struct stat64 st;
+ int fdin;
+
+ switch (write_dso (dso))
+ {
+ case 2:
+ error (0, 0, "Could not write %s: %s", dso->filename,
+ elf_errmsg (-1));
+ /* FALLTHROUGH */
+ case 1:
+ close_dso (dso);
+ return 1;
+ case 0:
+ break;
+ }
+
+ name1 = strdupa (dso->filename);
+ name2 = strdupa (dso->temp_filename);
+ if (fstat64 (dso->fdro, &st) < 0)
+ {
+ error (0, errno, "Could not stat %s", dso->filename);
+ close_dso (dso);
+ return 1;
+ }
+ if ((fchown (dso->fd, st.st_uid, st.st_gid) < 0
+ || fchmod (dso->fd, st.st_mode & 07777) < 0)
+ && orig_name == NULL)
+ {
+ error (0, errno, "Could not set %s owner or mode", dso->filename);
+ close_dso (dso);
+ return 1;
+ }
+ if (orig_name != NULL)
+ fdin = dup (dso->fd);
+ else
+ fdin = -1;
+ close_dso_1 (dso);
+ u.actime = time (NULL);
+ u.modtime = st.st_mtime;
+ wrap_utime (name2, &u);
+
+ if (set_security_context (name2, orig_name ? orig_name : name1,
+ orig_name != NULL))
+ {
+ if (fdin != -1)
+ close (fdin);
+ wrap_unlink (name2);
+ return 1;
+ }
+
+ if ((orig_name != NULL && strcmp (name1, "-") == 0)
+ || wrap_rename (name2, name1))
+ {
+ if (fdin != -1)
+ {
+ int err = copy_fd_to_file (fdin, name1, &st);
+
+ close (fdin);
+ wrap_unlink (name2);
+ if (err == 0)
+ return 0;
+ error (0, err, "Could not rename nor copy temporary to %s",
+ name1);
+ return 1;
+ }
+ wrap_unlink (name2);
+ error (0, errno, "Could not rename temporary to %s", name1);
+ return 1;
+ }
+ if (fdin != -1)
+ close (fdin);
+ }
+ else
+ close_dso_1 (dso);
+
+ return 0;
+}
+
+int allow_bad_textrel;
+
+int
+dso_has_bad_textrel (DSO *dso)
+{
+ if (allow_bad_textrel)
+ return 0;
+
+ switch (dso->arch->machine)
+ {
+ case EM_IA_64:
+ case EM_PPC:
+ case EM_PPC64:
+ case EM_X86_64:
+ case EM_ALPHA:
+ case EM_S390:
+ case EM_MIPS:
+ case EM_ARM:
+ return dynamic_info_is_set (dso, DT_TEXTREL);
+
+ default:
+ return 0;
+ }
+}
+#endif /* DSO_READONLY */
diff --git a/src/dwarf2.c b/src/dwarf2.c
new file mode 100644
index 0000000..b9588b1
--- /dev/null
+++ b/src/dwarf2.c
@@ -0,0 +1,1388 @@
+/* Copyright (C) 2001, 2002, 2003, 2005, 2006, 2009, 2010, 2011, 2012
+ Red Hat, Inc.
+ Written by Jakub Jelinek <jakub@redhat.com>, 2001.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include <config.h>
+#include <assert.h>
+#include <byteswap.h>
+#include <endian.h>
+#include <errno.h>
+#include <error.h>
+#include <limits.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include "dwarf2.h"
+#include "hashtab.h"
+#include "prelink.h"
+
+#define read_uleb128(ptr) ({ \
+ unsigned int ret = 0; \
+ unsigned int c; \
+ int shift = 0; \
+ do \
+ { \
+ c = *ptr++; \
+ ret |= (c & 0x7f) << shift; \
+ shift += 7; \
+ } while (c & 0x80); \
+ \
+ if (shift >= 35) \
+ ret = UINT_MAX; \
+ ret; \
+})
+
+static uint16_t (*do_read_16) (unsigned char *ptr);
+static uint32_t (*do_read_32) (unsigned char *ptr);
+static uint64_t (*do_read_32_64) (unsigned char *ptr);
+static uint64_t (*do_read_64) (unsigned char *ptr);
+static uint64_t (*do_read_ptr) (unsigned char *ptr);
+static void (*write_32) (unsigned char *ptr, GElf_Addr val);
+static void (*write_64) (unsigned char *ptr, GElf_Addr val);
+static void (*write_ptr) (unsigned char *ptr, GElf_Addr val);
+
+static int ptr_size;
+
+#define read_1(ptr) *ptr++
+
+#define read_16(ptr) ({ \
+ uint16_t ret = do_read_16 (ptr); \
+ ptr += 2; \
+ ret; \
+})
+
+#define read_32(ptr) ({ \
+ uint32_t ret = do_read_32 (ptr); \
+ ptr += 4; \
+ ret; \
+})
+
+#define read_64(ptr) ({ \
+ uint64_t ret = do_read_64 (ptr); \
+ ptr += 8; \
+ ret; \
+})
+
+#define read_ptr(ptr) ({ \
+ uint64_t ret = do_read_ptr (ptr); \
+ ptr += ptr_size; \
+ ret; \
+})
+
+static uint64_t
+buf_read_ule32_64 (unsigned char *p)
+{
+ return buf_read_ule32 (p);
+}
+
+static uint64_t
+buf_read_ube32_64 (unsigned char *p)
+{
+ return buf_read_ube32 (p);
+}
+
+static void
+dwarf2_write_le32 (unsigned char *p, GElf_Addr val)
+{
+ uint32_t v = (uint32_t) val;
+
+ p[0] = v;
+ p[1] = v >> 8;
+ p[2] = v >> 16;
+ p[3] = v >> 24;
+}
+
+static void
+dwarf2_write_le64 (unsigned char *p, GElf_Addr val)
+{
+ p[0] = val;
+ p[1] = val >> 8;
+ p[2] = val >> 16;
+ p[3] = val >> 24;
+ p[4] = val >> 32;
+ p[5] = val >> 40;
+ p[6] = val >> 48;
+ p[7] = val >> 56;
+}
+
+static void
+dwarf2_write_be32 (unsigned char *p, GElf_Addr val)
+{
+ uint32_t v = (uint32_t) val;
+
+ p[3] = v;
+ p[2] = v >> 8;
+ p[1] = v >> 16;
+ p[0] = v >> 24;
+}
+
+static void
+dwarf2_write_be64 (unsigned char *p, GElf_Addr val)
+{
+ p[7] = val;
+ p[6] = val >> 8;
+ p[5] = val >> 16;
+ p[4] = val >> 24;
+ p[3] = val >> 32;
+ p[2] = val >> 40;
+ p[1] = val >> 48;
+ p[0] = val >> 56;
+}
+
+static struct
+ {
+ const char *name;
+ unsigned char *data;
+ size_t size;
+ int sec;
+ } debug_sections[] =
+ {
+#define DEBUG_INFO 0
+#define DEBUG_ABBREV 1
+#define DEBUG_LINE 2
+#define DEBUG_ARANGES 3
+#define DEBUG_PUBNAMES 4
+#define DEBUG_PUBTYPES 5
+#define DEBUG_MACINFO 6
+#define DEBUG_LOC 7
+#define DEBUG_STR 8
+#define DEBUG_FRAME 9
+#define DEBUG_RANGES 10
+#define DEBUG_TYPES 11
+#define DEBUG_MACRO 12
+ { ".debug_info", NULL, 0, 0 },
+ { ".debug_abbrev", NULL, 0, 0 },
+ { ".debug_line", NULL, 0, 0 },
+ { ".debug_aranges", NULL, 0, 0 },
+ { ".debug_pubnames", NULL, 0, 0 },
+ { ".debug_pubtypes", NULL, 0, 0 },
+ { ".debug_macinfo", NULL, 0, 0 },
+ { ".debug_loc", NULL, 0, 0 },
+ { ".debug_str", NULL, 0, 0 },
+ { ".debug_frame", NULL, 0, 0 },
+ { ".debug_ranges", NULL, 0, 0 },
+ { ".debug_types", NULL, 0, 0 },
+ { ".debug_macro", NULL, 0, 0 },
+ { NULL, NULL, 0 }
+ };
+
+struct abbrev_attr
+ {
+ unsigned int attr;
+ unsigned int form;
+ };
+
+struct abbrev_tag
+ {
+ unsigned int entry;
+ unsigned int tag;
+ int nattr;
+ struct abbrev_attr attr[0];
+ };
+
+struct cu_data
+ {
+ GElf_Addr cu_entry_pc;
+ GElf_Addr cu_low_pc;
+ unsigned char cu_version;
+ };
+
+static hashval_t
+abbrev_hash (const void *p)
+{
+ struct abbrev_tag *t = (struct abbrev_tag *)p;
+
+ return t->entry;
+}
+
+static int
+abbrev_eq (const void *p, const void *q)
+{
+ struct abbrev_tag *t1 = (struct abbrev_tag *)p;
+ struct abbrev_tag *t2 = (struct abbrev_tag *)q;
+
+ return t1->entry == t2->entry;
+}
+
+static void
+abbrev_del (void *p)
+{
+ free (p);
+}
+
+static htab_t
+read_abbrev (DSO *dso, unsigned char *ptr)
+{
+ htab_t h = htab_try_create (50, abbrev_hash, abbrev_eq, abbrev_del);
+ unsigned int attr, form;
+ struct abbrev_tag *t;
+ int size;
+ void **slot;
+
+ if (h == NULL)
+ {
+no_memory:
+ error (0, ENOMEM, "%s: Could not read .debug_abbrev", dso->filename);
+ if (h)
+ htab_delete (h);
+ return NULL;
+ }
+
+ while ((attr = read_uleb128 (ptr)) != 0)
+ {
+ size = 10;
+ t = malloc (sizeof (*t) + size * sizeof (struct abbrev_attr));
+ if (t == NULL)
+ goto no_memory;
+ t->entry = attr;
+ t->nattr = 0;
+ slot = htab_find_slot (h, t, INSERT);
+ if (slot == NULL)
+ {
+ free (t);
+ goto no_memory;
+ }
+ if (*slot != NULL)
+ {
+ error (0, 0, "%s: Duplicate DWARF abbreviation %d", dso->filename,
+ t->entry);
+ free (t);
+ htab_delete (h);
+ return NULL;
+ }
+ t->tag = read_uleb128 (ptr);
+ ++ptr; /* skip children flag. */
+ while ((attr = read_uleb128 (ptr)) != 0)
+ {
+ if (t->nattr == size)
+ {
+ size += 10;
+ t = realloc (t, sizeof (*t) + size * sizeof (struct abbrev_attr));
+ if (t == NULL)
+ goto no_memory;
+ }
+ form = read_uleb128 (ptr);
+ if (form == 2
+ || (form > DW_FORM_flag_present
+ && form != DW_FORM_ref_sig8
+ && form != DW_FORM_GNU_ref_alt
+ && form != DW_FORM_GNU_strp_alt))
+ {
+ error (0, 0, "%s: Unknown DWARF DW_FORM_%d", dso->filename, form);
+ htab_delete (h);
+ return NULL;
+ }
+
+ t->attr[t->nattr].attr = attr;
+ t->attr[t->nattr++].form = form;
+ }
+ if (read_uleb128 (ptr) != 0)
+ {
+ error (0, 0, "%s: DWARF abbreviation does not end with 2 zeros",
+ dso->filename);
+ htab_delete (h);
+ return NULL;
+ }
+ *slot = t;
+ }
+
+ return h;
+}
+
+static int
+adjust_location_list (DSO *dso, struct cu_data *cu, unsigned char *ptr,
+ size_t len, GElf_Addr start, GElf_Addr adjust)
+{
+ unsigned char *end = ptr + len;
+ unsigned char op;
+ GElf_Addr addr;
+
+ while (ptr < end)
+ {
+ op = *ptr++;
+ switch (op)
+ {
+ case DW_OP_addr:
+ addr = read_ptr (ptr);
+ if (addr >= start && addr_to_sec (dso, addr) != -1)
+ write_ptr (ptr - ptr_size, addr + adjust);
+ break;
+ case DW_OP_deref:
+ case DW_OP_dup:
+ case DW_OP_drop:
+ case DW_OP_over:
+ case DW_OP_swap:
+ case DW_OP_rot:
+ case DW_OP_xderef:
+ case DW_OP_abs:
+ case DW_OP_and:
+ case DW_OP_div:
+ case DW_OP_minus:
+ case DW_OP_mod:
+ case DW_OP_mul:
+ case DW_OP_neg:
+ case DW_OP_not:
+ case DW_OP_or:
+ case DW_OP_plus:
+ case DW_OP_shl:
+ case DW_OP_shr:
+ case DW_OP_shra:
+ case DW_OP_xor:
+ case DW_OP_eq:
+ case DW_OP_ge:
+ case DW_OP_gt:
+ case DW_OP_le:
+ case DW_OP_lt:
+ case DW_OP_ne:
+ case DW_OP_lit0 ... DW_OP_lit31:
+ case DW_OP_reg0 ... DW_OP_reg31:
+ case DW_OP_nop:
+ case DW_OP_push_object_address:
+ case DW_OP_form_tls_address:
+ case DW_OP_call_frame_cfa:
+ case DW_OP_stack_value:
+ case DW_OP_GNU_push_tls_address:
+ case DW_OP_GNU_uninit:
+ break;
+ case DW_OP_const1u:
+ case DW_OP_pick:
+ case DW_OP_deref_size:
+ case DW_OP_xderef_size:
+ case DW_OP_const1s:
+ ++ptr;
+ break;
+ case DW_OP_const2u:
+ case DW_OP_const2s:
+ case DW_OP_skip:
+ case DW_OP_bra:
+ case DW_OP_call2:
+ ptr += 2;
+ break;
+ case DW_OP_const4u:
+ case DW_OP_const4s:
+ case DW_OP_call4:
+ case DW_OP_GNU_parameter_ref:
+ ptr += 4;
+ break;
+ case DW_OP_call_ref:
+ if (cu == NULL)
+ {
+ error (0, 0, "%s: DWARF DW_OP_call_ref shouldn't appear"
+ " in .debug_frame", dso->filename);
+ return 1;
+ }
+ if (cu->cu_version == 2)
+ ptr += ptr_size;
+ else
+ ptr += 4;
+ break;
+ case DW_OP_const8u:
+ case DW_OP_const8s:
+ ptr += 8;
+ break;
+ case DW_OP_constu:
+ case DW_OP_plus_uconst:
+ case DW_OP_regx:
+ case DW_OP_piece:
+ case DW_OP_consts:
+ case DW_OP_breg0 ... DW_OP_breg31:
+ case DW_OP_fbreg:
+ case DW_OP_GNU_convert:
+ case DW_OP_GNU_reinterpret:
+ read_uleb128 (ptr);
+ break;
+ case DW_OP_bregx:
+ case DW_OP_bit_piece:
+ case DW_OP_GNU_regval_type:
+ read_uleb128 (ptr);
+ read_uleb128 (ptr);
+ break;
+ case DW_OP_implicit_value:
+ {
+ uint32_t leni = read_uleb128 (ptr);
+ ptr += leni;
+ }
+ break;
+ case DW_OP_GNU_implicit_pointer:
+ if (cu == NULL)
+ {
+ error (0, 0, "%s: DWARF DW_OP_GNU_implicit_pointer shouldn't"
+ " appear in .debug_frame", dso->filename);
+ return 1;
+ }
+ if (cu->cu_version == 2)
+ ptr += ptr_size;
+ else
+ ptr += 4;
+ read_uleb128 (ptr);
+ break;
+ case DW_OP_GNU_entry_value:
+ {
+ uint32_t leni = read_uleb128 (ptr);
+ if ((end - ptr) < leni)
+ {
+ error (0, 0, "%s: DWARF DW_OP_GNU_entry_value with too large"
+ " length", dso->filename);
+ return 1;
+ }
+ if (adjust_location_list (dso, cu, ptr, leni, start, adjust))
+ return 1;
+ ptr += leni;
+ }
+ break;
+ case DW_OP_GNU_const_type:
+ read_uleb128 (ptr);
+ ptr += *ptr + 1;
+ break;
+ case DW_OP_GNU_deref_type:
+ ++ptr;
+ read_uleb128 (ptr);
+ break;
+ default:
+ error (0, 0, "%s: Unknown DWARF DW_OP_%d", dso->filename, op);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int
+adjust_dwarf2_ranges (DSO *dso, GElf_Addr offset, GElf_Addr base,
+ GElf_Addr start, GElf_Addr adjust)
+{
+ unsigned char *ptr, *endsec;
+ GElf_Addr low, high;
+ int adjusted_base;
+
+ ptr = debug_sections[DEBUG_RANGES].data;
+ if (ptr == NULL)
+ {
+ error (0, 0, "%s: DW_AT_ranges attribute, yet no .debug_ranges section",
+ dso->filename);
+ return 1;
+ }
+ if (offset >= debug_sections[DEBUG_RANGES].size)
+ {
+ error (0, 0,
+ "%s: DW_AT_ranges offset %Ld outside of .debug_ranges section",
+ dso->filename, (long long) offset);
+ return 1;
+ }
+ endsec = ptr + debug_sections[DEBUG_RANGES].size;
+ ptr += offset;
+ adjusted_base = (base && base >= start && addr_to_sec (dso, base) != -1);
+ while (ptr < endsec)
+ {
+ low = read_ptr (ptr);
+ high = read_ptr (ptr);
+ if (low == 0 && high == 0)
+ break;
+
+ if (low == ~ (GElf_Addr) 0 || (ptr_size == 4 && low == 0xffffffff))
+ {
+ base = high;
+ adjusted_base = (base && base >= start
+ && addr_to_sec (dso, base) != -1);
+ if (adjusted_base)
+ write_ptr (ptr - ptr_size, base + adjust);
+ }
+ else if (! adjusted_base)
+ {
+ if (base + low >= start && addr_to_sec (dso, base + low) != -1)
+ {
+ write_ptr (ptr - 2 * ptr_size, low + adjust);
+ if (high == low)
+ write_ptr (ptr - ptr_size, high + adjust);
+ }
+ if (low != high && base + high >= start
+ && addr_to_sec (dso, base + high - 1) != -1)
+ write_ptr (ptr - ptr_size, high + adjust);
+ }
+ }
+
+ elf_flagscn (dso->scn[debug_sections[DEBUG_RANGES].sec], ELF_C_SET,
+ ELF_F_DIRTY);
+ return 0;
+}
+
+static int
+adjust_dwarf2_loc (DSO *dso, struct cu_data *cu, GElf_Addr offset,
+ GElf_Addr base, GElf_Addr start, GElf_Addr adjust)
+{
+ unsigned char *ptr, *endsec;
+ GElf_Addr low, high;
+ int adjusted_base;
+ size_t len;
+
+ ptr = debug_sections[DEBUG_LOC].data;
+ if (ptr == NULL)
+ {
+ error (0, 0, "%s: loclistptr attribute, yet no .debug_loc section",
+ dso->filename);
+ return 1;
+ }
+ if (offset >= debug_sections[DEBUG_LOC].size)
+ {
+ error (0, 0,
+ "%s: loclistptr offset %Ld outside of .debug_loc section",
+ dso->filename, (long long) offset);
+ return 1;
+ }
+ endsec = ptr + debug_sections[DEBUG_LOC].size;
+ ptr += offset;
+ adjusted_base = (base && base >= start && addr_to_sec (dso, base) != -1);
+ while (ptr < endsec)
+ {
+ low = read_ptr (ptr);
+ high = read_ptr (ptr);
+ if (low == 0 && high == 0)
+ break;
+
+ if (low == ~ (GElf_Addr) 0 || (ptr_size == 4 && low == 0xffffffff))
+ {
+ base = high;
+ adjusted_base = (base && base >= start
+ && addr_to_sec (dso, base) != -1);
+ if (adjusted_base)
+ write_ptr (ptr - ptr_size, base + adjust);
+ continue;
+ }
+ len = read_16 (ptr);
+ assert (ptr + len <= endsec);
+
+ if (adjust_location_list (dso, cu, ptr, len, start, adjust))
+ return 1;
+
+ ptr += len;
+ }
+
+ elf_flagscn (dso->scn[debug_sections[DEBUG_LOC].sec], ELF_C_SET,
+ ELF_F_DIRTY);
+ return 0;
+}
+
+static unsigned char *
+adjust_attributes (DSO *dso, unsigned char *ptr, struct abbrev_tag *t,
+ struct cu_data *cu,
+ GElf_Addr start, GElf_Addr adjust, htab_t offset_hash)
+{
+ int i;
+ GElf_Addr addr;
+
+ for (i = 0; i < t->nattr; ++i)
+ {
+ uint32_t form = t->attr[i].form;
+ uint32_t len = 0;
+
+ while (1)
+ {
+ switch (t->attr[i].attr)
+ {
+ case DW_AT_data_member_location:
+ /* In DWARF4+ DW_AT_data_member_location
+ with DW_FORM_data[48] is just very high
+ constant, rather than loclistptr. */
+ if (cu->cu_version >= 4 && form != DW_FORM_sec_offset)
+ break;
+ /* FALLTHRU */
+ case DW_AT_location:
+ case DW_AT_string_length:
+ case DW_AT_return_addr:
+ case DW_AT_frame_base:
+ case DW_AT_segment:
+ case DW_AT_static_link:
+ case DW_AT_use_location:
+ case DW_AT_vtable_elem_location:
+ case DW_AT_ranges:
+ if (form == DW_FORM_data4 || form == DW_FORM_sec_offset)
+ addr = read_32 (ptr), ptr -= 4;
+ else if (form == DW_FORM_data8)
+ addr = read_64 (ptr), ptr -= 8;
+ else
+ break;
+ {
+ GElf_Addr base;
+
+ if (cu->cu_entry_pc != ~ (GElf_Addr) 0)
+ base = cu->cu_entry_pc;
+ else if (cu->cu_low_pc != ~ (GElf_Addr) 0)
+ base = cu->cu_low_pc;
+ else
+ base = 0;
+ if (t->attr[i].attr == DW_AT_ranges)
+ {
+ if (adjust_dwarf2_ranges (dso, addr, base, start, adjust))
+ return NULL;
+ }
+ else
+ {
+ GElf_Addr *offsetp = malloc (sizeof (addr));
+ void **slot;
+ if (offsetp == NULL)
+ return NULL;
+ *offsetp = addr;
+ slot = htab_find_slot (offset_hash, offsetp, INSERT);
+ if (slot == NULL)
+ {
+ free (offsetp);
+ return NULL;
+ }
+ if (*slot == NULL)
+ {
+ *slot = offsetp;
+ if (adjust_dwarf2_loc (dso, cu, addr, base,
+ start, adjust))
+ return NULL;
+ }
+ else
+ free (offsetp);
+ }
+ }
+ break;
+ }
+ switch (form)
+ {
+ case DW_FORM_addr:
+ addr = read_ptr (ptr);
+ if (t->tag == DW_TAG_compile_unit
+ || t->tag == DW_TAG_partial_unit)
+ {
+ if (t->attr[i].attr == DW_AT_entry_pc)
+ cu->cu_entry_pc = addr;
+ else if (t->attr[i].attr == DW_AT_low_pc)
+ cu->cu_low_pc = addr;
+ if (addr == 0)
+ break;
+ }
+ if (addr >= start
+ && addr_to_sec (dso,
+ ((t->attr[i].attr == DW_AT_high_pc
+ && addr > start)
+ ? addr - 1
+ : addr)) != -1)
+ write_ptr (ptr - ptr_size, addr + adjust);
+ break;
+ case DW_FORM_flag_present:
+ break;
+ case DW_FORM_ref1:
+ case DW_FORM_flag:
+ case DW_FORM_data1:
+ ++ptr;
+ break;
+ case DW_FORM_ref2:
+ case DW_FORM_data2:
+ ptr += 2;
+ break;
+ case DW_FORM_ref4:
+ case DW_FORM_GNU_ref_alt:
+ case DW_FORM_data4:
+ case DW_FORM_sec_offset:
+ ptr += 4;
+ break;
+ case DW_FORM_ref8:
+ case DW_FORM_data8:
+ case DW_FORM_ref_sig8:
+ ptr += 8;
+ break;
+ case DW_FORM_sdata:
+ case DW_FORM_ref_udata:
+ case DW_FORM_udata:
+ read_uleb128 (ptr);
+ break;
+ case DW_FORM_ref_addr:
+ if (cu->cu_version == 2)
+ ptr += ptr_size;
+ else
+ ptr += 4;
+ break;
+ case DW_FORM_strp:
+ case DW_FORM_GNU_strp_alt:
+ ptr += 4;
+ break;
+ case DW_FORM_string:
+ ptr = strchr (ptr, '\0') + 1;
+ break;
+ case DW_FORM_indirect:
+ form = read_uleb128 (ptr);
+ continue;
+ case DW_FORM_block1:
+ len = *ptr++;
+ break;
+ case DW_FORM_block2:
+ len = read_16 (ptr);
+ form = DW_FORM_block1;
+ break;
+ case DW_FORM_block4:
+ len = read_32 (ptr);
+ form = DW_FORM_block1;
+ break;
+ case DW_FORM_block:
+ len = read_uleb128 (ptr);
+ form = DW_FORM_block1;
+ assert (len < UINT_MAX);
+ break;
+ case DW_FORM_exprloc:
+ len = read_uleb128 (ptr);
+ assert (len < UINT_MAX);
+ break;
+ default:
+ error (0, 0, "%s: Unknown DWARF DW_FORM_%d", dso->filename,
+ form);
+ return NULL;
+ }
+
+ if (form == DW_FORM_block1)
+ {
+ switch (t->attr[i].attr)
+ {
+ case DW_AT_frame_base:
+ case DW_AT_location:
+ case DW_AT_data_member_location:
+ case DW_AT_vtable_elem_location:
+ case DW_AT_byte_size:
+ case DW_AT_bit_offset:
+ case DW_AT_bit_size:
+ case DW_AT_string_length:
+ case DW_AT_lower_bound:
+ case DW_AT_return_addr:
+ case DW_AT_bit_stride:
+ case DW_AT_upper_bound:
+ case DW_AT_count:
+ case DW_AT_segment:
+ case DW_AT_static_link:
+ case DW_AT_use_location:
+ case DW_AT_allocated:
+ case DW_AT_associated:
+ case DW_AT_data_location:
+ case DW_AT_byte_stride:
+ case DW_AT_GNU_call_site_value:
+ case DW_AT_GNU_call_site_data_value:
+ case DW_AT_GNU_call_site_target:
+ case DW_AT_GNU_call_site_target_clobbered:
+ if (adjust_location_list (dso, cu, ptr, len, start, adjust))
+ return NULL;
+ break;
+ default:
+ if (t->attr[i].attr <= DW_AT_linkage_name
+ || (t->attr[i].attr >= DW_AT_MIPS_fde
+ && t->attr[i].attr <= DW_AT_MIPS_has_inlines)
+ || (t->attr[i].attr >= DW_AT_sf_names
+ && t->attr[i].attr <= DW_AT_body_end))
+ break;
+ error (0, 0, "%s: Unknown DWARF DW_AT_%d with block DW_FORM",
+ dso->filename, t->attr[i].attr);
+ return NULL;
+ }
+ ptr += len;
+ }
+ else if (form == DW_FORM_exprloc)
+ {
+ if (adjust_location_list (dso, cu, ptr, len, start, adjust))
+ return NULL;
+ ptr += len;
+ }
+
+ break;
+ }
+ }
+
+ return ptr;
+}
+
+static int
+adjust_dwarf2_line (DSO *dso, GElf_Addr start, GElf_Addr adjust)
+{
+ unsigned char *ptr = debug_sections[DEBUG_LINE].data;
+ unsigned char *endsec = ptr + debug_sections[DEBUG_LINE].size;
+ unsigned char *endcu, *endprol;
+ unsigned char opcode_base, *opcode_lengths, op;
+ uint32_t value;
+ GElf_Addr addr;
+ int i;
+
+ while (ptr < endsec)
+ {
+ endcu = ptr + 4;
+ endcu += read_32 (ptr);
+ if (endcu == ptr + 0xffffffff)
+ {
+ error (0, 0, "%s: 64-bit DWARF not supported", dso->filename);
+ return 1;
+ }
+
+ if (endcu > endsec)
+ {
+ error (0, 0, "%s: .debug_line CU does not fit into section",
+ dso->filename);
+ return 1;
+ }
+
+ value = read_16 (ptr);
+ if (value != 2 && value != 3 && value != 4)
+ {
+ error (0, 0, "%s: DWARF version %d unhandled", dso->filename,
+ value);
+ return 1;
+ }
+
+ endprol = ptr + 4;
+ endprol += read_32 (ptr);
+ if (endprol > endcu)
+ {
+ error (0, 0, "%s: .debug_line CU prologue does not fit into CU",
+ dso->filename);
+ return 1;
+ }
+
+ opcode_base = ptr[4 + (value >= 4)];
+ opcode_lengths = ptr + 4 + (value >= 4);
+
+ ptr = endprol;
+ while (ptr < endcu)
+ {
+ op = *ptr++;
+ if (op >= opcode_base)
+ continue;
+ if (op == DW_LNS_extended_op)
+ {
+ unsigned int len = read_uleb128 (ptr);
+
+ assert (len < UINT_MAX);
+ op = *ptr++;
+ switch (op)
+ {
+ case DW_LNE_set_address:
+ addr = read_ptr (ptr);
+ if (addr >= start && addr_to_sec (dso, addr) != -1)
+ write_ptr (ptr - ptr_size, addr + adjust);
+ break;
+ case DW_LNE_end_sequence:
+ case DW_LNE_define_file:
+ case DW_LNE_set_discriminator:
+ default:
+ ptr += len - 1;
+ break;
+ }
+ }
+ else if (op == DW_LNS_fixed_advance_pc)
+ ptr += 2;
+ else
+ for (i = 0; i < opcode_lengths[op]; ++i)
+ read_uleb128 (ptr);
+ }
+ }
+
+ elf_flagscn (dso->scn[debug_sections[DEBUG_LINE].sec], ELF_C_SET,
+ ELF_F_DIRTY);
+ return 0;
+}
+
+static int
+adjust_dwarf2_aranges (DSO *dso, GElf_Addr start, GElf_Addr adjust)
+{
+ unsigned char *ptr = debug_sections[DEBUG_ARANGES].data;
+ unsigned char *endsec = ptr + debug_sections[DEBUG_ARANGES].size;
+ unsigned char *endcu;
+ GElf_Addr addr, len;
+ uint32_t value;
+
+ while (ptr < endsec)
+ {
+ endcu = ptr + 4;
+ endcu += read_32 (ptr);
+ if (endcu == ptr + 0xffffffff)
+ {
+ error (0, 0, "%s: 64-bit DWARF not supported", dso->filename);
+ return 1;
+ }
+
+ if (endcu > endsec)
+ {
+ error (0, 0, "%s: .debug_line CU does not fit into section",
+ dso->filename);
+ return 1;
+ }
+
+ value = read_16 (ptr);
+ if (value != 2)
+ {
+ error (0, 0, "%s: DWARF version %d unhandled", dso->filename,
+ value);
+ return 1;
+ }
+
+ ptr += 4;
+ if (ptr[0] != ptr_size || ptr[1])
+ {
+ error (0, 0, "%s: Unsupported .debug_aranges address size %d or segment size %d",
+ dso->filename, ptr[0], ptr[1]);
+ return 1;
+ }
+
+ ptr += 6;
+ while (ptr < endcu)
+ {
+ addr = read_ptr (ptr);
+ len = read_ptr (ptr);
+ if (addr == 0 && len == 0)
+ break;
+ if (addr >= start && addr_to_sec (dso, addr) != -1)
+ write_ptr (ptr - 2 * ptr_size, addr + adjust);
+ }
+ assert (ptr == endcu);
+ }
+
+ elf_flagscn (dso->scn[debug_sections[DEBUG_LINE].sec], ELF_C_SET,
+ ELF_F_DIRTY);
+ return 0;
+}
+
+static int
+adjust_dwarf2_frame (DSO *dso, GElf_Addr start, GElf_Addr adjust)
+{
+ unsigned char *ptr = debug_sections[DEBUG_FRAME].data;
+ unsigned char *endsec = ptr + debug_sections[DEBUG_FRAME].size;
+ unsigned char *endie;
+ GElf_Addr addr, len;
+ uint32_t value;
+
+ while (ptr < endsec)
+ {
+ endie = ptr + 4;
+ endie += read_32 (ptr);
+ if (endie == ptr + 0xffffffff)
+ {
+ error (0, 0, "%s: 64-bit DWARF not supported", dso->filename);
+ return 1;
+ }
+
+ if (endie > endsec)
+ {
+ error (0, 0, "%s: .debug_frame CIE/FDE does not fit into section",
+ dso->filename);
+ return 1;
+ }
+
+ value = read_32 (ptr);
+ if (value == 0xffffffff)
+ {
+ /* CIE. */
+ uint32_t version = *ptr++;
+ if (version != 1 && version != 3 && version != 4)
+ {
+ error (0, 0, "%s: unhandled .debug_frame version %d",
+ dso->filename, version);
+ return 1;
+ }
+ if (*ptr == 'S')
+ {
+ /* This is a signal frame. We don't care. */
+ ptr++;
+ }
+ if (*ptr != '\0')
+ {
+ error (0, 0, "%s: .debug_frame unhandled augmentation \"%s\"",
+ dso->filename, ptr);
+ return 1;
+ }
+ ptr++; /* Skip augmentation. */
+ if (version >= 4)
+ {
+ if (ptr[0] != ptr_size)
+ {
+ error (0, 0, "%s: .debug_frame unhandled pointer size %d",
+ dso->filename, ptr[0]);
+ return 1;
+ }
+ if (ptr[1] != 0)
+ {
+ error (0, 0, "%s: .debug_frame unhandled non-zero segment size",
+ dso->filename);
+ return 1;
+ }
+ ptr += 2;
+ }
+ read_uleb128 (ptr); /* Skip code_alignment factor. */
+ read_uleb128 (ptr); /* Skip data_alignment factor. */
+ if (version >= 3)
+ read_uleb128 (ptr); /* Skip return_address_register. */
+ else
+ ptr++;
+ }
+ else
+ {
+ addr = read_ptr (ptr);
+ if (addr >= start && addr_to_sec (dso, addr) != -1)
+ write_ptr (ptr - ptr_size, addr + adjust);
+ read_ptr (ptr); /* Skip address range. */
+ }
+
+ while (ptr < endie)
+ {
+ unsigned char insn = *ptr++;
+
+ if ((insn & 0xc0) == DW_CFA_advance_loc
+ || (insn & 0xc0) == DW_CFA_restore)
+ continue;
+ else if ((insn & 0xc0) == DW_CFA_offset)
+ {
+ read_uleb128 (ptr);
+ continue;
+ }
+ switch (insn)
+ {
+ case DW_CFA_nop:
+ case DW_CFA_remember_state:
+ case DW_CFA_restore_state:
+ case DW_CFA_GNU_window_save:
+ break;
+ case DW_CFA_offset_extended:
+ case DW_CFA_register:
+ case DW_CFA_def_cfa:
+ case DW_CFA_offset_extended_sf:
+ case DW_CFA_def_cfa_sf:
+ case DW_CFA_GNU_negative_offset_extended:
+ case DW_CFA_val_offset:
+ case DW_CFA_val_offset_sf:
+ read_uleb128 (ptr);
+ /* FALLTHROUGH */
+ case DW_CFA_restore_extended:
+ case DW_CFA_undefined:
+ case DW_CFA_same_value:
+ case DW_CFA_def_cfa_register:
+ case DW_CFA_def_cfa_offset:
+ case DW_CFA_def_cfa_offset_sf:
+ case DW_CFA_GNU_args_size:
+ read_uleb128 (ptr);
+ break;
+ case DW_CFA_set_loc:
+ addr = read_ptr (ptr);
+ if (addr >= start && addr_to_sec (dso, addr) != -1)
+ write_ptr (ptr - ptr_size, addr + adjust);
+ break;
+ case DW_CFA_advance_loc1:
+ ptr++;
+ break;
+ case DW_CFA_advance_loc2:
+ ptr += 2;
+ break;
+ case DW_CFA_advance_loc4:
+ ptr += 4;
+ break;
+ case DW_CFA_expression:
+ case DW_CFA_val_expression:
+ read_uleb128 (ptr);
+ /* FALLTHROUGH */
+ case DW_CFA_def_cfa_expression:
+ len = read_uleb128 (ptr);
+ if (adjust_location_list (dso, NULL, ptr, len, start, adjust))
+ return 1;
+ ptr += len;
+ break;
+ default:
+ error (0, 0, "%s: Unhandled DW_CFA_%02x operation",
+ dso->filename, insn);
+ return 1;
+ }
+ }
+ }
+
+ elf_flagscn (dso->scn[debug_sections[DEBUG_FRAME].sec], ELF_C_SET,
+ ELF_F_DIRTY);
+ return 0;
+}
+
+static hashval_t
+loclistoffset_hash (const void *p)
+{
+ GElf_Addr *offset = (GElf_Addr *)p;
+
+ return *offset;
+}
+
+static int
+loclistoffset_eq (const void *p, const void *q)
+{
+ GElf_Addr *offset1 = (GElf_Addr *)p;
+ GElf_Addr *offset2 = (GElf_Addr *)q;
+
+ return *offset1 = *offset2;
+}
+
+static void
+loclistoffset_del (void *p)
+{
+ free (p);
+}
+
+static int
+adjust_dwarf2_info (DSO *dso, GElf_Addr start, GElf_Addr adjust, int type)
+{
+ unsigned char *ptr, *endcu, *endsec;
+ uint32_t value;
+ htab_t abbrev;
+ struct abbrev_tag tag, *t;
+ struct cu_data cu;
+ htab_t offset_hash = htab_try_create (50, loclistoffset_hash,
+ loclistoffset_eq, loclistoffset_del);
+
+ if (offset_hash == NULL)
+ {
+ error (0, ENOMEM, "%s: Could not create hash for attributes",
+ dso->filename);
+ return 1;
+ }
+
+ memset (&cu, 0, sizeof(cu));
+ ptr = debug_sections[type].data;
+ endsec = ptr + debug_sections[type].size;
+ while (ptr < endsec)
+ {
+ if (ptr + 11 > endsec)
+ {
+ error (0, 0, "%s: .debug_info CU header too small", dso->filename);
+ htab_delete (offset_hash);
+ return 1;
+ }
+
+ endcu = ptr + 4;
+ endcu += read_32 (ptr);
+ if (endcu == ptr + 0xffffffff)
+ {
+ error (0, 0, "%s: 64-bit DWARF not supported", dso->filename);
+ htab_delete (offset_hash);
+ return 1;
+ }
+
+ if (endcu > endsec)
+ {
+ error (0, 0, "%s: .debug_info too small", dso->filename);
+ htab_delete (offset_hash);
+ return 1;
+ }
+
+ value = read_16 (ptr);
+ if (value != 2 && value != 3 && value != 4)
+ {
+ error (0, 0, "%s: DWARF version %d unhandled", dso->filename, value);
+ htab_delete (offset_hash);
+ return 1;
+ }
+ cu.cu_version = value;
+
+ value = read_32 (ptr);
+ if (value >= debug_sections[DEBUG_ABBREV].size)
+ {
+ if (debug_sections[DEBUG_ABBREV].data == NULL)
+ error (0, 0, "%s: .debug_abbrev not present", dso->filename);
+ else
+ error (0, 0, "%s: DWARF CU abbrev offset too large",
+ dso->filename);
+ htab_delete (offset_hash);
+ return 1;
+ }
+
+ if (ptr_size == 0)
+ {
+ ptr_size = read_1 (ptr);
+ if (ptr_size == 4)
+ {
+ do_read_ptr = do_read_32_64;
+ write_ptr = write_32;
+ }
+ else if (ptr_size == 8)
+ {
+ do_read_ptr = do_read_64;
+ write_ptr = write_64;
+ }
+ else
+ {
+ error (0, 0, "%s: Invalid DWARF pointer size %d",
+ dso->filename, ptr_size);
+ htab_delete (offset_hash);
+ return 1;
+ }
+ }
+ else if (read_1 (ptr) != ptr_size)
+ {
+ error (0, 0, "%s: DWARF pointer size differs between CUs",
+ dso->filename);
+ htab_delete (offset_hash);
+ return 1;
+ }
+
+ abbrev = read_abbrev (dso, debug_sections[DEBUG_ABBREV].data + value);
+ if (abbrev == NULL)
+ {
+ htab_delete (offset_hash);
+ return 1;
+ }
+
+ cu.cu_entry_pc = ~ (GElf_Addr) 0;
+ cu.cu_low_pc = ~ (GElf_Addr) 0;
+
+ if (type == DEBUG_TYPES)
+ {
+ ptr += 8; /* Skip type_signature. */
+ ptr += 4; /* Skip type_offset. */
+ }
+
+ while (ptr < endcu)
+ {
+ tag.entry = read_uleb128 (ptr);
+ if (tag.entry == 0)
+ continue;
+ t = htab_find_with_hash (abbrev, &tag, tag.entry);
+ if (t == NULL)
+ {
+ error (0, 0, "%s: Could not find DWARF abbreviation %d",
+ dso->filename, tag.entry);
+ htab_delete (abbrev);
+ htab_delete (offset_hash);
+ return 1;
+ }
+
+ ptr = adjust_attributes (dso, ptr, t, &cu, start, adjust,
+ offset_hash);
+ if (ptr == NULL)
+ {
+ htab_delete (abbrev);
+ htab_delete (offset_hash);
+ return 1;
+ }
+ }
+
+ htab_delete (abbrev);
+ }
+ htab_delete (offset_hash);
+ return 0;
+}
+
+int
+adjust_dwarf2 (DSO *dso, int n, GElf_Addr start, GElf_Addr adjust)
+{
+ Elf_Data *data;
+ Elf_Scn *scn;
+ int i, j;
+
+ for (i = 0; debug_sections[i].name; ++i)
+ {
+ debug_sections[i].data = NULL;
+ debug_sections[i].size = 0;
+ debug_sections[i].sec = 0;
+ }
+ ptr_size = 0;
+
+ for (i = 1; i < dso->ehdr.e_shnum; ++i)
+ if (! (dso->shdr[i].sh_flags & (SHF_ALLOC | SHF_WRITE | SHF_EXECINSTR))
+ && dso->shdr[i].sh_size)
+ {
+ const char *name = strptr (dso, dso->ehdr.e_shstrndx,
+ dso->shdr[i].sh_name);
+
+ if (strncmp (name, ".debug_", sizeof (".debug_") - 1) == 0)
+ {
+ for (j = 0; debug_sections[j].name; ++j)
+ if (strcmp (name, debug_sections[j].name) == 0)
+ {
+ if (debug_sections[j].data)
+ {
+ error (0, 0, "%s: Found two copies of %s section",
+ dso->filename, name);
+ return 1;
+ }
+
+ scn = dso->scn[i];
+ data = elf_getdata (scn, NULL);
+ assert (data != NULL && data->d_buf != NULL);
+ assert (elf_getdata (scn, data) == NULL);
+ assert (data->d_off == 0);
+ assert (data->d_size == dso->shdr[i].sh_size);
+ debug_sections[j].data = data->d_buf;
+ debug_sections[j].size = data->d_size;
+ debug_sections[j].sec = i;
+ break;
+ }
+
+ if (debug_sections[j].name == NULL)
+ {
+ error (0, 0, "%s: Unknown debugging section %s",
+ dso->filename, name);
+ return 1;
+ }
+ }
+ }
+
+ if (dso->ehdr.e_ident[EI_DATA] == ELFDATA2LSB)
+ {
+ do_read_16 = buf_read_ule16;
+ do_read_32 = buf_read_ule32;
+ do_read_32_64 = buf_read_ule32_64;
+ do_read_64 = buf_read_ule64;
+ write_32 = dwarf2_write_le32;
+ write_64 = dwarf2_write_le64;
+ }
+ else if (dso->ehdr.e_ident[EI_DATA] == ELFDATA2MSB)
+ {
+ do_read_16 = buf_read_ube16;
+ do_read_32 = buf_read_ube32;
+ do_read_32_64 = buf_read_ube32_64;
+ do_read_64 = buf_read_ube64;
+ write_32 = dwarf2_write_be32;
+ write_64 = dwarf2_write_be64;
+ }
+ else
+ {
+ error (0, 0, "%s: Wrong ELF data enconding", dso->filename);
+ return 1;
+ }
+
+ if (debug_sections[DEBUG_INFO].data != NULL
+ && adjust_dwarf2_info (dso, start, adjust, DEBUG_INFO))
+ return 1;
+
+ if (debug_sections[DEBUG_TYPES].data != NULL
+ && adjust_dwarf2_info (dso, start, adjust, DEBUG_TYPES))
+ return 1;
+
+ if (ptr_size == 0)
+ /* Should not happen. */
+ ptr_size = dso->ehdr.e_ident[EI_CLASS] == ELFCLASS64 ? 8 : 4;
+
+ if (debug_sections[DEBUG_LINE].data != NULL
+ && adjust_dwarf2_line (dso, start, adjust))
+ return 1;
+
+ if (debug_sections[DEBUG_ARANGES].data != NULL
+ && adjust_dwarf2_aranges (dso, start, adjust))
+ return 1;
+
+ if (debug_sections[DEBUG_FRAME].data != NULL
+ && adjust_dwarf2_frame (dso, start, adjust))
+ return 1;
+
+ /* .debug_abbrev requires no adjustement. */
+ /* .debug_pubnames requires no adjustement. */
+ /* .debug_pubtypes requires no adjustement. */
+ /* .debug_macinfo requires no adjustement. */
+ /* .debug_str requires no adjustement. */
+ /* .debug_ranges adjusted for each DW_AT_ranges pointing into it. */
+ /* .debug_loc adjusted for each loclistptr pointing into it. */
+
+ elf_flagscn (dso->scn[n], ELF_C_SET, ELF_F_DIRTY);
+ return 0;
+}
diff --git a/src/dwarf2.h b/src/dwarf2.h
new file mode 100644
index 0000000..b0c80b6
--- /dev/null
+++ b/src/dwarf2.h
@@ -0,0 +1,570 @@
+/* Copyright (C) 2001, 2002, 2009, 2010, 2011, 2012 Red Hat, Inc.
+ Written by Jakub Jelinek <jakub@redhat.com>, 2001.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#define DW_TAG_padding 0x00
+#define DW_TAG_array_type 0x01
+#define DW_TAG_class_type 0x02
+#define DW_TAG_entry_point 0x03
+#define DW_TAG_enumeration_type 0x04
+#define DW_TAG_formal_parameter 0x05
+#define DW_TAG_imported_declaration 0x08
+#define DW_TAG_label 0x0a
+#define DW_TAG_lexical_block 0x0b
+#define DW_TAG_member 0x0d
+#define DW_TAG_pointer_type 0x0f
+#define DW_TAG_reference_type 0x10
+#define DW_TAG_compile_unit 0x11
+#define DW_TAG_string_type 0x12
+#define DW_TAG_structure_type 0x13
+#define DW_TAG_subroutine_type 0x15
+#define DW_TAG_typedef 0x16
+#define DW_TAG_union_type 0x17
+#define DW_TAG_unspecified_parameters 0x18
+#define DW_TAG_variant 0x19
+#define DW_TAG_common_block 0x1a
+#define DW_TAG_common_inclusion 0x1b
+#define DW_TAG_inheritance 0x1c
+#define DW_TAG_inlined_subroutine 0x1d
+#define DW_TAG_module 0x1e
+#define DW_TAG_ptr_to_member_type 0x1f
+#define DW_TAG_set_type 0x20
+#define DW_TAG_subrange_type 0x21
+#define DW_TAG_with_stmt 0x22
+#define DW_TAG_access_declaration 0x23
+#define DW_TAG_base_type 0x24
+#define DW_TAG_catch_block 0x25
+#define DW_TAG_const_type 0x26
+#define DW_TAG_constant 0x27
+#define DW_TAG_enumerator 0x28
+#define DW_TAG_file_type 0x29
+#define DW_TAG_friend 0x2a
+#define DW_TAG_namelist 0x2b
+#define DW_TAG_namelist_item 0x2c
+#define DW_TAG_packed_type 0x2d
+#define DW_TAG_subprogram 0x2e
+#define DW_TAG_template_type_param 0x2f
+#define DW_TAG_template_value_param 0x30
+#define DW_TAG_thrown_type 0x31
+#define DW_TAG_try_block 0x32
+#define DW_TAG_variant_part 0x33
+#define DW_TAG_variable 0x34
+#define DW_TAG_volatile_type 0x35
+#define DW_TAG_dwarf_procedure 0x36
+#define DW_TAG_restrict_type 0x37
+#define DW_TAG_interface_type 0x38
+#define DW_TAG_namespace 0x39
+#define DW_TAG_imported_module 0x3a
+#define DW_TAG_unspecified_type 0x3b
+#define DW_TAG_partial_unit 0x3c
+#define DW_TAG_imported_unit 0x3d
+#define DW_TAG_condition 0x3f
+#define DW_TAG_shared_type 0x40
+#define DW_TAG_type_unit 0x41
+#define DW_TAG_rvalue_reference_type 0x42
+#define DW_TAG_template_alias 0x43
+#define DW_TAG_MIPS_loop 0x4081
+#define DW_TAG_format_label 0x4101
+#define DW_TAG_function_template 0x4102
+#define DW_TAG_class_template 0x4103
+#define DW_TAG_GNU_BINCL 0x4104
+#define DW_TAG_GNU_EINCL 0x4105
+#define DW_TAG_GNU_template_template_param 0x4106
+#define DW_TAG_GNU_template_parameter_pack 0x4107
+#define DW_TAG_GNU_formal_parameter_pack 0x4108
+#define DW_TAG_GNU_call_site 0x4109
+#define DW_TAG_GNU_call_site_parameter 0x410a
+#define DW_TAG_lo_user 0x4080
+#define DW_TAG_hi_user 0xffff
+
+#define DW_children_no 0x0
+#define DW_children_yes 0x1
+
+#define DW_FORM_addr 0x01
+#define DW_FORM_block2 0x03
+#define DW_FORM_block4 0x04
+#define DW_FORM_data2 0x05
+#define DW_FORM_data4 0x06
+#define DW_FORM_data8 0x07
+#define DW_FORM_string 0x08
+#define DW_FORM_block 0x09
+#define DW_FORM_block1 0x0a
+#define DW_FORM_data1 0x0b
+#define DW_FORM_flag 0x0c
+#define DW_FORM_sdata 0x0d
+#define DW_FORM_strp 0x0e
+#define DW_FORM_udata 0x0f
+#define DW_FORM_ref_addr 0x10
+#define DW_FORM_ref1 0x11
+#define DW_FORM_ref2 0x12
+#define DW_FORM_ref4 0x13
+#define DW_FORM_ref8 0x14
+#define DW_FORM_ref_udata 0x15
+#define DW_FORM_indirect 0x16
+#define DW_FORM_sec_offset 0x17
+#define DW_FORM_exprloc 0x18
+#define DW_FORM_flag_present 0x19
+#define DW_FORM_ref_sig8 0x20
+#define DW_FORM_GNU_ref_alt 0x1f20
+#define DW_FORM_GNU_strp_alt 0x1f21
+
+#define DW_AT_sibling 0x01
+#define DW_AT_location 0x02
+#define DW_AT_name 0x03
+#define DW_AT_ordering 0x09
+#define DW_AT_subscr_data 0x0a
+#define DW_AT_byte_size 0x0b
+#define DW_AT_bit_offset 0x0c
+#define DW_AT_bit_size 0x0d
+#define DW_AT_element_list 0x0f
+#define DW_AT_stmt_list 0x10
+#define DW_AT_low_pc 0x11
+#define DW_AT_high_pc 0x12
+#define DW_AT_language 0x13
+#define DW_AT_member 0x14
+#define DW_AT_discr 0x15
+#define DW_AT_discr_value 0x16
+#define DW_AT_visibility 0x17
+#define DW_AT_import 0x18
+#define DW_AT_string_length 0x19
+#define DW_AT_common_reference 0x1a
+#define DW_AT_comp_dir 0x1b
+#define DW_AT_const_value 0x1c
+#define DW_AT_containing_type 0x1d
+#define DW_AT_default_value 0x1e
+#define DW_AT_inline 0x20
+#define DW_AT_is_optional 0x21
+#define DW_AT_lower_bound 0x22
+#define DW_AT_producer 0x25
+#define DW_AT_prototyped 0x27
+#define DW_AT_return_addr 0x2a
+#define DW_AT_start_scope 0x2c
+#define DW_AT_stride_size 0x2e
+#define DW_AT_bit_stride 0x2e
+#define DW_AT_upper_bound 0x2f
+#define DW_AT_abstract_origin 0x31
+#define DW_AT_accessibility 0x32
+#define DW_AT_address_class 0x33
+#define DW_AT_artificial 0x34
+#define DW_AT_base_types 0x35
+#define DW_AT_calling_convention 0x36
+#define DW_AT_count 0x37
+#define DW_AT_data_member_location 0x38
+#define DW_AT_decl_column 0x39
+#define DW_AT_decl_file 0x3a
+#define DW_AT_decl_line 0x3b
+#define DW_AT_declaration 0x3c
+#define DW_AT_discr_list 0x3d
+#define DW_AT_encoding 0x3e
+#define DW_AT_external 0x3f
+#define DW_AT_frame_base 0x40
+#define DW_AT_friend 0x41
+#define DW_AT_identifier_case 0x42
+#define DW_AT_macro_info 0x43
+#define DW_AT_namelist_items 0x44
+#define DW_AT_priority 0x45
+#define DW_AT_segment 0x46
+#define DW_AT_specification 0x47
+#define DW_AT_static_link 0x48
+#define DW_AT_type 0x49
+#define DW_AT_use_location 0x4a
+#define DW_AT_variable_parameter 0x4b
+#define DW_AT_virtuality 0x4c
+#define DW_AT_vtable_elem_location 0x4d
+#define DW_AT_allocated 0x4e
+#define DW_AT_associated 0x4f
+#define DW_AT_data_location 0x50
+#define DW_AT_stride 0x51
+#define DW_AT_byte_stride 0x51
+#define DW_AT_entry_pc 0x52
+#define DW_AT_use_UTF8 0x53
+#define DW_AT_extension 0x54
+#define DW_AT_ranges 0x55
+#define DW_AT_trampoline 0x56
+#define DW_AT_call_column 0x57
+#define DW_AT_call_file 0x58
+#define DW_AT_call_line 0x59
+#define DW_AT_description 0x5a
+#define DW_AT_binary_scale 0x5b
+#define DW_AT_decimal_scale 0x5c
+#define DW_AT_small 0x5d
+#define DW_AT_decimal_sign 0x5e
+#define DW_AT_digit_count 0x5f
+#define DW_AT_picture_string 0x60
+#define DW_AT_mutable 0x61
+#define DW_AT_threads_scaled 0x62
+#define DW_AT_explicit 0x63
+#define DW_AT_object_pointer 0x64
+#define DW_AT_endianity 0x65
+#define DW_AT_elemental 0x66
+#define DW_AT_pure 0x67
+#define DW_AT_recursive 0x68
+#define DW_AT_signature 0x69
+#define DW_AT_main_subprogram 0x6a
+#define DW_AT_data_bit_offset 0x6b
+#define DW_AT_const_expr 0x6c
+#define DW_AT_enum_class 0x6d
+#define DW_AT_linkage_name 0x6e
+#define DW_AT_MIPS_fde 0x2001
+#define DW_AT_MIPS_loop_begin 0x2002
+#define DW_AT_MIPS_tail_loop_begin 0x2003
+#define DW_AT_MIPS_epilog_begin 0x2004
+#define DW_AT_MIPS_loop_unroll_factor 0x2005
+#define DW_AT_MIPS_software_pipeline_depth 0x2006
+#define DW_AT_MIPS_linkage_name 0x2007
+#define DW_AT_MIPS_stride 0x2008
+#define DW_AT_MIPS_abstract_name 0x2009
+#define DW_AT_MIPS_clone_origin 0x200a
+#define DW_AT_MIPS_has_inlines 0x200b
+#define DW_AT_sf_names 0x2101
+#define DW_AT_src_info 0x2102
+#define DW_AT_mac_info 0x2103
+#define DW_AT_src_coords 0x2104
+#define DW_AT_body_begin 0x2105
+#define DW_AT_body_end 0x2106
+#define DW_AT_GNU_vector 0x2107
+#define DW_AT_GNU_guarded_by 0x2108
+#define DW_AT_GNU_pt_guarded_by 0x2109
+#define DW_AT_GNU_guarded 0x210a
+#define DW_AT_GNU_pt_guarded 0x210b
+#define DW_AT_GNU_locks_excluded 0x210c
+#define DW_AT_GNU_exclusive_locks_required 0x210d
+#define DW_AT_GNU_shared_locks_required 0x210e
+#define DW_AT_GNU_odr_signature 0x210f
+#define DW_AT_GNU_template_name 0x2110
+#define DW_AT_GNU_call_site_value 0x2111
+#define DW_AT_GNU_call_site_data_value 0x2112
+#define DW_AT_GNU_call_site_target 0x2113
+#define DW_AT_GNU_call_site_target_clobbered 0x2114
+#define DW_AT_GNU_tail_call 0x2115
+#define DW_AT_GNU_all_tail_call_sites 0x2116
+#define DW_AT_GNU_all_call_sites 0x2117
+#define DW_AT_GNU_all_source_call_sites 0x2118
+#define DW_AT_lo_user 0x2000
+#define DW_AT_hi_user 0x3ff0
+
+#define DW_OP_addr 0x03
+#define DW_OP_deref 0x06
+#define DW_OP_const1u 0x08
+#define DW_OP_const1s 0x09
+#define DW_OP_const2u 0x0a
+#define DW_OP_const2s 0x0b
+#define DW_OP_const4u 0x0c
+#define DW_OP_const4s 0x0d
+#define DW_OP_const8u 0x0e
+#define DW_OP_const8s 0x0f
+#define DW_OP_constu 0x10
+#define DW_OP_consts 0x11
+#define DW_OP_dup 0x12
+#define DW_OP_drop 0x13
+#define DW_OP_over 0x14
+#define DW_OP_pick 0x15
+#define DW_OP_swap 0x16
+#define DW_OP_rot 0x17
+#define DW_OP_xderef 0x18
+#define DW_OP_abs 0x19
+#define DW_OP_and 0x1a
+#define DW_OP_div 0x1b
+#define DW_OP_minus 0x1c
+#define DW_OP_mod 0x1d
+#define DW_OP_mul 0x1e
+#define DW_OP_neg 0x1f
+#define DW_OP_not 0x20
+#define DW_OP_or 0x21
+#define DW_OP_plus 0x22
+#define DW_OP_plus_uconst 0x23
+#define DW_OP_shl 0x24
+#define DW_OP_shr 0x25
+#define DW_OP_shra 0x26
+#define DW_OP_xor 0x27
+#define DW_OP_bra 0x28
+#define DW_OP_eq 0x29
+#define DW_OP_ge 0x2a
+#define DW_OP_gt 0x2b
+#define DW_OP_le 0x2c
+#define DW_OP_lt 0x2d
+#define DW_OP_ne 0x2e
+#define DW_OP_skip 0x2f
+#define DW_OP_lit0 0x30
+#define DW_OP_lit1 0x31
+#define DW_OP_lit2 0x32
+#define DW_OP_lit3 0x33
+#define DW_OP_lit4 0x34
+#define DW_OP_lit5 0x35
+#define DW_OP_lit6 0x36
+#define DW_OP_lit7 0x37
+#define DW_OP_lit8 0x38
+#define DW_OP_lit9 0x39
+#define DW_OP_lit10 0x3a
+#define DW_OP_lit11 0x3b
+#define DW_OP_lit12 0x3c
+#define DW_OP_lit13 0x3d
+#define DW_OP_lit14 0x3e
+#define DW_OP_lit15 0x3f
+#define DW_OP_lit16 0x40
+#define DW_OP_lit17 0x41
+#define DW_OP_lit18 0x42
+#define DW_OP_lit19 0x43
+#define DW_OP_lit20 0x44
+#define DW_OP_lit21 0x45
+#define DW_OP_lit22 0x46
+#define DW_OP_lit23 0x47
+#define DW_OP_lit24 0x48
+#define DW_OP_lit25 0x49
+#define DW_OP_lit26 0x4a
+#define DW_OP_lit27 0x4b
+#define DW_OP_lit28 0x4c
+#define DW_OP_lit29 0x4d
+#define DW_OP_lit30 0x4e
+#define DW_OP_lit31 0x4f
+#define DW_OP_reg0 0x50
+#define DW_OP_reg1 0x51
+#define DW_OP_reg2 0x52
+#define DW_OP_reg3 0x53
+#define DW_OP_reg4 0x54
+#define DW_OP_reg5 0x55
+#define DW_OP_reg6 0x56
+#define DW_OP_reg7 0x57
+#define DW_OP_reg8 0x58
+#define DW_OP_reg9 0x59
+#define DW_OP_reg10 0x5a
+#define DW_OP_reg11 0x5b
+#define DW_OP_reg12 0x5c
+#define DW_OP_reg13 0x5d
+#define DW_OP_reg14 0x5e
+#define DW_OP_reg15 0x5f
+#define DW_OP_reg16 0x60
+#define DW_OP_reg17 0x61
+#define DW_OP_reg18 0x62
+#define DW_OP_reg19 0x63
+#define DW_OP_reg20 0x64
+#define DW_OP_reg21 0x65
+#define DW_OP_reg22 0x66
+#define DW_OP_reg23 0x67
+#define DW_OP_reg24 0x68
+#define DW_OP_reg25 0x69
+#define DW_OP_reg26 0x6a
+#define DW_OP_reg27 0x6b
+#define DW_OP_reg28 0x6c
+#define DW_OP_reg29 0x6d
+#define DW_OP_reg30 0x6e
+#define DW_OP_reg31 0x6f
+#define DW_OP_breg0 0x70
+#define DW_OP_breg1 0x71
+#define DW_OP_breg2 0x72
+#define DW_OP_breg3 0x73
+#define DW_OP_breg4 0x74
+#define DW_OP_breg5 0x75
+#define DW_OP_breg6 0x76
+#define DW_OP_breg7 0x77
+#define DW_OP_breg8 0x78
+#define DW_OP_breg9 0x79
+#define DW_OP_breg10 0x7a
+#define DW_OP_breg11 0x7b
+#define DW_OP_breg12 0x7c
+#define DW_OP_breg13 0x7d
+#define DW_OP_breg14 0x7e
+#define DW_OP_breg15 0x7f
+#define DW_OP_breg16 0x80
+#define DW_OP_breg17 0x81
+#define DW_OP_breg18 0x82
+#define DW_OP_breg19 0x83
+#define DW_OP_breg20 0x84
+#define DW_OP_breg21 0x85
+#define DW_OP_breg22 0x86
+#define DW_OP_breg23 0x87
+#define DW_OP_breg24 0x88
+#define DW_OP_breg25 0x89
+#define DW_OP_breg26 0x8a
+#define DW_OP_breg27 0x8b
+#define DW_OP_breg28 0x8c
+#define DW_OP_breg29 0x8d
+#define DW_OP_breg30 0x8e
+#define DW_OP_breg31 0x8f
+#define DW_OP_regx 0x90
+#define DW_OP_fbreg 0x91
+#define DW_OP_bregx 0x92
+#define DW_OP_piece 0x93
+#define DW_OP_deref_size 0x94
+#define DW_OP_xderef_size 0x95
+#define DW_OP_nop 0x96
+#define DW_OP_push_object_address 0x97
+#define DW_OP_call2 0x98
+#define DW_OP_call4 0x99
+#define DW_OP_call_ref 0x9a
+#define DW_OP_form_tls_address 0x9b
+#define DW_OP_call_frame_cfa 0x9c
+#define DW_OP_bit_piece 0x9d
+#define DW_OP_implicit_value 0x9e
+#define DW_OP_stack_value 0x9f
+#define DW_OP_GNU_push_tls_address 0xe0
+#define DW_OP_GNU_uninit 0xf0
+#define DW_OP_GNU_encoded_addr 0xf1
+#define DW_OP_GNU_implicit_pointer 0xf2
+#define DW_OP_GNU_entry_value 0xf3
+#define DW_OP_GNU_const_type 0xf4
+#define DW_OP_GNU_regval_type 0xf5
+#define DW_OP_GNU_deref_type 0xf6
+#define DW_OP_GNU_convert 0xf7
+#define DW_OP_GNU_reinterpret 0xf9
+#define DW_OP_GNU_parameter_ref 0xfa
+#define DW_OP_lo_user 0xe0
+#define DW_OP_hi_user 0xff
+
+#define DW_ATE_void 0x0
+#define DW_ATE_address 0x1
+#define DW_ATE_boolean 0x2
+#define DW_ATE_complex_float 0x3
+#define DW_ATE_float 0x4
+#define DW_ATE_signed 0x5
+#define DW_ATE_signed_char 0x6
+#define DW_ATE_unsigned 0x7
+#define DW_ATE_unsigned_char 0x8
+#define DW_ATE_imaginary_float 0x9
+#define DW_ATE_packed_decimal 0xa
+#define DW_ATE_numeric_string 0xb
+#define DW_ATE_edited 0xc
+#define DW_ATE_signed_fixed 0xd
+#define DW_ATE_unsigned_fixed 0xe
+#define DW_ATE_decimal_float 0xf
+#define DW_ATE_lo_user 0x80
+#define DW_ATE_hi_user 0xff
+
+#define DW_ORD_row_major 0x0
+#define DW_ORD_col_major 0x1
+
+#define DW_ACCESS_public 0x1
+#define DW_ACCESS_protected 0x2
+#define DW_ACCESS_private 0x3
+
+#define DW_VIS_local 0x1
+#define DW_VIS_exported 0x2
+#define DW_VIS_qualified 0x3
+
+#define DW_VIRTUALITY_none 0x0
+#define DW_VIRTUALITY_virtual 0x1
+#define DW_VIRTUALITY_pure_virtual 0x2
+
+#define DW_ID_case_sensitive 0x0
+#define DW_ID_up_case 0x1
+#define DW_ID_down_case 0x2
+#define DW_ID_case_insensitive 0x3
+
+#define DW_CC_normal 0x1
+#define DW_CC_program 0x2
+#define DW_CC_nocall 0x3
+#define DW_CC_lo_user 0x40
+#define DW_CC_hi_user 0xff
+
+#define DW_INL_not_inlined 0x0
+#define DW_INL_inlined 0x1
+#define DW_INL_declared_not_inlined 0x2
+#define DW_INL_declared_inlined 0x3
+
+#define DW_DSC_label 0x0
+#define DW_DSC_range 0x1
+
+#define DW_LNS_extended_op 0x0
+#define DW_LNS_copy 0x1
+#define DW_LNS_advance_pc 0x2
+#define DW_LNS_advance_line 0x3
+#define DW_LNS_set_file 0x4
+#define DW_LNS_set_column 0x5
+#define DW_LNS_negate_stmt 0x6
+#define DW_LNS_set_basic_block 0x7
+#define DW_LNS_const_add_pc 0x8
+#define DW_LNS_fixed_advance_pc 0x9
+#define DW_LNS_set_prologue_end 0xa
+#define DW_LNS_set_epilogue_begin 0xb
+#define DW_LNS_set_isa 0xc
+
+#define DW_LNE_end_sequence 0x1
+#define DW_LNE_set_address 0x2
+#define DW_LNE_define_file 0x3
+#define DW_LNE_set_discriminator 0x4
+
+#define DW_CFA_advance_loc 0x40
+#define DW_CFA_offset 0x80
+#define DW_CFA_restore 0xc0
+#define DW_CFA_nop 0x00
+#define DW_CFA_set_loc 0x01
+#define DW_CFA_advance_loc1 0x02
+#define DW_CFA_advance_loc2 0x03
+#define DW_CFA_advance_loc4 0x04
+#define DW_CFA_offset_extended 0x05
+#define DW_CFA_restore_extended 0x06
+#define DW_CFA_undefined 0x07
+#define DW_CFA_same_value 0x08
+#define DW_CFA_register 0x09
+#define DW_CFA_remember_state 0x0a
+#define DW_CFA_restore_state 0x0b
+#define DW_CFA_def_cfa 0x0c
+#define DW_CFA_def_cfa_register 0x0d
+#define DW_CFA_def_cfa_offset 0x0e
+#define DW_CFA_def_cfa_expression 0x0f
+#define DW_CFA_expression 0x10
+#define DW_CFA_offset_extended_sf 0x11
+#define DW_CFA_def_cfa_sf 0x12
+#define DW_CFA_def_cfa_offset_sf 0x13
+#define DW_CFA_val_offset 0x14
+#define DW_CFA_val_offset_sf 0x15
+#define DW_CFA_val_expression 0x16
+#define DW_CFA_MIPS_advance_loc8 0x1d
+#define DW_CFA_GNU_window_save 0x2d
+#define DW_CFA_GNU_args_size 0x2e
+#define DW_CFA_GNU_negative_offset_extended 0x2f
+
+#define DW_CIE_ID 0xffffffff
+#define DW_CIE_VERSION 1
+
+#define DW_CFA_extended 0
+#define DW_CFA_low_user 0x1c
+#define DW_CFA_high_user 0x3f
+
+#define DW_CHILDREN_no 0x00
+#define DW_CHILDREN_yes 0x01
+
+#define DW_ADDR_none 0
+
+#define DW_LANG_C89 0x0001
+#define DW_LANG_C 0x0002
+#define DW_LANG_Ada83 0x0003
+#define DW_LANG_C_plus_plus 0x0004
+#define DW_LANG_Cobol74 0x0005
+#define DW_LANG_Cobol85 0x0006
+#define DW_LANG_Fortran77 0x0007
+#define DW_LANG_Fortran90 0x0008
+#define DW_LANG_Pascal83 0x0009
+#define DW_LANG_Modula2 0x000a
+#define DW_LANG_Java 0x000b
+#define DW_LANG_C99 0x000c
+#define DW_LANG_Ada95 0x000d
+#define DW_LANG_Fortran95 0x000e
+#define DW_LANG_PLI 0x000f
+#define DW_LANG_ObjC 0x0010
+#define DW_LANG_ObjC_plus_plus 0x0011
+#define DW_LANG_UPC 0x0012
+#define DW_LANG_D 0x0013
+#define DW_LANG_Python 0x0014
+#define DW_LANG_Mips_Assembler 0x8001
+#define DW_LANG_lo_user 0x8000
+#define DW_LANG_hi_user 0xffff
+
+#define DW_MACINFO_define 1
+#define DW_MACINFO_undef 2
+#define DW_MACINFO_start_file 3
+#define DW_MACINFO_end_file 4
+#define DW_MACINFO_vendor_ext 255
diff --git a/src/elf.h b/src/elf.h
new file mode 100644
index 0000000..fbadda4
--- /dev/null
+++ b/src/elf.h
@@ -0,0 +1,3562 @@
+/* This file defines standard ELF types, structures, and macros.
+ Copyright (C) 1995-2015 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef _ELF_H
+#define _ELF_H 1
+
+#include <features.h>
+
+__BEGIN_DECLS
+
+/* Standard ELF types. */
+
+#include <stdint.h>
+
+/* Type for a 16-bit quantity. */
+typedef uint16_t Elf32_Half;
+typedef uint16_t Elf64_Half;
+
+/* Types for signed and unsigned 32-bit quantities. */
+typedef uint32_t Elf32_Word;
+typedef int32_t Elf32_Sword;
+typedef uint32_t Elf64_Word;
+typedef int32_t Elf64_Sword;
+
+/* Types for signed and unsigned 64-bit quantities. */
+typedef uint64_t Elf32_Xword;
+typedef int64_t Elf32_Sxword;
+typedef uint64_t Elf64_Xword;
+typedef int64_t Elf64_Sxword;
+
+/* Type of addresses. */
+typedef uint32_t Elf32_Addr;
+typedef uint64_t Elf64_Addr;
+
+/* Type of file offsets. */
+typedef uint32_t Elf32_Off;
+typedef uint64_t Elf64_Off;
+
+/* Type for section indices, which are 16-bit quantities. */
+typedef uint16_t Elf32_Section;
+typedef uint16_t Elf64_Section;
+
+/* Type for version symbol information. */
+typedef Elf32_Half Elf32_Versym;
+typedef Elf64_Half Elf64_Versym;
+
+
+/* The ELF file header. This appears at the start of every ELF file. */
+
+#define EI_NIDENT (16)
+
+typedef struct
+{
+ unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */
+ Elf32_Half e_type; /* Object file type */
+ Elf32_Half e_machine; /* Architecture */
+ Elf32_Word e_version; /* Object file version */
+ Elf32_Addr e_entry; /* Entry point virtual address */
+ Elf32_Off e_phoff; /* Program header table file offset */
+ Elf32_Off e_shoff; /* Section header table file offset */
+ Elf32_Word e_flags; /* Processor-specific flags */
+ Elf32_Half e_ehsize; /* ELF header size in bytes */
+ Elf32_Half e_phentsize; /* Program header table entry size */
+ Elf32_Half e_phnum; /* Program header table entry count */
+ Elf32_Half e_shentsize; /* Section header table entry size */
+ Elf32_Half e_shnum; /* Section header table entry count */
+ Elf32_Half e_shstrndx; /* Section header string table index */
+} Elf32_Ehdr;
+
+typedef struct
+{
+ unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */
+ Elf64_Half e_type; /* Object file type */
+ Elf64_Half e_machine; /* Architecture */
+ Elf64_Word e_version; /* Object file version */
+ Elf64_Addr e_entry; /* Entry point virtual address */
+ Elf64_Off e_phoff; /* Program header table file offset */
+ Elf64_Off e_shoff; /* Section header table file offset */
+ Elf64_Word e_flags; /* Processor-specific flags */
+ Elf64_Half e_ehsize; /* ELF header size in bytes */
+ Elf64_Half e_phentsize; /* Program header table entry size */
+ Elf64_Half e_phnum; /* Program header table entry count */
+ Elf64_Half e_shentsize; /* Section header table entry size */
+ Elf64_Half e_shnum; /* Section header table entry count */
+ Elf64_Half e_shstrndx; /* Section header string table index */
+} Elf64_Ehdr;
+
+/* Fields in the e_ident array. The EI_* macros are indices into the
+ array. The macros under each EI_* macro are the values the byte
+ may have. */
+
+#define EI_MAG0 0 /* File identification byte 0 index */
+#define ELFMAG0 0x7f /* Magic number byte 0 */
+
+#define EI_MAG1 1 /* File identification byte 1 index */
+#define ELFMAG1 'E' /* Magic number byte 1 */
+
+#define EI_MAG2 2 /* File identification byte 2 index */
+#define ELFMAG2 'L' /* Magic number byte 2 */
+
+#define EI_MAG3 3 /* File identification byte 3 index */
+#define ELFMAG3 'F' /* Magic number byte 3 */
+
+/* Conglomeration of the identification bytes, for easy testing as a word. */
+#define ELFMAG "\177ELF"
+#define SELFMAG 4
+
+#define EI_CLASS 4 /* File class byte index */
+#define ELFCLASSNONE 0 /* Invalid class */
+#define ELFCLASS32 1 /* 32-bit objects */
+#define ELFCLASS64 2 /* 64-bit objects */
+#define ELFCLASSNUM 3
+
+#define EI_DATA 5 /* Data encoding byte index */
+#define ELFDATANONE 0 /* Invalid data encoding */
+#define ELFDATA2LSB 1 /* 2's complement, little endian */
+#define ELFDATA2MSB 2 /* 2's complement, big endian */
+#define ELFDATANUM 3
+
+#define EI_VERSION 6 /* File version byte index */
+ /* Value must be EV_CURRENT */
+
+#define EI_OSABI 7 /* OS ABI identification */
+#define ELFOSABI_NONE 0 /* UNIX System V ABI */
+#define ELFOSABI_SYSV 0 /* Alias. */
+#define ELFOSABI_HPUX 1 /* HP-UX */
+#define ELFOSABI_NETBSD 2 /* NetBSD. */
+#define ELFOSABI_GNU 3 /* Object uses GNU ELF extensions. */
+#define ELFOSABI_LINUX ELFOSABI_GNU /* Compatibility alias. */
+#define ELFOSABI_SOLARIS 6 /* Sun Solaris. */
+#define ELFOSABI_AIX 7 /* IBM AIX. */
+#define ELFOSABI_IRIX 8 /* SGI Irix. */
+#define ELFOSABI_FREEBSD 9 /* FreeBSD. */
+#define ELFOSABI_TRU64 10 /* Compaq TRU64 UNIX. */
+#define ELFOSABI_MODESTO 11 /* Novell Modesto. */
+#define ELFOSABI_OPENBSD 12 /* OpenBSD. */
+#define ELFOSABI_ARM_AEABI 64 /* ARM EABI */
+#define ELFOSABI_ARM 97 /* ARM */
+#define ELFOSABI_STANDALONE 255 /* Standalone (embedded) application */
+
+#define EI_ABIVERSION 8 /* ABI version */
+
+#define EI_PAD 9 /* Byte index of padding bytes */
+
+/* Legal values for e_type (object file type). */
+
+#define ET_NONE 0 /* No file type */
+#define ET_REL 1 /* Relocatable file */
+#define ET_EXEC 2 /* Executable file */
+#define ET_DYN 3 /* Shared object file */
+#define ET_CORE 4 /* Core file */
+#define ET_NUM 5 /* Number of defined types */
+#define ET_LOOS 0xfe00 /* OS-specific range start */
+#define ET_HIOS 0xfeff /* OS-specific range end */
+#define ET_LOPROC 0xff00 /* Processor-specific range start */
+#define ET_HIPROC 0xffff /* Processor-specific range end */
+
+/* Legal values for e_machine (architecture). */
+
+#define EM_NONE 0 /* No machine */
+#define EM_M32 1 /* AT&T WE 32100 */
+#define EM_SPARC 2 /* SUN SPARC */
+#define EM_386 3 /* Intel 80386 */
+#define EM_68K 4 /* Motorola m68k family */
+#define EM_88K 5 /* Motorola m88k family */
+#define EM_860 7 /* Intel 80860 */
+#define EM_MIPS 8 /* MIPS R3000 big-endian */
+#define EM_S370 9 /* IBM System/370 */
+#define EM_MIPS_RS3_LE 10 /* MIPS R3000 little-endian */
+
+#define EM_PARISC 15 /* HPPA */
+#define EM_VPP500 17 /* Fujitsu VPP500 */
+#define EM_SPARC32PLUS 18 /* Sun's "v8plus" */
+#define EM_960 19 /* Intel 80960 */
+#define EM_PPC 20 /* PowerPC */
+#define EM_PPC64 21 /* PowerPC 64-bit */
+#define EM_S390 22 /* IBM S390 */
+
+#define EM_V800 36 /* NEC V800 series */
+#define EM_FR20 37 /* Fujitsu FR20 */
+#define EM_RH32 38 /* TRW RH-32 */
+#define EM_RCE 39 /* Motorola RCE */
+#define EM_ARM 40 /* ARM */
+#define EM_FAKE_ALPHA 41 /* Digital Alpha */
+#define EM_SH 42 /* Hitachi SH */
+#define EM_SPARCV9 43 /* SPARC v9 64-bit */
+#define EM_TRICORE 44 /* Siemens Tricore */
+#define EM_ARC 45 /* Argonaut RISC Core */
+#define EM_H8_300 46 /* Hitachi H8/300 */
+#define EM_H8_300H 47 /* Hitachi H8/300H */
+#define EM_H8S 48 /* Hitachi H8S */
+#define EM_H8_500 49 /* Hitachi H8/500 */
+#define EM_IA_64 50 /* Intel Merced */
+#define EM_MIPS_X 51 /* Stanford MIPS-X */
+#define EM_COLDFIRE 52 /* Motorola Coldfire */
+#define EM_68HC12 53 /* Motorola M68HC12 */
+#define EM_MMA 54 /* Fujitsu MMA Multimedia Accelerator*/
+#define EM_PCP 55 /* Siemens PCP */
+#define EM_NCPU 56 /* Sony nCPU embeeded RISC */
+#define EM_NDR1 57 /* Denso NDR1 microprocessor */
+#define EM_STARCORE 58 /* Motorola Start*Core processor */
+#define EM_ME16 59 /* Toyota ME16 processor */
+#define EM_ST100 60 /* STMicroelectronic ST100 processor */
+#define EM_TINYJ 61 /* Advanced Logic Corp. Tinyj emb.fam*/
+#define EM_X86_64 62 /* AMD x86-64 architecture */
+#define EM_PDSP 63 /* Sony DSP Processor */
+
+#define EM_FX66 66 /* Siemens FX66 microcontroller */
+#define EM_ST9PLUS 67 /* STMicroelectronics ST9+ 8/16 mc */
+#define EM_ST7 68 /* STmicroelectronics ST7 8 bit mc */
+#define EM_68HC16 69 /* Motorola MC68HC16 microcontroller */
+#define EM_68HC11 70 /* Motorola MC68HC11 microcontroller */
+#define EM_68HC08 71 /* Motorola MC68HC08 microcontroller */
+#define EM_68HC05 72 /* Motorola MC68HC05 microcontroller */
+#define EM_SVX 73 /* Silicon Graphics SVx */
+#define EM_ST19 74 /* STMicroelectronics ST19 8 bit mc */
+#define EM_VAX 75 /* Digital VAX */
+#define EM_CRIS 76 /* Axis Communications 32-bit embedded processor */
+#define EM_JAVELIN 77 /* Infineon Technologies 32-bit embedded processor */
+#define EM_FIREPATH 78 /* Element 14 64-bit DSP Processor */
+#define EM_ZSP 79 /* LSI Logic 16-bit DSP Processor */
+#define EM_MMIX 80 /* Donald Knuth's educational 64-bit processor */
+#define EM_HUANY 81 /* Harvard University machine-independent object files */
+#define EM_PRISM 82 /* SiTera Prism */
+#define EM_AVR 83 /* Atmel AVR 8-bit microcontroller */
+#define EM_FR30 84 /* Fujitsu FR30 */
+#define EM_D10V 85 /* Mitsubishi D10V */
+#define EM_D30V 86 /* Mitsubishi D30V */
+#define EM_V850 87 /* NEC v850 */
+#define EM_M32R 88 /* Mitsubishi M32R */
+#define EM_MN10300 89 /* Matsushita MN10300 */
+#define EM_MN10200 90 /* Matsushita MN10200 */
+#define EM_PJ 91 /* picoJava */
+#define EM_OPENRISC 92 /* OpenRISC 32-bit embedded processor */
+#define EM_ARC_A5 93 /* ARC Cores Tangent-A5 */
+#define EM_XTENSA 94 /* Tensilica Xtensa Architecture */
+#define EM_ALTERA_NIOS2 113 /* Altera Nios II */
+#define EM_AARCH64 183 /* ARM AARCH64 */
+#define EM_TILEPRO 188 /* Tilera TILEPro */
+#define EM_MICROBLAZE 189 /* Xilinx MicroBlaze */
+#define EM_TILEGX 191 /* Tilera TILE-Gx */
+#define EM_NUM 192
+
+/* If it is necessary to assign new unofficial EM_* values, please
+ pick large random numbers (0x8523, 0xa7f2, etc.) to minimize the
+ chances of collision with official or non-GNU unofficial values. */
+
+#define EM_ALPHA 0x9026
+
+/* Legal values for e_version (version). */
+
+#define EV_NONE 0 /* Invalid ELF version */
+#define EV_CURRENT 1 /* Current version */
+#define EV_NUM 2
+
+/* Section header. */
+
+typedef struct
+{
+ Elf32_Word sh_name; /* Section name (string tbl index) */
+ Elf32_Word sh_type; /* Section type */
+ Elf32_Word sh_flags; /* Section flags */
+ Elf32_Addr sh_addr; /* Section virtual addr at execution */
+ Elf32_Off sh_offset; /* Section file offset */
+ Elf32_Word sh_size; /* Section size in bytes */
+ Elf32_Word sh_link; /* Link to another section */
+ Elf32_Word sh_info; /* Additional section information */
+ Elf32_Word sh_addralign; /* Section alignment */
+ Elf32_Word sh_entsize; /* Entry size if section holds table */
+} Elf32_Shdr;
+
+typedef struct
+{
+ Elf64_Word sh_name; /* Section name (string tbl index) */
+ Elf64_Word sh_type; /* Section type */
+ Elf64_Xword sh_flags; /* Section flags */
+ Elf64_Addr sh_addr; /* Section virtual addr at execution */
+ Elf64_Off sh_offset; /* Section file offset */
+ Elf64_Xword sh_size; /* Section size in bytes */
+ Elf64_Word sh_link; /* Link to another section */
+ Elf64_Word sh_info; /* Additional section information */
+ Elf64_Xword sh_addralign; /* Section alignment */
+ Elf64_Xword sh_entsize; /* Entry size if section holds table */
+} Elf64_Shdr;
+
+/* Special section indices. */
+
+#define SHN_UNDEF 0 /* Undefined section */
+#define SHN_LORESERVE 0xff00 /* Start of reserved indices */
+#define SHN_LOPROC 0xff00 /* Start of processor-specific */
+#define SHN_BEFORE 0xff00 /* Order section before all others
+ (Solaris). */
+#define SHN_AFTER 0xff01 /* Order section after all others
+ (Solaris). */
+#define SHN_HIPROC 0xff1f /* End of processor-specific */
+#define SHN_LOOS 0xff20 /* Start of OS-specific */
+#define SHN_HIOS 0xff3f /* End of OS-specific */
+#define SHN_ABS 0xfff1 /* Associated symbol is absolute */
+#define SHN_COMMON 0xfff2 /* Associated symbol is common */
+#define SHN_XINDEX 0xffff /* Index is in extra table. */
+#define SHN_HIRESERVE 0xffff /* End of reserved indices */
+
+/* Legal values for sh_type (section type). */
+
+#define SHT_NULL 0 /* Section header table entry unused */
+#define SHT_PROGBITS 1 /* Program data */
+#define SHT_SYMTAB 2 /* Symbol table */
+#define SHT_STRTAB 3 /* String table */
+#define SHT_RELA 4 /* Relocation entries with addends */
+#define SHT_HASH 5 /* Symbol hash table */
+#define SHT_DYNAMIC 6 /* Dynamic linking information */
+#define SHT_NOTE 7 /* Notes */
+#define SHT_NOBITS 8 /* Program space with no data (bss) */
+#define SHT_REL 9 /* Relocation entries, no addends */
+#define SHT_SHLIB 10 /* Reserved */
+#define SHT_DYNSYM 11 /* Dynamic linker symbol table */
+#define SHT_INIT_ARRAY 14 /* Array of constructors */
+#define SHT_FINI_ARRAY 15 /* Array of destructors */
+#define SHT_PREINIT_ARRAY 16 /* Array of pre-constructors */
+#define SHT_GROUP 17 /* Section group */
+#define SHT_SYMTAB_SHNDX 18 /* Extended section indeces */
+#define SHT_NUM 19 /* Number of defined types. */
+#define SHT_LOOS 0x60000000 /* Start OS-specific. */
+#define SHT_GNU_ATTRIBUTES 0x6ffffff5 /* Object attributes. */
+#define SHT_GNU_HASH 0x6ffffff6 /* GNU-style hash table. */
+#define SHT_GNU_LIBLIST 0x6ffffff7 /* Prelink library list */
+#define SHT_CHECKSUM 0x6ffffff8 /* Checksum for DSO content. */
+#define SHT_LOSUNW 0x6ffffffa /* Sun-specific low bound. */
+#define SHT_SUNW_move 0x6ffffffa
+#define SHT_SUNW_COMDAT 0x6ffffffb
+#define SHT_SUNW_syminfo 0x6ffffffc
+#define SHT_GNU_verdef 0x6ffffffd /* Version definition section. */
+#define SHT_GNU_verneed 0x6ffffffe /* Version needs section. */
+#define SHT_GNU_versym 0x6fffffff /* Version symbol table. */
+#define SHT_HISUNW 0x6fffffff /* Sun-specific high bound. */
+#define SHT_HIOS 0x6fffffff /* End OS-specific type */
+#define SHT_LOPROC 0x70000000 /* Start of processor-specific */
+#define SHT_HIPROC 0x7fffffff /* End of processor-specific */
+#define SHT_LOUSER 0x80000000 /* Start of application-specific */
+#define SHT_HIUSER 0x8fffffff /* End of application-specific */
+
+/* Legal values for sh_flags (section flags). */
+
+#define SHF_WRITE (1 << 0) /* Writable */
+#define SHF_ALLOC (1 << 1) /* Occupies memory during execution */
+#define SHF_EXECINSTR (1 << 2) /* Executable */
+#define SHF_MERGE (1 << 4) /* Might be merged */
+#define SHF_STRINGS (1 << 5) /* Contains nul-terminated strings */
+#define SHF_INFO_LINK (1 << 6) /* `sh_info' contains SHT index */
+#define SHF_LINK_ORDER (1 << 7) /* Preserve order after combining */
+#define SHF_OS_NONCONFORMING (1 << 8) /* Non-standard OS specific handling
+ required */
+#define SHF_GROUP (1 << 9) /* Section is member of a group. */
+#define SHF_TLS (1 << 10) /* Section hold thread-local data. */
+#define SHF_COMPRESSED (1 << 11) /* Section with compressed data. */
+#define SHF_MASKOS 0x0ff00000 /* OS-specific. */
+#define SHF_MASKPROC 0xf0000000 /* Processor-specific */
+#define SHF_ORDERED (1 << 30) /* Special ordering requirement
+ (Solaris). */
+#define SHF_EXCLUDE (1U << 31) /* Section is excluded unless
+ referenced or allocated (Solaris).*/
+
+/* Section compression header. Used when SHF_COMPRESSED is set. */
+
+typedef struct
+{
+ Elf32_Word ch_type; /* Compression format. */
+ Elf32_Word ch_size; /* Uncompressed data size. */
+ Elf32_Word ch_addralign; /* Uncompressed data alignment. */
+} Elf32_Chdr;
+
+typedef struct
+{
+ Elf64_Word ch_type; /* Compression format. */
+ Elf64_Word ch_reserved;
+ Elf64_Xword ch_size; /* Uncompressed data size. */
+ Elf64_Xword ch_addralign; /* Uncompressed data alignment. */
+} Elf64_Chdr;
+
+/* Legal values for ch_type (compression algorithm). */
+#define ELFCOMPRESS_ZLIB 1 /* ZLIB/DEFLATE algorithm. */
+#define ELFCOMPRESS_LOOS 0x60000000 /* Start of OS-specific. */
+#define ELFCOMPRESS_HIOS 0x6fffffff /* End of OS-specific. */
+#define ELFCOMPRESS_LOPROC 0x70000000 /* Start of processor-specific. */
+#define ELFCOMPRESS_HIPROC 0x7fffffff /* End of processor-specific. */
+
+/* Section group handling. */
+#define GRP_COMDAT 0x1 /* Mark group as COMDAT. */
+
+/* Symbol table entry. */
+
+typedef struct
+{
+ Elf32_Word st_name; /* Symbol name (string tbl index) */
+ Elf32_Addr st_value; /* Symbol value */
+ Elf32_Word st_size; /* Symbol size */
+ unsigned char st_info; /* Symbol type and binding */
+ unsigned char st_other; /* Symbol visibility */
+ Elf32_Section st_shndx; /* Section index */
+} Elf32_Sym;
+
+typedef struct
+{
+ Elf64_Word st_name; /* Symbol name (string tbl index) */
+ unsigned char st_info; /* Symbol type and binding */
+ unsigned char st_other; /* Symbol visibility */
+ Elf64_Section st_shndx; /* Section index */
+ Elf64_Addr st_value; /* Symbol value */
+ Elf64_Xword st_size; /* Symbol size */
+} Elf64_Sym;
+
+/* The syminfo section if available contains additional information about
+ every dynamic symbol. */
+
+typedef struct
+{
+ Elf32_Half si_boundto; /* Direct bindings, symbol bound to */
+ Elf32_Half si_flags; /* Per symbol flags */
+} Elf32_Syminfo;
+
+typedef struct
+{
+ Elf64_Half si_boundto; /* Direct bindings, symbol bound to */
+ Elf64_Half si_flags; /* Per symbol flags */
+} Elf64_Syminfo;
+
+/* Possible values for si_boundto. */
+#define SYMINFO_BT_SELF 0xffff /* Symbol bound to self */
+#define SYMINFO_BT_PARENT 0xfffe /* Symbol bound to parent */
+#define SYMINFO_BT_LOWRESERVE 0xff00 /* Beginning of reserved entries */
+
+/* Possible bitmasks for si_flags. */
+#define SYMINFO_FLG_DIRECT 0x0001 /* Direct bound symbol */
+#define SYMINFO_FLG_PASSTHRU 0x0002 /* Pass-thru symbol for translator */
+#define SYMINFO_FLG_COPY 0x0004 /* Symbol is a copy-reloc */
+#define SYMINFO_FLG_LAZYLOAD 0x0008 /* Symbol bound to object to be lazy
+ loaded */
+/* Syminfo version values. */
+#define SYMINFO_NONE 0
+#define SYMINFO_CURRENT 1
+#define SYMINFO_NUM 2
+
+
+/* How to extract and insert information held in the st_info field. */
+
+#define ELF32_ST_BIND(val) (((unsigned char) (val)) >> 4)
+#define ELF32_ST_TYPE(val) ((val) & 0xf)
+#define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type) & 0xf))
+
+/* Both Elf32_Sym and Elf64_Sym use the same one-byte st_info field. */
+#define ELF64_ST_BIND(val) ELF32_ST_BIND (val)
+#define ELF64_ST_TYPE(val) ELF32_ST_TYPE (val)
+#define ELF64_ST_INFO(bind, type) ELF32_ST_INFO ((bind), (type))
+
+/* Legal values for ST_BIND subfield of st_info (symbol binding). */
+
+#define STB_LOCAL 0 /* Local symbol */
+#define STB_GLOBAL 1 /* Global symbol */
+#define STB_WEAK 2 /* Weak symbol */
+#define STB_NUM 3 /* Number of defined types. */
+#define STB_LOOS 10 /* Start of OS-specific */
+#define STB_GNU_UNIQUE 10 /* Unique symbol. */
+#define STB_HIOS 12 /* End of OS-specific */
+#define STB_LOPROC 13 /* Start of processor-specific */
+#define STB_HIPROC 15 /* End of processor-specific */
+
+/* Legal values for ST_TYPE subfield of st_info (symbol type). */
+
+#define STT_NOTYPE 0 /* Symbol type is unspecified */
+#define STT_OBJECT 1 /* Symbol is a data object */
+#define STT_FUNC 2 /* Symbol is a code object */
+#define STT_SECTION 3 /* Symbol associated with a section */
+#define STT_FILE 4 /* Symbol's name is file name */
+#define STT_COMMON 5 /* Symbol is a common data object */
+#define STT_TLS 6 /* Symbol is thread-local data object*/
+#define STT_NUM 7 /* Number of defined types. */
+#define STT_LOOS 10 /* Start of OS-specific */
+#define STT_GNU_IFUNC 10 /* Symbol is indirect code object */
+#define STT_HIOS 12 /* End of OS-specific */
+#define STT_LOPROC 13 /* Start of processor-specific */
+#define STT_HIPROC 15 /* End of processor-specific */
+
+
+/* Symbol table indices are found in the hash buckets and chain table
+ of a symbol hash table section. This special index value indicates
+ the end of a chain, meaning no further symbols are found in that bucket. */
+
+#define STN_UNDEF 0 /* End of a chain. */
+
+
+/* How to extract and insert information held in the st_other field. */
+
+#define ELF32_ST_VISIBILITY(o) ((o) & 0x03)
+
+/* For ELF64 the definitions are the same. */
+#define ELF64_ST_VISIBILITY(o) ELF32_ST_VISIBILITY (o)
+
+/* Symbol visibility specification encoded in the st_other field. */
+#define STV_DEFAULT 0 /* Default symbol visibility rules */
+#define STV_INTERNAL 1 /* Processor specific hidden class */
+#define STV_HIDDEN 2 /* Sym unavailable in other modules */
+#define STV_PROTECTED 3 /* Not preemptible, not exported */
+
+
+/* Relocation table entry without addend (in section of type SHT_REL). */
+
+typedef struct
+{
+ Elf32_Addr r_offset; /* Address */
+ Elf32_Word r_info; /* Relocation type and symbol index */
+} Elf32_Rel;
+
+/* I have seen two different definitions of the Elf64_Rel and
+ Elf64_Rela structures, so we'll leave them out until Novell (or
+ whoever) gets their act together. */
+/* The following, at least, is used on Sparc v9, MIPS, and Alpha. */
+
+typedef struct
+{
+ Elf64_Addr r_offset; /* Address */
+ Elf64_Xword r_info; /* Relocation type and symbol index */
+} Elf64_Rel;
+
+/* Relocation table entry with addend (in section of type SHT_RELA). */
+
+typedef struct
+{
+ Elf32_Addr r_offset; /* Address */
+ Elf32_Word r_info; /* Relocation type and symbol index */
+ Elf32_Sword r_addend; /* Addend */
+} Elf32_Rela;
+
+typedef struct
+{
+ Elf64_Addr r_offset; /* Address */
+ Elf64_Xword r_info; /* Relocation type and symbol index */
+ Elf64_Sxword r_addend; /* Addend */
+} Elf64_Rela;
+
+/* How to extract and insert information held in the r_info field. */
+
+#define ELF32_R_SYM(val) ((val) >> 8)
+#define ELF32_R_TYPE(val) ((val) & 0xff)
+#define ELF32_R_INFO(sym, type) (((sym) << 8) + ((type) & 0xff))
+
+#define ELF64_R_SYM(i) ((i) >> 32)
+#define ELF64_R_TYPE(i) ((i) & 0xffffffff)
+#define ELF64_R_INFO(sym,type) ((((Elf64_Xword) (sym)) << 32) + (type))
+
+/* Program segment header. */
+
+typedef struct
+{
+ Elf32_Word p_type; /* Segment type */
+ Elf32_Off p_offset; /* Segment file offset */
+ Elf32_Addr p_vaddr; /* Segment virtual address */
+ Elf32_Addr p_paddr; /* Segment physical address */
+ Elf32_Word p_filesz; /* Segment size in file */
+ Elf32_Word p_memsz; /* Segment size in memory */
+ Elf32_Word p_flags; /* Segment flags */
+ Elf32_Word p_align; /* Segment alignment */
+} Elf32_Phdr;
+
+typedef struct
+{
+ Elf64_Word p_type; /* Segment type */
+ Elf64_Word p_flags; /* Segment flags */
+ Elf64_Off p_offset; /* Segment file offset */
+ Elf64_Addr p_vaddr; /* Segment virtual address */
+ Elf64_Addr p_paddr; /* Segment physical address */
+ Elf64_Xword p_filesz; /* Segment size in file */
+ Elf64_Xword p_memsz; /* Segment size in memory */
+ Elf64_Xword p_align; /* Segment alignment */
+} Elf64_Phdr;
+
+/* Special value for e_phnum. This indicates that the real number of
+ program headers is too large to fit into e_phnum. Instead the real
+ value is in the field sh_info of section 0. */
+
+#define PN_XNUM 0xffff
+
+/* Legal values for p_type (segment type). */
+
+#define PT_NULL 0 /* Program header table entry unused */
+#define PT_LOAD 1 /* Loadable program segment */
+#define PT_DYNAMIC 2 /* Dynamic linking information */
+#define PT_INTERP 3 /* Program interpreter */
+#define PT_NOTE 4 /* Auxiliary information */
+#define PT_SHLIB 5 /* Reserved */
+#define PT_PHDR 6 /* Entry for header table itself */
+#define PT_TLS 7 /* Thread-local storage segment */
+#define PT_NUM 8 /* Number of defined types */
+#define PT_LOOS 0x60000000 /* Start of OS-specific */
+#define PT_GNU_EH_FRAME 0x6474e550 /* GCC .eh_frame_hdr segment */
+#define PT_GNU_STACK 0x6474e551 /* Indicates stack executability */
+#define PT_GNU_RELRO 0x6474e552 /* Read-only after relocation */
+#define PT_LOSUNW 0x6ffffffa
+#define PT_SUNWBSS 0x6ffffffa /* Sun Specific segment */
+#define PT_SUNWSTACK 0x6ffffffb /* Stack segment */
+#define PT_HISUNW 0x6fffffff
+#define PT_HIOS 0x6fffffff /* End of OS-specific */
+#define PT_LOPROC 0x70000000 /* Start of processor-specific */
+#define PT_HIPROC 0x7fffffff /* End of processor-specific */
+
+/* Legal values for p_flags (segment flags). */
+
+#define PF_X (1 << 0) /* Segment is executable */
+#define PF_W (1 << 1) /* Segment is writable */
+#define PF_R (1 << 2) /* Segment is readable */
+#define PF_MASKOS 0x0ff00000 /* OS-specific */
+#define PF_MASKPROC 0xf0000000 /* Processor-specific */
+
+/* Legal values for note segment descriptor types for core files. */
+
+#define NT_PRSTATUS 1 /* Contains copy of prstatus struct */
+#define NT_FPREGSET 2 /* Contains copy of fpregset struct */
+#define NT_PRPSINFO 3 /* Contains copy of prpsinfo struct */
+#define NT_PRXREG 4 /* Contains copy of prxregset struct */
+#define NT_TASKSTRUCT 4 /* Contains copy of task structure */
+#define NT_PLATFORM 5 /* String from sysinfo(SI_PLATFORM) */
+#define NT_AUXV 6 /* Contains copy of auxv array */
+#define NT_GWINDOWS 7 /* Contains copy of gwindows struct */
+#define NT_ASRS 8 /* Contains copy of asrset struct */
+#define NT_PSTATUS 10 /* Contains copy of pstatus struct */
+#define NT_PSINFO 13 /* Contains copy of psinfo struct */
+#define NT_PRCRED 14 /* Contains copy of prcred struct */
+#define NT_UTSNAME 15 /* Contains copy of utsname struct */
+#define NT_LWPSTATUS 16 /* Contains copy of lwpstatus struct */
+#define NT_LWPSINFO 17 /* Contains copy of lwpinfo struct */
+#define NT_PRFPXREG 20 /* Contains copy of fprxregset struct */
+#define NT_SIGINFO 0x53494749 /* Contains copy of siginfo_t,
+ size might increase */
+#define NT_FILE 0x46494c45 /* Contains information about mapped
+ files */
+#define NT_PRXFPREG 0x46e62b7f /* Contains copy of user_fxsr_struct */
+#define NT_PPC_VMX 0x100 /* PowerPC Altivec/VMX registers */
+#define NT_PPC_SPE 0x101 /* PowerPC SPE/EVR registers */
+#define NT_PPC_VSX 0x102 /* PowerPC VSX registers */
+#define NT_386_TLS 0x200 /* i386 TLS slots (struct user_desc) */
+#define NT_386_IOPERM 0x201 /* x86 io permission bitmap (1=deny) */
+#define NT_X86_XSTATE 0x202 /* x86 extended state using xsave */
+#define NT_S390_HIGH_GPRS 0x300 /* s390 upper register halves */
+#define NT_S390_TIMER 0x301 /* s390 timer register */
+#define NT_S390_TODCMP 0x302 /* s390 TOD clock comparator register */
+#define NT_S390_TODPREG 0x303 /* s390 TOD programmable register */
+#define NT_S390_CTRS 0x304 /* s390 control registers */
+#define NT_S390_PREFIX 0x305 /* s390 prefix register */
+#define NT_S390_LAST_BREAK 0x306 /* s390 breaking event address */
+#define NT_S390_SYSTEM_CALL 0x307 /* s390 system call restart data */
+#define NT_S390_TDB 0x308 /* s390 transaction diagnostic block */
+#define NT_ARM_VFP 0x400 /* ARM VFP/NEON registers */
+#define NT_ARM_TLS 0x401 /* ARM TLS register */
+#define NT_ARM_HW_BREAK 0x402 /* ARM hardware breakpoint registers */
+#define NT_ARM_HW_WATCH 0x403 /* ARM hardware watchpoint registers */
+
+/* Legal values for the note segment descriptor types for object files. */
+
+#define NT_VERSION 1 /* Contains a version string. */
+
+
+/* Dynamic section entry. */
+
+typedef struct
+{
+ Elf32_Sword d_tag; /* Dynamic entry type */
+ union
+ {
+ Elf32_Word d_val; /* Integer value */
+ Elf32_Addr d_ptr; /* Address value */
+ } d_un;
+} Elf32_Dyn;
+
+typedef struct
+{
+ Elf64_Sxword d_tag; /* Dynamic entry type */
+ union
+ {
+ Elf64_Xword d_val; /* Integer value */
+ Elf64_Addr d_ptr; /* Address value */
+ } d_un;
+} Elf64_Dyn;
+
+/* Legal values for d_tag (dynamic entry type). */
+
+#define DT_NULL 0 /* Marks end of dynamic section */
+#define DT_NEEDED 1 /* Name of needed library */
+#define DT_PLTRELSZ 2 /* Size in bytes of PLT relocs */
+#define DT_PLTGOT 3 /* Processor defined value */
+#define DT_HASH 4 /* Address of symbol hash table */
+#define DT_STRTAB 5 /* Address of string table */
+#define DT_SYMTAB 6 /* Address of symbol table */
+#define DT_RELA 7 /* Address of Rela relocs */
+#define DT_RELASZ 8 /* Total size of Rela relocs */
+#define DT_RELAENT 9 /* Size of one Rela reloc */
+#define DT_STRSZ 10 /* Size of string table */
+#define DT_SYMENT 11 /* Size of one symbol table entry */
+#define DT_INIT 12 /* Address of init function */
+#define DT_FINI 13 /* Address of termination function */
+#define DT_SONAME 14 /* Name of shared object */
+#define DT_RPATH 15 /* Library search path (deprecated) */
+#define DT_SYMBOLIC 16 /* Start symbol search here */
+#define DT_REL 17 /* Address of Rel relocs */
+#define DT_RELSZ 18 /* Total size of Rel relocs */
+#define DT_RELENT 19 /* Size of one Rel reloc */
+#define DT_PLTREL 20 /* Type of reloc in PLT */
+#define DT_DEBUG 21 /* For debugging; unspecified */
+#define DT_TEXTREL 22 /* Reloc might modify .text */
+#define DT_JMPREL 23 /* Address of PLT relocs */
+#define DT_BIND_NOW 24 /* Process relocations of object */
+#define DT_INIT_ARRAY 25 /* Array with addresses of init fct */
+#define DT_FINI_ARRAY 26 /* Array with addresses of fini fct */
+#define DT_INIT_ARRAYSZ 27 /* Size in bytes of DT_INIT_ARRAY */
+#define DT_FINI_ARRAYSZ 28 /* Size in bytes of DT_FINI_ARRAY */
+#define DT_RUNPATH 29 /* Library search path */
+#define DT_FLAGS 30 /* Flags for the object being loaded */
+#define DT_ENCODING 32 /* Start of encoded range */
+#define DT_PREINIT_ARRAY 32 /* Array with addresses of preinit fct*/
+#define DT_PREINIT_ARRAYSZ 33 /* size in bytes of DT_PREINIT_ARRAY */
+#define DT_NUM 34 /* Number used */
+#define DT_LOOS 0x6000000d /* Start of OS-specific */
+#define DT_HIOS 0x6ffff000 /* End of OS-specific */
+#define DT_LOPROC 0x70000000 /* Start of processor-specific */
+#define DT_HIPROC 0x7fffffff /* End of processor-specific */
+#define DT_PROCNUM DT_MIPS_NUM /* Most used by any processor */
+
+/* DT_* entries which fall between DT_VALRNGHI & DT_VALRNGLO use the
+ Dyn.d_un.d_val field of the Elf*_Dyn structure. This follows Sun's
+ approach. */
+#define DT_VALRNGLO 0x6ffffd00
+#define DT_GNU_PRELINKED 0x6ffffdf5 /* Prelinking timestamp */
+#define DT_GNU_CONFLICTSZ 0x6ffffdf6 /* Size of conflict section */
+#define DT_GNU_LIBLISTSZ 0x6ffffdf7 /* Size of library list */
+#define DT_CHECKSUM 0x6ffffdf8
+#define DT_PLTPADSZ 0x6ffffdf9
+#define DT_MOVEENT 0x6ffffdfa
+#define DT_MOVESZ 0x6ffffdfb
+#define DT_FEATURE_1 0x6ffffdfc /* Feature selection (DTF_*). */
+#define DT_POSFLAG_1 0x6ffffdfd /* Flags for DT_* entries, effecting
+ the following DT_* entry. */
+#define DT_SYMINSZ 0x6ffffdfe /* Size of syminfo table (in bytes) */
+#define DT_SYMINENT 0x6ffffdff /* Entry size of syminfo */
+#define DT_VALRNGHI 0x6ffffdff
+#define DT_VALTAGIDX(tag) (DT_VALRNGHI - (tag)) /* Reverse order! */
+#define DT_VALNUM 12
+
+/* DT_* entries which fall between DT_ADDRRNGHI & DT_ADDRRNGLO use the
+ Dyn.d_un.d_ptr field of the Elf*_Dyn structure.
+
+ If any adjustment is made to the ELF object after it has been
+ built these entries will need to be adjusted. */
+#define DT_ADDRRNGLO 0x6ffffe00
+#define DT_GNU_HASH 0x6ffffef5 /* GNU-style hash table. */
+#define DT_TLSDESC_PLT 0x6ffffef6
+#define DT_TLSDESC_GOT 0x6ffffef7
+#define DT_GNU_CONFLICT 0x6ffffef8 /* Start of conflict section */
+#define DT_GNU_LIBLIST 0x6ffffef9 /* Library list */
+#define DT_CONFIG 0x6ffffefa /* Configuration information. */
+#define DT_DEPAUDIT 0x6ffffefb /* Dependency auditing. */
+#define DT_AUDIT 0x6ffffefc /* Object auditing. */
+#define DT_PLTPAD 0x6ffffefd /* PLT padding. */
+#define DT_MOVETAB 0x6ffffefe /* Move table. */
+#define DT_SYMINFO 0x6ffffeff /* Syminfo table. */
+#define DT_ADDRRNGHI 0x6ffffeff
+#define DT_ADDRTAGIDX(tag) (DT_ADDRRNGHI - (tag)) /* Reverse order! */
+#define DT_ADDRNUM 11
+
+/* The versioning entry types. The next are defined as part of the
+ GNU extension. */
+#define DT_VERSYM 0x6ffffff0
+
+#define DT_RELACOUNT 0x6ffffff9
+#define DT_RELCOUNT 0x6ffffffa
+
+/* These were chosen by Sun. */
+#define DT_FLAGS_1 0x6ffffffb /* State flags, see DF_1_* below. */
+#define DT_VERDEF 0x6ffffffc /* Address of version definition
+ table */
+#define DT_VERDEFNUM 0x6ffffffd /* Number of version definitions */
+#define DT_VERNEED 0x6ffffffe /* Address of table with needed
+ versions */
+#define DT_VERNEEDNUM 0x6fffffff /* Number of needed versions */
+#define DT_VERSIONTAGIDX(tag) (DT_VERNEEDNUM - (tag)) /* Reverse order! */
+#define DT_VERSIONTAGNUM 16
+
+/* Sun added these machine-independent extensions in the "processor-specific"
+ range. Be compatible. */
+#define DT_AUXILIARY 0x7ffffffd /* Shared object to load before self */
+#define DT_FILTER 0x7fffffff /* Shared object to get values from */
+#define DT_EXTRATAGIDX(tag) ((Elf32_Word)-((Elf32_Sword) (tag) <<1>>1)-1)
+#define DT_EXTRANUM 3
+
+/* Values of `d_un.d_val' in the DT_FLAGS entry. */
+#define DF_ORIGIN 0x00000001 /* Object may use DF_ORIGIN */
+#define DF_SYMBOLIC 0x00000002 /* Symbol resolutions starts here */
+#define DF_TEXTREL 0x00000004 /* Object contains text relocations */
+#define DF_BIND_NOW 0x00000008 /* No lazy binding for this object */
+#define DF_STATIC_TLS 0x00000010 /* Module uses the static TLS model */
+
+/* State flags selectable in the `d_un.d_val' element of the DT_FLAGS_1
+ entry in the dynamic section. */
+#define DF_1_NOW 0x00000001 /* Set RTLD_NOW for this object. */
+#define DF_1_GLOBAL 0x00000002 /* Set RTLD_GLOBAL for this object. */
+#define DF_1_GROUP 0x00000004 /* Set RTLD_GROUP for this object. */
+#define DF_1_NODELETE 0x00000008 /* Set RTLD_NODELETE for this object.*/
+#define DF_1_LOADFLTR 0x00000010 /* Trigger filtee loading at runtime.*/
+#define DF_1_INITFIRST 0x00000020 /* Set RTLD_INITFIRST for this object*/
+#define DF_1_NOOPEN 0x00000040 /* Set RTLD_NOOPEN for this object. */
+#define DF_1_ORIGIN 0x00000080 /* $ORIGIN must be handled. */
+#define DF_1_DIRECT 0x00000100 /* Direct binding enabled. */
+#define DF_1_TRANS 0x00000200
+#define DF_1_INTERPOSE 0x00000400 /* Object is used to interpose. */
+#define DF_1_NODEFLIB 0x00000800 /* Ignore default lib search path. */
+#define DF_1_NODUMP 0x00001000 /* Object can't be dldump'ed. */
+#define DF_1_CONFALT 0x00002000 /* Configuration alternative created.*/
+#define DF_1_ENDFILTEE 0x00004000 /* Filtee terminates filters search. */
+#define DF_1_DISPRELDNE 0x00008000 /* Disp reloc applied at build time. */
+#define DF_1_DISPRELPND 0x00010000 /* Disp reloc applied at run-time. */
+#define DF_1_NODIRECT 0x00020000 /* Object has no-direct binding. */
+#define DF_1_IGNMULDEF 0x00040000
+#define DF_1_NOKSYMS 0x00080000
+#define DF_1_NOHDR 0x00100000
+#define DF_1_EDITED 0x00200000 /* Object is modified after built. */
+#define DF_1_NORELOC 0x00400000
+#define DF_1_SYMINTPOSE 0x00800000 /* Object has individual interposers. */
+#define DF_1_GLOBAUDIT 0x01000000 /* Global auditing required. */
+#define DF_1_SINGLETON 0x02000000 /* Singleton symbols are used. */
+
+/* Flags for the feature selection in DT_FEATURE_1. */
+#define DTF_1_PARINIT 0x00000001
+#define DTF_1_CONFEXP 0x00000002
+
+/* Flags in the DT_POSFLAG_1 entry effecting only the next DT_* entry. */
+#define DF_P1_LAZYLOAD 0x00000001 /* Lazyload following object. */
+#define DF_P1_GROUPPERM 0x00000002 /* Symbols from next object are not
+ generally available. */
+
+/* Version definition sections. */
+
+typedef struct
+{
+ Elf32_Half vd_version; /* Version revision */
+ Elf32_Half vd_flags; /* Version information */
+ Elf32_Half vd_ndx; /* Version Index */
+ Elf32_Half vd_cnt; /* Number of associated aux entries */
+ Elf32_Word vd_hash; /* Version name hash value */
+ Elf32_Word vd_aux; /* Offset in bytes to verdaux array */
+ Elf32_Word vd_next; /* Offset in bytes to next verdef
+ entry */
+} Elf32_Verdef;
+
+typedef struct
+{
+ Elf64_Half vd_version; /* Version revision */
+ Elf64_Half vd_flags; /* Version information */
+ Elf64_Half vd_ndx; /* Version Index */
+ Elf64_Half vd_cnt; /* Number of associated aux entries */
+ Elf64_Word vd_hash; /* Version name hash value */
+ Elf64_Word vd_aux; /* Offset in bytes to verdaux array */
+ Elf64_Word vd_next; /* Offset in bytes to next verdef
+ entry */
+} Elf64_Verdef;
+
+
+/* Legal values for vd_version (version revision). */
+#define VER_DEF_NONE 0 /* No version */
+#define VER_DEF_CURRENT 1 /* Current version */
+#define VER_DEF_NUM 2 /* Given version number */
+
+/* Legal values for vd_flags (version information flags). */
+#define VER_FLG_BASE 0x1 /* Version definition of file itself */
+#define VER_FLG_WEAK 0x2 /* Weak version identifier */
+
+/* Versym symbol index values. */
+#define VER_NDX_LOCAL 0 /* Symbol is local. */
+#define VER_NDX_GLOBAL 1 /* Symbol is global. */
+#define VER_NDX_LORESERVE 0xff00 /* Beginning of reserved entries. */
+#define VER_NDX_ELIMINATE 0xff01 /* Symbol is to be eliminated. */
+
+/* Auxialiary version information. */
+
+typedef struct
+{
+ Elf32_Word vda_name; /* Version or dependency names */
+ Elf32_Word vda_next; /* Offset in bytes to next verdaux
+ entry */
+} Elf32_Verdaux;
+
+typedef struct
+{
+ Elf64_Word vda_name; /* Version or dependency names */
+ Elf64_Word vda_next; /* Offset in bytes to next verdaux
+ entry */
+} Elf64_Verdaux;
+
+
+/* Version dependency section. */
+
+typedef struct
+{
+ Elf32_Half vn_version; /* Version of structure */
+ Elf32_Half vn_cnt; /* Number of associated aux entries */
+ Elf32_Word vn_file; /* Offset of filename for this
+ dependency */
+ Elf32_Word vn_aux; /* Offset in bytes to vernaux array */
+ Elf32_Word vn_next; /* Offset in bytes to next verneed
+ entry */
+} Elf32_Verneed;
+
+typedef struct
+{
+ Elf64_Half vn_version; /* Version of structure */
+ Elf64_Half vn_cnt; /* Number of associated aux entries */
+ Elf64_Word vn_file; /* Offset of filename for this
+ dependency */
+ Elf64_Word vn_aux; /* Offset in bytes to vernaux array */
+ Elf64_Word vn_next; /* Offset in bytes to next verneed
+ entry */
+} Elf64_Verneed;
+
+
+/* Legal values for vn_version (version revision). */
+#define VER_NEED_NONE 0 /* No version */
+#define VER_NEED_CURRENT 1 /* Current version */
+#define VER_NEED_NUM 2 /* Given version number */
+
+/* Auxiliary needed version information. */
+
+typedef struct
+{
+ Elf32_Word vna_hash; /* Hash value of dependency name */
+ Elf32_Half vna_flags; /* Dependency specific information */
+ Elf32_Half vna_other; /* Unused */
+ Elf32_Word vna_name; /* Dependency name string offset */
+ Elf32_Word vna_next; /* Offset in bytes to next vernaux
+ entry */
+} Elf32_Vernaux;
+
+typedef struct
+{
+ Elf64_Word vna_hash; /* Hash value of dependency name */
+ Elf64_Half vna_flags; /* Dependency specific information */
+ Elf64_Half vna_other; /* Unused */
+ Elf64_Word vna_name; /* Dependency name string offset */
+ Elf64_Word vna_next; /* Offset in bytes to next vernaux
+ entry */
+} Elf64_Vernaux;
+
+
+/* Legal values for vna_flags. */
+#define VER_FLG_WEAK 0x2 /* Weak version identifier */
+
+
+/* Auxiliary vector. */
+
+/* This vector is normally only used by the program interpreter. The
+ usual definition in an ABI supplement uses the name auxv_t. The
+ vector is not usually defined in a standard <elf.h> file, but it
+ can't hurt. We rename it to avoid conflicts. The sizes of these
+ types are an arrangement between the exec server and the program
+ interpreter, so we don't fully specify them here. */
+
+typedef struct
+{
+ uint32_t a_type; /* Entry type */
+ union
+ {
+ uint32_t a_val; /* Integer value */
+ /* We use to have pointer elements added here. We cannot do that,
+ though, since it does not work when using 32-bit definitions
+ on 64-bit platforms and vice versa. */
+ } a_un;
+} Elf32_auxv_t;
+
+typedef struct
+{
+ uint64_t a_type; /* Entry type */
+ union
+ {
+ uint64_t a_val; /* Integer value */
+ /* We use to have pointer elements added here. We cannot do that,
+ though, since it does not work when using 32-bit definitions
+ on 64-bit platforms and vice versa. */
+ } a_un;
+} Elf64_auxv_t;
+
+/* Legal values for a_type (entry type). */
+
+#define AT_NULL 0 /* End of vector */
+#define AT_IGNORE 1 /* Entry should be ignored */
+#define AT_EXECFD 2 /* File descriptor of program */
+#define AT_PHDR 3 /* Program headers for program */
+#define AT_PHENT 4 /* Size of program header entry */
+#define AT_PHNUM 5 /* Number of program headers */
+#define AT_PAGESZ 6 /* System page size */
+#define AT_BASE 7 /* Base address of interpreter */
+#define AT_FLAGS 8 /* Flags */
+#define AT_ENTRY 9 /* Entry point of program */
+#define AT_NOTELF 10 /* Program is not ELF */
+#define AT_UID 11 /* Real uid */
+#define AT_EUID 12 /* Effective uid */
+#define AT_GID 13 /* Real gid */
+#define AT_EGID 14 /* Effective gid */
+#define AT_CLKTCK 17 /* Frequency of times() */
+
+/* Some more special a_type values describing the hardware. */
+#define AT_PLATFORM 15 /* String identifying platform. */
+#define AT_HWCAP 16 /* Machine-dependent hints about
+ processor capabilities. */
+
+/* This entry gives some information about the FPU initialization
+ performed by the kernel. */
+#define AT_FPUCW 18 /* Used FPU control word. */
+
+/* Cache block sizes. */
+#define AT_DCACHEBSIZE 19 /* Data cache block size. */
+#define AT_ICACHEBSIZE 20 /* Instruction cache block size. */
+#define AT_UCACHEBSIZE 21 /* Unified cache block size. */
+
+/* A special ignored value for PPC, used by the kernel to control the
+ interpretation of the AUXV. Must be > 16. */
+#define AT_IGNOREPPC 22 /* Entry should be ignored. */
+
+#define AT_SECURE 23 /* Boolean, was exec setuid-like? */
+
+#define AT_BASE_PLATFORM 24 /* String identifying real platforms.*/
+
+#define AT_RANDOM 25 /* Address of 16 random bytes. */
+
+#define AT_HWCAP2 26 /* More machine-dependent hints about
+ processor capabilities. */
+
+#define AT_EXECFN 31 /* Filename of executable. */
+
+/* Pointer to the global system page used for system calls and other
+ nice things. */
+#define AT_SYSINFO 32
+#define AT_SYSINFO_EHDR 33
+
+/* Shapes of the caches. Bits 0-3 contains associativity; bits 4-7 contains
+ log2 of line size; mask those to get cache size. */
+#define AT_L1I_CACHESHAPE 34
+#define AT_L1D_CACHESHAPE 35
+#define AT_L2_CACHESHAPE 36
+#define AT_L3_CACHESHAPE 37
+
+/* Note section contents. Each entry in the note section begins with
+ a header of a fixed form. */
+
+typedef struct
+{
+ Elf32_Word n_namesz; /* Length of the note's name. */
+ Elf32_Word n_descsz; /* Length of the note's descriptor. */
+ Elf32_Word n_type; /* Type of the note. */
+} Elf32_Nhdr;
+
+typedef struct
+{
+ Elf64_Word n_namesz; /* Length of the note's name. */
+ Elf64_Word n_descsz; /* Length of the note's descriptor. */
+ Elf64_Word n_type; /* Type of the note. */
+} Elf64_Nhdr;
+
+/* Known names of notes. */
+
+/* Solaris entries in the note section have this name. */
+#define ELF_NOTE_SOLARIS "SUNW Solaris"
+
+/* Note entries for GNU systems have this name. */
+#define ELF_NOTE_GNU "GNU"
+
+
+/* Defined types of notes for Solaris. */
+
+/* Value of descriptor (one word) is desired pagesize for the binary. */
+#define ELF_NOTE_PAGESIZE_HINT 1
+
+
+/* Defined note types for GNU systems. */
+
+/* ABI information. The descriptor consists of words:
+ word 0: OS descriptor
+ word 1: major version of the ABI
+ word 2: minor version of the ABI
+ word 3: subminor version of the ABI
+*/
+#define NT_GNU_ABI_TAG 1
+#define ELF_NOTE_ABI NT_GNU_ABI_TAG /* Old name. */
+
+/* Known OSes. These values can appear in word 0 of an
+ NT_GNU_ABI_TAG note section entry. */
+#define ELF_NOTE_OS_LINUX 0
+#define ELF_NOTE_OS_GNU 1
+#define ELF_NOTE_OS_SOLARIS2 2
+#define ELF_NOTE_OS_FREEBSD 3
+
+/* Synthetic hwcap information. The descriptor begins with two words:
+ word 0: number of entries
+ word 1: bitmask of enabled entries
+ Then follow variable-length entries, one byte followed by a
+ '\0'-terminated hwcap name string. The byte gives the bit
+ number to test if enabled, (1U << bit) & bitmask. */
+#define NT_GNU_HWCAP 2
+
+/* Build ID bits as generated by ld --build-id.
+ The descriptor consists of any nonzero number of bytes. */
+#define NT_GNU_BUILD_ID 3
+
+/* Version note generated by GNU gold containing a version string. */
+#define NT_GNU_GOLD_VERSION 4
+
+
+/* Move records. */
+typedef struct
+{
+ Elf32_Xword m_value; /* Symbol value. */
+ Elf32_Word m_info; /* Size and index. */
+ Elf32_Word m_poffset; /* Symbol offset. */
+ Elf32_Half m_repeat; /* Repeat count. */
+ Elf32_Half m_stride; /* Stride info. */
+} Elf32_Move;
+
+typedef struct
+{
+ Elf64_Xword m_value; /* Symbol value. */
+ Elf64_Xword m_info; /* Size and index. */
+ Elf64_Xword m_poffset; /* Symbol offset. */
+ Elf64_Half m_repeat; /* Repeat count. */
+ Elf64_Half m_stride; /* Stride info. */
+} Elf64_Move;
+
+/* Macro to construct move records. */
+#define ELF32_M_SYM(info) ((info) >> 8)
+#define ELF32_M_SIZE(info) ((unsigned char) (info))
+#define ELF32_M_INFO(sym, size) (((sym) << 8) + (unsigned char) (size))
+
+#define ELF64_M_SYM(info) ELF32_M_SYM (info)
+#define ELF64_M_SIZE(info) ELF32_M_SIZE (info)
+#define ELF64_M_INFO(sym, size) ELF32_M_INFO (sym, size)
+
+
+/* Motorola 68k specific definitions. */
+
+/* Values for Elf32_Ehdr.e_flags. */
+#define EF_CPU32 0x00810000
+
+/* m68k relocs. */
+
+#define R_68K_NONE 0 /* No reloc */
+#define R_68K_32 1 /* Direct 32 bit */
+#define R_68K_16 2 /* Direct 16 bit */
+#define R_68K_8 3 /* Direct 8 bit */
+#define R_68K_PC32 4 /* PC relative 32 bit */
+#define R_68K_PC16 5 /* PC relative 16 bit */
+#define R_68K_PC8 6 /* PC relative 8 bit */
+#define R_68K_GOT32 7 /* 32 bit PC relative GOT entry */
+#define R_68K_GOT16 8 /* 16 bit PC relative GOT entry */
+#define R_68K_GOT8 9 /* 8 bit PC relative GOT entry */
+#define R_68K_GOT32O 10 /* 32 bit GOT offset */
+#define R_68K_GOT16O 11 /* 16 bit GOT offset */
+#define R_68K_GOT8O 12 /* 8 bit GOT offset */
+#define R_68K_PLT32 13 /* 32 bit PC relative PLT address */
+#define R_68K_PLT16 14 /* 16 bit PC relative PLT address */
+#define R_68K_PLT8 15 /* 8 bit PC relative PLT address */
+#define R_68K_PLT32O 16 /* 32 bit PLT offset */
+#define R_68K_PLT16O 17 /* 16 bit PLT offset */
+#define R_68K_PLT8O 18 /* 8 bit PLT offset */
+#define R_68K_COPY 19 /* Copy symbol at runtime */
+#define R_68K_GLOB_DAT 20 /* Create GOT entry */
+#define R_68K_JMP_SLOT 21 /* Create PLT entry */
+#define R_68K_RELATIVE 22 /* Adjust by program base */
+#define R_68K_TLS_GD32 25 /* 32 bit GOT offset for GD */
+#define R_68K_TLS_GD16 26 /* 16 bit GOT offset for GD */
+#define R_68K_TLS_GD8 27 /* 8 bit GOT offset for GD */
+#define R_68K_TLS_LDM32 28 /* 32 bit GOT offset for LDM */
+#define R_68K_TLS_LDM16 29 /* 16 bit GOT offset for LDM */
+#define R_68K_TLS_LDM8 30 /* 8 bit GOT offset for LDM */
+#define R_68K_TLS_LDO32 31 /* 32 bit module-relative offset */
+#define R_68K_TLS_LDO16 32 /* 16 bit module-relative offset */
+#define R_68K_TLS_LDO8 33 /* 8 bit module-relative offset */
+#define R_68K_TLS_IE32 34 /* 32 bit GOT offset for IE */
+#define R_68K_TLS_IE16 35 /* 16 bit GOT offset for IE */
+#define R_68K_TLS_IE8 36 /* 8 bit GOT offset for IE */
+#define R_68K_TLS_LE32 37 /* 32 bit offset relative to
+ static TLS block */
+#define R_68K_TLS_LE16 38 /* 16 bit offset relative to
+ static TLS block */
+#define R_68K_TLS_LE8 39 /* 8 bit offset relative to
+ static TLS block */
+#define R_68K_TLS_DTPMOD32 40 /* 32 bit module number */
+#define R_68K_TLS_DTPREL32 41 /* 32 bit module-relative offset */
+#define R_68K_TLS_TPREL32 42 /* 32 bit TP-relative offset */
+/* Keep this the last entry. */
+#define R_68K_NUM 43
+
+/* Intel 80386 specific definitions. */
+
+/* i386 relocs. */
+
+#define R_386_NONE 0 /* No reloc */
+#define R_386_32 1 /* Direct 32 bit */
+#define R_386_PC32 2 /* PC relative 32 bit */
+#define R_386_GOT32 3 /* 32 bit GOT entry */
+#define R_386_PLT32 4 /* 32 bit PLT address */
+#define R_386_COPY 5 /* Copy symbol at runtime */
+#define R_386_GLOB_DAT 6 /* Create GOT entry */
+#define R_386_JMP_SLOT 7 /* Create PLT entry */
+#define R_386_RELATIVE 8 /* Adjust by program base */
+#define R_386_GOTOFF 9 /* 32 bit offset to GOT */
+#define R_386_GOTPC 10 /* 32 bit PC relative offset to GOT */
+#define R_386_32PLT 11
+#define R_386_TLS_TPOFF 14 /* Offset in static TLS block */
+#define R_386_TLS_IE 15 /* Address of GOT entry for static TLS
+ block offset */
+#define R_386_TLS_GOTIE 16 /* GOT entry for static TLS block
+ offset */
+#define R_386_TLS_LE 17 /* Offset relative to static TLS
+ block */
+#define R_386_TLS_GD 18 /* Direct 32 bit for GNU version of
+ general dynamic thread local data */
+#define R_386_TLS_LDM 19 /* Direct 32 bit for GNU version of
+ local dynamic thread local data
+ in LE code */
+#define R_386_16 20
+#define R_386_PC16 21
+#define R_386_8 22
+#define R_386_PC8 23
+#define R_386_TLS_GD_32 24 /* Direct 32 bit for general dynamic
+ thread local data */
+#define R_386_TLS_GD_PUSH 25 /* Tag for pushl in GD TLS code */
+#define R_386_TLS_GD_CALL 26 /* Relocation for call to
+ __tls_get_addr() */
+#define R_386_TLS_GD_POP 27 /* Tag for popl in GD TLS code */
+#define R_386_TLS_LDM_32 28 /* Direct 32 bit for local dynamic
+ thread local data in LE code */
+#define R_386_TLS_LDM_PUSH 29 /* Tag for pushl in LDM TLS code */
+#define R_386_TLS_LDM_CALL 30 /* Relocation for call to
+ __tls_get_addr() in LDM code */
+#define R_386_TLS_LDM_POP 31 /* Tag for popl in LDM TLS code */
+#define R_386_TLS_LDO_32 32 /* Offset relative to TLS block */
+#define R_386_TLS_IE_32 33 /* GOT entry for negated static TLS
+ block offset */
+#define R_386_TLS_LE_32 34 /* Negated offset relative to static
+ TLS block */
+#define R_386_TLS_DTPMOD32 35 /* ID of module containing symbol */
+#define R_386_TLS_DTPOFF32 36 /* Offset in TLS block */
+#define R_386_TLS_TPOFF32 37 /* Negated offset in static TLS block */
+#define R_386_SIZE32 38 /* 32-bit symbol size */
+#define R_386_TLS_GOTDESC 39 /* GOT offset for TLS descriptor. */
+#define R_386_TLS_DESC_CALL 40 /* Marker of call through TLS
+ descriptor for
+ relaxation. */
+#define R_386_TLS_DESC 41 /* TLS descriptor containing
+ pointer to code and to
+ argument, returning the TLS
+ offset for the symbol. */
+#define R_386_IRELATIVE 42 /* Adjust indirectly by program base */
+/* Keep this the last entry. */
+#define R_386_NUM 43
+
+/* SUN SPARC specific definitions. */
+
+/* Legal values for ST_TYPE subfield of st_info (symbol type). */
+
+#define STT_SPARC_REGISTER 13 /* Global register reserved to app. */
+
+/* Values for Elf64_Ehdr.e_flags. */
+
+#define EF_SPARCV9_MM 3
+#define EF_SPARCV9_TSO 0
+#define EF_SPARCV9_PSO 1
+#define EF_SPARCV9_RMO 2
+#define EF_SPARC_LEDATA 0x800000 /* little endian data */
+#define EF_SPARC_EXT_MASK 0xFFFF00
+#define EF_SPARC_32PLUS 0x000100 /* generic V8+ features */
+#define EF_SPARC_SUN_US1 0x000200 /* Sun UltraSPARC1 extensions */
+#define EF_SPARC_HAL_R1 0x000400 /* HAL R1 extensions */
+#define EF_SPARC_SUN_US3 0x000800 /* Sun UltraSPARCIII extensions */
+
+/* SPARC relocs. */
+
+#define R_SPARC_NONE 0 /* No reloc */
+#define R_SPARC_8 1 /* Direct 8 bit */
+#define R_SPARC_16 2 /* Direct 16 bit */
+#define R_SPARC_32 3 /* Direct 32 bit */
+#define R_SPARC_DISP8 4 /* PC relative 8 bit */
+#define R_SPARC_DISP16 5 /* PC relative 16 bit */
+#define R_SPARC_DISP32 6 /* PC relative 32 bit */
+#define R_SPARC_WDISP30 7 /* PC relative 30 bit shifted */
+#define R_SPARC_WDISP22 8 /* PC relative 22 bit shifted */
+#define R_SPARC_HI22 9 /* High 22 bit */
+#define R_SPARC_22 10 /* Direct 22 bit */
+#define R_SPARC_13 11 /* Direct 13 bit */
+#define R_SPARC_LO10 12 /* Truncated 10 bit */
+#define R_SPARC_GOT10 13 /* Truncated 10 bit GOT entry */
+#define R_SPARC_GOT13 14 /* 13 bit GOT entry */
+#define R_SPARC_GOT22 15 /* 22 bit GOT entry shifted */
+#define R_SPARC_PC10 16 /* PC relative 10 bit truncated */
+#define R_SPARC_PC22 17 /* PC relative 22 bit shifted */
+#define R_SPARC_WPLT30 18 /* 30 bit PC relative PLT address */
+#define R_SPARC_COPY 19 /* Copy symbol at runtime */
+#define R_SPARC_GLOB_DAT 20 /* Create GOT entry */
+#define R_SPARC_JMP_SLOT 21 /* Create PLT entry */
+#define R_SPARC_RELATIVE 22 /* Adjust by program base */
+#define R_SPARC_UA32 23 /* Direct 32 bit unaligned */
+
+/* Additional Sparc64 relocs. */
+
+#define R_SPARC_PLT32 24 /* Direct 32 bit ref to PLT entry */
+#define R_SPARC_HIPLT22 25 /* High 22 bit PLT entry */
+#define R_SPARC_LOPLT10 26 /* Truncated 10 bit PLT entry */
+#define R_SPARC_PCPLT32 27 /* PC rel 32 bit ref to PLT entry */
+#define R_SPARC_PCPLT22 28 /* PC rel high 22 bit PLT entry */
+#define R_SPARC_PCPLT10 29 /* PC rel trunc 10 bit PLT entry */
+#define R_SPARC_10 30 /* Direct 10 bit */
+#define R_SPARC_11 31 /* Direct 11 bit */
+#define R_SPARC_64 32 /* Direct 64 bit */
+#define R_SPARC_OLO10 33 /* 10bit with secondary 13bit addend */
+#define R_SPARC_HH22 34 /* Top 22 bits of direct 64 bit */
+#define R_SPARC_HM10 35 /* High middle 10 bits of ... */
+#define R_SPARC_LM22 36 /* Low middle 22 bits of ... */
+#define R_SPARC_PC_HH22 37 /* Top 22 bits of pc rel 64 bit */
+#define R_SPARC_PC_HM10 38 /* High middle 10 bit of ... */
+#define R_SPARC_PC_LM22 39 /* Low miggle 22 bits of ... */
+#define R_SPARC_WDISP16 40 /* PC relative 16 bit shifted */
+#define R_SPARC_WDISP19 41 /* PC relative 19 bit shifted */
+#define R_SPARC_GLOB_JMP 42 /* was part of v9 ABI but was removed */
+#define R_SPARC_7 43 /* Direct 7 bit */
+#define R_SPARC_5 44 /* Direct 5 bit */
+#define R_SPARC_6 45 /* Direct 6 bit */
+#define R_SPARC_DISP64 46 /* PC relative 64 bit */
+#define R_SPARC_PLT64 47 /* Direct 64 bit ref to PLT entry */
+#define R_SPARC_HIX22 48 /* High 22 bit complemented */
+#define R_SPARC_LOX10 49 /* Truncated 11 bit complemented */
+#define R_SPARC_H44 50 /* Direct high 12 of 44 bit */
+#define R_SPARC_M44 51 /* Direct mid 22 of 44 bit */
+#define R_SPARC_L44 52 /* Direct low 10 of 44 bit */
+#define R_SPARC_REGISTER 53 /* Global register usage */
+#define R_SPARC_UA64 54 /* Direct 64 bit unaligned */
+#define R_SPARC_UA16 55 /* Direct 16 bit unaligned */
+#define R_SPARC_TLS_GD_HI22 56
+#define R_SPARC_TLS_GD_LO10 57
+#define R_SPARC_TLS_GD_ADD 58
+#define R_SPARC_TLS_GD_CALL 59
+#define R_SPARC_TLS_LDM_HI22 60
+#define R_SPARC_TLS_LDM_LO10 61
+#define R_SPARC_TLS_LDM_ADD 62
+#define R_SPARC_TLS_LDM_CALL 63
+#define R_SPARC_TLS_LDO_HIX22 64
+#define R_SPARC_TLS_LDO_LOX10 65
+#define R_SPARC_TLS_LDO_ADD 66
+#define R_SPARC_TLS_IE_HI22 67
+#define R_SPARC_TLS_IE_LO10 68
+#define R_SPARC_TLS_IE_LD 69
+#define R_SPARC_TLS_IE_LDX 70
+#define R_SPARC_TLS_IE_ADD 71
+#define R_SPARC_TLS_LE_HIX22 72
+#define R_SPARC_TLS_LE_LOX10 73
+#define R_SPARC_TLS_DTPMOD32 74
+#define R_SPARC_TLS_DTPMOD64 75
+#define R_SPARC_TLS_DTPOFF32 76
+#define R_SPARC_TLS_DTPOFF64 77
+#define R_SPARC_TLS_TPOFF32 78
+#define R_SPARC_TLS_TPOFF64 79
+#define R_SPARC_GOTDATA_HIX22 80
+#define R_SPARC_GOTDATA_LOX10 81
+#define R_SPARC_GOTDATA_OP_HIX22 82
+#define R_SPARC_GOTDATA_OP_LOX10 83
+#define R_SPARC_GOTDATA_OP 84
+#define R_SPARC_H34 85
+#define R_SPARC_SIZE32 86
+#define R_SPARC_SIZE64 87
+#define R_SPARC_WDISP10 88
+#define R_SPARC_JMP_IREL 248
+#define R_SPARC_IRELATIVE 249
+#define R_SPARC_GNU_VTINHERIT 250
+#define R_SPARC_GNU_VTENTRY 251
+#define R_SPARC_REV32 252
+/* Keep this the last entry. */
+#define R_SPARC_NUM 253
+
+/* For Sparc64, legal values for d_tag of Elf64_Dyn. */
+
+#define DT_SPARC_REGISTER 0x70000001
+#define DT_SPARC_NUM 2
+
+/* MIPS R3000 specific definitions. */
+
+/* Legal values for e_flags field of Elf32_Ehdr. */
+
+#define EF_MIPS_NOREORDER 1 /* A .noreorder directive was used. */
+#define EF_MIPS_PIC 2 /* Contains PIC code. */
+#define EF_MIPS_CPIC 4 /* Uses PIC calling sequence. */
+#define EF_MIPS_XGOT 8
+#define EF_MIPS_64BIT_WHIRL 16
+#define EF_MIPS_ABI2 32
+#define EF_MIPS_ABI_ON32 64
+#define EF_MIPS_FP64 512 /* Uses FP64 (12 callee-saved). */
+#define EF_MIPS_NAN2008 1024 /* Uses IEEE 754-2008 NaN encoding. */
+#define EF_MIPS_ARCH 0xf0000000 /* MIPS architecture level. */
+
+/* Legal values for MIPS architecture level. */
+
+#define EF_MIPS_ARCH_1 0x00000000 /* -mips1 code. */
+#define EF_MIPS_ARCH_2 0x10000000 /* -mips2 code. */
+#define EF_MIPS_ARCH_3 0x20000000 /* -mips3 code. */
+#define EF_MIPS_ARCH_4 0x30000000 /* -mips4 code. */
+#define EF_MIPS_ARCH_5 0x40000000 /* -mips5 code. */
+#define EF_MIPS_ARCH_32 0x50000000 /* MIPS32 code. */
+#define EF_MIPS_ARCH_64 0x60000000 /* MIPS64 code. */
+#define EF_MIPS_ARCH_32R2 0x70000000 /* MIPS32r2 code. */
+#define EF_MIPS_ARCH_64R2 0x80000000 /* MIPS64r2 code. */
+
+/* The following are unofficial names and should not be used. */
+
+#define E_MIPS_ARCH_1 EF_MIPS_ARCH_1
+#define E_MIPS_ARCH_2 EF_MIPS_ARCH_2
+#define E_MIPS_ARCH_3 EF_MIPS_ARCH_3
+#define E_MIPS_ARCH_4 EF_MIPS_ARCH_4
+#define E_MIPS_ARCH_5 EF_MIPS_ARCH_5
+#define E_MIPS_ARCH_32 EF_MIPS_ARCH_32
+#define E_MIPS_ARCH_64 EF_MIPS_ARCH_64
+
+/* Special section indices. */
+
+#define SHN_MIPS_ACOMMON 0xff00 /* Allocated common symbols. */
+#define SHN_MIPS_TEXT 0xff01 /* Allocated test symbols. */
+#define SHN_MIPS_DATA 0xff02 /* Allocated data symbols. */
+#define SHN_MIPS_SCOMMON 0xff03 /* Small common symbols. */
+#define SHN_MIPS_SUNDEFINED 0xff04 /* Small undefined symbols. */
+
+/* Legal values for sh_type field of Elf32_Shdr. */
+
+#define SHT_MIPS_LIBLIST 0x70000000 /* Shared objects used in link. */
+#define SHT_MIPS_MSYM 0x70000001
+#define SHT_MIPS_CONFLICT 0x70000002 /* Conflicting symbols. */
+#define SHT_MIPS_GPTAB 0x70000003 /* Global data area sizes. */
+#define SHT_MIPS_UCODE 0x70000004 /* Reserved for SGI/MIPS compilers */
+#define SHT_MIPS_DEBUG 0x70000005 /* MIPS ECOFF debugging info. */
+#define SHT_MIPS_REGINFO 0x70000006 /* Register usage information. */
+#define SHT_MIPS_PACKAGE 0x70000007
+#define SHT_MIPS_PACKSYM 0x70000008
+#define SHT_MIPS_RELD 0x70000009
+#define SHT_MIPS_IFACE 0x7000000b
+#define SHT_MIPS_CONTENT 0x7000000c
+#define SHT_MIPS_OPTIONS 0x7000000d /* Miscellaneous options. */
+#define SHT_MIPS_SHDR 0x70000010
+#define SHT_MIPS_FDESC 0x70000011
+#define SHT_MIPS_EXTSYM 0x70000012
+#define SHT_MIPS_DENSE 0x70000013
+#define SHT_MIPS_PDESC 0x70000014
+#define SHT_MIPS_LOCSYM 0x70000015
+#define SHT_MIPS_AUXSYM 0x70000016
+#define SHT_MIPS_OPTSYM 0x70000017
+#define SHT_MIPS_LOCSTR 0x70000018
+#define SHT_MIPS_LINE 0x70000019
+#define SHT_MIPS_RFDESC 0x7000001a
+#define SHT_MIPS_DELTASYM 0x7000001b
+#define SHT_MIPS_DELTAINST 0x7000001c
+#define SHT_MIPS_DELTACLASS 0x7000001d
+#define SHT_MIPS_DWARF 0x7000001e /* DWARF debugging information. */
+#define SHT_MIPS_DELTADECL 0x7000001f
+#define SHT_MIPS_SYMBOL_LIB 0x70000020
+#define SHT_MIPS_EVENTS 0x70000021 /* Event section. */
+#define SHT_MIPS_TRANSLATE 0x70000022
+#define SHT_MIPS_PIXIE 0x70000023
+#define SHT_MIPS_XLATE 0x70000024
+#define SHT_MIPS_XLATE_DEBUG 0x70000025
+#define SHT_MIPS_WHIRL 0x70000026
+#define SHT_MIPS_EH_REGION 0x70000027
+#define SHT_MIPS_XLATE_OLD 0x70000028
+#define SHT_MIPS_PDR_EXCEPTION 0x70000029
+
+/* Legal values for sh_flags field of Elf32_Shdr. */
+
+#define SHF_MIPS_GPREL 0x10000000 /* Must be in global data area. */
+#define SHF_MIPS_MERGE 0x20000000
+#define SHF_MIPS_ADDR 0x40000000
+#define SHF_MIPS_STRINGS 0x80000000
+#define SHF_MIPS_NOSTRIP 0x08000000
+#define SHF_MIPS_LOCAL 0x04000000
+#define SHF_MIPS_NAMES 0x02000000
+#define SHF_MIPS_NODUPE 0x01000000
+
+
+/* Symbol tables. */
+
+/* MIPS specific values for `st_other'. */
+#define STO_MIPS_DEFAULT 0x0
+#define STO_MIPS_INTERNAL 0x1
+#define STO_MIPS_HIDDEN 0x2
+#define STO_MIPS_PROTECTED 0x3
+#define STO_MIPS_PLT 0x8
+#define STO_MIPS_SC_ALIGN_UNUSED 0xff
+
+/* MIPS specific values for `st_info'. */
+#define STB_MIPS_SPLIT_COMMON 13
+
+/* Entries found in sections of type SHT_MIPS_GPTAB. */
+
+typedef union
+{
+ struct
+ {
+ Elf32_Word gt_current_g_value; /* -G value used for compilation. */
+ Elf32_Word gt_unused; /* Not used. */
+ } gt_header; /* First entry in section. */
+ struct
+ {
+ Elf32_Word gt_g_value; /* If this value were used for -G. */
+ Elf32_Word gt_bytes; /* This many bytes would be used. */
+ } gt_entry; /* Subsequent entries in section. */
+} Elf32_gptab;
+
+/* Entry found in sections of type SHT_MIPS_REGINFO. */
+
+typedef struct
+{
+ Elf32_Word ri_gprmask; /* General registers used. */
+ Elf32_Word ri_cprmask[4]; /* Coprocessor registers used. */
+ Elf32_Sword ri_gp_value; /* $gp register value. */
+} Elf32_RegInfo;
+
+/* Entries found in sections of type SHT_MIPS_OPTIONS. */
+
+typedef struct
+{
+ unsigned char kind; /* Determines interpretation of the
+ variable part of descriptor. */
+ unsigned char size; /* Size of descriptor, including header. */
+ Elf32_Section section; /* Section header index of section affected,
+ 0 for global options. */
+ Elf32_Word info; /* Kind-specific information. */
+} Elf_Options;
+
+/* Values for `kind' field in Elf_Options. */
+
+#define ODK_NULL 0 /* Undefined. */
+#define ODK_REGINFO 1 /* Register usage information. */
+#define ODK_EXCEPTIONS 2 /* Exception processing options. */
+#define ODK_PAD 3 /* Section padding options. */
+#define ODK_HWPATCH 4 /* Hardware workarounds performed */
+#define ODK_FILL 5 /* record the fill value used by the linker. */
+#define ODK_TAGS 6 /* reserve space for desktop tools to write. */
+#define ODK_HWAND 7 /* HW workarounds. 'AND' bits when merging. */
+#define ODK_HWOR 8 /* HW workarounds. 'OR' bits when merging. */
+
+/* Values for `info' in Elf_Options for ODK_EXCEPTIONS entries. */
+
+#define OEX_FPU_MIN 0x1f /* FPE's which MUST be enabled. */
+#define OEX_FPU_MAX 0x1f00 /* FPE's which MAY be enabled. */
+#define OEX_PAGE0 0x10000 /* page zero must be mapped. */
+#define OEX_SMM 0x20000 /* Force sequential memory mode? */
+#define OEX_FPDBUG 0x40000 /* Force floating point debug mode? */
+#define OEX_PRECISEFP OEX_FPDBUG
+#define OEX_DISMISS 0x80000 /* Dismiss invalid address faults? */
+
+#define OEX_FPU_INVAL 0x10
+#define OEX_FPU_DIV0 0x08
+#define OEX_FPU_OFLO 0x04
+#define OEX_FPU_UFLO 0x02
+#define OEX_FPU_INEX 0x01
+
+/* Masks for `info' in Elf_Options for an ODK_HWPATCH entry. */
+
+#define OHW_R4KEOP 0x1 /* R4000 end-of-page patch. */
+#define OHW_R8KPFETCH 0x2 /* may need R8000 prefetch patch. */
+#define OHW_R5KEOP 0x4 /* R5000 end-of-page patch. */
+#define OHW_R5KCVTL 0x8 /* R5000 cvt.[ds].l bug. clean=1. */
+
+#define OPAD_PREFIX 0x1
+#define OPAD_POSTFIX 0x2
+#define OPAD_SYMBOL 0x4
+
+/* Entry found in `.options' section. */
+
+typedef struct
+{
+ Elf32_Word hwp_flags1; /* Extra flags. */
+ Elf32_Word hwp_flags2; /* Extra flags. */
+} Elf_Options_Hw;
+
+/* Masks for `info' in ElfOptions for ODK_HWAND and ODK_HWOR entries. */
+
+#define OHWA0_R4KEOP_CHECKED 0x00000001
+#define OHWA1_R4KEOP_CLEAN 0x00000002
+
+/* MIPS relocs. */
+
+#define R_MIPS_NONE 0 /* No reloc */
+#define R_MIPS_16 1 /* Direct 16 bit */
+#define R_MIPS_32 2 /* Direct 32 bit */
+#define R_MIPS_REL32 3 /* PC relative 32 bit */
+#define R_MIPS_26 4 /* Direct 26 bit shifted */
+#define R_MIPS_HI16 5 /* High 16 bit */
+#define R_MIPS_LO16 6 /* Low 16 bit */
+#define R_MIPS_GPREL16 7 /* GP relative 16 bit */
+#define R_MIPS_LITERAL 8 /* 16 bit literal entry */
+#define R_MIPS_GOT16 9 /* 16 bit GOT entry */
+#define R_MIPS_PC16 10 /* PC relative 16 bit */
+#define R_MIPS_CALL16 11 /* 16 bit GOT entry for function */
+#define R_MIPS_GPREL32 12 /* GP relative 32 bit */
+
+#define R_MIPS_SHIFT5 16
+#define R_MIPS_SHIFT6 17
+#define R_MIPS_64 18
+#define R_MIPS_GOT_DISP 19
+#define R_MIPS_GOT_PAGE 20
+#define R_MIPS_GOT_OFST 21
+#define R_MIPS_GOT_HI16 22
+#define R_MIPS_GOT_LO16 23
+#define R_MIPS_SUB 24
+#define R_MIPS_INSERT_A 25
+#define R_MIPS_INSERT_B 26
+#define R_MIPS_DELETE 27
+#define R_MIPS_HIGHER 28
+#define R_MIPS_HIGHEST 29
+#define R_MIPS_CALL_HI16 30
+#define R_MIPS_CALL_LO16 31
+#define R_MIPS_SCN_DISP 32
+#define R_MIPS_REL16 33
+#define R_MIPS_ADD_IMMEDIATE 34
+#define R_MIPS_PJUMP 35
+#define R_MIPS_RELGOT 36
+#define R_MIPS_JALR 37
+#define R_MIPS_TLS_DTPMOD32 38 /* Module number 32 bit */
+#define R_MIPS_TLS_DTPREL32 39 /* Module-relative offset 32 bit */
+#define R_MIPS_TLS_DTPMOD64 40 /* Module number 64 bit */
+#define R_MIPS_TLS_DTPREL64 41 /* Module-relative offset 64 bit */
+#define R_MIPS_TLS_GD 42 /* 16 bit GOT offset for GD */
+#define R_MIPS_TLS_LDM 43 /* 16 bit GOT offset for LDM */
+#define R_MIPS_TLS_DTPREL_HI16 44 /* Module-relative offset, high 16 bits */
+#define R_MIPS_TLS_DTPREL_LO16 45 /* Module-relative offset, low 16 bits */
+#define R_MIPS_TLS_GOTTPREL 46 /* 16 bit GOT offset for IE */
+#define R_MIPS_TLS_TPREL32 47 /* TP-relative offset, 32 bit */
+#define R_MIPS_TLS_TPREL64 48 /* TP-relative offset, 64 bit */
+#define R_MIPS_TLS_TPREL_HI16 49 /* TP-relative offset, high 16 bits */
+#define R_MIPS_TLS_TPREL_LO16 50 /* TP-relative offset, low 16 bits */
+#define R_MIPS_GLOB_DAT 51
+#define R_MIPS_COPY 126
+#define R_MIPS_JUMP_SLOT 127
+/* Keep this the last entry. */
+#define R_MIPS_NUM 128
+
+/* Legal values for p_type field of Elf32_Phdr. */
+
+#define PT_MIPS_REGINFO 0x70000000 /* Register usage information. */
+#define PT_MIPS_RTPROC 0x70000001 /* Runtime procedure table. */
+#define PT_MIPS_OPTIONS 0x70000002
+#define PT_MIPS_ABIFLAGS 0x70000003 /* FP mode requirement. */
+
+/* Special program header types. */
+
+#define PF_MIPS_LOCAL 0x10000000
+
+/* Legal values for d_tag field of Elf32_Dyn. */
+
+#define DT_MIPS_RLD_VERSION 0x70000001 /* Runtime linker interface version */
+#define DT_MIPS_TIME_STAMP 0x70000002 /* Timestamp */
+#define DT_MIPS_ICHECKSUM 0x70000003 /* Checksum */
+#define DT_MIPS_IVERSION 0x70000004 /* Version string (string tbl index) */
+#define DT_MIPS_FLAGS 0x70000005 /* Flags */
+#define DT_MIPS_BASE_ADDRESS 0x70000006 /* Base address */
+#define DT_MIPS_MSYM 0x70000007
+#define DT_MIPS_CONFLICT 0x70000008 /* Address of CONFLICT section */
+#define DT_MIPS_LIBLIST 0x70000009 /* Address of LIBLIST section */
+#define DT_MIPS_LOCAL_GOTNO 0x7000000a /* Number of local GOT entries */
+#define DT_MIPS_CONFLICTNO 0x7000000b /* Number of CONFLICT entries */
+#define DT_MIPS_LIBLISTNO 0x70000010 /* Number of LIBLIST entries */
+#define DT_MIPS_SYMTABNO 0x70000011 /* Number of DYNSYM entries */
+#define DT_MIPS_UNREFEXTNO 0x70000012 /* First external DYNSYM */
+#define DT_MIPS_GOTSYM 0x70000013 /* First GOT entry in DYNSYM */
+#define DT_MIPS_HIPAGENO 0x70000014 /* Number of GOT page table entries */
+#define DT_MIPS_RLD_MAP 0x70000016 /* Address of run time loader map. */
+#define DT_MIPS_DELTA_CLASS 0x70000017 /* Delta C++ class definition. */
+#define DT_MIPS_DELTA_CLASS_NO 0x70000018 /* Number of entries in
+ DT_MIPS_DELTA_CLASS. */
+#define DT_MIPS_DELTA_INSTANCE 0x70000019 /* Delta C++ class instances. */
+#define DT_MIPS_DELTA_INSTANCE_NO 0x7000001a /* Number of entries in
+ DT_MIPS_DELTA_INSTANCE. */
+#define DT_MIPS_DELTA_RELOC 0x7000001b /* Delta relocations. */
+#define DT_MIPS_DELTA_RELOC_NO 0x7000001c /* Number of entries in
+ DT_MIPS_DELTA_RELOC. */
+#define DT_MIPS_DELTA_SYM 0x7000001d /* Delta symbols that Delta
+ relocations refer to. */
+#define DT_MIPS_DELTA_SYM_NO 0x7000001e /* Number of entries in
+ DT_MIPS_DELTA_SYM. */
+#define DT_MIPS_DELTA_CLASSSYM 0x70000020 /* Delta symbols that hold the
+ class declaration. */
+#define DT_MIPS_DELTA_CLASSSYM_NO 0x70000021 /* Number of entries in
+ DT_MIPS_DELTA_CLASSSYM. */
+#define DT_MIPS_CXX_FLAGS 0x70000022 /* Flags indicating for C++ flavor. */
+#define DT_MIPS_PIXIE_INIT 0x70000023
+#define DT_MIPS_SYMBOL_LIB 0x70000024
+#define DT_MIPS_LOCALPAGE_GOTIDX 0x70000025
+#define DT_MIPS_LOCAL_GOTIDX 0x70000026
+#define DT_MIPS_HIDDEN_GOTIDX 0x70000027
+#define DT_MIPS_PROTECTED_GOTIDX 0x70000028
+#define DT_MIPS_OPTIONS 0x70000029 /* Address of .options. */
+#define DT_MIPS_INTERFACE 0x7000002a /* Address of .interface. */
+#define DT_MIPS_DYNSTR_ALIGN 0x7000002b
+#define DT_MIPS_INTERFACE_SIZE 0x7000002c /* Size of the .interface section. */
+#define DT_MIPS_RLD_TEXT_RESOLVE_ADDR 0x7000002d /* Address of rld_text_rsolve
+ function stored in GOT. */
+#define DT_MIPS_PERF_SUFFIX 0x7000002e /* Default suffix of dso to be added
+ by rld on dlopen() calls. */
+#define DT_MIPS_COMPACT_SIZE 0x7000002f /* (O32)Size of compact rel section. */
+#define DT_MIPS_GP_VALUE 0x70000030 /* GP value for aux GOTs. */
+#define DT_MIPS_AUX_DYNAMIC 0x70000031 /* Address of aux .dynamic. */
+/* The address of .got.plt in an executable using the new non-PIC ABI. */
+#define DT_MIPS_PLTGOT 0x70000032
+/* The base of the PLT in an executable using the new non-PIC ABI if that
+ PLT is writable. For a non-writable PLT, this is omitted or has a zero
+ value. */
+#define DT_MIPS_RWPLT 0x70000034
+/* An alternative description of the classic MIPS RLD_MAP that is usable
+ in a PIE as it stores a relative offset from the address of the tag
+ rather than an absolute address. */
+#define DT_MIPS_RLD_MAP_REL 0x70000035
+#define DT_MIPS_NUM 0x36
+
+/* Legal values for DT_MIPS_FLAGS Elf32_Dyn entry. */
+
+#define RHF_NONE 0 /* No flags */
+#define RHF_QUICKSTART (1 << 0) /* Use quickstart */
+#define RHF_NOTPOT (1 << 1) /* Hash size not power of 2 */
+#define RHF_NO_LIBRARY_REPLACEMENT (1 << 2) /* Ignore LD_LIBRARY_PATH */
+#define RHF_NO_MOVE (1 << 3)
+#define RHF_SGI_ONLY (1 << 4)
+#define RHF_GUARANTEE_INIT (1 << 5)
+#define RHF_DELTA_C_PLUS_PLUS (1 << 6)
+#define RHF_GUARANTEE_START_INIT (1 << 7)
+#define RHF_PIXIE (1 << 8)
+#define RHF_DEFAULT_DELAY_LOAD (1 << 9)
+#define RHF_REQUICKSTART (1 << 10)
+#define RHF_REQUICKSTARTED (1 << 11)
+#define RHF_CORD (1 << 12)
+#define RHF_NO_UNRES_UNDEF (1 << 13)
+#define RHF_RLD_ORDER_SAFE (1 << 14)
+
+/* Entries found in sections of type SHT_MIPS_LIBLIST. */
+
+typedef struct
+{
+ Elf32_Word l_name; /* Name (string table index) */
+ Elf32_Word l_time_stamp; /* Timestamp */
+ Elf32_Word l_checksum; /* Checksum */
+ Elf32_Word l_version; /* Interface version */
+ Elf32_Word l_flags; /* Flags */
+} Elf32_Lib;
+
+typedef struct
+{
+ Elf64_Word l_name; /* Name (string table index) */
+ Elf64_Word l_time_stamp; /* Timestamp */
+ Elf64_Word l_checksum; /* Checksum */
+ Elf64_Word l_version; /* Interface version */
+ Elf64_Word l_flags; /* Flags */
+} Elf64_Lib;
+
+
+/* Legal values for l_flags. */
+
+#define LL_NONE 0
+#define LL_EXACT_MATCH (1 << 0) /* Require exact match */
+#define LL_IGNORE_INT_VER (1 << 1) /* Ignore interface version */
+#define LL_REQUIRE_MINOR (1 << 2)
+#define LL_EXPORTS (1 << 3)
+#define LL_DELAY_LOAD (1 << 4)
+#define LL_DELTA (1 << 5)
+
+/* Entries found in sections of type SHT_MIPS_CONFLICT. */
+
+typedef Elf32_Addr Elf32_Conflict;
+
+typedef struct
+{
+ /* Version of flags structure. */
+ Elf32_Half version;
+ /* The level of the ISA: 1-5, 32, 64. */
+ unsigned char isa_level;
+ /* The revision of ISA: 0 for MIPS V and below, 1-n otherwise. */
+ unsigned char isa_rev;
+ /* The size of general purpose registers. */
+ unsigned char gpr_size;
+ /* The size of co-processor 1 registers. */
+ unsigned char cpr1_size;
+ /* The size of co-processor 2 registers. */
+ unsigned char cpr2_size;
+ /* The floating-point ABI. */
+ unsigned char fp_abi;
+ /* Processor-specific extension. */
+ Elf32_Word isa_ext;
+ /* Mask of ASEs used. */
+ Elf32_Word ases;
+ /* Mask of general flags. */
+ Elf32_Word flags1;
+ Elf32_Word flags2;
+} Elf_MIPS_ABIFlags_v0;
+
+/* Values for the register size bytes of an abi flags structure. */
+
+#define MIPS_AFL_REG_NONE 0x00 /* No registers. */
+#define MIPS_AFL_REG_32 0x01 /* 32-bit registers. */
+#define MIPS_AFL_REG_64 0x02 /* 64-bit registers. */
+#define MIPS_AFL_REG_128 0x03 /* 128-bit registers. */
+
+/* Masks for the ases word of an ABI flags structure. */
+
+#define MIPS_AFL_ASE_DSP 0x00000001 /* DSP ASE. */
+#define MIPS_AFL_ASE_DSPR2 0x00000002 /* DSP R2 ASE. */
+#define MIPS_AFL_ASE_EVA 0x00000004 /* Enhanced VA Scheme. */
+#define MIPS_AFL_ASE_MCU 0x00000008 /* MCU (MicroController) ASE. */
+#define MIPS_AFL_ASE_MDMX 0x00000010 /* MDMX ASE. */
+#define MIPS_AFL_ASE_MIPS3D 0x00000020 /* MIPS-3D ASE. */
+#define MIPS_AFL_ASE_MT 0x00000040 /* MT ASE. */
+#define MIPS_AFL_ASE_SMARTMIPS 0x00000080 /* SmartMIPS ASE. */
+#define MIPS_AFL_ASE_VIRT 0x00000100 /* VZ ASE. */
+#define MIPS_AFL_ASE_MSA 0x00000200 /* MSA ASE. */
+#define MIPS_AFL_ASE_MIPS16 0x00000400 /* MIPS16 ASE. */
+#define MIPS_AFL_ASE_MICROMIPS 0x00000800 /* MICROMIPS ASE. */
+#define MIPS_AFL_ASE_XPA 0x00001000 /* XPA ASE. */
+#define MIPS_AFL_ASE_MASK 0x00001fff /* All ASEs. */
+
+/* Values for the isa_ext word of an ABI flags structure. */
+
+#define MIPS_AFL_EXT_XLR 1 /* RMI Xlr instruction. */
+#define MIPS_AFL_EXT_OCTEON2 2 /* Cavium Networks Octeon2. */
+#define MIPS_AFL_EXT_OCTEONP 3 /* Cavium Networks OcteonP. */
+#define MIPS_AFL_EXT_LOONGSON_3A 4 /* Loongson 3A. */
+#define MIPS_AFL_EXT_OCTEON 5 /* Cavium Networks Octeon. */
+#define MIPS_AFL_EXT_5900 6 /* MIPS R5900 instruction. */
+#define MIPS_AFL_EXT_4650 7 /* MIPS R4650 instruction. */
+#define MIPS_AFL_EXT_4010 8 /* LSI R4010 instruction. */
+#define MIPS_AFL_EXT_4100 9 /* NEC VR4100 instruction. */
+#define MIPS_AFL_EXT_3900 10 /* Toshiba R3900 instruction. */
+#define MIPS_AFL_EXT_10000 11 /* MIPS R10000 instruction. */
+#define MIPS_AFL_EXT_SB1 12 /* Broadcom SB-1 instruction. */
+#define MIPS_AFL_EXT_4111 13 /* NEC VR4111/VR4181 instruction. */
+#define MIPS_AFL_EXT_4120 14 /* NEC VR4120 instruction. */
+#define MIPS_AFL_EXT_5400 15 /* NEC VR5400 instruction. */
+#define MIPS_AFL_EXT_5500 16 /* NEC VR5500 instruction. */
+#define MIPS_AFL_EXT_LOONGSON_2E 17 /* ST Microelectronics Loongson 2E. */
+#define MIPS_AFL_EXT_LOONGSON_2F 18 /* ST Microelectronics Loongson 2F. */
+
+/* Masks for the flags1 word of an ABI flags structure. */
+#define MIPS_AFL_FLAGS1_ODDSPREG 1 /* Uses odd single-precision registers. */
+
+/* Object attribute values. */
+enum
+{
+ /* Not tagged or not using any ABIs affected by the differences. */
+ Val_GNU_MIPS_ABI_FP_ANY = 0,
+ /* Using hard-float -mdouble-float. */
+ Val_GNU_MIPS_ABI_FP_DOUBLE = 1,
+ /* Using hard-float -msingle-float. */
+ Val_GNU_MIPS_ABI_FP_SINGLE = 2,
+ /* Using soft-float. */
+ Val_GNU_MIPS_ABI_FP_SOFT = 3,
+ /* Using -mips32r2 -mfp64. */
+ Val_GNU_MIPS_ABI_FP_OLD_64 = 4,
+ /* Using -mfpxx. */
+ Val_GNU_MIPS_ABI_FP_XX = 5,
+ /* Using -mips32r2 -mfp64. */
+ Val_GNU_MIPS_ABI_FP_64 = 6,
+ /* Using -mips32r2 -mfp64 -mno-odd-spreg. */
+ Val_GNU_MIPS_ABI_FP_64A = 7,
+ /* Maximum allocated FP ABI value. */
+ Val_GNU_MIPS_ABI_FP_MAX = 7
+};
+
+/* HPPA specific definitions. */
+
+/* Legal values for e_flags field of Elf32_Ehdr. */
+
+#define EF_PARISC_TRAPNIL 0x00010000 /* Trap nil pointer dereference. */
+#define EF_PARISC_EXT 0x00020000 /* Program uses arch. extensions. */
+#define EF_PARISC_LSB 0x00040000 /* Program expects little endian. */
+#define EF_PARISC_WIDE 0x00080000 /* Program expects wide mode. */
+#define EF_PARISC_NO_KABP 0x00100000 /* No kernel assisted branch
+ prediction. */
+#define EF_PARISC_LAZYSWAP 0x00400000 /* Allow lazy swapping. */
+#define EF_PARISC_ARCH 0x0000ffff /* Architecture version. */
+
+/* Defined values for `e_flags & EF_PARISC_ARCH' are: */
+
+#define EFA_PARISC_1_0 0x020b /* PA-RISC 1.0 big-endian. */
+#define EFA_PARISC_1_1 0x0210 /* PA-RISC 1.1 big-endian. */
+#define EFA_PARISC_2_0 0x0214 /* PA-RISC 2.0 big-endian. */
+
+/* Additional section indeces. */
+
+#define SHN_PARISC_ANSI_COMMON 0xff00 /* Section for tenatively declared
+ symbols in ANSI C. */
+#define SHN_PARISC_HUGE_COMMON 0xff01 /* Common blocks in huge model. */
+
+/* Legal values for sh_type field of Elf32_Shdr. */
+
+#define SHT_PARISC_EXT 0x70000000 /* Contains product specific ext. */
+#define SHT_PARISC_UNWIND 0x70000001 /* Unwind information. */
+#define SHT_PARISC_DOC 0x70000002 /* Debug info for optimized code. */
+
+/* Legal values for sh_flags field of Elf32_Shdr. */
+
+#define SHF_PARISC_SHORT 0x20000000 /* Section with short addressing. */
+#define SHF_PARISC_HUGE 0x40000000 /* Section far from gp. */
+#define SHF_PARISC_SBP 0x80000000 /* Static branch prediction code. */
+
+/* Legal values for ST_TYPE subfield of st_info (symbol type). */
+
+#define STT_PARISC_MILLICODE 13 /* Millicode function entry point. */
+
+#define STT_HP_OPAQUE (STT_LOOS + 0x1)
+#define STT_HP_STUB (STT_LOOS + 0x2)
+
+/* HPPA relocs. */
+
+#define R_PARISC_NONE 0 /* No reloc. */
+#define R_PARISC_DIR32 1 /* Direct 32-bit reference. */
+#define R_PARISC_DIR21L 2 /* Left 21 bits of eff. address. */
+#define R_PARISC_DIR17R 3 /* Right 17 bits of eff. address. */
+#define R_PARISC_DIR17F 4 /* 17 bits of eff. address. */
+#define R_PARISC_DIR14R 6 /* Right 14 bits of eff. address. */
+#define R_PARISC_PCREL32 9 /* 32-bit rel. address. */
+#define R_PARISC_PCREL21L 10 /* Left 21 bits of rel. address. */
+#define R_PARISC_PCREL17R 11 /* Right 17 bits of rel. address. */
+#define R_PARISC_PCREL17F 12 /* 17 bits of rel. address. */
+#define R_PARISC_PCREL14R 14 /* Right 14 bits of rel. address. */
+#define R_PARISC_DPREL21L 18 /* Left 21 bits of rel. address. */
+#define R_PARISC_DPREL14R 22 /* Right 14 bits of rel. address. */
+#define R_PARISC_GPREL21L 26 /* GP-relative, left 21 bits. */
+#define R_PARISC_GPREL14R 30 /* GP-relative, right 14 bits. */
+#define R_PARISC_LTOFF21L 34 /* LT-relative, left 21 bits. */
+#define R_PARISC_LTOFF14R 38 /* LT-relative, right 14 bits. */
+#define R_PARISC_SECREL32 41 /* 32 bits section rel. address. */
+#define R_PARISC_SEGBASE 48 /* No relocation, set segment base. */
+#define R_PARISC_SEGREL32 49 /* 32 bits segment rel. address. */
+#define R_PARISC_PLTOFF21L 50 /* PLT rel. address, left 21 bits. */
+#define R_PARISC_PLTOFF14R 54 /* PLT rel. address, right 14 bits. */
+#define R_PARISC_LTOFF_FPTR32 57 /* 32 bits LT-rel. function pointer. */
+#define R_PARISC_LTOFF_FPTR21L 58 /* LT-rel. fct ptr, left 21 bits. */
+#define R_PARISC_LTOFF_FPTR14R 62 /* LT-rel. fct ptr, right 14 bits. */
+#define R_PARISC_FPTR64 64 /* 64 bits function address. */
+#define R_PARISC_PLABEL32 65 /* 32 bits function address. */
+#define R_PARISC_PLABEL21L 66 /* Left 21 bits of fdesc address. */
+#define R_PARISC_PLABEL14R 70 /* Right 14 bits of fdesc address. */
+#define R_PARISC_PCREL64 72 /* 64 bits PC-rel. address. */
+#define R_PARISC_PCREL22F 74 /* 22 bits PC-rel. address. */
+#define R_PARISC_PCREL14WR 75 /* PC-rel. address, right 14 bits. */
+#define R_PARISC_PCREL14DR 76 /* PC rel. address, right 14 bits. */
+#define R_PARISC_PCREL16F 77 /* 16 bits PC-rel. address. */
+#define R_PARISC_PCREL16WF 78 /* 16 bits PC-rel. address. */
+#define R_PARISC_PCREL16DF 79 /* 16 bits PC-rel. address. */
+#define R_PARISC_DIR64 80 /* 64 bits of eff. address. */
+#define R_PARISC_DIR14WR 83 /* 14 bits of eff. address. */
+#define R_PARISC_DIR14DR 84 /* 14 bits of eff. address. */
+#define R_PARISC_DIR16F 85 /* 16 bits of eff. address. */
+#define R_PARISC_DIR16WF 86 /* 16 bits of eff. address. */
+#define R_PARISC_DIR16DF 87 /* 16 bits of eff. address. */
+#define R_PARISC_GPREL64 88 /* 64 bits of GP-rel. address. */
+#define R_PARISC_GPREL14WR 91 /* GP-rel. address, right 14 bits. */
+#define R_PARISC_GPREL14DR 92 /* GP-rel. address, right 14 bits. */
+#define R_PARISC_GPREL16F 93 /* 16 bits GP-rel. address. */
+#define R_PARISC_GPREL16WF 94 /* 16 bits GP-rel. address. */
+#define R_PARISC_GPREL16DF 95 /* 16 bits GP-rel. address. */
+#define R_PARISC_LTOFF64 96 /* 64 bits LT-rel. address. */
+#define R_PARISC_LTOFF14WR 99 /* LT-rel. address, right 14 bits. */
+#define R_PARISC_LTOFF14DR 100 /* LT-rel. address, right 14 bits. */
+#define R_PARISC_LTOFF16F 101 /* 16 bits LT-rel. address. */
+#define R_PARISC_LTOFF16WF 102 /* 16 bits LT-rel. address. */
+#define R_PARISC_LTOFF16DF 103 /* 16 bits LT-rel. address. */
+#define R_PARISC_SECREL64 104 /* 64 bits section rel. address. */
+#define R_PARISC_SEGREL64 112 /* 64 bits segment rel. address. */
+#define R_PARISC_PLTOFF14WR 115 /* PLT-rel. address, right 14 bits. */
+#define R_PARISC_PLTOFF14DR 116 /* PLT-rel. address, right 14 bits. */
+#define R_PARISC_PLTOFF16F 117 /* 16 bits LT-rel. address. */
+#define R_PARISC_PLTOFF16WF 118 /* 16 bits PLT-rel. address. */
+#define R_PARISC_PLTOFF16DF 119 /* 16 bits PLT-rel. address. */
+#define R_PARISC_LTOFF_FPTR64 120 /* 64 bits LT-rel. function ptr. */
+#define R_PARISC_LTOFF_FPTR14WR 123 /* LT-rel. fct. ptr., right 14 bits. */
+#define R_PARISC_LTOFF_FPTR14DR 124 /* LT-rel. fct. ptr., right 14 bits. */
+#define R_PARISC_LTOFF_FPTR16F 125 /* 16 bits LT-rel. function ptr. */
+#define R_PARISC_LTOFF_FPTR16WF 126 /* 16 bits LT-rel. function ptr. */
+#define R_PARISC_LTOFF_FPTR16DF 127 /* 16 bits LT-rel. function ptr. */
+#define R_PARISC_LORESERVE 128
+#define R_PARISC_COPY 128 /* Copy relocation. */
+#define R_PARISC_IPLT 129 /* Dynamic reloc, imported PLT */
+#define R_PARISC_EPLT 130 /* Dynamic reloc, exported PLT */
+#define R_PARISC_TPREL32 153 /* 32 bits TP-rel. address. */
+#define R_PARISC_TPREL21L 154 /* TP-rel. address, left 21 bits. */
+#define R_PARISC_TPREL14R 158 /* TP-rel. address, right 14 bits. */
+#define R_PARISC_LTOFF_TP21L 162 /* LT-TP-rel. address, left 21 bits. */
+#define R_PARISC_LTOFF_TP14R 166 /* LT-TP-rel. address, right 14 bits.*/
+#define R_PARISC_LTOFF_TP14F 167 /* 14 bits LT-TP-rel. address. */
+#define R_PARISC_TPREL64 216 /* 64 bits TP-rel. address. */
+#define R_PARISC_TPREL14WR 219 /* TP-rel. address, right 14 bits. */
+#define R_PARISC_TPREL14DR 220 /* TP-rel. address, right 14 bits. */
+#define R_PARISC_TPREL16F 221 /* 16 bits TP-rel. address. */
+#define R_PARISC_TPREL16WF 222 /* 16 bits TP-rel. address. */
+#define R_PARISC_TPREL16DF 223 /* 16 bits TP-rel. address. */
+#define R_PARISC_LTOFF_TP64 224 /* 64 bits LT-TP-rel. address. */
+#define R_PARISC_LTOFF_TP14WR 227 /* LT-TP-rel. address, right 14 bits.*/
+#define R_PARISC_LTOFF_TP14DR 228 /* LT-TP-rel. address, right 14 bits.*/
+#define R_PARISC_LTOFF_TP16F 229 /* 16 bits LT-TP-rel. address. */
+#define R_PARISC_LTOFF_TP16WF 230 /* 16 bits LT-TP-rel. address. */
+#define R_PARISC_LTOFF_TP16DF 231 /* 16 bits LT-TP-rel. address. */
+#define R_PARISC_GNU_VTENTRY 232
+#define R_PARISC_GNU_VTINHERIT 233
+#define R_PARISC_TLS_GD21L 234 /* GD 21-bit left. */
+#define R_PARISC_TLS_GD14R 235 /* GD 14-bit right. */
+#define R_PARISC_TLS_GDCALL 236 /* GD call to __t_g_a. */
+#define R_PARISC_TLS_LDM21L 237 /* LD module 21-bit left. */
+#define R_PARISC_TLS_LDM14R 238 /* LD module 14-bit right. */
+#define R_PARISC_TLS_LDMCALL 239 /* LD module call to __t_g_a. */
+#define R_PARISC_TLS_LDO21L 240 /* LD offset 21-bit left. */
+#define R_PARISC_TLS_LDO14R 241 /* LD offset 14-bit right. */
+#define R_PARISC_TLS_DTPMOD32 242 /* DTP module 32-bit. */
+#define R_PARISC_TLS_DTPMOD64 243 /* DTP module 64-bit. */
+#define R_PARISC_TLS_DTPOFF32 244 /* DTP offset 32-bit. */
+#define R_PARISC_TLS_DTPOFF64 245 /* DTP offset 32-bit. */
+#define R_PARISC_TLS_LE21L R_PARISC_TPREL21L
+#define R_PARISC_TLS_LE14R R_PARISC_TPREL14R
+#define R_PARISC_TLS_IE21L R_PARISC_LTOFF_TP21L
+#define R_PARISC_TLS_IE14R R_PARISC_LTOFF_TP14R
+#define R_PARISC_TLS_TPREL32 R_PARISC_TPREL32
+#define R_PARISC_TLS_TPREL64 R_PARISC_TPREL64
+#define R_PARISC_HIRESERVE 255
+
+/* Legal values for p_type field of Elf32_Phdr/Elf64_Phdr. */
+
+#define PT_HP_TLS (PT_LOOS + 0x0)
+#define PT_HP_CORE_NONE (PT_LOOS + 0x1)
+#define PT_HP_CORE_VERSION (PT_LOOS + 0x2)
+#define PT_HP_CORE_KERNEL (PT_LOOS + 0x3)
+#define PT_HP_CORE_COMM (PT_LOOS + 0x4)
+#define PT_HP_CORE_PROC (PT_LOOS + 0x5)
+#define PT_HP_CORE_LOADABLE (PT_LOOS + 0x6)
+#define PT_HP_CORE_STACK (PT_LOOS + 0x7)
+#define PT_HP_CORE_SHM (PT_LOOS + 0x8)
+#define PT_HP_CORE_MMF (PT_LOOS + 0x9)
+#define PT_HP_PARALLEL (PT_LOOS + 0x10)
+#define PT_HP_FASTBIND (PT_LOOS + 0x11)
+#define PT_HP_OPT_ANNOT (PT_LOOS + 0x12)
+#define PT_HP_HSL_ANNOT (PT_LOOS + 0x13)
+#define PT_HP_STACK (PT_LOOS + 0x14)
+
+#define PT_PARISC_ARCHEXT 0x70000000
+#define PT_PARISC_UNWIND 0x70000001
+
+/* Legal values for p_flags field of Elf32_Phdr/Elf64_Phdr. */
+
+#define PF_PARISC_SBP 0x08000000
+
+#define PF_HP_PAGE_SIZE 0x00100000
+#define PF_HP_FAR_SHARED 0x00200000
+#define PF_HP_NEAR_SHARED 0x00400000
+#define PF_HP_CODE 0x01000000
+#define PF_HP_MODIFY 0x02000000
+#define PF_HP_LAZYSWAP 0x04000000
+#define PF_HP_SBP 0x08000000
+
+
+/* Alpha specific definitions. */
+
+/* Legal values for e_flags field of Elf64_Ehdr. */
+
+#define EF_ALPHA_32BIT 1 /* All addresses must be < 2GB. */
+#define EF_ALPHA_CANRELAX 2 /* Relocations for relaxing exist. */
+
+/* Legal values for sh_type field of Elf64_Shdr. */
+
+/* These two are primerily concerned with ECOFF debugging info. */
+#define SHT_ALPHA_DEBUG 0x70000001
+#define SHT_ALPHA_REGINFO 0x70000002
+
+/* Legal values for sh_flags field of Elf64_Shdr. */
+
+#define SHF_ALPHA_GPREL 0x10000000
+
+/* Legal values for st_other field of Elf64_Sym. */
+#define STO_ALPHA_NOPV 0x80 /* No PV required. */
+#define STO_ALPHA_STD_GPLOAD 0x88 /* PV only used for initial ldgp. */
+
+/* Alpha relocs. */
+
+#define R_ALPHA_NONE 0 /* No reloc */
+#define R_ALPHA_REFLONG 1 /* Direct 32 bit */
+#define R_ALPHA_REFQUAD 2 /* Direct 64 bit */
+#define R_ALPHA_GPREL32 3 /* GP relative 32 bit */
+#define R_ALPHA_LITERAL 4 /* GP relative 16 bit w/optimization */
+#define R_ALPHA_LITUSE 5 /* Optimization hint for LITERAL */
+#define R_ALPHA_GPDISP 6 /* Add displacement to GP */
+#define R_ALPHA_BRADDR 7 /* PC+4 relative 23 bit shifted */
+#define R_ALPHA_HINT 8 /* PC+4 relative 16 bit shifted */
+#define R_ALPHA_SREL16 9 /* PC relative 16 bit */
+#define R_ALPHA_SREL32 10 /* PC relative 32 bit */
+#define R_ALPHA_SREL64 11 /* PC relative 64 bit */
+#define R_ALPHA_GPRELHIGH 17 /* GP relative 32 bit, high 16 bits */
+#define R_ALPHA_GPRELLOW 18 /* GP relative 32 bit, low 16 bits */
+#define R_ALPHA_GPREL16 19 /* GP relative 16 bit */
+#define R_ALPHA_COPY 24 /* Copy symbol at runtime */
+#define R_ALPHA_GLOB_DAT 25 /* Create GOT entry */
+#define R_ALPHA_JMP_SLOT 26 /* Create PLT entry */
+#define R_ALPHA_RELATIVE 27 /* Adjust by program base */
+#define R_ALPHA_TLS_GD_HI 28
+#define R_ALPHA_TLSGD 29
+#define R_ALPHA_TLS_LDM 30
+#define R_ALPHA_DTPMOD64 31
+#define R_ALPHA_GOTDTPREL 32
+#define R_ALPHA_DTPREL64 33
+#define R_ALPHA_DTPRELHI 34
+#define R_ALPHA_DTPRELLO 35
+#define R_ALPHA_DTPREL16 36
+#define R_ALPHA_GOTTPREL 37
+#define R_ALPHA_TPREL64 38
+#define R_ALPHA_TPRELHI 39
+#define R_ALPHA_TPRELLO 40
+#define R_ALPHA_TPREL16 41
+/* Keep this the last entry. */
+#define R_ALPHA_NUM 46
+
+/* Magic values of the LITUSE relocation addend. */
+#define LITUSE_ALPHA_ADDR 0
+#define LITUSE_ALPHA_BASE 1
+#define LITUSE_ALPHA_BYTOFF 2
+#define LITUSE_ALPHA_JSR 3
+#define LITUSE_ALPHA_TLS_GD 4
+#define LITUSE_ALPHA_TLS_LDM 5
+
+/* Legal values for d_tag of Elf64_Dyn. */
+#define DT_ALPHA_PLTRO (DT_LOPROC + 0)
+#define DT_ALPHA_NUM 1
+
+/* PowerPC specific declarations */
+
+/* Values for Elf32/64_Ehdr.e_flags. */
+#define EF_PPC_EMB 0x80000000 /* PowerPC embedded flag */
+
+/* Cygnus local bits below */
+#define EF_PPC_RELOCATABLE 0x00010000 /* PowerPC -mrelocatable flag*/
+#define EF_PPC_RELOCATABLE_LIB 0x00008000 /* PowerPC -mrelocatable-lib
+ flag */
+
+/* PowerPC relocations defined by the ABIs */
+#define R_PPC_NONE 0
+#define R_PPC_ADDR32 1 /* 32bit absolute address */
+#define R_PPC_ADDR24 2 /* 26bit address, 2 bits ignored. */
+#define R_PPC_ADDR16 3 /* 16bit absolute address */
+#define R_PPC_ADDR16_LO 4 /* lower 16bit of absolute address */
+#define R_PPC_ADDR16_HI 5 /* high 16bit of absolute address */
+#define R_PPC_ADDR16_HA 6 /* adjusted high 16bit */
+#define R_PPC_ADDR14 7 /* 16bit address, 2 bits ignored */
+#define R_PPC_ADDR14_BRTAKEN 8
+#define R_PPC_ADDR14_BRNTAKEN 9
+#define R_PPC_REL24 10 /* PC relative 26 bit */
+#define R_PPC_REL14 11 /* PC relative 16 bit */
+#define R_PPC_REL14_BRTAKEN 12
+#define R_PPC_REL14_BRNTAKEN 13
+#define R_PPC_GOT16 14
+#define R_PPC_GOT16_LO 15
+#define R_PPC_GOT16_HI 16
+#define R_PPC_GOT16_HA 17
+#define R_PPC_PLTREL24 18
+#define R_PPC_COPY 19
+#define R_PPC_GLOB_DAT 20
+#define R_PPC_JMP_SLOT 21
+#define R_PPC_RELATIVE 22
+#define R_PPC_LOCAL24PC 23
+#define R_PPC_UADDR32 24
+#define R_PPC_UADDR16 25
+#define R_PPC_REL32 26
+#define R_PPC_PLT32 27
+#define R_PPC_PLTREL32 28
+#define R_PPC_PLT16_LO 29
+#define R_PPC_PLT16_HI 30
+#define R_PPC_PLT16_HA 31
+#define R_PPC_SDAREL16 32
+#define R_PPC_SECTOFF 33
+#define R_PPC_SECTOFF_LO 34
+#define R_PPC_SECTOFF_HI 35
+#define R_PPC_SECTOFF_HA 36
+
+/* PowerPC relocations defined for the TLS access ABI. */
+#define R_PPC_TLS 67 /* none (sym+add)@tls */
+#define R_PPC_DTPMOD32 68 /* word32 (sym+add)@dtpmod */
+#define R_PPC_TPREL16 69 /* half16* (sym+add)@tprel */
+#define R_PPC_TPREL16_LO 70 /* half16 (sym+add)@tprel@l */
+#define R_PPC_TPREL16_HI 71 /* half16 (sym+add)@tprel@h */
+#define R_PPC_TPREL16_HA 72 /* half16 (sym+add)@tprel@ha */
+#define R_PPC_TPREL32 73 /* word32 (sym+add)@tprel */
+#define R_PPC_DTPREL16 74 /* half16* (sym+add)@dtprel */
+#define R_PPC_DTPREL16_LO 75 /* half16 (sym+add)@dtprel@l */
+#define R_PPC_DTPREL16_HI 76 /* half16 (sym+add)@dtprel@h */
+#define R_PPC_DTPREL16_HA 77 /* half16 (sym+add)@dtprel@ha */
+#define R_PPC_DTPREL32 78 /* word32 (sym+add)@dtprel */
+#define R_PPC_GOT_TLSGD16 79 /* half16* (sym+add)@got@tlsgd */
+#define R_PPC_GOT_TLSGD16_LO 80 /* half16 (sym+add)@got@tlsgd@l */
+#define R_PPC_GOT_TLSGD16_HI 81 /* half16 (sym+add)@got@tlsgd@h */
+#define R_PPC_GOT_TLSGD16_HA 82 /* half16 (sym+add)@got@tlsgd@ha */
+#define R_PPC_GOT_TLSLD16 83 /* half16* (sym+add)@got@tlsld */
+#define R_PPC_GOT_TLSLD16_LO 84 /* half16 (sym+add)@got@tlsld@l */
+#define R_PPC_GOT_TLSLD16_HI 85 /* half16 (sym+add)@got@tlsld@h */
+#define R_PPC_GOT_TLSLD16_HA 86 /* half16 (sym+add)@got@tlsld@ha */
+#define R_PPC_GOT_TPREL16 87 /* half16* (sym+add)@got@tprel */
+#define R_PPC_GOT_TPREL16_LO 88 /* half16 (sym+add)@got@tprel@l */
+#define R_PPC_GOT_TPREL16_HI 89 /* half16 (sym+add)@got@tprel@h */
+#define R_PPC_GOT_TPREL16_HA 90 /* half16 (sym+add)@got@tprel@ha */
+#define R_PPC_GOT_DTPREL16 91 /* half16* (sym+add)@got@dtprel */
+#define R_PPC_GOT_DTPREL16_LO 92 /* half16* (sym+add)@got@dtprel@l */
+#define R_PPC_GOT_DTPREL16_HI 93 /* half16* (sym+add)@got@dtprel@h */
+#define R_PPC_GOT_DTPREL16_HA 94 /* half16* (sym+add)@got@dtprel@ha */
+#define R_PPC_TLSGD 95 /* none (sym+add)@tlsgd */
+#define R_PPC_TLSLD 96 /* none (sym+add)@tlsld */
+
+/* The remaining relocs are from the Embedded ELF ABI, and are not
+ in the SVR4 ELF ABI. */
+#define R_PPC_EMB_NADDR32 101
+#define R_PPC_EMB_NADDR16 102
+#define R_PPC_EMB_NADDR16_LO 103
+#define R_PPC_EMB_NADDR16_HI 104
+#define R_PPC_EMB_NADDR16_HA 105
+#define R_PPC_EMB_SDAI16 106
+#define R_PPC_EMB_SDA2I16 107
+#define R_PPC_EMB_SDA2REL 108
+#define R_PPC_EMB_SDA21 109 /* 16 bit offset in SDA */
+#define R_PPC_EMB_MRKREF 110
+#define R_PPC_EMB_RELSEC16 111
+#define R_PPC_EMB_RELST_LO 112
+#define R_PPC_EMB_RELST_HI 113
+#define R_PPC_EMB_RELST_HA 114
+#define R_PPC_EMB_BIT_FLD 115
+#define R_PPC_EMB_RELSDA 116 /* 16 bit relative offset in SDA */
+
+/* Diab tool relocations. */
+#define R_PPC_DIAB_SDA21_LO 180 /* like EMB_SDA21, but lower 16 bit */
+#define R_PPC_DIAB_SDA21_HI 181 /* like EMB_SDA21, but high 16 bit */
+#define R_PPC_DIAB_SDA21_HA 182 /* like EMB_SDA21, adjusted high 16 */
+#define R_PPC_DIAB_RELSDA_LO 183 /* like EMB_RELSDA, but lower 16 bit */
+#define R_PPC_DIAB_RELSDA_HI 184 /* like EMB_RELSDA, but high 16 bit */
+#define R_PPC_DIAB_RELSDA_HA 185 /* like EMB_RELSDA, adjusted high 16 */
+
+/* GNU extension to support local ifunc. */
+#define R_PPC_IRELATIVE 248
+
+/* GNU relocs used in PIC code sequences. */
+#define R_PPC_REL16 249 /* half16 (sym+add-.) */
+#define R_PPC_REL16_LO 250 /* half16 (sym+add-.)@l */
+#define R_PPC_REL16_HI 251 /* half16 (sym+add-.)@h */
+#define R_PPC_REL16_HA 252 /* half16 (sym+add-.)@ha */
+
+/* This is a phony reloc to handle any old fashioned TOC16 references
+ that may still be in object files. */
+#define R_PPC_TOC16 255
+
+/* PowerPC specific values for the Dyn d_tag field. */
+#define DT_PPC_GOT (DT_LOPROC + 0)
+#define DT_PPC_OPT (DT_LOPROC + 1)
+#define DT_PPC_NUM 2
+
+/* PowerPC specific values for the DT_PPC_OPT Dyn entry. */
+#define PPC_OPT_TLS 1
+
+/* PowerPC64 relocations defined by the ABIs */
+#define R_PPC64_NONE R_PPC_NONE
+#define R_PPC64_ADDR32 R_PPC_ADDR32 /* 32bit absolute address */
+#define R_PPC64_ADDR24 R_PPC_ADDR24 /* 26bit address, word aligned */
+#define R_PPC64_ADDR16 R_PPC_ADDR16 /* 16bit absolute address */
+#define R_PPC64_ADDR16_LO R_PPC_ADDR16_LO /* lower 16bits of address */
+#define R_PPC64_ADDR16_HI R_PPC_ADDR16_HI /* high 16bits of address. */
+#define R_PPC64_ADDR16_HA R_PPC_ADDR16_HA /* adjusted high 16bits. */
+#define R_PPC64_ADDR14 R_PPC_ADDR14 /* 16bit address, word aligned */
+#define R_PPC64_ADDR14_BRTAKEN R_PPC_ADDR14_BRTAKEN
+#define R_PPC64_ADDR14_BRNTAKEN R_PPC_ADDR14_BRNTAKEN
+#define R_PPC64_REL24 R_PPC_REL24 /* PC-rel. 26 bit, word aligned */
+#define R_PPC64_REL14 R_PPC_REL14 /* PC relative 16 bit */
+#define R_PPC64_REL14_BRTAKEN R_PPC_REL14_BRTAKEN
+#define R_PPC64_REL14_BRNTAKEN R_PPC_REL14_BRNTAKEN
+#define R_PPC64_GOT16 R_PPC_GOT16
+#define R_PPC64_GOT16_LO R_PPC_GOT16_LO
+#define R_PPC64_GOT16_HI R_PPC_GOT16_HI
+#define R_PPC64_GOT16_HA R_PPC_GOT16_HA
+
+#define R_PPC64_COPY R_PPC_COPY
+#define R_PPC64_GLOB_DAT R_PPC_GLOB_DAT
+#define R_PPC64_JMP_SLOT R_PPC_JMP_SLOT
+#define R_PPC64_RELATIVE R_PPC_RELATIVE
+
+#define R_PPC64_UADDR32 R_PPC_UADDR32
+#define R_PPC64_UADDR16 R_PPC_UADDR16
+#define R_PPC64_REL32 R_PPC_REL32
+#define R_PPC64_PLT32 R_PPC_PLT32
+#define R_PPC64_PLTREL32 R_PPC_PLTREL32
+#define R_PPC64_PLT16_LO R_PPC_PLT16_LO
+#define R_PPC64_PLT16_HI R_PPC_PLT16_HI
+#define R_PPC64_PLT16_HA R_PPC_PLT16_HA
+
+#define R_PPC64_SECTOFF R_PPC_SECTOFF
+#define R_PPC64_SECTOFF_LO R_PPC_SECTOFF_LO
+#define R_PPC64_SECTOFF_HI R_PPC_SECTOFF_HI
+#define R_PPC64_SECTOFF_HA R_PPC_SECTOFF_HA
+#define R_PPC64_ADDR30 37 /* word30 (S + A - P) >> 2 */
+#define R_PPC64_ADDR64 38 /* doubleword64 S + A */
+#define R_PPC64_ADDR16_HIGHER 39 /* half16 #higher(S + A) */
+#define R_PPC64_ADDR16_HIGHERA 40 /* half16 #highera(S + A) */
+#define R_PPC64_ADDR16_HIGHEST 41 /* half16 #highest(S + A) */
+#define R_PPC64_ADDR16_HIGHESTA 42 /* half16 #highesta(S + A) */
+#define R_PPC64_UADDR64 43 /* doubleword64 S + A */
+#define R_PPC64_REL64 44 /* doubleword64 S + A - P */
+#define R_PPC64_PLT64 45 /* doubleword64 L + A */
+#define R_PPC64_PLTREL64 46 /* doubleword64 L + A - P */
+#define R_PPC64_TOC16 47 /* half16* S + A - .TOC */
+#define R_PPC64_TOC16_LO 48 /* half16 #lo(S + A - .TOC.) */
+#define R_PPC64_TOC16_HI 49 /* half16 #hi(S + A - .TOC.) */
+#define R_PPC64_TOC16_HA 50 /* half16 #ha(S + A - .TOC.) */
+#define R_PPC64_TOC 51 /* doubleword64 .TOC */
+#define R_PPC64_PLTGOT16 52 /* half16* M + A */
+#define R_PPC64_PLTGOT16_LO 53 /* half16 #lo(M + A) */
+#define R_PPC64_PLTGOT16_HI 54 /* half16 #hi(M + A) */
+#define R_PPC64_PLTGOT16_HA 55 /* half16 #ha(M + A) */
+
+#define R_PPC64_ADDR16_DS 56 /* half16ds* (S + A) >> 2 */
+#define R_PPC64_ADDR16_LO_DS 57 /* half16ds #lo(S + A) >> 2 */
+#define R_PPC64_GOT16_DS 58 /* half16ds* (G + A) >> 2 */
+#define R_PPC64_GOT16_LO_DS 59 /* half16ds #lo(G + A) >> 2 */
+#define R_PPC64_PLT16_LO_DS 60 /* half16ds #lo(L + A) >> 2 */
+#define R_PPC64_SECTOFF_DS 61 /* half16ds* (R + A) >> 2 */
+#define R_PPC64_SECTOFF_LO_DS 62 /* half16ds #lo(R + A) >> 2 */
+#define R_PPC64_TOC16_DS 63 /* half16ds* (S + A - .TOC.) >> 2 */
+#define R_PPC64_TOC16_LO_DS 64 /* half16ds #lo(S + A - .TOC.) >> 2 */
+#define R_PPC64_PLTGOT16_DS 65 /* half16ds* (M + A) >> 2 */
+#define R_PPC64_PLTGOT16_LO_DS 66 /* half16ds #lo(M + A) >> 2 */
+
+/* PowerPC64 relocations defined for the TLS access ABI. */
+#define R_PPC64_TLS 67 /* none (sym+add)@tls */
+#define R_PPC64_DTPMOD64 68 /* doubleword64 (sym+add)@dtpmod */
+#define R_PPC64_TPREL16 69 /* half16* (sym+add)@tprel */
+#define R_PPC64_TPREL16_LO 70 /* half16 (sym+add)@tprel@l */
+#define R_PPC64_TPREL16_HI 71 /* half16 (sym+add)@tprel@h */
+#define R_PPC64_TPREL16_HA 72 /* half16 (sym+add)@tprel@ha */
+#define R_PPC64_TPREL64 73 /* doubleword64 (sym+add)@tprel */
+#define R_PPC64_DTPREL16 74 /* half16* (sym+add)@dtprel */
+#define R_PPC64_DTPREL16_LO 75 /* half16 (sym+add)@dtprel@l */
+#define R_PPC64_DTPREL16_HI 76 /* half16 (sym+add)@dtprel@h */
+#define R_PPC64_DTPREL16_HA 77 /* half16 (sym+add)@dtprel@ha */
+#define R_PPC64_DTPREL64 78 /* doubleword64 (sym+add)@dtprel */
+#define R_PPC64_GOT_TLSGD16 79 /* half16* (sym+add)@got@tlsgd */
+#define R_PPC64_GOT_TLSGD16_LO 80 /* half16 (sym+add)@got@tlsgd@l */
+#define R_PPC64_GOT_TLSGD16_HI 81 /* half16 (sym+add)@got@tlsgd@h */
+#define R_PPC64_GOT_TLSGD16_HA 82 /* half16 (sym+add)@got@tlsgd@ha */
+#define R_PPC64_GOT_TLSLD16 83 /* half16* (sym+add)@got@tlsld */
+#define R_PPC64_GOT_TLSLD16_LO 84 /* half16 (sym+add)@got@tlsld@l */
+#define R_PPC64_GOT_TLSLD16_HI 85 /* half16 (sym+add)@got@tlsld@h */
+#define R_PPC64_GOT_TLSLD16_HA 86 /* half16 (sym+add)@got@tlsld@ha */
+#define R_PPC64_GOT_TPREL16_DS 87 /* half16ds* (sym+add)@got@tprel */
+#define R_PPC64_GOT_TPREL16_LO_DS 88 /* half16ds (sym+add)@got@tprel@l */
+#define R_PPC64_GOT_TPREL16_HI 89 /* half16 (sym+add)@got@tprel@h */
+#define R_PPC64_GOT_TPREL16_HA 90 /* half16 (sym+add)@got@tprel@ha */
+#define R_PPC64_GOT_DTPREL16_DS 91 /* half16ds* (sym+add)@got@dtprel */
+#define R_PPC64_GOT_DTPREL16_LO_DS 92 /* half16ds (sym+add)@got@dtprel@l */
+#define R_PPC64_GOT_DTPREL16_HI 93 /* half16 (sym+add)@got@dtprel@h */
+#define R_PPC64_GOT_DTPREL16_HA 94 /* half16 (sym+add)@got@dtprel@ha */
+#define R_PPC64_TPREL16_DS 95 /* half16ds* (sym+add)@tprel */
+#define R_PPC64_TPREL16_LO_DS 96 /* half16ds (sym+add)@tprel@l */
+#define R_PPC64_TPREL16_HIGHER 97 /* half16 (sym+add)@tprel@higher */
+#define R_PPC64_TPREL16_HIGHERA 98 /* half16 (sym+add)@tprel@highera */
+#define R_PPC64_TPREL16_HIGHEST 99 /* half16 (sym+add)@tprel@highest */
+#define R_PPC64_TPREL16_HIGHESTA 100 /* half16 (sym+add)@tprel@highesta */
+#define R_PPC64_DTPREL16_DS 101 /* half16ds* (sym+add)@dtprel */
+#define R_PPC64_DTPREL16_LO_DS 102 /* half16ds (sym+add)@dtprel@l */
+#define R_PPC64_DTPREL16_HIGHER 103 /* half16 (sym+add)@dtprel@higher */
+#define R_PPC64_DTPREL16_HIGHERA 104 /* half16 (sym+add)@dtprel@highera */
+#define R_PPC64_DTPREL16_HIGHEST 105 /* half16 (sym+add)@dtprel@highest */
+#define R_PPC64_DTPREL16_HIGHESTA 106 /* half16 (sym+add)@dtprel@highesta */
+#define R_PPC64_TLSGD 107 /* none (sym+add)@tlsgd */
+#define R_PPC64_TLSLD 108 /* none (sym+add)@tlsld */
+#define R_PPC64_TOCSAVE 109 /* none */
+
+/* Added when HA and HI relocs were changed to report overflows. */
+#define R_PPC64_ADDR16_HIGH 110
+#define R_PPC64_ADDR16_HIGHA 111
+#define R_PPC64_TPREL16_HIGH 112
+#define R_PPC64_TPREL16_HIGHA 113
+#define R_PPC64_DTPREL16_HIGH 114
+#define R_PPC64_DTPREL16_HIGHA 115
+
+/* GNU extension to support local ifunc. */
+#define R_PPC64_JMP_IREL 247
+#define R_PPC64_IRELATIVE 248
+#define R_PPC64_REL16 249 /* half16 (sym+add-.) */
+#define R_PPC64_REL16_LO 250 /* half16 (sym+add-.)@l */
+#define R_PPC64_REL16_HI 251 /* half16 (sym+add-.)@h */
+#define R_PPC64_REL16_HA 252 /* half16 (sym+add-.)@ha */
+
+/* e_flags bits specifying ABI.
+ 1 for original function descriptor using ABI,
+ 2 for revised ABI without function descriptors,
+ 0 for unspecified or not using any features affected by the differences. */
+#define EF_PPC64_ABI 3
+
+/* PowerPC64 specific values for the Dyn d_tag field. */
+#define DT_PPC64_GLINK (DT_LOPROC + 0)
+#define DT_PPC64_OPD (DT_LOPROC + 1)
+#define DT_PPC64_OPDSZ (DT_LOPROC + 2)
+#define DT_PPC64_OPT (DT_LOPROC + 3)
+#define DT_PPC64_NUM 4
+
+/* PowerPC64 specific values for the DT_PPC64_OPT Dyn entry. */
+#define PPC64_OPT_TLS 1
+#define PPC64_OPT_MULTI_TOC 2
+
+/* PowerPC64 specific values for the Elf64_Sym st_other field. */
+#define STO_PPC64_LOCAL_BIT 5
+#define STO_PPC64_LOCAL_MASK (7 << STO_PPC64_LOCAL_BIT)
+#define PPC64_LOCAL_ENTRY_OFFSET(other) \
+ (((1 << (((other) & STO_PPC64_LOCAL_MASK) >> STO_PPC64_LOCAL_BIT)) >> 2) << 2)
+
+
+/* ARM specific declarations */
+
+/* Processor specific flags for the ELF header e_flags field. */
+#define EF_ARM_RELEXEC 0x01
+#define EF_ARM_HASENTRY 0x02
+#define EF_ARM_INTERWORK 0x04
+#define EF_ARM_APCS_26 0x08
+#define EF_ARM_APCS_FLOAT 0x10
+#define EF_ARM_PIC 0x20
+#define EF_ARM_ALIGN8 0x40 /* 8-bit structure alignment is in use */
+#define EF_ARM_NEW_ABI 0x80
+#define EF_ARM_OLD_ABI 0x100
+#define EF_ARM_SOFT_FLOAT 0x200
+#define EF_ARM_VFP_FLOAT 0x400
+#define EF_ARM_MAVERICK_FLOAT 0x800
+
+#define EF_ARM_ABI_FLOAT_SOFT 0x200 /* NB conflicts with EF_ARM_SOFT_FLOAT */
+#define EF_ARM_ABI_FLOAT_HARD 0x400 /* NB conflicts with EF_ARM_VFP_FLOAT */
+
+
+/* Other constants defined in the ARM ELF spec. version B-01. */
+/* NB. These conflict with values defined above. */
+#define EF_ARM_SYMSARESORTED 0x04
+#define EF_ARM_DYNSYMSUSESEGIDX 0x08
+#define EF_ARM_MAPSYMSFIRST 0x10
+#define EF_ARM_EABIMASK 0XFF000000
+
+/* Constants defined in AAELF. */
+#define EF_ARM_BE8 0x00800000
+#define EF_ARM_LE8 0x00400000
+
+#define EF_ARM_EABI_VERSION(flags) ((flags) & EF_ARM_EABIMASK)
+#define EF_ARM_EABI_UNKNOWN 0x00000000
+#define EF_ARM_EABI_VER1 0x01000000
+#define EF_ARM_EABI_VER2 0x02000000
+#define EF_ARM_EABI_VER3 0x03000000
+#define EF_ARM_EABI_VER4 0x04000000
+#define EF_ARM_EABI_VER5 0x05000000
+
+/* Additional symbol types for Thumb. */
+#define STT_ARM_TFUNC STT_LOPROC /* A Thumb function. */
+#define STT_ARM_16BIT STT_HIPROC /* A Thumb label. */
+
+/* ARM-specific values for sh_flags */
+#define SHF_ARM_ENTRYSECT 0x10000000 /* Section contains an entry point */
+#define SHF_ARM_COMDEF 0x80000000 /* Section may be multiply defined
+ in the input to a link step. */
+
+/* ARM-specific program header flags */
+#define PF_ARM_SB 0x10000000 /* Segment contains the location
+ addressed by the static base. */
+#define PF_ARM_PI 0x20000000 /* Position-independent segment. */
+#define PF_ARM_ABS 0x40000000 /* Absolute segment. */
+
+/* Processor specific values for the Phdr p_type field. */
+#define PT_ARM_EXIDX (PT_LOPROC + 1) /* ARM unwind segment. */
+
+/* Processor specific values for the Shdr sh_type field. */
+#define SHT_ARM_EXIDX (SHT_LOPROC + 1) /* ARM unwind section. */
+#define SHT_ARM_PREEMPTMAP (SHT_LOPROC + 2) /* Preemption details. */
+#define SHT_ARM_ATTRIBUTES (SHT_LOPROC + 3) /* ARM attributes section. */
+
+
+/* AArch64 relocs. */
+
+#define R_AARCH64_NONE 0 /* No relocation. */
+
+/* ILP32 AArch64 relocs. */
+#define R_AARCH64_P32_ABS32 1 /* Direct 32 bit. */
+#define R_AARCH64_P32_COPY 180 /* Copy symbol at runtime. */
+#define R_AARCH64_P32_GLOB_DAT 181 /* Create GOT entry. */
+#define R_AARCH64_P32_JUMP_SLOT 182 /* Create PLT entry. */
+#define R_AARCH64_P32_RELATIVE 183 /* Adjust by program base. */
+#define R_AARCH64_P32_TLS_DTPMOD 184 /* Module number, 32 bit. */
+#define R_AARCH64_P32_TLS_DTPREL 185 /* Module-relative offset, 32 bit. */
+#define R_AARCH64_P32_TLS_TPREL 186 /* TP-relative offset, 32 bit. */
+#define R_AARCH64_P32_TLSDESC 187 /* TLS Descriptor. */
+#define R_AARCH64_P32_IRELATIVE 188 /* STT_GNU_IFUNC relocation. */
+
+/* LP64 AArch64 relocs. */
+#define R_AARCH64_ABS64 257 /* Direct 64 bit. */
+#define R_AARCH64_ABS32 258 /* Direct 32 bit. */
+#define R_AARCH64_ABS16 259 /* Direct 16-bit. */
+#define R_AARCH64_PREL64 260 /* PC-relative 64-bit. */
+#define R_AARCH64_PREL32 261 /* PC-relative 32-bit. */
+#define R_AARCH64_PREL16 262 /* PC-relative 16-bit. */
+#define R_AARCH64_MOVW_UABS_G0 263 /* Dir. MOVZ imm. from bits 15:0. */
+#define R_AARCH64_MOVW_UABS_G0_NC 264 /* Likewise for MOVK; no check. */
+#define R_AARCH64_MOVW_UABS_G1 265 /* Dir. MOVZ imm. from bits 31:16. */
+#define R_AARCH64_MOVW_UABS_G1_NC 266 /* Likewise for MOVK; no check. */
+#define R_AARCH64_MOVW_UABS_G2 267 /* Dir. MOVZ imm. from bits 47:32. */
+#define R_AARCH64_MOVW_UABS_G2_NC 268 /* Likewise for MOVK; no check. */
+#define R_AARCH64_MOVW_UABS_G3 269 /* Dir. MOV{K,Z} imm. from 63:48. */
+#define R_AARCH64_MOVW_SABS_G0 270 /* Dir. MOV{N,Z} imm. from 15:0. */
+#define R_AARCH64_MOVW_SABS_G1 271 /* Dir. MOV{N,Z} imm. from 31:16. */
+#define R_AARCH64_MOVW_SABS_G2 272 /* Dir. MOV{N,Z} imm. from 47:32. */
+#define R_AARCH64_LD_PREL_LO19 273 /* PC-rel. LD imm. from bits 20:2. */
+#define R_AARCH64_ADR_PREL_LO21 274 /* PC-rel. ADR imm. from bits 20:0. */
+#define R_AARCH64_ADR_PREL_PG_HI21 275 /* Page-rel. ADRP imm. from 32:12. */
+#define R_AARCH64_ADR_PREL_PG_HI21_NC 276 /* Likewise; no overflow check. */
+#define R_AARCH64_ADD_ABS_LO12_NC 277 /* Dir. ADD imm. from bits 11:0. */
+#define R_AARCH64_LDST8_ABS_LO12_NC 278 /* Likewise for LD/ST; no check. */
+#define R_AARCH64_TSTBR14 279 /* PC-rel. TBZ/TBNZ imm. from 15:2. */
+#define R_AARCH64_CONDBR19 280 /* PC-rel. cond. br. imm. from 20:2. */
+#define R_AARCH64_JUMP26 282 /* PC-rel. B imm. from bits 27:2. */
+#define R_AARCH64_CALL26 283 /* Likewise for CALL. */
+#define R_AARCH64_LDST16_ABS_LO12_NC 284 /* Dir. ADD imm. from bits 11:1. */
+#define R_AARCH64_LDST32_ABS_LO12_NC 285 /* Likewise for bits 11:2. */
+#define R_AARCH64_LDST64_ABS_LO12_NC 286 /* Likewise for bits 11:3. */
+#define R_AARCH64_MOVW_PREL_G0 287 /* PC-rel. MOV{N,Z} imm. from 15:0. */
+#define R_AARCH64_MOVW_PREL_G0_NC 288 /* Likewise for MOVK; no check. */
+#define R_AARCH64_MOVW_PREL_G1 289 /* PC-rel. MOV{N,Z} imm. from 31:16. */
+#define R_AARCH64_MOVW_PREL_G1_NC 290 /* Likewise for MOVK; no check. */
+#define R_AARCH64_MOVW_PREL_G2 291 /* PC-rel. MOV{N,Z} imm. from 47:32. */
+#define R_AARCH64_MOVW_PREL_G2_NC 292 /* Likewise for MOVK; no check. */
+#define R_AARCH64_MOVW_PREL_G3 293 /* PC-rel. MOV{N,Z} imm. from 63:48. */
+#define R_AARCH64_LDST128_ABS_LO12_NC 299 /* Dir. ADD imm. from bits 11:4. */
+#define R_AARCH64_MOVW_GOTOFF_G0 300 /* GOT-rel. off. MOV{N,Z} imm. 15:0. */
+#define R_AARCH64_MOVW_GOTOFF_G0_NC 301 /* Likewise for MOVK; no check. */
+#define R_AARCH64_MOVW_GOTOFF_G1 302 /* GOT-rel. o. MOV{N,Z} imm. 31:16. */
+#define R_AARCH64_MOVW_GOTOFF_G1_NC 303 /* Likewise for MOVK; no check. */
+#define R_AARCH64_MOVW_GOTOFF_G2 304 /* GOT-rel. o. MOV{N,Z} imm. 47:32. */
+#define R_AARCH64_MOVW_GOTOFF_G2_NC 305 /* Likewise for MOVK; no check. */
+#define R_AARCH64_MOVW_GOTOFF_G3 306 /* GOT-rel. o. MOV{N,Z} imm. 63:48. */
+#define R_AARCH64_GOTREL64 307 /* GOT-relative 64-bit. */
+#define R_AARCH64_GOTREL32 308 /* GOT-relative 32-bit. */
+#define R_AARCH64_GOT_LD_PREL19 309 /* PC-rel. GOT off. load imm. 20:2. */
+#define R_AARCH64_LD64_GOTOFF_LO15 310 /* GOT-rel. off. LD/ST imm. 14:3. */
+#define R_AARCH64_ADR_GOT_PAGE 311 /* P-page-rel. GOT off. ADRP 32:12. */
+#define R_AARCH64_LD64_GOT_LO12_NC 312 /* Dir. GOT off. LD/ST imm. 11:3. */
+#define R_AARCH64_LD64_GOTPAGE_LO15 313 /* GOT-page-rel. GOT off. LD/ST 14:3 */
+#define R_AARCH64_TLSGD_ADR_PREL21 512 /* PC-relative ADR imm. 20:0. */
+#define R_AARCH64_TLSGD_ADR_PAGE21 513 /* page-rel. ADRP imm. 32:12. */
+#define R_AARCH64_TLSGD_ADD_LO12_NC 514 /* direct ADD imm. from 11:0. */
+#define R_AARCH64_TLSGD_MOVW_G1 515 /* GOT-rel. MOV{N,Z} 31:16. */
+#define R_AARCH64_TLSGD_MOVW_G0_NC 516 /* GOT-rel. MOVK imm. 15:0. */
+#define R_AARCH64_TLSLD_ADR_PREL21 517 /* Like 512; local dynamic model. */
+#define R_AARCH64_TLSLD_ADR_PAGE21 518 /* Like 513; local dynamic model. */
+#define R_AARCH64_TLSLD_ADD_LO12_NC 519 /* Like 514; local dynamic model. */
+#define R_AARCH64_TLSLD_MOVW_G1 520 /* Like 515; local dynamic model. */
+#define R_AARCH64_TLSLD_MOVW_G0_NC 521 /* Like 516; local dynamic model. */
+#define R_AARCH64_TLSLD_LD_PREL19 522 /* TLS PC-rel. load imm. 20:2. */
+#define R_AARCH64_TLSLD_MOVW_DTPREL_G2 523 /* TLS DTP-rel. MOV{N,Z} 47:32. */
+#define R_AARCH64_TLSLD_MOVW_DTPREL_G1 524 /* TLS DTP-rel. MOV{N,Z} 31:16. */
+#define R_AARCH64_TLSLD_MOVW_DTPREL_G1_NC 525 /* Likewise; MOVK; no check. */
+#define R_AARCH64_TLSLD_MOVW_DTPREL_G0 526 /* TLS DTP-rel. MOV{N,Z} 15:0. */
+#define R_AARCH64_TLSLD_MOVW_DTPREL_G0_NC 527 /* Likewise; MOVK; no check. */
+#define R_AARCH64_TLSLD_ADD_DTPREL_HI12 528 /* DTP-rel. ADD imm. from 23:12. */
+#define R_AARCH64_TLSLD_ADD_DTPREL_LO12 529 /* DTP-rel. ADD imm. from 11:0. */
+#define R_AARCH64_TLSLD_ADD_DTPREL_LO12_NC 530 /* Likewise; no ovfl. check. */
+#define R_AARCH64_TLSLD_LDST8_DTPREL_LO12 531 /* DTP-rel. LD/ST imm. 11:0. */
+#define R_AARCH64_TLSLD_LDST8_DTPREL_LO12_NC 532 /* Likewise; no check. */
+#define R_AARCH64_TLSLD_LDST16_DTPREL_LO12 533 /* DTP-rel. LD/ST imm. 11:1. */
+#define R_AARCH64_TLSLD_LDST16_DTPREL_LO12_NC 534 /* Likewise; no check. */
+#define R_AARCH64_TLSLD_LDST32_DTPREL_LO12 535 /* DTP-rel. LD/ST imm. 11:2. */
+#define R_AARCH64_TLSLD_LDST32_DTPREL_LO12_NC 536 /* Likewise; no check. */
+#define R_AARCH64_TLSLD_LDST64_DTPREL_LO12 537 /* DTP-rel. LD/ST imm. 11:3. */
+#define R_AARCH64_TLSLD_LDST64_DTPREL_LO12_NC 538 /* Likewise; no check. */
+#define R_AARCH64_TLSIE_MOVW_GOTTPREL_G1 539 /* GOT-rel. MOV{N,Z} 31:16. */
+#define R_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC 540 /* GOT-rel. MOVK 15:0. */
+#define R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 541 /* Page-rel. ADRP 32:12. */
+#define R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC 542 /* Direct LD off. 11:3. */
+#define R_AARCH64_TLSIE_LD_GOTTPREL_PREL19 543 /* PC-rel. load imm. 20:2. */
+#define R_AARCH64_TLSLE_MOVW_TPREL_G2 544 /* TLS TP-rel. MOV{N,Z} 47:32. */
+#define R_AARCH64_TLSLE_MOVW_TPREL_G1 545 /* TLS TP-rel. MOV{N,Z} 31:16. */
+#define R_AARCH64_TLSLE_MOVW_TPREL_G1_NC 546 /* Likewise; MOVK; no check. */
+#define R_AARCH64_TLSLE_MOVW_TPREL_G0 547 /* TLS TP-rel. MOV{N,Z} 15:0. */
+#define R_AARCH64_TLSLE_MOVW_TPREL_G0_NC 548 /* Likewise; MOVK; no check. */
+#define R_AARCH64_TLSLE_ADD_TPREL_HI12 549 /* TP-rel. ADD imm. 23:12. */
+#define R_AARCH64_TLSLE_ADD_TPREL_LO12 550 /* TP-rel. ADD imm. 11:0. */
+#define R_AARCH64_TLSLE_ADD_TPREL_LO12_NC 551 /* Likewise; no ovfl. check. */
+#define R_AARCH64_TLSLE_LDST8_TPREL_LO12 552 /* TP-rel. LD/ST off. 11:0. */
+#define R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC 553 /* Likewise; no ovfl. check. */
+#define R_AARCH64_TLSLE_LDST16_TPREL_LO12 554 /* TP-rel. LD/ST off. 11:1. */
+#define R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC 555 /* Likewise; no check. */
+#define R_AARCH64_TLSLE_LDST32_TPREL_LO12 556 /* TP-rel. LD/ST off. 11:2. */
+#define R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC 557 /* Likewise; no check. */
+#define R_AARCH64_TLSLE_LDST64_TPREL_LO12 558 /* TP-rel. LD/ST off. 11:3. */
+#define R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC 559 /* Likewise; no check. */
+#define R_AARCH64_TLSDESC_LD_PREL19 560 /* PC-rel. load immediate 20:2. */
+#define R_AARCH64_TLSDESC_ADR_PREL21 561 /* PC-rel. ADR immediate 20:0. */
+#define R_AARCH64_TLSDESC_ADR_PAGE21 562 /* Page-rel. ADRP imm. 32:12. */
+#define R_AARCH64_TLSDESC_LD64_LO12 563 /* Direct LD off. from 11:3. */
+#define R_AARCH64_TLSDESC_ADD_LO12 564 /* Direct ADD imm. from 11:0. */
+#define R_AARCH64_TLSDESC_OFF_G1 565 /* GOT-rel. MOV{N,Z} imm. 31:16. */
+#define R_AARCH64_TLSDESC_OFF_G0_NC 566 /* GOT-rel. MOVK imm. 15:0; no ck. */
+#define R_AARCH64_TLSDESC_LDR 567 /* Relax LDR. */
+#define R_AARCH64_TLSDESC_ADD 568 /* Relax ADD. */
+#define R_AARCH64_TLSDESC_CALL 569 /* Relax BLR. */
+#define R_AARCH64_TLSLE_LDST128_TPREL_LO12 570 /* TP-rel. LD/ST off. 11:4. */
+#define R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC 571 /* Likewise; no check. */
+#define R_AARCH64_TLSLD_LDST128_DTPREL_LO12 572 /* DTP-rel. LD/ST imm. 11:4. */
+#define R_AARCH64_TLSLD_LDST128_DTPREL_LO12_NC 573 /* Likewise; no check. */
+#define R_AARCH64_COPY 1024 /* Copy symbol at runtime. */
+#define R_AARCH64_GLOB_DAT 1025 /* Create GOT entry. */
+#define R_AARCH64_JUMP_SLOT 1026 /* Create PLT entry. */
+#define R_AARCH64_RELATIVE 1027 /* Adjust by program base. */
+#define R_AARCH64_TLS_DTPMOD 1028 /* Module number, 64 bit. */
+#define R_AARCH64_TLS_DTPREL 1029 /* Module-relative offset, 64 bit. */
+#define R_AARCH64_TLS_TPREL 1030 /* TP-relative offset, 64 bit. */
+#define R_AARCH64_TLSDESC 1031 /* TLS Descriptor. */
+#define R_AARCH64_IRELATIVE 1032 /* STT_GNU_IFUNC relocation. */
+
+/* ARM relocs. */
+
+#define R_ARM_NONE 0 /* No reloc */
+#define R_ARM_PC24 1 /* Deprecated PC relative 26
+ bit branch. */
+#define R_ARM_ABS32 2 /* Direct 32 bit */
+#define R_ARM_REL32 3 /* PC relative 32 bit */
+#define R_ARM_PC13 4
+#define R_ARM_ABS16 5 /* Direct 16 bit */
+#define R_ARM_ABS12 6 /* Direct 12 bit */
+#define R_ARM_THM_ABS5 7 /* Direct & 0x7C (LDR, STR). */
+#define R_ARM_ABS8 8 /* Direct 8 bit */
+#define R_ARM_SBREL32 9
+#define R_ARM_THM_PC22 10 /* PC relative 24 bit (Thumb32 BL). */
+#define R_ARM_THM_PC8 11 /* PC relative & 0x3FC
+ (Thumb16 LDR, ADD, ADR). */
+#define R_ARM_AMP_VCALL9 12
+#define R_ARM_SWI24 13 /* Obsolete static relocation. */
+#define R_ARM_TLS_DESC 13 /* Dynamic relocation. */
+#define R_ARM_THM_SWI8 14 /* Reserved. */
+#define R_ARM_XPC25 15 /* Reserved. */
+#define R_ARM_THM_XPC22 16 /* Reserved. */
+#define R_ARM_TLS_DTPMOD32 17 /* ID of module containing symbol */
+#define R_ARM_TLS_DTPOFF32 18 /* Offset in TLS block */
+#define R_ARM_TLS_TPOFF32 19 /* Offset in static TLS block */
+#define R_ARM_COPY 20 /* Copy symbol at runtime */
+#define R_ARM_GLOB_DAT 21 /* Create GOT entry */
+#define R_ARM_JUMP_SLOT 22 /* Create PLT entry */
+#define R_ARM_RELATIVE 23 /* Adjust by program base */
+#define R_ARM_GOTOFF 24 /* 32 bit offset to GOT */
+#define R_ARM_GOTPC 25 /* 32 bit PC relative offset to GOT */
+#define R_ARM_GOT32 26 /* 32 bit GOT entry */
+#define R_ARM_PLT32 27 /* Deprecated, 32 bit PLT address. */
+#define R_ARM_CALL 28 /* PC relative 24 bit (BL, BLX). */
+#define R_ARM_JUMP24 29 /* PC relative 24 bit
+ (B, BL<cond>). */
+#define R_ARM_THM_JUMP24 30 /* PC relative 24 bit (Thumb32 B.W). */
+#define R_ARM_BASE_ABS 31 /* Adjust by program base. */
+#define R_ARM_ALU_PCREL_7_0 32 /* Obsolete. */
+#define R_ARM_ALU_PCREL_15_8 33 /* Obsolete. */
+#define R_ARM_ALU_PCREL_23_15 34 /* Obsolete. */
+#define R_ARM_LDR_SBREL_11_0 35 /* Deprecated, prog. base relative. */
+#define R_ARM_ALU_SBREL_19_12 36 /* Deprecated, prog. base relative. */
+#define R_ARM_ALU_SBREL_27_20 37 /* Deprecated, prog. base relative. */
+#define R_ARM_TARGET1 38
+#define R_ARM_SBREL31 39 /* Program base relative. */
+#define R_ARM_V4BX 40
+#define R_ARM_TARGET2 41
+#define R_ARM_PREL31 42 /* 32 bit PC relative. */
+#define R_ARM_MOVW_ABS_NC 43 /* Direct 16-bit (MOVW). */
+#define R_ARM_MOVT_ABS 44 /* Direct high 16-bit (MOVT). */
+#define R_ARM_MOVW_PREL_NC 45 /* PC relative 16-bit (MOVW). */
+#define R_ARM_MOVT_PREL 46 /* PC relative (MOVT). */
+#define R_ARM_THM_MOVW_ABS_NC 47 /* Direct 16 bit (Thumb32 MOVW). */
+#define R_ARM_THM_MOVT_ABS 48 /* Direct high 16 bit
+ (Thumb32 MOVT). */
+#define R_ARM_THM_MOVW_PREL_NC 49 /* PC relative 16 bit
+ (Thumb32 MOVW). */
+#define R_ARM_THM_MOVT_PREL 50 /* PC relative high 16 bit
+ (Thumb32 MOVT). */
+#define R_ARM_THM_JUMP19 51 /* PC relative 20 bit
+ (Thumb32 B<cond>.W). */
+#define R_ARM_THM_JUMP6 52 /* PC relative X & 0x7E
+ (Thumb16 CBZ, CBNZ). */
+#define R_ARM_THM_ALU_PREL_11_0 53 /* PC relative 12 bit
+ (Thumb32 ADR.W). */
+#define R_ARM_THM_PC12 54 /* PC relative 12 bit
+ (Thumb32 LDR{D,SB,H,SH}). */
+#define R_ARM_ABS32_NOI 55 /* Direct 32-bit. */
+#define R_ARM_REL32_NOI 56 /* PC relative 32-bit. */
+#define R_ARM_ALU_PC_G0_NC 57 /* PC relative (ADD, SUB). */
+#define R_ARM_ALU_PC_G0 58 /* PC relative (ADD, SUB). */
+#define R_ARM_ALU_PC_G1_NC 59 /* PC relative (ADD, SUB). */
+#define R_ARM_ALU_PC_G1 60 /* PC relative (ADD, SUB). */
+#define R_ARM_ALU_PC_G2 61 /* PC relative (ADD, SUB). */
+#define R_ARM_LDR_PC_G1 62 /* PC relative (LDR,STR,LDRB,STRB). */
+#define R_ARM_LDR_PC_G2 63 /* PC relative (LDR,STR,LDRB,STRB). */
+#define R_ARM_LDRS_PC_G0 64 /* PC relative (STR{D,H},
+ LDR{D,SB,H,SH}). */
+#define R_ARM_LDRS_PC_G1 65 /* PC relative (STR{D,H},
+ LDR{D,SB,H,SH}). */
+#define R_ARM_LDRS_PC_G2 66 /* PC relative (STR{D,H},
+ LDR{D,SB,H,SH}). */
+#define R_ARM_LDC_PC_G0 67 /* PC relative (LDC, STC). */
+#define R_ARM_LDC_PC_G1 68 /* PC relative (LDC, STC). */
+#define R_ARM_LDC_PC_G2 69 /* PC relative (LDC, STC). */
+#define R_ARM_ALU_SB_G0_NC 70 /* Program base relative (ADD,SUB). */
+#define R_ARM_ALU_SB_G0 71 /* Program base relative (ADD,SUB). */
+#define R_ARM_ALU_SB_G1_NC 72 /* Program base relative (ADD,SUB). */
+#define R_ARM_ALU_SB_G1 73 /* Program base relative (ADD,SUB). */
+#define R_ARM_ALU_SB_G2 74 /* Program base relative (ADD,SUB). */
+#define R_ARM_LDR_SB_G0 75 /* Program base relative (LDR,
+ STR, LDRB, STRB). */
+#define R_ARM_LDR_SB_G1 76 /* Program base relative
+ (LDR, STR, LDRB, STRB). */
+#define R_ARM_LDR_SB_G2 77 /* Program base relative
+ (LDR, STR, LDRB, STRB). */
+#define R_ARM_LDRS_SB_G0 78 /* Program base relative
+ (LDR, STR, LDRB, STRB). */
+#define R_ARM_LDRS_SB_G1 79 /* Program base relative
+ (LDR, STR, LDRB, STRB). */
+#define R_ARM_LDRS_SB_G2 80 /* Program base relative
+ (LDR, STR, LDRB, STRB). */
+#define R_ARM_LDC_SB_G0 81 /* Program base relative (LDC,STC). */
+#define R_ARM_LDC_SB_G1 82 /* Program base relative (LDC,STC). */
+#define R_ARM_LDC_SB_G2 83 /* Program base relative (LDC,STC). */
+#define R_ARM_MOVW_BREL_NC 84 /* Program base relative 16
+ bit (MOVW). */
+#define R_ARM_MOVT_BREL 85 /* Program base relative high
+ 16 bit (MOVT). */
+#define R_ARM_MOVW_BREL 86 /* Program base relative 16
+ bit (MOVW). */
+#define R_ARM_THM_MOVW_BREL_NC 87 /* Program base relative 16
+ bit (Thumb32 MOVW). */
+#define R_ARM_THM_MOVT_BREL 88 /* Program base relative high
+ 16 bit (Thumb32 MOVT). */
+#define R_ARM_THM_MOVW_BREL 89 /* Program base relative 16
+ bit (Thumb32 MOVW). */
+#define R_ARM_TLS_GOTDESC 90
+#define R_ARM_TLS_CALL 91
+#define R_ARM_TLS_DESCSEQ 92 /* TLS relaxation. */
+#define R_ARM_THM_TLS_CALL 93
+#define R_ARM_PLT32_ABS 94
+#define R_ARM_GOT_ABS 95 /* GOT entry. */
+#define R_ARM_GOT_PREL 96 /* PC relative GOT entry. */
+#define R_ARM_GOT_BREL12 97 /* GOT entry relative to GOT
+ origin (LDR). */
+#define R_ARM_GOTOFF12 98 /* 12 bit, GOT entry relative
+ to GOT origin (LDR, STR). */
+#define R_ARM_GOTRELAX 99
+#define R_ARM_GNU_VTENTRY 100
+#define R_ARM_GNU_VTINHERIT 101
+#define R_ARM_THM_PC11 102 /* PC relative & 0xFFE (Thumb16 B). */
+#define R_ARM_THM_PC9 103 /* PC relative & 0x1FE
+ (Thumb16 B/B<cond>). */
+#define R_ARM_TLS_GD32 104 /* PC-rel 32 bit for global dynamic
+ thread local data */
+#define R_ARM_TLS_LDM32 105 /* PC-rel 32 bit for local dynamic
+ thread local data */
+#define R_ARM_TLS_LDO32 106 /* 32 bit offset relative to TLS
+ block */
+#define R_ARM_TLS_IE32 107 /* PC-rel 32 bit for GOT entry of
+ static TLS block offset */
+#define R_ARM_TLS_LE32 108 /* 32 bit offset relative to static
+ TLS block */
+#define R_ARM_TLS_LDO12 109 /* 12 bit relative to TLS
+ block (LDR, STR). */
+#define R_ARM_TLS_LE12 110 /* 12 bit relative to static
+ TLS block (LDR, STR). */
+#define R_ARM_TLS_IE12GP 111 /* 12 bit GOT entry relative
+ to GOT origin (LDR). */
+#define R_ARM_ME_TOO 128 /* Obsolete. */
+#define R_ARM_THM_TLS_DESCSEQ 129
+#define R_ARM_THM_TLS_DESCSEQ16 129
+#define R_ARM_THM_TLS_DESCSEQ32 130
+#define R_ARM_THM_GOT_BREL12 131 /* GOT entry relative to GOT
+ origin, 12 bit (Thumb32 LDR). */
+#define R_ARM_IRELATIVE 160
+#define R_ARM_RXPC25 249
+#define R_ARM_RSBREL32 250
+#define R_ARM_THM_RPC22 251
+#define R_ARM_RREL32 252
+#define R_ARM_RABS22 253
+#define R_ARM_RPC24 254
+#define R_ARM_RBASE 255
+/* Keep this the last entry. */
+#define R_ARM_NUM 256
+
+/* IA-64 specific declarations. */
+
+/* Processor specific flags for the Ehdr e_flags field. */
+#define EF_IA_64_MASKOS 0x0000000f /* os-specific flags */
+#define EF_IA_64_ABI64 0x00000010 /* 64-bit ABI */
+#define EF_IA_64_ARCH 0xff000000 /* arch. version mask */
+
+/* Processor specific values for the Phdr p_type field. */
+#define PT_IA_64_ARCHEXT (PT_LOPROC + 0) /* arch extension bits */
+#define PT_IA_64_UNWIND (PT_LOPROC + 1) /* ia64 unwind bits */
+#define PT_IA_64_HP_OPT_ANOT (PT_LOOS + 0x12)
+#define PT_IA_64_HP_HSL_ANOT (PT_LOOS + 0x13)
+#define PT_IA_64_HP_STACK (PT_LOOS + 0x14)
+
+/* Processor specific flags for the Phdr p_flags field. */
+#define PF_IA_64_NORECOV 0x80000000 /* spec insns w/o recovery */
+
+/* Processor specific values for the Shdr sh_type field. */
+#define SHT_IA_64_EXT (SHT_LOPROC + 0) /* extension bits */
+#define SHT_IA_64_UNWIND (SHT_LOPROC + 1) /* unwind bits */
+
+/* Processor specific flags for the Shdr sh_flags field. */
+#define SHF_IA_64_SHORT 0x10000000 /* section near gp */
+#define SHF_IA_64_NORECOV 0x20000000 /* spec insns w/o recovery */
+
+/* Processor specific values for the Dyn d_tag field. */
+#define DT_IA_64_PLT_RESERVE (DT_LOPROC + 0)
+#define DT_IA_64_NUM 1
+
+/* IA-64 relocations. */
+#define R_IA64_NONE 0x00 /* none */
+#define R_IA64_IMM14 0x21 /* symbol + addend, add imm14 */
+#define R_IA64_IMM22 0x22 /* symbol + addend, add imm22 */
+#define R_IA64_IMM64 0x23 /* symbol + addend, mov imm64 */
+#define R_IA64_DIR32MSB 0x24 /* symbol + addend, data4 MSB */
+#define R_IA64_DIR32LSB 0x25 /* symbol + addend, data4 LSB */
+#define R_IA64_DIR64MSB 0x26 /* symbol + addend, data8 MSB */
+#define R_IA64_DIR64LSB 0x27 /* symbol + addend, data8 LSB */
+#define R_IA64_GPREL22 0x2a /* @gprel(sym + add), add imm22 */
+#define R_IA64_GPREL64I 0x2b /* @gprel(sym + add), mov imm64 */
+#define R_IA64_GPREL32MSB 0x2c /* @gprel(sym + add), data4 MSB */
+#define R_IA64_GPREL32LSB 0x2d /* @gprel(sym + add), data4 LSB */
+#define R_IA64_GPREL64MSB 0x2e /* @gprel(sym + add), data8 MSB */
+#define R_IA64_GPREL64LSB 0x2f /* @gprel(sym + add), data8 LSB */
+#define R_IA64_LTOFF22 0x32 /* @ltoff(sym + add), add imm22 */
+#define R_IA64_LTOFF64I 0x33 /* @ltoff(sym + add), mov imm64 */
+#define R_IA64_PLTOFF22 0x3a /* @pltoff(sym + add), add imm22 */
+#define R_IA64_PLTOFF64I 0x3b /* @pltoff(sym + add), mov imm64 */
+#define R_IA64_PLTOFF64MSB 0x3e /* @pltoff(sym + add), data8 MSB */
+#define R_IA64_PLTOFF64LSB 0x3f /* @pltoff(sym + add), data8 LSB */
+#define R_IA64_FPTR64I 0x43 /* @fptr(sym + add), mov imm64 */
+#define R_IA64_FPTR32MSB 0x44 /* @fptr(sym + add), data4 MSB */
+#define R_IA64_FPTR32LSB 0x45 /* @fptr(sym + add), data4 LSB */
+#define R_IA64_FPTR64MSB 0x46 /* @fptr(sym + add), data8 MSB */
+#define R_IA64_FPTR64LSB 0x47 /* @fptr(sym + add), data8 LSB */
+#define R_IA64_PCREL60B 0x48 /* @pcrel(sym + add), brl */
+#define R_IA64_PCREL21B 0x49 /* @pcrel(sym + add), ptb, call */
+#define R_IA64_PCREL21M 0x4a /* @pcrel(sym + add), chk.s */
+#define R_IA64_PCREL21F 0x4b /* @pcrel(sym + add), fchkf */
+#define R_IA64_PCREL32MSB 0x4c /* @pcrel(sym + add), data4 MSB */
+#define R_IA64_PCREL32LSB 0x4d /* @pcrel(sym + add), data4 LSB */
+#define R_IA64_PCREL64MSB 0x4e /* @pcrel(sym + add), data8 MSB */
+#define R_IA64_PCREL64LSB 0x4f /* @pcrel(sym + add), data8 LSB */
+#define R_IA64_LTOFF_FPTR22 0x52 /* @ltoff(@fptr(s+a)), imm22 */
+#define R_IA64_LTOFF_FPTR64I 0x53 /* @ltoff(@fptr(s+a)), imm64 */
+#define R_IA64_LTOFF_FPTR32MSB 0x54 /* @ltoff(@fptr(s+a)), data4 MSB */
+#define R_IA64_LTOFF_FPTR32LSB 0x55 /* @ltoff(@fptr(s+a)), data4 LSB */
+#define R_IA64_LTOFF_FPTR64MSB 0x56 /* @ltoff(@fptr(s+a)), data8 MSB */
+#define R_IA64_LTOFF_FPTR64LSB 0x57 /* @ltoff(@fptr(s+a)), data8 LSB */
+#define R_IA64_SEGREL32MSB 0x5c /* @segrel(sym + add), data4 MSB */
+#define R_IA64_SEGREL32LSB 0x5d /* @segrel(sym + add), data4 LSB */
+#define R_IA64_SEGREL64MSB 0x5e /* @segrel(sym + add), data8 MSB */
+#define R_IA64_SEGREL64LSB 0x5f /* @segrel(sym + add), data8 LSB */
+#define R_IA64_SECREL32MSB 0x64 /* @secrel(sym + add), data4 MSB */
+#define R_IA64_SECREL32LSB 0x65 /* @secrel(sym + add), data4 LSB */
+#define R_IA64_SECREL64MSB 0x66 /* @secrel(sym + add), data8 MSB */
+#define R_IA64_SECREL64LSB 0x67 /* @secrel(sym + add), data8 LSB */
+#define R_IA64_REL32MSB 0x6c /* data 4 + REL */
+#define R_IA64_REL32LSB 0x6d /* data 4 + REL */
+#define R_IA64_REL64MSB 0x6e /* data 8 + REL */
+#define R_IA64_REL64LSB 0x6f /* data 8 + REL */
+#define R_IA64_LTV32MSB 0x74 /* symbol + addend, data4 MSB */
+#define R_IA64_LTV32LSB 0x75 /* symbol + addend, data4 LSB */
+#define R_IA64_LTV64MSB 0x76 /* symbol + addend, data8 MSB */
+#define R_IA64_LTV64LSB 0x77 /* symbol + addend, data8 LSB */
+#define R_IA64_PCREL21BI 0x79 /* @pcrel(sym + add), 21bit inst */
+#define R_IA64_PCREL22 0x7a /* @pcrel(sym + add), 22bit inst */
+#define R_IA64_PCREL64I 0x7b /* @pcrel(sym + add), 64bit inst */
+#define R_IA64_IPLTMSB 0x80 /* dynamic reloc, imported PLT, MSB */
+#define R_IA64_IPLTLSB 0x81 /* dynamic reloc, imported PLT, LSB */
+#define R_IA64_COPY 0x84 /* copy relocation */
+#define R_IA64_SUB 0x85 /* Addend and symbol difference */
+#define R_IA64_LTOFF22X 0x86 /* LTOFF22, relaxable. */
+#define R_IA64_LDXMOV 0x87 /* Use of LTOFF22X. */
+#define R_IA64_TPREL14 0x91 /* @tprel(sym + add), imm14 */
+#define R_IA64_TPREL22 0x92 /* @tprel(sym + add), imm22 */
+#define R_IA64_TPREL64I 0x93 /* @tprel(sym + add), imm64 */
+#define R_IA64_TPREL64MSB 0x96 /* @tprel(sym + add), data8 MSB */
+#define R_IA64_TPREL64LSB 0x97 /* @tprel(sym + add), data8 LSB */
+#define R_IA64_LTOFF_TPREL22 0x9a /* @ltoff(@tprel(s+a)), imm2 */
+#define R_IA64_DTPMOD64MSB 0xa6 /* @dtpmod(sym + add), data8 MSB */
+#define R_IA64_DTPMOD64LSB 0xa7 /* @dtpmod(sym + add), data8 LSB */
+#define R_IA64_LTOFF_DTPMOD22 0xaa /* @ltoff(@dtpmod(sym + add)), imm22 */
+#define R_IA64_DTPREL14 0xb1 /* @dtprel(sym + add), imm14 */
+#define R_IA64_DTPREL22 0xb2 /* @dtprel(sym + add), imm22 */
+#define R_IA64_DTPREL64I 0xb3 /* @dtprel(sym + add), imm64 */
+#define R_IA64_DTPREL32MSB 0xb4 /* @dtprel(sym + add), data4 MSB */
+#define R_IA64_DTPREL32LSB 0xb5 /* @dtprel(sym + add), data4 LSB */
+#define R_IA64_DTPREL64MSB 0xb6 /* @dtprel(sym + add), data8 MSB */
+#define R_IA64_DTPREL64LSB 0xb7 /* @dtprel(sym + add), data8 LSB */
+#define R_IA64_LTOFF_DTPREL22 0xba /* @ltoff(@dtprel(s+a)), imm22 */
+
+/* SH specific declarations */
+
+/* Processor specific flags for the ELF header e_flags field. */
+#define EF_SH_MACH_MASK 0x1f
+#define EF_SH_UNKNOWN 0x0
+#define EF_SH1 0x1
+#define EF_SH2 0x2
+#define EF_SH3 0x3
+#define EF_SH_DSP 0x4
+#define EF_SH3_DSP 0x5
+#define EF_SH4AL_DSP 0x6
+#define EF_SH3E 0x8
+#define EF_SH4 0x9
+#define EF_SH2E 0xb
+#define EF_SH4A 0xc
+#define EF_SH2A 0xd
+#define EF_SH4_NOFPU 0x10
+#define EF_SH4A_NOFPU 0x11
+#define EF_SH4_NOMMU_NOFPU 0x12
+#define EF_SH2A_NOFPU 0x13
+#define EF_SH3_NOMMU 0x14
+#define EF_SH2A_SH4_NOFPU 0x15
+#define EF_SH2A_SH3_NOFPU 0x16
+#define EF_SH2A_SH4 0x17
+#define EF_SH2A_SH3E 0x18
+
+/* SH relocs. */
+#define R_SH_NONE 0
+#define R_SH_DIR32 1
+#define R_SH_REL32 2
+#define R_SH_DIR8WPN 3
+#define R_SH_IND12W 4
+#define R_SH_DIR8WPL 5
+#define R_SH_DIR8WPZ 6
+#define R_SH_DIR8BP 7
+#define R_SH_DIR8W 8
+#define R_SH_DIR8L 9
+#define R_SH_SWITCH16 25
+#define R_SH_SWITCH32 26
+#define R_SH_USES 27
+#define R_SH_COUNT 28
+#define R_SH_ALIGN 29
+#define R_SH_CODE 30
+#define R_SH_DATA 31
+#define R_SH_LABEL 32
+#define R_SH_SWITCH8 33
+#define R_SH_GNU_VTINHERIT 34
+#define R_SH_GNU_VTENTRY 35
+#define R_SH_TLS_GD_32 144
+#define R_SH_TLS_LD_32 145
+#define R_SH_TLS_LDO_32 146
+#define R_SH_TLS_IE_32 147
+#define R_SH_TLS_LE_32 148
+#define R_SH_TLS_DTPMOD32 149
+#define R_SH_TLS_DTPOFF32 150
+#define R_SH_TLS_TPOFF32 151
+#define R_SH_GOT32 160
+#define R_SH_PLT32 161
+#define R_SH_COPY 162
+#define R_SH_GLOB_DAT 163
+#define R_SH_JMP_SLOT 164
+#define R_SH_RELATIVE 165
+#define R_SH_GOTOFF 166
+#define R_SH_GOTPC 167
+/* Keep this the last entry. */
+#define R_SH_NUM 256
+
+/* S/390 specific definitions. */
+
+/* Valid values for the e_flags field. */
+
+#define EF_S390_HIGH_GPRS 0x00000001 /* High GPRs kernel facility needed. */
+
+/* Additional s390 relocs */
+
+#define R_390_NONE 0 /* No reloc. */
+#define R_390_8 1 /* Direct 8 bit. */
+#define R_390_12 2 /* Direct 12 bit. */
+#define R_390_16 3 /* Direct 16 bit. */
+#define R_390_32 4 /* Direct 32 bit. */
+#define R_390_PC32 5 /* PC relative 32 bit. */
+#define R_390_GOT12 6 /* 12 bit GOT offset. */
+#define R_390_GOT32 7 /* 32 bit GOT offset. */
+#define R_390_PLT32 8 /* 32 bit PC relative PLT address. */
+#define R_390_COPY 9 /* Copy symbol at runtime. */
+#define R_390_GLOB_DAT 10 /* Create GOT entry. */
+#define R_390_JMP_SLOT 11 /* Create PLT entry. */
+#define R_390_RELATIVE 12 /* Adjust by program base. */
+#define R_390_GOTOFF32 13 /* 32 bit offset to GOT. */
+#define R_390_GOTPC 14 /* 32 bit PC relative offset to GOT. */
+#define R_390_GOT16 15 /* 16 bit GOT offset. */
+#define R_390_PC16 16 /* PC relative 16 bit. */
+#define R_390_PC16DBL 17 /* PC relative 16 bit shifted by 1. */
+#define R_390_PLT16DBL 18 /* 16 bit PC rel. PLT shifted by 1. */
+#define R_390_PC32DBL 19 /* PC relative 32 bit shifted by 1. */
+#define R_390_PLT32DBL 20 /* 32 bit PC rel. PLT shifted by 1. */
+#define R_390_GOTPCDBL 21 /* 32 bit PC rel. GOT shifted by 1. */
+#define R_390_64 22 /* Direct 64 bit. */
+#define R_390_PC64 23 /* PC relative 64 bit. */
+#define R_390_GOT64 24 /* 64 bit GOT offset. */
+#define R_390_PLT64 25 /* 64 bit PC relative PLT address. */
+#define R_390_GOTENT 26 /* 32 bit PC rel. to GOT entry >> 1. */
+#define R_390_GOTOFF16 27 /* 16 bit offset to GOT. */
+#define R_390_GOTOFF64 28 /* 64 bit offset to GOT. */
+#define R_390_GOTPLT12 29 /* 12 bit offset to jump slot. */
+#define R_390_GOTPLT16 30 /* 16 bit offset to jump slot. */
+#define R_390_GOTPLT32 31 /* 32 bit offset to jump slot. */
+#define R_390_GOTPLT64 32 /* 64 bit offset to jump slot. */
+#define R_390_GOTPLTENT 33 /* 32 bit rel. offset to jump slot. */
+#define R_390_PLTOFF16 34 /* 16 bit offset from GOT to PLT. */
+#define R_390_PLTOFF32 35 /* 32 bit offset from GOT to PLT. */
+#define R_390_PLTOFF64 36 /* 16 bit offset from GOT to PLT. */
+#define R_390_TLS_LOAD 37 /* Tag for load insn in TLS code. */
+#define R_390_TLS_GDCALL 38 /* Tag for function call in general
+ dynamic TLS code. */
+#define R_390_TLS_LDCALL 39 /* Tag for function call in local
+ dynamic TLS code. */
+#define R_390_TLS_GD32 40 /* Direct 32 bit for general dynamic
+ thread local data. */
+#define R_390_TLS_GD64 41 /* Direct 64 bit for general dynamic
+ thread local data. */
+#define R_390_TLS_GOTIE12 42 /* 12 bit GOT offset for static TLS
+ block offset. */
+#define R_390_TLS_GOTIE32 43 /* 32 bit GOT offset for static TLS
+ block offset. */
+#define R_390_TLS_GOTIE64 44 /* 64 bit GOT offset for static TLS
+ block offset. */
+#define R_390_TLS_LDM32 45 /* Direct 32 bit for local dynamic
+ thread local data in LE code. */
+#define R_390_TLS_LDM64 46 /* Direct 64 bit for local dynamic
+ thread local data in LE code. */
+#define R_390_TLS_IE32 47 /* 32 bit address of GOT entry for
+ negated static TLS block offset. */
+#define R_390_TLS_IE64 48 /* 64 bit address of GOT entry for
+ negated static TLS block offset. */
+#define R_390_TLS_IEENT 49 /* 32 bit rel. offset to GOT entry for
+ negated static TLS block offset. */
+#define R_390_TLS_LE32 50 /* 32 bit negated offset relative to
+ static TLS block. */
+#define R_390_TLS_LE64 51 /* 64 bit negated offset relative to
+ static TLS block. */
+#define R_390_TLS_LDO32 52 /* 32 bit offset relative to TLS
+ block. */
+#define R_390_TLS_LDO64 53 /* 64 bit offset relative to TLS
+ block. */
+#define R_390_TLS_DTPMOD 54 /* ID of module containing symbol. */
+#define R_390_TLS_DTPOFF 55 /* Offset in TLS block. */
+#define R_390_TLS_TPOFF 56 /* Negated offset in static TLS
+ block. */
+#define R_390_20 57 /* Direct 20 bit. */
+#define R_390_GOT20 58 /* 20 bit GOT offset. */
+#define R_390_GOTPLT20 59 /* 20 bit offset to jump slot. */
+#define R_390_TLS_GOTIE20 60 /* 20 bit GOT offset for static TLS
+ block offset. */
+#define R_390_IRELATIVE 61 /* STT_GNU_IFUNC relocation. */
+/* Keep this the last entry. */
+#define R_390_NUM 62
+
+
+/* CRIS relocations. */
+#define R_CRIS_NONE 0
+#define R_CRIS_8 1
+#define R_CRIS_16 2
+#define R_CRIS_32 3
+#define R_CRIS_8_PCREL 4
+#define R_CRIS_16_PCREL 5
+#define R_CRIS_32_PCREL 6
+#define R_CRIS_GNU_VTINHERIT 7
+#define R_CRIS_GNU_VTENTRY 8
+#define R_CRIS_COPY 9
+#define R_CRIS_GLOB_DAT 10
+#define R_CRIS_JUMP_SLOT 11
+#define R_CRIS_RELATIVE 12
+#define R_CRIS_16_GOT 13
+#define R_CRIS_32_GOT 14
+#define R_CRIS_16_GOTPLT 15
+#define R_CRIS_32_GOTPLT 16
+#define R_CRIS_32_GOTREL 17
+#define R_CRIS_32_PLT_GOTREL 18
+#define R_CRIS_32_PLT_PCREL 19
+
+#define R_CRIS_NUM 20
+
+
+/* AMD x86-64 relocations. */
+#define R_X86_64_NONE 0 /* No reloc */
+#define R_X86_64_64 1 /* Direct 64 bit */
+#define R_X86_64_PC32 2 /* PC relative 32 bit signed */
+#define R_X86_64_GOT32 3 /* 32 bit GOT entry */
+#define R_X86_64_PLT32 4 /* 32 bit PLT address */
+#define R_X86_64_COPY 5 /* Copy symbol at runtime */
+#define R_X86_64_GLOB_DAT 6 /* Create GOT entry */
+#define R_X86_64_JUMP_SLOT 7 /* Create PLT entry */
+#define R_X86_64_RELATIVE 8 /* Adjust by program base */
+#define R_X86_64_GOTPCREL 9 /* 32 bit signed PC relative
+ offset to GOT */
+#define R_X86_64_32 10 /* Direct 32 bit zero extended */
+#define R_X86_64_32S 11 /* Direct 32 bit sign extended */
+#define R_X86_64_16 12 /* Direct 16 bit zero extended */
+#define R_X86_64_PC16 13 /* 16 bit sign extended pc relative */
+#define R_X86_64_8 14 /* Direct 8 bit sign extended */
+#define R_X86_64_PC8 15 /* 8 bit sign extended pc relative */
+#define R_X86_64_DTPMOD64 16 /* ID of module containing symbol */
+#define R_X86_64_DTPOFF64 17 /* Offset in module's TLS block */
+#define R_X86_64_TPOFF64 18 /* Offset in initial TLS block */
+#define R_X86_64_TLSGD 19 /* 32 bit signed PC relative offset
+ to two GOT entries for GD symbol */
+#define R_X86_64_TLSLD 20 /* 32 bit signed PC relative offset
+ to two GOT entries for LD symbol */
+#define R_X86_64_DTPOFF32 21 /* Offset in TLS block */
+#define R_X86_64_GOTTPOFF 22 /* 32 bit signed PC relative offset
+ to GOT entry for IE symbol */
+#define R_X86_64_TPOFF32 23 /* Offset in initial TLS block */
+#define R_X86_64_PC64 24 /* PC relative 64 bit */
+#define R_X86_64_GOTOFF64 25 /* 64 bit offset to GOT */
+#define R_X86_64_GOTPC32 26 /* 32 bit signed pc relative
+ offset to GOT */
+#define R_X86_64_GOT64 27 /* 64-bit GOT entry offset */
+#define R_X86_64_GOTPCREL64 28 /* 64-bit PC relative offset
+ to GOT entry */
+#define R_X86_64_GOTPC64 29 /* 64-bit PC relative offset to GOT */
+#define R_X86_64_GOTPLT64 30 /* like GOT64, says PLT entry needed */
+#define R_X86_64_PLTOFF64 31 /* 64-bit GOT relative offset
+ to PLT entry */
+#define R_X86_64_SIZE32 32 /* Size of symbol plus 32-bit addend */
+#define R_X86_64_SIZE64 33 /* Size of symbol plus 64-bit addend */
+#define R_X86_64_GOTPC32_TLSDESC 34 /* GOT offset for TLS descriptor. */
+#define R_X86_64_TLSDESC_CALL 35 /* Marker for call through TLS
+ descriptor. */
+#define R_X86_64_TLSDESC 36 /* TLS descriptor. */
+#define R_X86_64_IRELATIVE 37 /* Adjust indirectly by program base */
+#define R_X86_64_RELATIVE64 38 /* 64-bit adjust by program base */
+
+#define R_X86_64_NUM 39
+
+
+/* AM33 relocations. */
+#define R_MN10300_NONE 0 /* No reloc. */
+#define R_MN10300_32 1 /* Direct 32 bit. */
+#define R_MN10300_16 2 /* Direct 16 bit. */
+#define R_MN10300_8 3 /* Direct 8 bit. */
+#define R_MN10300_PCREL32 4 /* PC-relative 32-bit. */
+#define R_MN10300_PCREL16 5 /* PC-relative 16-bit signed. */
+#define R_MN10300_PCREL8 6 /* PC-relative 8-bit signed. */
+#define R_MN10300_GNU_VTINHERIT 7 /* Ancient C++ vtable garbage... */
+#define R_MN10300_GNU_VTENTRY 8 /* ... collection annotation. */
+#define R_MN10300_24 9 /* Direct 24 bit. */
+#define R_MN10300_GOTPC32 10 /* 32-bit PCrel offset to GOT. */
+#define R_MN10300_GOTPC16 11 /* 16-bit PCrel offset to GOT. */
+#define R_MN10300_GOTOFF32 12 /* 32-bit offset from GOT. */
+#define R_MN10300_GOTOFF24 13 /* 24-bit offset from GOT. */
+#define R_MN10300_GOTOFF16 14 /* 16-bit offset from GOT. */
+#define R_MN10300_PLT32 15 /* 32-bit PCrel to PLT entry. */
+#define R_MN10300_PLT16 16 /* 16-bit PCrel to PLT entry. */
+#define R_MN10300_GOT32 17 /* 32-bit offset to GOT entry. */
+#define R_MN10300_GOT24 18 /* 24-bit offset to GOT entry. */
+#define R_MN10300_GOT16 19 /* 16-bit offset to GOT entry. */
+#define R_MN10300_COPY 20 /* Copy symbol at runtime. */
+#define R_MN10300_GLOB_DAT 21 /* Create GOT entry. */
+#define R_MN10300_JMP_SLOT 22 /* Create PLT entry. */
+#define R_MN10300_RELATIVE 23 /* Adjust by program base. */
+#define R_MN10300_TLS_GD 24 /* 32-bit offset for global dynamic. */
+#define R_MN10300_TLS_LD 25 /* 32-bit offset for local dynamic. */
+#define R_MN10300_TLS_LDO 26 /* Module-relative offset. */
+#define R_MN10300_TLS_GOTIE 27 /* GOT offset for static TLS block
+ offset. */
+#define R_MN10300_TLS_IE 28 /* GOT address for static TLS block
+ offset. */
+#define R_MN10300_TLS_LE 29 /* Offset relative to static TLS
+ block. */
+#define R_MN10300_TLS_DTPMOD 30 /* ID of module containing symbol. */
+#define R_MN10300_TLS_DTPOFF 31 /* Offset in module TLS block. */
+#define R_MN10300_TLS_TPOFF 32 /* Offset in static TLS block. */
+#define R_MN10300_SYM_DIFF 33 /* Adjustment for next reloc as needed
+ by linker relaxation. */
+#define R_MN10300_ALIGN 34 /* Alignment requirement for linker
+ relaxation. */
+#define R_MN10300_NUM 35
+
+
+/* M32R relocs. */
+#define R_M32R_NONE 0 /* No reloc. */
+#define R_M32R_16 1 /* Direct 16 bit. */
+#define R_M32R_32 2 /* Direct 32 bit. */
+#define R_M32R_24 3 /* Direct 24 bit. */
+#define R_M32R_10_PCREL 4 /* PC relative 10 bit shifted. */
+#define R_M32R_18_PCREL 5 /* PC relative 18 bit shifted. */
+#define R_M32R_26_PCREL 6 /* PC relative 26 bit shifted. */
+#define R_M32R_HI16_ULO 7 /* High 16 bit with unsigned low. */
+#define R_M32R_HI16_SLO 8 /* High 16 bit with signed low. */
+#define R_M32R_LO16 9 /* Low 16 bit. */
+#define R_M32R_SDA16 10 /* 16 bit offset in SDA. */
+#define R_M32R_GNU_VTINHERIT 11
+#define R_M32R_GNU_VTENTRY 12
+/* M32R relocs use SHT_RELA. */
+#define R_M32R_16_RELA 33 /* Direct 16 bit. */
+#define R_M32R_32_RELA 34 /* Direct 32 bit. */
+#define R_M32R_24_RELA 35 /* Direct 24 bit. */
+#define R_M32R_10_PCREL_RELA 36 /* PC relative 10 bit shifted. */
+#define R_M32R_18_PCREL_RELA 37 /* PC relative 18 bit shifted. */
+#define R_M32R_26_PCREL_RELA 38 /* PC relative 26 bit shifted. */
+#define R_M32R_HI16_ULO_RELA 39 /* High 16 bit with unsigned low */
+#define R_M32R_HI16_SLO_RELA 40 /* High 16 bit with signed low */
+#define R_M32R_LO16_RELA 41 /* Low 16 bit */
+#define R_M32R_SDA16_RELA 42 /* 16 bit offset in SDA */
+#define R_M32R_RELA_GNU_VTINHERIT 43
+#define R_M32R_RELA_GNU_VTENTRY 44
+#define R_M32R_REL32 45 /* PC relative 32 bit. */
+
+#define R_M32R_GOT24 48 /* 24 bit GOT entry */
+#define R_M32R_26_PLTREL 49 /* 26 bit PC relative to PLT shifted */
+#define R_M32R_COPY 50 /* Copy symbol at runtime */
+#define R_M32R_GLOB_DAT 51 /* Create GOT entry */
+#define R_M32R_JMP_SLOT 52 /* Create PLT entry */
+#define R_M32R_RELATIVE 53 /* Adjust by program base */
+#define R_M32R_GOTOFF 54 /* 24 bit offset to GOT */
+#define R_M32R_GOTPC24 55 /* 24 bit PC relative offset to GOT */
+#define R_M32R_GOT16_HI_ULO 56 /* High 16 bit GOT entry with unsigned
+ low */
+#define R_M32R_GOT16_HI_SLO 57 /* High 16 bit GOT entry with signed
+ low */
+#define R_M32R_GOT16_LO 58 /* Low 16 bit GOT entry */
+#define R_M32R_GOTPC_HI_ULO 59 /* High 16 bit PC relative offset to
+ GOT with unsigned low */
+#define R_M32R_GOTPC_HI_SLO 60 /* High 16 bit PC relative offset to
+ GOT with signed low */
+#define R_M32R_GOTPC_LO 61 /* Low 16 bit PC relative offset to
+ GOT */
+#define R_M32R_GOTOFF_HI_ULO 62 /* High 16 bit offset to GOT
+ with unsigned low */
+#define R_M32R_GOTOFF_HI_SLO 63 /* High 16 bit offset to GOT
+ with signed low */
+#define R_M32R_GOTOFF_LO 64 /* Low 16 bit offset to GOT */
+#define R_M32R_NUM 256 /* Keep this the last entry. */
+
+/* MicroBlaze relocations */
+#define R_MICROBLAZE_NONE 0 /* No reloc. */
+#define R_MICROBLAZE_32 1 /* Direct 32 bit. */
+#define R_MICROBLAZE_32_PCREL 2 /* PC relative 32 bit. */
+#define R_MICROBLAZE_64_PCREL 3 /* PC relative 64 bit. */
+#define R_MICROBLAZE_32_PCREL_LO 4 /* Low 16 bits of PCREL32. */
+#define R_MICROBLAZE_64 5 /* Direct 64 bit. */
+#define R_MICROBLAZE_32_LO 6 /* Low 16 bit. */
+#define R_MICROBLAZE_SRO32 7 /* Read-only small data area. */
+#define R_MICROBLAZE_SRW32 8 /* Read-write small data area. */
+#define R_MICROBLAZE_64_NONE 9 /* No reloc. */
+#define R_MICROBLAZE_32_SYM_OP_SYM 10 /* Symbol Op Symbol relocation. */
+#define R_MICROBLAZE_GNU_VTINHERIT 11 /* GNU C++ vtable hierarchy. */
+#define R_MICROBLAZE_GNU_VTENTRY 12 /* GNU C++ vtable member usage. */
+#define R_MICROBLAZE_GOTPC_64 13 /* PC-relative GOT offset. */
+#define R_MICROBLAZE_GOT_64 14 /* GOT entry offset. */
+#define R_MICROBLAZE_PLT_64 15 /* PLT offset (PC-relative). */
+#define R_MICROBLAZE_REL 16 /* Adjust by program base. */
+#define R_MICROBLAZE_JUMP_SLOT 17 /* Create PLT entry. */
+#define R_MICROBLAZE_GLOB_DAT 18 /* Create GOT entry. */
+#define R_MICROBLAZE_GOTOFF_64 19 /* 64 bit offset to GOT. */
+#define R_MICROBLAZE_GOTOFF_32 20 /* 32 bit offset to GOT. */
+#define R_MICROBLAZE_COPY 21 /* Runtime copy. */
+#define R_MICROBLAZE_TLS 22 /* TLS Reloc. */
+#define R_MICROBLAZE_TLSGD 23 /* TLS General Dynamic. */
+#define R_MICROBLAZE_TLSLD 24 /* TLS Local Dynamic. */
+#define R_MICROBLAZE_TLSDTPMOD32 25 /* TLS Module ID. */
+#define R_MICROBLAZE_TLSDTPREL32 26 /* TLS Offset Within TLS Block. */
+#define R_MICROBLAZE_TLSDTPREL64 27 /* TLS Offset Within TLS Block. */
+#define R_MICROBLAZE_TLSGOTTPREL32 28 /* TLS Offset From Thread Pointer. */
+#define R_MICROBLAZE_TLSTPREL32 29 /* TLS Offset From Thread Pointer. */
+
+/* Legal values for d_tag (dynamic entry type). */
+#define DT_NIOS2_GP 0x70000002 /* Address of _gp. */
+
+/* Nios II relocations. */
+#define R_NIOS2_NONE 0 /* No reloc. */
+#define R_NIOS2_S16 1 /* Direct signed 16 bit. */
+#define R_NIOS2_U16 2 /* Direct unsigned 16 bit. */
+#define R_NIOS2_PCREL16 3 /* PC relative 16 bit. */
+#define R_NIOS2_CALL26 4 /* Direct call. */
+#define R_NIOS2_IMM5 5 /* 5 bit constant expression. */
+#define R_NIOS2_CACHE_OPX 6 /* 5 bit expression, shift 22. */
+#define R_NIOS2_IMM6 7 /* 6 bit constant expression. */
+#define R_NIOS2_IMM8 8 /* 8 bit constant expression. */
+#define R_NIOS2_HI16 9 /* High 16 bit. */
+#define R_NIOS2_LO16 10 /* Low 16 bit. */
+#define R_NIOS2_HIADJ16 11 /* High 16 bit, adjusted. */
+#define R_NIOS2_BFD_RELOC_32 12 /* 32 bit symbol value + addend. */
+#define R_NIOS2_BFD_RELOC_16 13 /* 16 bit symbol value + addend. */
+#define R_NIOS2_BFD_RELOC_8 14 /* 8 bit symbol value + addend. */
+#define R_NIOS2_GPREL 15 /* 16 bit GP pointer offset. */
+#define R_NIOS2_GNU_VTINHERIT 16 /* GNU C++ vtable hierarchy. */
+#define R_NIOS2_GNU_VTENTRY 17 /* GNU C++ vtable member usage. */
+#define R_NIOS2_UJMP 18 /* Unconditional branch. */
+#define R_NIOS2_CJMP 19 /* Conditional branch. */
+#define R_NIOS2_CALLR 20 /* Indirect call through register. */
+#define R_NIOS2_ALIGN 21 /* Alignment requirement for
+ linker relaxation. */
+#define R_NIOS2_GOT16 22 /* 16 bit GOT entry. */
+#define R_NIOS2_CALL16 23 /* 16 bit GOT entry for function. */
+#define R_NIOS2_GOTOFF_LO 24 /* %lo of offset to GOT pointer. */
+#define R_NIOS2_GOTOFF_HA 25 /* %hiadj of offset to GOT pointer. */
+#define R_NIOS2_PCREL_LO 26 /* %lo of PC relative offset. */
+#define R_NIOS2_PCREL_HA 27 /* %hiadj of PC relative offset. */
+#define R_NIOS2_TLS_GD16 28 /* 16 bit GOT offset for TLS GD. */
+#define R_NIOS2_TLS_LDM16 29 /* 16 bit GOT offset for TLS LDM. */
+#define R_NIOS2_TLS_LDO16 30 /* 16 bit module relative offset. */
+#define R_NIOS2_TLS_IE16 31 /* 16 bit GOT offset for TLS IE. */
+#define R_NIOS2_TLS_LE16 32 /* 16 bit LE TP-relative offset. */
+#define R_NIOS2_TLS_DTPMOD 33 /* Module number. */
+#define R_NIOS2_TLS_DTPREL 34 /* Module-relative offset. */
+#define R_NIOS2_TLS_TPREL 35 /* TP-relative offset. */
+#define R_NIOS2_COPY 36 /* Copy symbol at runtime. */
+#define R_NIOS2_GLOB_DAT 37 /* Create GOT entry. */
+#define R_NIOS2_JUMP_SLOT 38 /* Create PLT entry. */
+#define R_NIOS2_RELATIVE 39 /* Adjust by program base. */
+#define R_NIOS2_GOTOFF 40 /* 16 bit offset to GOT pointer. */
+#define R_NIOS2_CALL26_NOAT 41 /* Direct call in .noat section. */
+#define R_NIOS2_GOT_LO 42 /* %lo() of GOT entry. */
+#define R_NIOS2_GOT_HA 43 /* %hiadj() of GOT entry. */
+#define R_NIOS2_CALL_LO 44 /* %lo() of function GOT entry. */
+#define R_NIOS2_CALL_HA 45 /* %hiadj() of function GOT entry. */
+
+/* TILEPro relocations. */
+#define R_TILEPRO_NONE 0 /* No reloc */
+#define R_TILEPRO_32 1 /* Direct 32 bit */
+#define R_TILEPRO_16 2 /* Direct 16 bit */
+#define R_TILEPRO_8 3 /* Direct 8 bit */
+#define R_TILEPRO_32_PCREL 4 /* PC relative 32 bit */
+#define R_TILEPRO_16_PCREL 5 /* PC relative 16 bit */
+#define R_TILEPRO_8_PCREL 6 /* PC relative 8 bit */
+#define R_TILEPRO_LO16 7 /* Low 16 bit */
+#define R_TILEPRO_HI16 8 /* High 16 bit */
+#define R_TILEPRO_HA16 9 /* High 16 bit, adjusted */
+#define R_TILEPRO_COPY 10 /* Copy relocation */
+#define R_TILEPRO_GLOB_DAT 11 /* Create GOT entry */
+#define R_TILEPRO_JMP_SLOT 12 /* Create PLT entry */
+#define R_TILEPRO_RELATIVE 13 /* Adjust by program base */
+#define R_TILEPRO_BROFF_X1 14 /* X1 pipe branch offset */
+#define R_TILEPRO_JOFFLONG_X1 15 /* X1 pipe jump offset */
+#define R_TILEPRO_JOFFLONG_X1_PLT 16 /* X1 pipe jump offset to PLT */
+#define R_TILEPRO_IMM8_X0 17 /* X0 pipe 8-bit */
+#define R_TILEPRO_IMM8_Y0 18 /* Y0 pipe 8-bit */
+#define R_TILEPRO_IMM8_X1 19 /* X1 pipe 8-bit */
+#define R_TILEPRO_IMM8_Y1 20 /* Y1 pipe 8-bit */
+#define R_TILEPRO_MT_IMM15_X1 21 /* X1 pipe mtspr */
+#define R_TILEPRO_MF_IMM15_X1 22 /* X1 pipe mfspr */
+#define R_TILEPRO_IMM16_X0 23 /* X0 pipe 16-bit */
+#define R_TILEPRO_IMM16_X1 24 /* X1 pipe 16-bit */
+#define R_TILEPRO_IMM16_X0_LO 25 /* X0 pipe low 16-bit */
+#define R_TILEPRO_IMM16_X1_LO 26 /* X1 pipe low 16-bit */
+#define R_TILEPRO_IMM16_X0_HI 27 /* X0 pipe high 16-bit */
+#define R_TILEPRO_IMM16_X1_HI 28 /* X1 pipe high 16-bit */
+#define R_TILEPRO_IMM16_X0_HA 29 /* X0 pipe high 16-bit, adjusted */
+#define R_TILEPRO_IMM16_X1_HA 30 /* X1 pipe high 16-bit, adjusted */
+#define R_TILEPRO_IMM16_X0_PCREL 31 /* X0 pipe PC relative 16 bit */
+#define R_TILEPRO_IMM16_X1_PCREL 32 /* X1 pipe PC relative 16 bit */
+#define R_TILEPRO_IMM16_X0_LO_PCREL 33 /* X0 pipe PC relative low 16 bit */
+#define R_TILEPRO_IMM16_X1_LO_PCREL 34 /* X1 pipe PC relative low 16 bit */
+#define R_TILEPRO_IMM16_X0_HI_PCREL 35 /* X0 pipe PC relative high 16 bit */
+#define R_TILEPRO_IMM16_X1_HI_PCREL 36 /* X1 pipe PC relative high 16 bit */
+#define R_TILEPRO_IMM16_X0_HA_PCREL 37 /* X0 pipe PC relative ha() 16 bit */
+#define R_TILEPRO_IMM16_X1_HA_PCREL 38 /* X1 pipe PC relative ha() 16 bit */
+#define R_TILEPRO_IMM16_X0_GOT 39 /* X0 pipe 16-bit GOT offset */
+#define R_TILEPRO_IMM16_X1_GOT 40 /* X1 pipe 16-bit GOT offset */
+#define R_TILEPRO_IMM16_X0_GOT_LO 41 /* X0 pipe low 16-bit GOT offset */
+#define R_TILEPRO_IMM16_X1_GOT_LO 42 /* X1 pipe low 16-bit GOT offset */
+#define R_TILEPRO_IMM16_X0_GOT_HI 43 /* X0 pipe high 16-bit GOT offset */
+#define R_TILEPRO_IMM16_X1_GOT_HI 44 /* X1 pipe high 16-bit GOT offset */
+#define R_TILEPRO_IMM16_X0_GOT_HA 45 /* X0 pipe ha() 16-bit GOT offset */
+#define R_TILEPRO_IMM16_X1_GOT_HA 46 /* X1 pipe ha() 16-bit GOT offset */
+#define R_TILEPRO_MMSTART_X0 47 /* X0 pipe mm "start" */
+#define R_TILEPRO_MMEND_X0 48 /* X0 pipe mm "end" */
+#define R_TILEPRO_MMSTART_X1 49 /* X1 pipe mm "start" */
+#define R_TILEPRO_MMEND_X1 50 /* X1 pipe mm "end" */
+#define R_TILEPRO_SHAMT_X0 51 /* X0 pipe shift amount */
+#define R_TILEPRO_SHAMT_X1 52 /* X1 pipe shift amount */
+#define R_TILEPRO_SHAMT_Y0 53 /* Y0 pipe shift amount */
+#define R_TILEPRO_SHAMT_Y1 54 /* Y1 pipe shift amount */
+#define R_TILEPRO_DEST_IMM8_X1 55 /* X1 pipe destination 8-bit */
+/* Relocs 56-59 are currently not defined. */
+#define R_TILEPRO_TLS_GD_CALL 60 /* "jal" for TLS GD */
+#define R_TILEPRO_IMM8_X0_TLS_GD_ADD 61 /* X0 pipe "addi" for TLS GD */
+#define R_TILEPRO_IMM8_X1_TLS_GD_ADD 62 /* X1 pipe "addi" for TLS GD */
+#define R_TILEPRO_IMM8_Y0_TLS_GD_ADD 63 /* Y0 pipe "addi" for TLS GD */
+#define R_TILEPRO_IMM8_Y1_TLS_GD_ADD 64 /* Y1 pipe "addi" for TLS GD */
+#define R_TILEPRO_TLS_IE_LOAD 65 /* "lw_tls" for TLS IE */
+#define R_TILEPRO_IMM16_X0_TLS_GD 66 /* X0 pipe 16-bit TLS GD offset */
+#define R_TILEPRO_IMM16_X1_TLS_GD 67 /* X1 pipe 16-bit TLS GD offset */
+#define R_TILEPRO_IMM16_X0_TLS_GD_LO 68 /* X0 pipe low 16-bit TLS GD offset */
+#define R_TILEPRO_IMM16_X1_TLS_GD_LO 69 /* X1 pipe low 16-bit TLS GD offset */
+#define R_TILEPRO_IMM16_X0_TLS_GD_HI 70 /* X0 pipe high 16-bit TLS GD offset */
+#define R_TILEPRO_IMM16_X1_TLS_GD_HI 71 /* X1 pipe high 16-bit TLS GD offset */
+#define R_TILEPRO_IMM16_X0_TLS_GD_HA 72 /* X0 pipe ha() 16-bit TLS GD offset */
+#define R_TILEPRO_IMM16_X1_TLS_GD_HA 73 /* X1 pipe ha() 16-bit TLS GD offset */
+#define R_TILEPRO_IMM16_X0_TLS_IE 74 /* X0 pipe 16-bit TLS IE offset */
+#define R_TILEPRO_IMM16_X1_TLS_IE 75 /* X1 pipe 16-bit TLS IE offset */
+#define R_TILEPRO_IMM16_X0_TLS_IE_LO 76 /* X0 pipe low 16-bit TLS IE offset */
+#define R_TILEPRO_IMM16_X1_TLS_IE_LO 77 /* X1 pipe low 16-bit TLS IE offset */
+#define R_TILEPRO_IMM16_X0_TLS_IE_HI 78 /* X0 pipe high 16-bit TLS IE offset */
+#define R_TILEPRO_IMM16_X1_TLS_IE_HI 79 /* X1 pipe high 16-bit TLS IE offset */
+#define R_TILEPRO_IMM16_X0_TLS_IE_HA 80 /* X0 pipe ha() 16-bit TLS IE offset */
+#define R_TILEPRO_IMM16_X1_TLS_IE_HA 81 /* X1 pipe ha() 16-bit TLS IE offset */
+#define R_TILEPRO_TLS_DTPMOD32 82 /* ID of module containing symbol */
+#define R_TILEPRO_TLS_DTPOFF32 83 /* Offset in TLS block */
+#define R_TILEPRO_TLS_TPOFF32 84 /* Offset in static TLS block */
+#define R_TILEPRO_IMM16_X0_TLS_LE 85 /* X0 pipe 16-bit TLS LE offset */
+#define R_TILEPRO_IMM16_X1_TLS_LE 86 /* X1 pipe 16-bit TLS LE offset */
+#define R_TILEPRO_IMM16_X0_TLS_LE_LO 87 /* X0 pipe low 16-bit TLS LE offset */
+#define R_TILEPRO_IMM16_X1_TLS_LE_LO 88 /* X1 pipe low 16-bit TLS LE offset */
+#define R_TILEPRO_IMM16_X0_TLS_LE_HI 89 /* X0 pipe high 16-bit TLS LE offset */
+#define R_TILEPRO_IMM16_X1_TLS_LE_HI 90 /* X1 pipe high 16-bit TLS LE offset */
+#define R_TILEPRO_IMM16_X0_TLS_LE_HA 91 /* X0 pipe ha() 16-bit TLS LE offset */
+#define R_TILEPRO_IMM16_X1_TLS_LE_HA 92 /* X1 pipe ha() 16-bit TLS LE offset */
+
+#define R_TILEPRO_GNU_VTINHERIT 128 /* GNU C++ vtable hierarchy */
+#define R_TILEPRO_GNU_VTENTRY 129 /* GNU C++ vtable member usage */
+
+#define R_TILEPRO_NUM 130
+
+
+/* TILE-Gx relocations. */
+#define R_TILEGX_NONE 0 /* No reloc */
+#define R_TILEGX_64 1 /* Direct 64 bit */
+#define R_TILEGX_32 2 /* Direct 32 bit */
+#define R_TILEGX_16 3 /* Direct 16 bit */
+#define R_TILEGX_8 4 /* Direct 8 bit */
+#define R_TILEGX_64_PCREL 5 /* PC relative 64 bit */
+#define R_TILEGX_32_PCREL 6 /* PC relative 32 bit */
+#define R_TILEGX_16_PCREL 7 /* PC relative 16 bit */
+#define R_TILEGX_8_PCREL 8 /* PC relative 8 bit */
+#define R_TILEGX_HW0 9 /* hword 0 16-bit */
+#define R_TILEGX_HW1 10 /* hword 1 16-bit */
+#define R_TILEGX_HW2 11 /* hword 2 16-bit */
+#define R_TILEGX_HW3 12 /* hword 3 16-bit */
+#define R_TILEGX_HW0_LAST 13 /* last hword 0 16-bit */
+#define R_TILEGX_HW1_LAST 14 /* last hword 1 16-bit */
+#define R_TILEGX_HW2_LAST 15 /* last hword 2 16-bit */
+#define R_TILEGX_COPY 16 /* Copy relocation */
+#define R_TILEGX_GLOB_DAT 17 /* Create GOT entry */
+#define R_TILEGX_JMP_SLOT 18 /* Create PLT entry */
+#define R_TILEGX_RELATIVE 19 /* Adjust by program base */
+#define R_TILEGX_BROFF_X1 20 /* X1 pipe branch offset */
+#define R_TILEGX_JUMPOFF_X1 21 /* X1 pipe jump offset */
+#define R_TILEGX_JUMPOFF_X1_PLT 22 /* X1 pipe jump offset to PLT */
+#define R_TILEGX_IMM8_X0 23 /* X0 pipe 8-bit */
+#define R_TILEGX_IMM8_Y0 24 /* Y0 pipe 8-bit */
+#define R_TILEGX_IMM8_X1 25 /* X1 pipe 8-bit */
+#define R_TILEGX_IMM8_Y1 26 /* Y1 pipe 8-bit */
+#define R_TILEGX_DEST_IMM8_X1 27 /* X1 pipe destination 8-bit */
+#define R_TILEGX_MT_IMM14_X1 28 /* X1 pipe mtspr */
+#define R_TILEGX_MF_IMM14_X1 29 /* X1 pipe mfspr */
+#define R_TILEGX_MMSTART_X0 30 /* X0 pipe mm "start" */
+#define R_TILEGX_MMEND_X0 31 /* X0 pipe mm "end" */
+#define R_TILEGX_SHAMT_X0 32 /* X0 pipe shift amount */
+#define R_TILEGX_SHAMT_X1 33 /* X1 pipe shift amount */
+#define R_TILEGX_SHAMT_Y0 34 /* Y0 pipe shift amount */
+#define R_TILEGX_SHAMT_Y1 35 /* Y1 pipe shift amount */
+#define R_TILEGX_IMM16_X0_HW0 36 /* X0 pipe hword 0 */
+#define R_TILEGX_IMM16_X1_HW0 37 /* X1 pipe hword 0 */
+#define R_TILEGX_IMM16_X0_HW1 38 /* X0 pipe hword 1 */
+#define R_TILEGX_IMM16_X1_HW1 39 /* X1 pipe hword 1 */
+#define R_TILEGX_IMM16_X0_HW2 40 /* X0 pipe hword 2 */
+#define R_TILEGX_IMM16_X1_HW2 41 /* X1 pipe hword 2 */
+#define R_TILEGX_IMM16_X0_HW3 42 /* X0 pipe hword 3 */
+#define R_TILEGX_IMM16_X1_HW3 43 /* X1 pipe hword 3 */
+#define R_TILEGX_IMM16_X0_HW0_LAST 44 /* X0 pipe last hword 0 */
+#define R_TILEGX_IMM16_X1_HW0_LAST 45 /* X1 pipe last hword 0 */
+#define R_TILEGX_IMM16_X0_HW1_LAST 46 /* X0 pipe last hword 1 */
+#define R_TILEGX_IMM16_X1_HW1_LAST 47 /* X1 pipe last hword 1 */
+#define R_TILEGX_IMM16_X0_HW2_LAST 48 /* X0 pipe last hword 2 */
+#define R_TILEGX_IMM16_X1_HW2_LAST 49 /* X1 pipe last hword 2 */
+#define R_TILEGX_IMM16_X0_HW0_PCREL 50 /* X0 pipe PC relative hword 0 */
+#define R_TILEGX_IMM16_X1_HW0_PCREL 51 /* X1 pipe PC relative hword 0 */
+#define R_TILEGX_IMM16_X0_HW1_PCREL 52 /* X0 pipe PC relative hword 1 */
+#define R_TILEGX_IMM16_X1_HW1_PCREL 53 /* X1 pipe PC relative hword 1 */
+#define R_TILEGX_IMM16_X0_HW2_PCREL 54 /* X0 pipe PC relative hword 2 */
+#define R_TILEGX_IMM16_X1_HW2_PCREL 55 /* X1 pipe PC relative hword 2 */
+#define R_TILEGX_IMM16_X0_HW3_PCREL 56 /* X0 pipe PC relative hword 3 */
+#define R_TILEGX_IMM16_X1_HW3_PCREL 57 /* X1 pipe PC relative hword 3 */
+#define R_TILEGX_IMM16_X0_HW0_LAST_PCREL 58 /* X0 pipe PC-rel last hword 0 */
+#define R_TILEGX_IMM16_X1_HW0_LAST_PCREL 59 /* X1 pipe PC-rel last hword 0 */
+#define R_TILEGX_IMM16_X0_HW1_LAST_PCREL 60 /* X0 pipe PC-rel last hword 1 */
+#define R_TILEGX_IMM16_X1_HW1_LAST_PCREL 61 /* X1 pipe PC-rel last hword 1 */
+#define R_TILEGX_IMM16_X0_HW2_LAST_PCREL 62 /* X0 pipe PC-rel last hword 2 */
+#define R_TILEGX_IMM16_X1_HW2_LAST_PCREL 63 /* X1 pipe PC-rel last hword 2 */
+#define R_TILEGX_IMM16_X0_HW0_GOT 64 /* X0 pipe hword 0 GOT offset */
+#define R_TILEGX_IMM16_X1_HW0_GOT 65 /* X1 pipe hword 0 GOT offset */
+#define R_TILEGX_IMM16_X0_HW0_PLT_PCREL 66 /* X0 pipe PC-rel PLT hword 0 */
+#define R_TILEGX_IMM16_X1_HW0_PLT_PCREL 67 /* X1 pipe PC-rel PLT hword 0 */
+#define R_TILEGX_IMM16_X0_HW1_PLT_PCREL 68 /* X0 pipe PC-rel PLT hword 1 */
+#define R_TILEGX_IMM16_X1_HW1_PLT_PCREL 69 /* X1 pipe PC-rel PLT hword 1 */
+#define R_TILEGX_IMM16_X0_HW2_PLT_PCREL 70 /* X0 pipe PC-rel PLT hword 2 */
+#define R_TILEGX_IMM16_X1_HW2_PLT_PCREL 71 /* X1 pipe PC-rel PLT hword 2 */
+#define R_TILEGX_IMM16_X0_HW0_LAST_GOT 72 /* X0 pipe last hword 0 GOT offset */
+#define R_TILEGX_IMM16_X1_HW0_LAST_GOT 73 /* X1 pipe last hword 0 GOT offset */
+#define R_TILEGX_IMM16_X0_HW1_LAST_GOT 74 /* X0 pipe last hword 1 GOT offset */
+#define R_TILEGX_IMM16_X1_HW1_LAST_GOT 75 /* X1 pipe last hword 1 GOT offset */
+#define R_TILEGX_IMM16_X0_HW3_PLT_PCREL 76 /* X0 pipe PC-rel PLT hword 3 */
+#define R_TILEGX_IMM16_X1_HW3_PLT_PCREL 77 /* X1 pipe PC-rel PLT hword 3 */
+#define R_TILEGX_IMM16_X0_HW0_TLS_GD 78 /* X0 pipe hword 0 TLS GD offset */
+#define R_TILEGX_IMM16_X1_HW0_TLS_GD 79 /* X1 pipe hword 0 TLS GD offset */
+#define R_TILEGX_IMM16_X0_HW0_TLS_LE 80 /* X0 pipe hword 0 TLS LE offset */
+#define R_TILEGX_IMM16_X1_HW0_TLS_LE 81 /* X1 pipe hword 0 TLS LE offset */
+#define R_TILEGX_IMM16_X0_HW0_LAST_TLS_LE 82 /* X0 pipe last hword 0 LE off */
+#define R_TILEGX_IMM16_X1_HW0_LAST_TLS_LE 83 /* X1 pipe last hword 0 LE off */
+#define R_TILEGX_IMM16_X0_HW1_LAST_TLS_LE 84 /* X0 pipe last hword 1 LE off */
+#define R_TILEGX_IMM16_X1_HW1_LAST_TLS_LE 85 /* X1 pipe last hword 1 LE off */
+#define R_TILEGX_IMM16_X0_HW0_LAST_TLS_GD 86 /* X0 pipe last hword 0 GD off */
+#define R_TILEGX_IMM16_X1_HW0_LAST_TLS_GD 87 /* X1 pipe last hword 0 GD off */
+#define R_TILEGX_IMM16_X0_HW1_LAST_TLS_GD 88 /* X0 pipe last hword 1 GD off */
+#define R_TILEGX_IMM16_X1_HW1_LAST_TLS_GD 89 /* X1 pipe last hword 1 GD off */
+/* Relocs 90-91 are currently not defined. */
+#define R_TILEGX_IMM16_X0_HW0_TLS_IE 92 /* X0 pipe hword 0 TLS IE offset */
+#define R_TILEGX_IMM16_X1_HW0_TLS_IE 93 /* X1 pipe hword 0 TLS IE offset */
+#define R_TILEGX_IMM16_X0_HW0_LAST_PLT_PCREL 94 /* X0 pipe PC-rel PLT last hword 0 */
+#define R_TILEGX_IMM16_X1_HW0_LAST_PLT_PCREL 95 /* X1 pipe PC-rel PLT last hword 0 */
+#define R_TILEGX_IMM16_X0_HW1_LAST_PLT_PCREL 96 /* X0 pipe PC-rel PLT last hword 1 */
+#define R_TILEGX_IMM16_X1_HW1_LAST_PLT_PCREL 97 /* X1 pipe PC-rel PLT last hword 1 */
+#define R_TILEGX_IMM16_X0_HW2_LAST_PLT_PCREL 98 /* X0 pipe PC-rel PLT last hword 2 */
+#define R_TILEGX_IMM16_X1_HW2_LAST_PLT_PCREL 99 /* X1 pipe PC-rel PLT last hword 2 */
+#define R_TILEGX_IMM16_X0_HW0_LAST_TLS_IE 100 /* X0 pipe last hword 0 IE off */
+#define R_TILEGX_IMM16_X1_HW0_LAST_TLS_IE 101 /* X1 pipe last hword 0 IE off */
+#define R_TILEGX_IMM16_X0_HW1_LAST_TLS_IE 102 /* X0 pipe last hword 1 IE off */
+#define R_TILEGX_IMM16_X1_HW1_LAST_TLS_IE 103 /* X1 pipe last hword 1 IE off */
+/* Relocs 104-105 are currently not defined. */
+#define R_TILEGX_TLS_DTPMOD64 106 /* 64-bit ID of symbol's module */
+#define R_TILEGX_TLS_DTPOFF64 107 /* 64-bit offset in TLS block */
+#define R_TILEGX_TLS_TPOFF64 108 /* 64-bit offset in static TLS block */
+#define R_TILEGX_TLS_DTPMOD32 109 /* 32-bit ID of symbol's module */
+#define R_TILEGX_TLS_DTPOFF32 110 /* 32-bit offset in TLS block */
+#define R_TILEGX_TLS_TPOFF32 111 /* 32-bit offset in static TLS block */
+#define R_TILEGX_TLS_GD_CALL 112 /* "jal" for TLS GD */
+#define R_TILEGX_IMM8_X0_TLS_GD_ADD 113 /* X0 pipe "addi" for TLS GD */
+#define R_TILEGX_IMM8_X1_TLS_GD_ADD 114 /* X1 pipe "addi" for TLS GD */
+#define R_TILEGX_IMM8_Y0_TLS_GD_ADD 115 /* Y0 pipe "addi" for TLS GD */
+#define R_TILEGX_IMM8_Y1_TLS_GD_ADD 116 /* Y1 pipe "addi" for TLS GD */
+#define R_TILEGX_TLS_IE_LOAD 117 /* "ld_tls" for TLS IE */
+#define R_TILEGX_IMM8_X0_TLS_ADD 118 /* X0 pipe "addi" for TLS GD/IE */
+#define R_TILEGX_IMM8_X1_TLS_ADD 119 /* X1 pipe "addi" for TLS GD/IE */
+#define R_TILEGX_IMM8_Y0_TLS_ADD 120 /* Y0 pipe "addi" for TLS GD/IE */
+#define R_TILEGX_IMM8_Y1_TLS_ADD 121 /* Y1 pipe "addi" for TLS GD/IE */
+
+#define R_TILEGX_GNU_VTINHERIT 128 /* GNU C++ vtable hierarchy */
+#define R_TILEGX_GNU_VTENTRY 129 /* GNU C++ vtable member usage */
+
+#define R_TILEGX_NUM 130
+
+
+__END_DECLS
+
+#endif /* elf.h */
diff --git a/src/exec.c b/src/exec.c
new file mode 100644
index 0000000..22870c2
--- /dev/null
+++ b/src/exec.c
@@ -0,0 +1,1074 @@
+/* Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006 Red Hat, Inc.
+ Written by Jakub Jelinek <jakub@redhat.com>, 2001.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include <config.h>
+#include <assert.h>
+#include <errno.h>
+#include <error.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include "prelink.h"
+#include "reloc.h"
+#include "space.h"
+
+int
+update_dynamic_tags (DSO *dso, GElf_Shdr *shdr, GElf_Shdr *old_shdr,
+ struct section_move *move)
+{
+ int i, j;
+
+ for (i = 1; i < move->new_shnum; ++i)
+ {
+ j = move->new_to_old[i];
+ if (j == -1)
+ continue;
+ if ((dynamic_info_is_set (dso, DT_HASH)
+ && dso->info[DT_HASH] == old_shdr[j].sh_addr
+ && old_shdr[j].sh_type == SHT_HASH
+ && set_dynamic (dso, DT_HASH, shdr[i].sh_addr, 1))
+ || (dynamic_info_is_set (dso, DT_SYMTAB)
+ && dso->info[DT_SYMTAB] == old_shdr[j].sh_addr
+ && old_shdr[j].sh_type == SHT_DYNSYM
+ && set_dynamic (dso, DT_SYMTAB, shdr[i].sh_addr, 1))
+ || (dynamic_info_is_set (dso, DT_STRTAB)
+ && dso->info[DT_STRTAB] == old_shdr[j].sh_addr
+ && old_shdr[j].sh_type == SHT_STRTAB
+ && set_dynamic (dso, DT_STRTAB, shdr[i].sh_addr, 1))
+ || (dynamic_info_is_set (dso, DT_VERDEF_BIT)
+ && dso->info_DT_VERDEF == old_shdr[j].sh_addr
+ && old_shdr[j].sh_type == SHT_GNU_verdef
+ && set_dynamic (dso, DT_VERDEF, shdr[i].sh_addr, 1))
+ || (dynamic_info_is_set (dso, DT_VERNEED_BIT)
+ && dso->info_DT_VERNEED == old_shdr[j].sh_addr
+ && old_shdr[j].sh_type == SHT_GNU_verneed
+ && set_dynamic (dso, DT_VERNEED, shdr[i].sh_addr, 1))
+ || (dynamic_info_is_set (dso, DT_VERSYM_BIT)
+ && dso->info_DT_VERSYM == old_shdr[j].sh_addr
+ && old_shdr[j].sh_type == SHT_GNU_versym
+ && set_dynamic (dso, DT_VERSYM, shdr[i].sh_addr, 1))
+ || (dynamic_info_is_set (dso, DT_GNU_HASH_BIT)
+ && dso->info_DT_GNU_HASH == old_shdr[j].sh_addr
+ && old_shdr[j].sh_type == SHT_GNU_HASH
+ && set_dynamic (dso, DT_GNU_HASH, shdr[i].sh_addr, 1)))
+ return 1;
+ }
+
+ return 0;
+}
+
+int
+prelink_exec (struct prelink_info *info)
+{
+ int i, j, ndeps = info->ent->ndepends + 1;
+ int dynstrndx, dynstrndxnew, growdynstr = 0, shstrndxnew;
+ int old_conflict = 0, old_liblist = 0;
+ int new_conflict = -1, new_liblist = -1;
+ int new_reloc = -1, new_plt = -1, new_dynstr = -1;
+ int old_dynbss = -1, old_bss = -1, new_dynbss = -1;
+ int old_sdynbss = -1, old_sbss = -1, new_sdynbss = -1;
+ int addcnt, undo, shnum_after_undo;
+ struct reloc_info rinfo, rinfonew;
+ DSO *dso = info->dso;
+ GElf_Ehdr ehdr;
+ GElf_Phdr phdr[dso->ehdr.e_phnum + 1];
+ GElf_Shdr old_shdr[dso->ehdr.e_shnum], new_shdr[dso->ehdr.e_shnum + 20];
+ GElf_Shdr shdr_after_undo[dso->ehdr.e_shnum + 20];
+ GElf_Shdr *shdr;
+ Elf32_Lib *liblist = NULL;
+ struct readonly_adjust adjust;
+ struct section_move *move = NULL;
+
+ if (prelink_build_conflicts (info))
+ return 1;
+
+ if (find_reloc_sections (dso, &rinfo))
+ return 1;
+
+ move = init_section_move (dso);
+ if (move == NULL)
+ return 1;
+
+ ehdr = dso->ehdr;
+ memcpy (phdr, dso->phdr, dso->ehdr.e_phnum * sizeof (GElf_Phdr));
+ memcpy (old_shdr, dso->shdr, dso->ehdr.e_shnum * sizeof (GElf_Shdr));
+ shdr = new_shdr;
+ memcpy (shdr, dso->shdr, dso->ehdr.e_shnum * sizeof (GElf_Shdr));
+
+ for (undo = 1; undo < dso->ehdr.e_shnum; ++undo)
+ if (! strcmp (strptr (dso, dso->ehdr.e_shstrndx, dso->shdr[undo].sh_name),
+ ".gnu.prelink_undo"))
+ break;
+
+ if (undo < dso->ehdr.e_shnum)
+ {
+ Elf_Data *data;
+
+ if (undo_sections (dso, undo, move, &rinfo, &ehdr, phdr, shdr))
+ {
+error_out:
+ free (liblist);
+ free (move);
+ return 1;
+ }
+
+ data = elf_getdata (dso->scn[undo], NULL);
+ assert (data->d_buf != NULL);
+ assert (data->d_off == 0);
+ assert (data->d_size == dso->shdr[undo].sh_size);
+ dso->undo = *data;
+ dso->undo.d_buf = malloc (dso->undo.d_size);
+ if (dso->undo.d_buf == NULL)
+ {
+ error (0, ENOMEM, "%s: Could not create .gnu.prelink_undo section",
+ dso->filename);
+ goto error_out;
+ }
+ memcpy (dso->undo.d_buf, data->d_buf, data->d_size);
+ ehdr.e_shstrndx = dso->ehdr.e_shstrndx;
+ }
+ undo = 0;
+
+ memcpy (shdr_after_undo, shdr, ehdr.e_shnum * sizeof (GElf_Shdr));
+
+ for (dynstrndx = 1; dynstrndx < dso->ehdr.e_shnum; ++dynstrndx)
+ if (! strcmp (strptr (dso, dso->ehdr.e_shstrndx,
+ dso->shdr[dynstrndx].sh_name),
+ ".dynstr"))
+ break;
+
+ if (dynstrndx == dso->ehdr.e_shnum)
+ {
+ error (0, 0, "%s: Could not find .dynstr section", dso->filename);
+ goto error_out;
+ }
+
+ dynstrndxnew = move->old_to_new[dynstrndx];
+ shstrndxnew = move->old_to_new[dso->ehdr.e_shstrndx];
+ shnum_after_undo = move->new_shnum;
+
+ if (ndeps > 1)
+ {
+ liblist = calloc (ndeps - 1, sizeof (Elf32_Lib));
+ if (liblist == NULL)
+ {
+ error (0, ENOMEM, "%s: Cannot build .gnu.liblist section",
+ dso->filename);
+ goto error_out;
+ }
+ }
+ else
+ liblist = NULL;
+
+ for (i = 0; i < ndeps - 1; ++i)
+ {
+ struct prelink_entry *ent = info->ent->depends[i];
+
+ liblist[i].l_name = strtabfind (dso, dynstrndx, info->sonames[i + 1]);
+ if (liblist[i].l_name >= shdr[dynstrndxnew].sh_size)
+ liblist[i].l_name = 0;
+ if (liblist[i].l_name == 0)
+ growdynstr += strlen (info->sonames[i + 1]) + 1;
+ liblist[i].l_time_stamp = ent->timestamp;
+ liblist[i].l_checksum = ent->checksum;
+ }
+
+ if (info->dynbss)
+ {
+ old_bss = addr_to_sec (dso, info->dynbss_base);
+ assert (old_bss != -1);
+ if (move->old_to_new[old_bss] == -1)
+ ++old_bss;
+ assert (move->old_to_new[old_bss] != -1);
+ assert (shdr[move->old_to_new[old_bss]].sh_addr <= info->dynbss_base);
+ assert (shdr[move->old_to_new[old_bss]].sh_addr
+ + shdr[move->old_to_new[old_bss]].sh_size > info->dynbss_base);
+ }
+ if (info->sdynbss)
+ {
+ old_sbss = addr_to_sec (dso, info->sdynbss_base);
+ assert (old_sbss != -1);
+ if (move->old_to_new[old_sbss] == -1)
+ ++old_sbss;
+ assert (move->old_to_new[old_sbss] != -1);
+ assert (shdr[move->old_to_new[old_sbss]].sh_addr <= info->sdynbss_base);
+ assert (shdr[move->old_to_new[old_sbss]].sh_addr
+ + shdr[move->old_to_new[old_sbss]].sh_size > info->sdynbss_base);
+ }
+
+ rinfonew = rinfo;
+ if (rinfo.first != -1)
+ {
+ rinfonew.first = move->old_to_new[rinfo.first];
+ rinfonew.last = move->old_to_new[rinfo.last];
+ if (shdr[rinfonew.first].sh_type == SHT_REL
+ && dso->shdr[rinfo.first].sh_type == SHT_RELA)
+ {
+ rinfonew.rel_to_rela = 1;
+ rinfonew.reldyn_rela = 0;
+ }
+ }
+ if (rinfo.plt != -1)
+ {
+ rinfonew.plt = move->old_to_new[rinfo.plt];
+ if (shdr[rinfonew.plt].sh_type == SHT_REL
+ && dso->shdr[rinfo.plt].sh_type == SHT_RELA)
+ {
+ rinfonew.rel_to_rela_plt = 1;
+ rinfonew.plt_rela = 0;
+ }
+ }
+
+ for (i = 1, j = 1; i < ehdr.e_shnum; ++i)
+ {
+ const char *name;
+ name = strptr (dso, dso->ehdr.e_shstrndx, shdr[i].sh_name);
+ if (! strcmp (name, ".dynbss"))
+ old_dynbss = move->new_to_old[j];
+ else if (! strcmp (name, ".sdynbss"))
+ old_sdynbss = move->new_to_old[j];
+ else if (! strcmp (name, ".gnu.prelink_undo"))
+ undo = -1;
+ if (! strcmp (name, ".gnu.conflict"))
+ {
+ old_conflict = move->new_to_old[j];
+ remove_section (move, j);
+ }
+ else if (! strcmp (name, ".gnu.liblist"))
+ {
+ old_liblist = move->new_to_old[j];
+ remove_section (move, j);
+ }
+ else if (rinfonew.rel_to_rela
+ && i >= rinfonew.first && i <= rinfonew.last)
+ remove_section (move, j);
+ else if (i == rinfonew.plt
+ && (rinfonew.rel_to_rela || rinfonew.rel_to_rela_plt))
+ remove_section (move, j);
+ else if (i == dynstrndxnew && growdynstr)
+ remove_section (move, j);
+ else
+ shdr[j++] = shdr[i];
+ }
+ assert (j == move->new_shnum);
+ ehdr.e_shnum = j;
+
+ if (old_sdynbss != -1 && old_dynbss == -1)
+ {
+ old_dynbss = old_sdynbss;
+ old_sdynbss = -1;
+ }
+
+ GElf_Shdr add[rinfo.last - rinfo.first + 5];
+ int old[rinfo.last - rinfo.first + 5];
+ int new[rinfo.last - rinfo.first + 5];
+ memset (add, 0, sizeof (add));
+ memset (old, 0, sizeof (old));
+ memset (new, 0, sizeof (new));
+
+ i = 0;
+ if (rinfonew.rel_to_rela)
+ {
+ add[i] = shdr_after_undo[rinfonew.first];
+ add[i].sh_size = shdr_after_undo[rinfonew.last].sh_addr
+ + shdr_after_undo[rinfonew.last].sh_size
+ - add[i].sh_addr;
+ assert (sizeof (Elf32_Rel) * 3 == sizeof (Elf32_Rela) * 2);
+ assert (sizeof (Elf64_Rel) * 3 == sizeof (Elf64_Rela) * 2);
+ add[i].sh_size = add[i].sh_size / 2 * 3;
+ old[i] = rinfo.first;
+ new_reloc = i++;
+ for (j = rinfo.first + 1; j <= rinfo.last; ++j)
+ {
+ add[i] = shdr_after_undo[rinfonew.first - rinfo.first + j];
+ add[i].sh_size = add[i].sh_size / 2 * 3;
+ old[i++] = j;
+ }
+ if (rinfonew.plt)
+ {
+ add[i] = shdr_after_undo[rinfonew.plt];
+ if (rinfonew.rel_to_rela_plt)
+ add[i].sh_size = add[i].sh_size / 2 * 3;
+ /* Temporarily merge them, so that they are allocated adjacently. */
+ add[new_reloc].sh_size += add[i].sh_size;
+ old[i] = rinfo.plt;
+ new_plt = i++;
+ }
+ }
+ else if (rinfonew.rel_to_rela_plt)
+ {
+ add[i] = shdr_after_undo[rinfonew.plt];
+ assert (sizeof (Elf32_Rel) * 3 == sizeof (Elf32_Rela) * 2);
+ assert (sizeof (Elf64_Rel) * 3 == sizeof (Elf64_Rela) * 2);
+ add[i].sh_size = add[i].sh_size / 2 * 3;
+ old[i] = rinfo.plt;
+ new_plt = i++;
+ }
+ if (growdynstr)
+ {
+ add[i] = shdr_after_undo[dynstrndxnew];
+ add[i].sh_size += growdynstr;
+ old[i] = dynstrndx;
+ new_dynstr = i++;
+ }
+ add[i].sh_flags = SHF_ALLOC;
+ add[i].sh_type = SHT_GNU_LIBLIST;
+ add[i].sh_size = (ndeps - 1) * sizeof (Elf32_Lib);
+ add[i].sh_addralign = sizeof (GElf_Word);
+ add[i].sh_entsize = sizeof (Elf32_Lib);
+ old[i] = old_liblist;
+ new_liblist = i++;
+ if (info->conflict_rela_size)
+ {
+ add[i].sh_flags = SHF_ALLOC;
+ add[i].sh_type = SHT_RELA;
+ add[i].sh_entsize = gelf_fsize (dso->elf, ELF_T_RELA, 1, EV_CURRENT);
+ add[i].sh_size = info->conflict_rela_size * add[i].sh_entsize;
+ add[i].sh_addralign = gelf_fsize (dso->elf, ELF_T_ADDR, 1, EV_CURRENT);
+ old[i] = old_conflict;
+ new_conflict = i++;
+ }
+ addcnt = i;
+ memset (&adjust, 0, sizeof (adjust));
+ adjust.new = new;
+ adjust.move = move;
+
+ for (i = 0; i < addcnt; ++i)
+ {
+ new[i] = find_readonly_space (dso, add + i, &ehdr, phdr, shdr, &adjust);
+ if (new[i] == 0)
+ goto error_out;
+ add_section (move, new[i]);
+ ++adjust.newcount;
+ if (old[i])
+ {
+ move->old_to_new[old[i]] = new[i];
+ move->new_to_old[new[i]] = old[i];
+ }
+ if (i == new_reloc)
+ {
+ int k, l = new[new_reloc];
+
+ j = rinfo.last - rinfo.first + (new_plt != -1);
+ shdr[l].sh_size = shdr_after_undo[rinfonew.first].sh_size / 2 * 3;
+ for (k = 1; k <= j; ++k)
+ {
+ insert_readonly_section (&ehdr, shdr, l + k, &adjust);
+ shdr[l + k] = add[new_reloc + k];
+ shdr[l + k].sh_addr = shdr[l + k - 1].sh_addr
+ + shdr[l + k - 1].sh_size;
+ shdr[l + k].sh_offset = shdr[l + k - 1].sh_offset
+ + shdr[l + k - 1].sh_size;
+ new[++i] = l + k;
+ add_section (move, l + k);
+ move->old_to_new[rinfo.first + k] = l + k;
+ move->new_to_old[l + k] = rinfo.first + k;
+ ++adjust.newcount;
+ }
+ }
+ }
+
+ if (info->sdynbss)
+ {
+ if (old_sdynbss == -1)
+ {
+ new_sdynbss = move->old_to_new[old_sbss];
+ memmove (&shdr[new_sdynbss + 1], &shdr[new_sdynbss],
+ (ehdr.e_shnum - new_sdynbss) * sizeof (GElf_Shdr));
+ shdr[new_sdynbss].sh_size = 0;
+ ++ehdr.e_shnum;
+ add_section (move, new_sdynbss);
+ for (i = 0; i < addcnt; ++i)
+ if (new[i] >= new_sdynbss)
+ ++new[i];
+ }
+ else
+ new_sdynbss = move->old_to_new[old_sdynbss];
+ }
+
+ if (info->dynbss)
+ {
+ if (old_dynbss == -1)
+ {
+ new_dynbss = move->old_to_new[old_bss];
+ memmove (&shdr[new_dynbss + 1], &shdr[new_dynbss],
+ (ehdr.e_shnum - new_dynbss) * sizeof (GElf_Shdr));
+ shdr[new_dynbss].sh_size = 0;
+ ++ehdr.e_shnum;
+ add_section (move, new_dynbss);
+ for (i = 0; i < addcnt; ++i)
+ if (new[i] >= new_dynbss)
+ ++new[i];
+ }
+ else
+ new_dynbss = move->old_to_new[old_dynbss];
+ }
+
+ if (undo != -1)
+ {
+ undo = move->old_to_new[dso->ehdr.e_shstrndx];
+ memmove (&shdr[undo + 1], &shdr[undo],
+ (ehdr.e_shnum - undo) * sizeof (GElf_Shdr));
+ memset (&shdr[undo], 0, sizeof (shdr[undo]));
+ shdr[undo].sh_type = SHT_PROGBITS;
+ shdr[undo].sh_addralign = dso->undo.d_align;
+ ++ehdr.e_shnum;
+ for (i = 0; i < addcnt; ++i)
+ if (new[i] >= undo)
+ ++new[i];
+ add_section (move, undo);
+ }
+
+ i = ehdr.e_shnum;
+ ehdr.e_shnum = dso->ehdr.e_shnum;
+ dso->ehdr = ehdr;
+ memcpy (dso->phdr, phdr, ehdr.e_phnum * sizeof (GElf_Phdr));
+ if (reopen_dso (dso, move, NULL))
+ goto error_out;
+
+ assert (i == dso->ehdr.e_shnum);
+
+ if (shnum_after_undo != move->new_shnum)
+ adjust_nonalloc (dso, &dso->ehdr, shdr, 0,
+ dso->ehdr.e_shoff + 1,
+ ((long) move->new_shnum - (long) shnum_after_undo)
+ * gelf_fsize (dso->elf, ELF_T_SHDR, 1, EV_CURRENT));
+
+ if (shdr_after_undo[shstrndxnew].sh_size
+ < dso->shdr[dso->ehdr.e_shstrndx].sh_size)
+ {
+ Elf_Data *data = elf_getdata (dso->scn[dso->ehdr.e_shstrndx], NULL);
+
+ assert (elf_getdata (dso->scn[dso->ehdr.e_shstrndx], data) == NULL);
+ assert (data->d_off == 0);
+ assert (shdr_after_undo[shstrndxnew].sh_size
+ == shdr[dso->ehdr.e_shstrndx].sh_size);
+ assert (data->d_size == dso->shdr[dso->ehdr.e_shstrndx].sh_size);
+ data->d_size = shdr_after_undo[shstrndxnew].sh_size;
+ }
+
+ for (i = 1; i < dso->ehdr.e_shnum; ++i)
+ if (move->new_to_old[i] == -1)
+ dso->shdr[i] = shdr[i];
+ else
+ {
+ if (shdr[i].sh_type == SHT_PROGBITS
+ && dso->shdr[i].sh_type == SHT_NOBITS)
+ {
+ Elf_Data *data = elf_getdata (dso->scn[i], NULL);
+
+ assert (data->d_buf == NULL);
+ data->d_size = shdr[i].sh_size;
+ if (data->d_size)
+ {
+ data->d_buf = calloc (shdr[i].sh_size, 1);
+ if (data->d_buf == NULL)
+ {
+ error (0, ENOMEM, "%s: Could not convert NOBITS section into PROGBITS",
+ dso->filename);
+ goto error_out;
+ }
+ }
+ data->d_type = ELF_T_BYTE;
+ }
+ dso->shdr[i].sh_type = shdr[i].sh_type;
+ dso->shdr[i].sh_addr = shdr[i].sh_addr;
+ dso->shdr[i].sh_size = shdr[i].sh_size;
+ dso->shdr[i].sh_offset = shdr[i].sh_offset;
+ }
+
+ for (i = 0; i < dso->ehdr.e_phnum; ++i)
+ if (dso->phdr[i].p_type == PT_LOAD)
+ {
+ GElf_Addr last_offset = dso->phdr[i].p_offset;
+ GElf_Addr adj = 0;
+ int sfirst = 0, slast = 0, last = 0;
+
+ for (j = 1; j < dso->ehdr.e_shnum; ++j)
+ if ((dso->shdr[j].sh_size > 0
+ || j == new_dynbss
+ || j == new_sdynbss)
+ && dso->shdr[j].sh_addr >= dso->phdr[i].p_vaddr
+ && dso->shdr[j].sh_addr + dso->shdr[j].sh_size
+ <= dso->phdr[i].p_vaddr + dso->phdr[i].p_memsz)
+ {
+ if (dso->shdr[j].sh_type != SHT_NOBITS
+ || (dso->shdr[j].sh_flags & SHF_TLS))
+ {
+ if (sfirst)
+ {
+ error (0, 0, "%s: NOBITS section followed by non-NOBITS section in the same segment",
+ dso->filename);
+ goto error_out;
+ }
+ continue;
+ }
+
+ if (!sfirst)
+ sfirst = j;
+ if (strcmp (strptr (dso, dso->ehdr.e_shstrndx,
+ dso->shdr[j].sh_name), ".plt") == 0)
+ slast = j + 1;
+ else if (j == new_dynbss || j == new_sdynbss)
+ slast = j;
+ }
+
+ if (sfirst && slast)
+ {
+ for (j = sfirst; j < slast; ++j)
+ {
+ Elf_Data *data = elf_getdata (dso->scn[j], NULL);
+
+ assert (data->d_size == dso->shdr[j].sh_size
+ || j == new_dynbss + 1
+ || j == new_sdynbss + 1);
+ if (data->d_size)
+ {
+ data->d_buf = realloc (data->d_buf, data->d_size);
+ if (data->d_buf == NULL)
+ {
+ error (0, ENOMEM, "%s: Could not convert NOBITS section into PROGBITS",
+ dso->filename);
+ goto error_out;
+ }
+ }
+ memset (data->d_buf, 0, data->d_size);
+ data->d_type = ELF_T_BYTE;
+ dso->shdr[j].sh_type = SHT_PROGBITS;
+ }
+
+ adj = dso->shdr[slast - 1].sh_addr + dso->shdr[slast - 1].sh_size
+ - dso->phdr[i].p_vaddr;
+
+ if (adj > dso->phdr[i].p_filesz)
+ {
+ adj -= dso->phdr[i].p_filesz;
+ for (j = slast;
+ j < dso->ehdr.e_shnum
+ && (dso->shdr[j].sh_flags
+ & (SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR));
+ ++j)
+ if (dso->shdr[j].sh_addr >= dso->phdr[i].p_vaddr
+ + dso->phdr[i].p_memsz)
+ adj = (adj + dso->shdr[j].sh_addralign - 1)
+ & ~(dso->shdr[j].sh_addralign - 1);
+
+ dso->phdr[i].p_filesz += adj;
+ }
+ else
+ adj = 0;
+ }
+
+ for (j = 1; j < dso->ehdr.e_shnum; ++j)
+ if ((dso->shdr[j].sh_size > 0
+ || j == new_dynbss
+ || j == new_sdynbss)
+ && dso->shdr[j].sh_addr >= dso->phdr[i].p_vaddr
+ && dso->shdr[j].sh_addr + dso->shdr[j].sh_size
+ <= dso->phdr[i].p_vaddr + dso->phdr[i].p_memsz)
+ {
+ last = j;
+ if (dso->shdr[j].sh_type == SHT_NOBITS)
+ {
+ last_offset += dso->shdr[j].sh_addralign - 1;
+ last_offset &= ~(dso->shdr[j].sh_addralign - 1);
+ if (last_offset > dso->phdr[i].p_offset
+ + dso->phdr[i].p_filesz)
+ last_offset = dso->phdr[i].p_offset
+ + dso->phdr[i].p_filesz;
+ dso->shdr[j].sh_offset = last_offset;
+ }
+ else if (dso->shdr[j].sh_addr + dso->shdr[j].sh_size
+ > dso->phdr[i].p_vaddr + dso->phdr[i].p_filesz)
+ {
+ error (0, 0, "%s: section spans beyond end of segment",
+ dso->filename);
+ goto error_out;
+ }
+ else
+ {
+ dso->shdr[j].sh_offset
+ = dso->phdr[i].p_offset + dso->shdr[j].sh_addr
+ - dso->phdr[i].p_vaddr;
+ last_offset = dso->shdr[j].sh_offset + dso->shdr[j].sh_size;
+ }
+ }
+
+ if (adj)
+ {
+ for (j = i + 1; j < dso->ehdr.e_phnum; ++j)
+ if (dso->phdr[j].p_type == PT_LOAD
+ && dso->phdr[j].p_vaddr >= dso->shdr[slast - 1].sh_addr)
+ {
+ dso->phdr[j].p_vaddr += adj;
+ dso->phdr[j].p_paddr += adj;
+ dso->phdr[j].p_offset += adj;
+ }
+
+ j = last + 1;
+ while (j < dso->ehdr.e_shnum
+ && (dso->shdr[j].sh_flags
+ & (SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR)))
+ {
+ dso->shdr[j].sh_offset += adj;
+ dso->shdr[j++].sh_addr += adj;
+ }
+
+ if (adjust_dso_nonalloc (dso, last + 1,
+ dso->shdr[sfirst].sh_offset,
+ adj))
+ goto error_out;
+ }
+ }
+
+ /* Adjust .rel*.dyn (or .rel*.*) if necessary. */
+ assert (new_reloc == -1
+ || (rinfo.last - rinfo.first
+ == (move->old_to_new[rinfo.last]
+ - move->old_to_new[rinfo.first])));
+ rinfo.first = move->old_to_new[rinfo.first];
+ rinfo.last = move->old_to_new[rinfo.last];
+ assert (new_reloc == -1 || rinfo.first == new[new_reloc]);
+
+ if (rinfo.rel_to_rela)
+ {
+ assert (sizeof (Elf32_Rel) * 3 == sizeof (Elf32_Rela) * 2);
+ assert (sizeof (Elf64_Rel) * 3 == sizeof (Elf64_Rela) * 2);
+ assert (new_reloc != -1);
+ for (j = rinfo.first; j <= rinfo.last; ++j)
+ {
+ dso->shdr[j].sh_size
+ = dso->shdr[j].sh_size / 3 * 2;
+ if (convert_rel_to_rela (dso, j))
+ goto error_out;
+ dso->shdr[j].sh_size = shdr[j].sh_size;
+ }
+ }
+ else if (rinfonew.rel_to_rela)
+ {
+ assert (new_reloc != -1);
+ for (j = rinfo.first; j <= rinfo.last; ++j)
+ {
+ dso->shdr[j].sh_entsize
+ = gelf_fsize (dso->elf, ELF_T_RELA, 1, EV_CURRENT);
+ dso->shdr[j].sh_type = SHT_RELA;
+ }
+ }
+
+ /* Adjust .rel*.plt if necessary. */
+ rinfo.plt = move->old_to_new[rinfo.plt];
+ if (new_plt != -1)
+ {
+ assert (rinfo.plt == new[new_plt]);
+ if (rinfo.rel_to_rela_plt)
+ {
+ assert (sizeof (Elf32_Rel) * 3 == sizeof (Elf32_Rela) * 2);
+ assert (sizeof (Elf64_Rel) * 3 == sizeof (Elf64_Rela) * 2);
+ dso->shdr[rinfo.first].sh_size
+ = dso->shdr[rinfo.first].sh_size / 3 * 2;
+ if (convert_rel_to_rela (dso, rinfo.plt))
+ goto error_out;
+ dso->shdr[rinfo.plt].sh_size = shdr[rinfo.plt].sh_size;
+ }
+ else if (rinfonew.rel_to_rela_plt)
+ {
+ dso->shdr[rinfo.plt].sh_entsize
+ = gelf_fsize (dso->elf, ELF_T_RELA, 1, EV_CURRENT);
+ dso->shdr[rinfo.plt].sh_type = SHT_RELA;
+ }
+ }
+
+ /* Add new strings into .dynstr if necessary. */
+ if (new_dynstr != -1)
+ {
+ Elf_Data *data;
+ char *ptr;
+
+ i = new[new_dynstr];
+ data = elf_getdata (dso->scn[i], NULL);
+ assert (data->d_off == 0);
+ data->d_buf = realloc (data->d_buf, dso->shdr[i].sh_size);
+ if (data->d_buf == NULL)
+ {
+ error (0, ENOMEM, "%s: Could not append names needed for .gnu.liblist to .dynstr",
+ dso->filename);
+ goto error_out;
+ }
+ ptr = data->d_buf + shdr_after_undo[dynstrndxnew].sh_size;
+ data->d_size = dso->shdr[i].sh_size;
+ for (j = 0; j < ndeps - 1; ++j)
+ if (liblist[j].l_name == 0)
+ {
+ liblist[j].l_name = ptr - (char *) data->d_buf;
+ ptr = stpcpy (ptr, info->sonames[j + 1]) + 1;
+ }
+ assert (ptr == (char *) data->d_buf + data->d_size);
+ }
+
+ /* Create or update .sdynbss if necessary. */
+ if (new_sdynbss != -1)
+ {
+ Elf_Data *data;
+
+ if (old_sdynbss == -1)
+ {
+ dso->shdr[new_sdynbss] = dso->shdr[new_sdynbss + 1];
+
+ dso->shdr[new_sdynbss].sh_name = shstrtabadd (dso, ".sdynbss");
+ if (dso->shdr[new_sdynbss].sh_name == 0)
+ goto error_out;
+
+ dso->shdr[new_sdynbss].sh_size =
+ info->sdynbss_base + info->sdynbss_size
+ - dso->shdr[new_sdynbss].sh_addr;
+
+ dso->shdr[new_sdynbss + 1].sh_size
+ -= dso->shdr[new_sdynbss].sh_size;
+ dso->shdr[new_sdynbss + 1].sh_addr
+ += dso->shdr[new_sdynbss].sh_size;
+ dso->shdr[new_sdynbss + 1].sh_offset
+ += dso->shdr[new_sdynbss].sh_size;
+ dso->shdr[new_sdynbss].sh_type = SHT_PROGBITS;
+ }
+ else
+ {
+ if (dso->shdr[new_sdynbss].sh_type != SHT_PROGBITS
+ || dso->shdr[new_sdynbss].sh_addr > info->sdynbss_base
+ || dso->shdr[new_sdynbss].sh_addr
+ + dso->shdr[new_sdynbss].sh_size
+ < info->sdynbss_base + info->sdynbss_size)
+ {
+ error (0, 0, "%s: Copy relocs don't point into .sdynbss section",
+ dso->filename);
+ goto error_out;
+ }
+ }
+ data = elf_getdata (dso->scn[new_sdynbss], NULL);
+ free (data->d_buf);
+ data->d_buf = info->sdynbss;
+ info->sdynbss = NULL;
+ data->d_off = info->sdynbss_base - dso->shdr[new_sdynbss].sh_addr;
+ data->d_size = info->sdynbss_size;
+ data->d_type = ELF_T_BYTE;
+ if (old_sdynbss == -1)
+ {
+ data = elf_getdata (dso->scn[new_sdynbss + 1], NULL);
+ assert (dso->shdr[new_sdynbss + 1].sh_type != SHT_NOBITS
+ || data->d_buf == NULL);
+ if (data->d_size != dso->shdr[new_sdynbss + 1].sh_size)
+ {
+ assert (data->d_size == dso->shdr[new_sdynbss].sh_size
+ + dso->shdr[new_sdynbss + 1].sh_size);
+ data->d_size -= dso->shdr[new_sdynbss].sh_size;
+ }
+ }
+ }
+
+ /* Create or update .dynbss if necessary. */
+ if (new_dynbss != -1)
+ {
+ Elf_Data *data;
+
+ if (old_dynbss == -1)
+ {
+ GElf_Addr adj;
+
+ dso->shdr[new_dynbss] = dso->shdr[new_dynbss + 1];
+
+ if (! strcmp (strptr (dso, dso->ehdr.e_shstrndx,
+ dso->shdr[new_dynbss + 1].sh_name),
+ ".sbss")
+ && new_sdynbss == -1)
+ dso->shdr[new_dynbss].sh_name = shstrtabadd (dso, ".sdynbss");
+ else
+ dso->shdr[new_dynbss].sh_name = shstrtabadd (dso, ".dynbss");
+ if (dso->shdr[new_dynbss].sh_name == 0)
+ goto error_out;
+
+ dso->shdr[new_dynbss].sh_size =
+ info->dynbss_base + info->dynbss_size
+ - dso->shdr[new_dynbss].sh_addr;
+
+ dso->shdr[new_dynbss + 1].sh_size
+ -= dso->shdr[new_dynbss].sh_size;
+ dso->shdr[new_dynbss + 1].sh_addr
+ += dso->shdr[new_dynbss].sh_size;
+ dso->shdr[new_dynbss + 1].sh_offset
+ += dso->shdr[new_dynbss].sh_size;
+ dso->shdr[new_dynbss].sh_type = SHT_PROGBITS;
+
+ if (dso->shdr[new_dynbss + 1].sh_type == SHT_NOBITS)
+ {
+ GElf_Addr last_offset;
+
+ for (i = 0; i < dso->ehdr.e_phnum; ++i)
+ if (dso->phdr[i].p_type == PT_LOAD
+ && dso->phdr[i].p_vaddr <= dso->shdr[new_dynbss].sh_addr
+ && dso->phdr[i].p_vaddr + dso->phdr[i].p_memsz
+ >= info->dynbss_base + info->dynbss_size)
+ break;
+ assert (i < dso->ehdr.e_phnum);
+
+ for (j = new_dynbss - 1; j; --j)
+ {
+ if (dso->shdr[j].sh_addr < dso->phdr[i].p_vaddr)
+ break;
+ if (dso->shdr[j].sh_type == SHT_NOBITS
+ && (dso->shdr[j].sh_flags & SHF_TLS) == 0)
+ {
+ error (0, 0, "%s: COPY relocs not present at start of first SHT_NOBITS section",
+ dso->filename);
+ goto error_out;
+ }
+ }
+
+ if (dso->phdr[i].p_filesz
+ < info->dynbss_base + info->dynbss_size
+ - dso->phdr[i].p_vaddr)
+ {
+ dso->phdr[i].p_filesz =
+ info->dynbss_base + info->dynbss_size
+ - dso->phdr[i].p_vaddr;
+ assert (dso->phdr[i].p_filesz <= dso->phdr[i].p_memsz);
+ }
+
+ adj = dso->phdr[i].p_offset + dso->shdr[new_dynbss].sh_addr
+ - dso->phdr[i].p_vaddr - dso->shdr[new_dynbss].sh_offset;
+
+ dso->shdr[new_dynbss].sh_offset += adj;
+ dso->shdr[new_dynbss + 1].sh_offset += adj;
+
+ adj += dso->shdr[new_dynbss].sh_size;
+
+ for (j = new_dynbss + 2;
+ j < dso->ehdr.e_shnum
+ && (dso->shdr[j].sh_flags
+ & (SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR));
+ ++j)
+ if (dso->shdr[j].sh_addr >= dso->phdr[i].p_vaddr
+ + dso->phdr[i].p_memsz)
+ adj = (adj + dso->shdr[j].sh_addralign - 1)
+ & ~(dso->shdr[j].sh_addralign - 1);
+
+ for (j = i + 1; j < dso->ehdr.e_phnum; ++j)
+ if (dso->phdr[j].p_type == PT_LOAD
+ && dso->phdr[j].p_vaddr >= dso->shdr[new_dynbss].sh_addr)
+ {
+ dso->phdr[j].p_vaddr += adj;
+ dso->phdr[j].p_paddr += adj;
+ dso->phdr[j].p_offset += adj;
+ }
+
+ last_offset = dso->shdr[new_dynbss + 1].sh_offset;
+ for (j = new_dynbss + 2; j < dso->ehdr.e_shnum; ++j)
+ if (dso->shdr[j].sh_type != SHT_NOBITS
+ || dso->shdr[j].sh_addr < dso->phdr[i].p_vaddr
+ || dso->shdr[j].sh_addr + dso->shdr[j].sh_size
+ > dso->phdr[i].p_vaddr + dso->phdr[i].p_memsz)
+ break;
+ else
+ {
+ last_offset += dso->shdr[j].sh_addralign - 1;
+ last_offset &= ~(dso->shdr[j].sh_addralign - 1);
+ if (last_offset > dso->phdr[i].p_offset
+ + dso->phdr[i].p_filesz)
+ last_offset = dso->phdr[i].p_offset
+ + dso->phdr[i].p_filesz;
+ dso->shdr[j].sh_offset = last_offset;
+ }
+
+ while (j < dso->ehdr.e_shnum
+ && (dso->shdr[j].sh_flags
+ & (SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR)))
+ {
+ dso->shdr[j].sh_offset += adj;
+ dso->shdr[j++].sh_addr += adj;
+ }
+
+ if (adjust_dso_nonalloc (dso, new_dynbss + 2,
+ dso->shdr[new_dynbss].sh_offset,
+ adj))
+ goto error_out;
+ }
+ }
+ else
+ {
+ if (dso->shdr[new_dynbss].sh_type != SHT_PROGBITS
+ || dso->shdr[new_dynbss].sh_addr > info->dynbss_base
+ || dso->shdr[new_dynbss].sh_addr
+ + dso->shdr[new_dynbss].sh_size
+ < info->dynbss_base + info->dynbss_size)
+ {
+ error (0, 0, "%s: Copy relocs don't point into .dynbss section",
+ dso->filename);
+ goto error_out;
+ }
+ }
+ data = elf_getdata (dso->scn[new_dynbss], NULL);
+ free (data->d_buf);
+ data->d_buf = info->dynbss;
+ info->dynbss = NULL;
+ data->d_off = info->dynbss_base - dso->shdr[new_dynbss].sh_addr;
+ data->d_size = info->dynbss_size;
+ data->d_type = ELF_T_BYTE;
+ if (old_dynbss == -1)
+ {
+ data = elf_getdata (dso->scn[new_dynbss + 1], NULL);
+ if (dso->shdr[new_dynbss + 1].sh_type == SHT_NOBITS
+ && data->d_buf != NULL)
+ {
+#ifndef NDEBUG
+ char *buf_start = data->d_buf;
+ char *buf_end = buf_start + data->d_size;
+
+ while (buf_start < buf_end)
+ if (*buf_start++)
+ break;
+ assert (buf_start == buf_end);
+#endif
+ free (data->d_buf);
+ data->d_buf = NULL;
+ }
+ if (data->d_size != dso->shdr[new_dynbss + 1].sh_size)
+ {
+ assert (data->d_size == dso->shdr[new_dynbss].sh_size
+ + dso->shdr[new_dynbss + 1].sh_size);
+ data->d_size -= dso->shdr[new_dynbss].sh_size;
+ }
+ }
+ }
+
+ /* Create the liblist. */
+ i = new[new_liblist];
+ dso->shdr[i].sh_flags = shdr[i].sh_flags;
+ dso->shdr[i].sh_addralign = shdr[i].sh_addralign;
+ dso->shdr[i].sh_entsize = shdr[i].sh_entsize;
+ dso->shdr[i].sh_name = shstrtabadd (dso, ".gnu.liblist");
+ if (dso->shdr[i].sh_name == 0)
+ goto error_out;
+ else
+ {
+ Elf_Data *data;
+
+ dso->shdr[i].sh_link
+ = new_dynstr != -1 ? new[new_dynstr] : move->old_to_new[dynstrndx];
+ data = elf_getdata (dso->scn[i], NULL);
+ data->d_type = ELF_T_WORD;
+ data->d_size = (ndeps - 1) * sizeof (Elf32_Lib);
+ free (data->d_buf);
+ data->d_buf = liblist;
+ liblist = NULL;
+ data->d_off = 0;
+ data->d_align = sizeof (GElf_Word);
+ data->d_version = EV_CURRENT;
+ if (set_dynamic (dso, DT_GNU_LIBLIST, dso->shdr[i].sh_addr, 1))
+ goto error_out;
+ if (set_dynamic (dso, DT_GNU_LIBLISTSZ, dso->shdr[i].sh_size, 1))
+ goto error_out;
+ }
+
+ /* Create the conflict list if necessary. */
+ if (new_conflict != -1)
+ {
+ Elf_Data *data;
+
+ i = new[new_conflict];
+ data = elf_getdata (dso->scn[i], NULL);
+ data->d_type = ELF_T_RELA;
+ data->d_size = info->conflict_rela_size
+ * gelf_fsize (dso->elf, ELF_T_RELA, 1, EV_CURRENT);
+ data->d_off = 0;
+ data->d_align = gelf_fsize (dso->elf, ELF_T_ADDR, 1, EV_CURRENT);
+ data->d_version = EV_CURRENT;
+ if (data->d_size)
+ {
+ data->d_buf = realloc (data->d_buf, data->d_size);
+ if (data->d_buf == NULL)
+ {
+ error (0, ENOMEM, "%s: Could not build .gnu.conflict section",
+ dso->filename);
+ goto error_out;
+ }
+ }
+ else
+ {
+ free (data->d_buf);
+ data->d_buf = NULL;
+ }
+ for (j = 0; j < info->conflict_rela_size; ++j)
+ gelfx_update_rela (dso->elf, data, j, info->conflict_rela + j);
+ free (info->conflict_rela);
+ info->conflict_rela = NULL;
+
+ dso->shdr[i].sh_flags = shdr[i].sh_flags;
+ dso->shdr[i].sh_addralign = shdr[i].sh_addralign;
+ dso->shdr[i].sh_entsize = shdr[i].sh_entsize;
+ for (j = 1; j < dso->ehdr.e_shnum; ++j)
+ if (dso->shdr[j].sh_type == SHT_DYNSYM)
+ break;
+ assert (j < dso->ehdr.e_shnum);
+ dso->shdr[i].sh_link = j;
+ dso->shdr[i].sh_name = shstrtabadd (dso, ".gnu.conflict");
+ if (dso->shdr[i].sh_name == 0)
+ goto error_out;
+ if (set_dynamic (dso, DT_GNU_CONFLICT, dso->shdr[i].sh_addr, 1))
+ goto error_out;
+ if (set_dynamic (dso, DT_GNU_CONFLICTSZ, dso->shdr[i].sh_size, 1))
+ goto error_out;
+ }
+
+ if (undo != -1)
+ {
+ Elf_Scn *scn;
+ Elf_Data *data;
+ GElf_Addr newoffset;
+
+ dso->shdr[undo].sh_name = shstrtabadd (dso, ".gnu.prelink_undo");
+ if (dso->shdr[undo].sh_name == 0)
+ return 1;
+ dso->shdr[undo].sh_offset = dso->shdr[undo - 1].sh_offset;
+ if (dso->shdr[undo - 1].sh_type != SHT_NOBITS)
+ dso->shdr[undo].sh_offset += dso->shdr[undo - 1].sh_size;
+ dso->shdr[undo].sh_entsize = 1;
+ dso->shdr[undo].sh_size = dso->undo.d_size;
+ newoffset = dso->shdr[undo].sh_offset + dso->undo.d_align - 1;
+ newoffset &= ~(dso->shdr[undo].sh_addralign - 1);
+ if (adjust_dso_nonalloc (dso, undo + 1, dso->shdr[undo].sh_offset,
+ dso->undo.d_size + newoffset
+ - dso->shdr[undo].sh_offset))
+ return 1;
+ dso->shdr[undo].sh_offset = newoffset;
+ scn = dso->scn[undo];
+ data = elf_getdata (scn, NULL);
+ assert (data != NULL && elf_getdata (scn, data) == NULL);
+ free (data->d_buf);
+ *data = dso->undo;
+ dso->undo.d_buf = NULL;
+ }
+
+ recompute_nonalloc_offsets (dso);
+
+ if (update_dynamic_tags (dso, dso->shdr, old_shdr, move))
+ goto error_out;
+
+ if (update_dynamic_rel (dso, &rinfo))
+ goto error_out;
+
+ free (move);
+ return 0;
+}
diff --git a/src/execle_open.c b/src/execle_open.c
new file mode 100644
index 0000000..2ee5cbc
--- /dev/null
+++ b/src/execle_open.c
@@ -0,0 +1,81 @@
+/* Copyright (C) 2001 Red Hat, Inc.
+ Written by Jakub Jelinek <jakub@redhat.com>, 2001.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include <config.h>
+#include <errno.h>
+#include <error.h>
+#include <stdio.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+static pid_t pid;
+
+int
+execve_close (FILE *f)
+{
+ pid_t p;
+ int status;
+
+ if (f != NULL)
+ fclose (f);
+ while ((p = waitpid (pid, &status, 0)) == -1 && errno == EINTR);
+ if (p == -1 || ! WIFEXITED (status))
+ return -1;
+ return WEXITSTATUS (status);
+}
+
+FILE *
+execve_open (const char *path, char *const argv[], char *const envp[])
+{
+ int p[2];
+ FILE *f;
+
+ if (pipe (p) < 0)
+ {
+ error (0, errno, "Could not run %s", path);
+ return NULL;
+ }
+
+ switch (pid = vfork ())
+ {
+ case -1:
+ error (0, errno, "Could not run %s", path);
+ return NULL;
+ case 0:
+ close (p[0]);
+ if (p[1] != 1)
+ {
+ dup2 (p[1], 1);
+ close (p[1]);
+ }
+ dup2 (1, 2);
+ execve (path, argv, envp);
+ error (0, errno, "Could not run %s", path);
+ _exit (127);
+ }
+
+ close (p[1]);
+
+ f = fdopen (p[0], "r");
+ if (f == NULL)
+ {
+ close (p[0]);
+ execve_close (NULL);
+ }
+
+ return f;
+}
diff --git a/src/execstack.c b/src/execstack.c
new file mode 100644
index 0000000..dda6bc7
--- /dev/null
+++ b/src/execstack.c
@@ -0,0 +1,483 @@
+/* Copyright (C) 2003, 2005, 2010 Red Hat, Inc.
+ Written by Jakub Jelinek <jakub@redhat.com>, 2003.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include <config.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <locale.h>
+#include <error.h>
+#include <argp.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/wait.h>
+
+#include "prelink.h"
+
+int set;
+int execflag;
+
+const char *argp_program_version = EXECSTACK_PROG PKGVERSION " 1.0";
+
+const char *argp_program_bug_address = REPORT_BUGS_TO;
+
+static char argp_doc[] = EXECSTACK_PROG " -- program to query or set executable stack flag";
+
+static struct argp_option options[] = {
+ {"set-execstack", 's', 0, 0, "Set executable stack flag bit" },
+ {"execstack", 's', 0, OPTION_HIDDEN, "" },
+ {"clear-execstack", 'c', 0, 0, "Clear executable stack flag bit" },
+ {"noexecstack", 'c', 0, OPTION_HIDDEN, "" },
+ {"query", 'q', 0, 0, "Query executable stack flag bit" },
+ { 0 }
+};
+
+/* The cached value of argv[0]. */
+const char *program_path;
+
+/* The full pathname of the prelink tool, or NULL if it hasn't been
+ computed yet. */
+const char *prelink_path;
+
+static error_t
+parse_opt (int key, char *arg, struct argp_state *state)
+{
+ switch (key)
+ {
+ case 's':
+ set = 1;
+ execflag = 1;
+ break;
+ case 'c':
+ set = 1;
+ execflag = 0;
+ break;
+ case 'q':
+ set = 0;
+ break;
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+}
+
+static struct argp argp = { options, parse_opt, 0, argp_doc };
+
+static int execstack_set (DSO *dso, int flag);
+
+static void
+execstack_fill_phdr (DSO *dso, int i, int flag)
+{
+ memset (&dso->phdr[i], 0, sizeof (dso->phdr[i]));
+ dso->phdr[i].p_type = PT_GNU_STACK;
+ dso->phdr[i].p_flags = PF_W | PF_R | (flag ? PF_X : 0);
+ dso->phdr[i].p_align = gelf_fsize (dso->elf, ELF_T_ADDR, 1, EV_CURRENT);
+}
+
+static int
+execstack_make_rdwr (DSO *dso, int flag)
+{
+ int i, fd = -1, status;
+ pid_t pid;
+ DSO *ndso = NULL;
+ char *p = NULL;
+ char filename[strlen (dso->filename) + sizeof ".#execstack#.XXXXXX"];
+ extern char *make_relative_prefix (const char *, const char *, const char *);
+ char *dirname;
+
+ for (i = 0; i < dso->ehdr.e_shnum; ++i)
+ {
+ const char *name = strptr (dso, dso->ehdr.e_shstrndx,
+ dso->shdr[i].sh_name);
+ if (strcmp (name, ".gnu.prelink_undo") == 0)
+ break;
+ }
+
+ if (i == dso->ehdr.e_shnum)
+ return reopen_dso (dso, NULL, NULL) ? 1 : -1;
+
+ /* We need to unprelink the file first, so that prelink --undo
+ or reprelinking it doesn't destroy the PT_GNU_STACK segment
+ header we've created. */
+ sprintf (filename, "%s.#execstack#.XXXXXX", dso->filename);
+
+ fd = wrap_mkstemp (filename);
+ if (fd == -1)
+ {
+ error (0, 0, "%s: Cannot create temporary file",
+ dso->filename);
+ goto error_out;
+ }
+
+ p = strdup (dso->filename);
+ if (p == NULL)
+ {
+ error (0, ENOMEM, "%s: Cannot create temporary file",
+ dso->filename);
+ goto error_out;
+ }
+
+ if (prelink_path == NULL)
+ {
+ dirname = make_relative_prefix (program_path, BINDIR, SBINDIR);
+ asprintf (&prelink_path, "%s/%s", dirname, PRELINK_PROG EXEEXT);
+ free (dirname);
+ }
+
+ pid = vfork ();
+ if (pid == 0)
+ {
+ close (fd);
+ execl (prelink_path, prelink_path, "-u", "-o", filename,
+ dso->filename, NULL);
+ _exit (-1);
+ }
+
+ if (pid < 0)
+ {
+ error (0, errno, "%s: Cannot run prelink --undo",
+ dso->filename);
+ goto error_out;
+ }
+
+ if (waitpid (pid, &status, 0) < 0
+ || !WIFEXITED (status)
+ || WEXITSTATUS (status))
+ {
+ error (0, 0, "%s: prelink --undo failed", dso->filename);
+ goto error_out;
+ }
+
+ ndso = open_dso (filename);
+ if (ndso == NULL)
+ {
+ error (0, 0, "%s: Couldn't open prelink --undo output",
+ dso->filename);
+ goto error_out;
+ }
+
+ for (i = 0; i < ndso->ehdr.e_shnum; ++i)
+ {
+ const char *name = strptr (ndso, ndso->ehdr.e_shstrndx,
+ ndso->shdr[i].sh_name);
+ if (strcmp (name, ".gnu.prelink_undo") == 0)
+ break;
+ }
+
+ if (i != ndso->ehdr.e_shnum)
+ {
+ error (0, 0, "%s: prelink --undo output contains .gnu.prelink_undo section",
+ dso->filename);
+ goto error_out;
+ }
+
+ if (ndso->ehdr.e_type != dso->ehdr.e_type)
+ {
+ error (0, 0, "%s: Object type changed during prelink --undo operation",
+ dso->filename);
+ }
+
+ if (ndso->filename != ndso->soname)
+ free ((char *) ndso->filename);
+ ndso->filename = p;
+ p = NULL;
+
+ wrap_unlink (filename);
+ fsync (fd);
+ close (fd);
+ fd = -1;
+ close_dso (dso);
+ return execstack_set (ndso, flag);
+
+error_out:
+ free (p);
+ if (ndso != NULL)
+ close_dso (ndso);
+ if (fd != -1)
+ {
+ wrap_unlink (filename);
+ fsync (fd);
+ close (fd);
+ }
+ close_dso (dso);
+ return 1;
+}
+
+static int
+execstack_set (DSO *dso, int flag)
+{
+ int i, null = -1, last, ret;
+ GElf_Addr lowoff = ~(GElf_Addr) 0, start = 0, align = 0;
+ GElf_Addr adjust;
+
+ for (i = 0; i < dso->ehdr.e_phnum; ++i)
+ if (dso->phdr[i].p_type == PT_GNU_STACK)
+ {
+ /* Found PT_GNU_STACK. Check if we need any change or not. */
+ if (flag ^ ((dso->phdr[i].p_flags & PF_X) != 0))
+ {
+ ret = execstack_make_rdwr (dso, flag);
+ if (ret != -1)
+ return ret;
+ dso->phdr[i].p_flags ^= PF_X;
+ goto out_write;
+ }
+ else
+ goto out_close;
+ }
+ else if (dso->phdr[i].p_type == PT_NULL)
+ null = i;
+
+ if (null != -1)
+ {
+ /* Overwrite PT_NULL segment with PT_GNU_STACK. */
+ ret = execstack_make_rdwr (dso, flag);
+ if (ret != -1)
+ return ret;
+ execstack_fill_phdr (dso, i, flag);
+ goto out_write;
+ }
+
+ if (dso->ehdr.e_shnum == 0)
+ {
+ error (0, 0, "%s: Section header table missing", dso->filename);
+ goto error_out;
+ }
+
+ for (i = 1; i < dso->ehdr.e_shnum; ++i)
+ {
+ if (lowoff > dso->shdr[i].sh_offset)
+ {
+ if (dso->shdr[i].sh_flags & (SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR))
+ {
+ lowoff = dso->shdr[i].sh_offset;
+ start = dso->shdr[i].sh_addr;
+ }
+ else
+ {
+ error (0, 0, "%s: Non-alloced sections before alloced ones",
+ dso->filename);
+ goto error_out;
+ }
+ }
+
+ if (dso->shdr[i].sh_addralign > align)
+ align = dso->shdr[i].sh_addralign;
+ }
+
+ if (dso->ehdr.e_phoff >= lowoff)
+ {
+ error (0, 0, "%s: Program header table not before all sections",
+ dso->filename);
+ goto error_out;
+ }
+
+ if (dso->ehdr.e_shoff <= lowoff)
+ {
+ error (0, 0, "%s: Section header table before first section",
+ dso->filename);
+ goto error_out;
+ }
+
+ if (dso->ehdr.e_phoff + (dso->ehdr.e_phnum + 1) * dso->ehdr.e_phentsize
+ <= lowoff)
+ {
+ /* There is enough space for the headers even without reshuffling
+ anything. */
+ for (i = 0; i < dso->ehdr.e_phnum; ++i)
+ if (dso->phdr[i].p_type == PT_PHDR)
+ {
+ if (dso->phdr[i].p_filesz
+ == dso->ehdr.e_phnum * dso->ehdr.e_phentsize)
+ dso->phdr[i].p_filesz += dso->ehdr.e_phentsize;
+ if (dso->phdr[i].p_memsz
+ == dso->ehdr.e_phnum * dso->ehdr.e_phentsize)
+ dso->phdr[i].p_memsz += dso->ehdr.e_phentsize;
+ }
+ i = dso->ehdr.e_phnum++;
+ ret = execstack_make_rdwr (dso, flag);
+ if (ret != -1)
+ return ret;
+ execstack_fill_phdr (dso, i, flag);
+ goto out_write;
+ }
+
+ if (dso->ehdr.e_type != ET_DYN)
+ {
+ error (0, 0, "%s: Reshuffling of objects to make room for\n"
+ "program header entry only supported for shared libraries",
+ dso->filename);
+ goto error_out;
+ }
+
+ adjust = dso->ehdr.e_phoff + (dso->ehdr.e_phnum + 1) * dso->ehdr.e_phentsize
+ - lowoff;
+ if (align)
+ adjust = (adjust + align - 1) & ~(align - 1);
+
+ /* Need to make sure adjust doesn't cause different Phdr segments
+ to overlap on the same page. */
+ last = -1;
+ for (i = 0; i < dso->ehdr.e_phnum; ++i)
+ if (dso->phdr[i].p_type == PT_LOAD
+ && dso->phdr[i].p_vaddr + dso->phdr[i].p_memsz >= start)
+ {
+ if (last != -1
+ && (((dso->phdr[last].p_vaddr + dso->phdr[last].p_memsz - 1)
+ ^ dso->phdr[i].p_vaddr)
+ & ~(dso->arch->max_page_size - 1))
+ && !(((dso->phdr[last].p_vaddr + dso->phdr[last].p_memsz
+ + adjust - 1)
+ ^ (dso->phdr[i].p_vaddr + adjust))
+ & ~(dso->arch->max_page_size - 1)))
+ {
+ if (align >= dso->arch->max_page_size)
+ {
+ error (0, 0, "%s: Cannot grow reloc sections", dso->filename);
+ goto error_out;
+ }
+ adjust = (adjust + dso->arch->max_page_size - 1)
+ & ~(dso->arch->max_page_size - 1);
+ }
+ last = i;
+ }
+
+ for (i = 0; i < dso->ehdr.e_phnum; ++i)
+ if (dso->phdr[i].p_type == PT_PHDR)
+ {
+ if (dso->phdr[i].p_filesz == dso->ehdr.e_phnum * dso->ehdr.e_phentsize)
+ dso->phdr[i].p_filesz += dso->ehdr.e_phentsize;
+ if (dso->phdr[i].p_memsz == dso->ehdr.e_phnum * dso->ehdr.e_phentsize)
+ dso->phdr[i].p_memsz += dso->ehdr.e_phentsize;
+ }
+
+ i = dso->ehdr.e_phnum++;
+ ret = execstack_make_rdwr (dso, flag);
+ if (ret != -1)
+ return ret;
+
+ if (adjust_dso (dso, start, adjust))
+ goto error_out;
+
+ execstack_fill_phdr (dso, i, flag);
+
+out_write:
+ if (dynamic_info_is_set (dso, DT_CHECKSUM_BIT)
+ && dso_is_rdwr (dso)
+ && prelink_set_checksum (dso))
+ goto error_out;
+
+ dso->permissive = 1;
+
+ return update_dso (dso, NULL);
+
+out_close:
+ close_dso (dso);
+ return 0;
+
+error_out:
+ close_dso (dso);
+ return 1;
+}
+
+static int
+execstack_query (DSO *dso)
+{
+ int stack = '?', i;
+
+ for (i = 0; i < dso->ehdr.e_phnum; ++i)
+ if (dso->phdr[i].p_type == PT_GNU_STACK)
+ {
+ stack = (dso->phdr[i].p_flags & PF_X) ? 'X' : '-';
+ break;
+ }
+ printf ("%c %s\n", stack, dso->filename);
+ close_dso (dso);
+ return 0;
+}
+
+int
+main (int argc, char *argv[])
+{
+ int remaining, failures = 0;
+
+ program_path = argv[0];
+
+ setlocale (LC_ALL, "");
+
+ argp_parse (&argp, argc, argv, 0, &remaining, 0);
+
+ elf_version (EV_CURRENT);
+
+ if (remaining == argc)
+ error (EXIT_FAILURE, 0, "no files given");
+
+ while (remaining < argc)
+ {
+ DSO *dso = open_dso (argv[remaining++]);
+ int ret;
+
+ if (dso == NULL)
+ {
+ ++failures;
+ continue;
+ }
+
+ if (dso->ehdr.e_type != ET_DYN
+ && dso->ehdr.e_type != ET_EXEC)
+ {
+ ++failures;
+ error (0, 0, "%s is not a shared library nor executable", dso->filename);
+ continue;
+ }
+
+ if (set)
+ ret = execstack_set (dso, execflag);
+ else
+ ret = execstack_query (dso);
+
+ if (ret)
+ ++failures;
+ }
+
+ return failures;
+}
+
+/* FIXME: Dummy. When arch dependent files are split into adjust and prelink
+ parts, this can go away. */
+struct prelink_conflict *
+prelink_conflict (struct prelink_info *info, GElf_Word r_sym, int reloc_type)
+{
+ abort ();
+}
+
+GElf_Rela *
+prelink_conflict_add_rela (struct prelink_info *info)
+{
+ abort ();
+}
+
+ssize_t
+send_file (int outfd, int infd, off_t *poff, size_t count)
+{
+ abort ();
+}
+
+GElf_Addr mmap_reg_start;
+GElf_Addr mmap_reg_end;
+int exec_shield;
diff --git a/src/fptr.c b/src/fptr.c
new file mode 100644
index 0000000..cfe3aed
--- /dev/null
+++ b/src/fptr.c
@@ -0,0 +1,465 @@
+/* Copyright (C) 2001, 2002, 2003, 2007 Red Hat, Inc.
+ Written by Jakub Jelinek <jakub@redhat.com>, 2001.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include <config.h>
+#include <assert.h>
+#include <errno.h>
+#include <error.h>
+#include "fptr.h"
+
+struct opd_refent;
+
+struct opd_tabent
+{
+ struct opd_ent *ent;
+ struct opd_refent *ref;
+};
+
+struct opd_refent
+{
+ GElf_Addr val;
+ GElf_Addr gp;
+ struct opd_refent *first;
+ struct opd_tabent *tabent;
+ struct opd_refent *next, *nextref;
+ GElf_Word refcnt;
+};
+
+struct opd_fptr
+{
+ /* The first 2 fields have to match opd_refent. */
+ GElf_Addr val;
+ GElf_Addr gp;
+ struct opd_ent *ent;
+};
+
+static void
+opd_del (void *p)
+{
+ free (p);
+}
+
+static hashval_t
+opd_tabent_hash (const void *p)
+{
+ struct opd_tabent *e = (struct opd_tabent *)p;
+
+ return e->ent->opd;
+}
+
+static int
+opd_tabent_eq (const void *p, const void *q)
+{
+ struct opd_tabent *e = (struct opd_tabent *)p;
+ struct opd_tabent *f = (struct opd_tabent *)q;
+
+ return e->ent == f->ent;
+}
+
+static hashval_t
+opd_refent_hash (const void *p)
+{
+ struct opd_refent *e = (struct opd_refent *)p;
+
+ return e->val ^ (e->val >> 31);
+}
+
+static int
+opd_refent_eq (const void *p, const void *q)
+{
+ struct opd_refent *e = (struct opd_refent *)p;
+ struct opd_refent *f = (struct opd_refent *)q;
+
+ return e->val == f->val && e->gp == f->gp;
+}
+
+static int
+opd_gather_refent (void **p, void *info)
+{
+ struct opd_refent ***ptr = (struct opd_refent ***) info;
+ struct opd_refent *r = *(struct opd_refent **) p, *t;
+
+ for (t = r; t; t = t->next)
+ {
+ *(*ptr)++ = t;
+ t->first = r;
+ }
+ return 1;
+}
+
+static int
+opd_refent_cmp (const void *A, const void *B)
+{
+ struct opd_refent *a = * (struct opd_refent **) A;
+ struct opd_refent *b = * (struct opd_refent **) B;
+
+ if (a->refcnt > b->refcnt)
+ return -1;
+ if (a->refcnt < b->refcnt)
+ return 1;
+ return 0;
+}
+
+int
+opd_init (struct prelink_info *info)
+{
+ int i, j, nrefent = 0;
+ struct opd_lib *l;
+ struct opd_refent refent, *r, **refarr, **a;
+ struct opd_tabent tabent, *t;
+ void **tabslot;
+ htab_t tabent_htab = NULL, refent_htab = NULL;
+
+ l = calloc (sizeof (struct opd_lib), 1);
+ if (l == NULL)
+ goto error_mem;
+ l->nrefs = (info->symtab_end - info->symtab_start) / info->symtab_entsize;
+ if (l->nrefs)
+ {
+ l->u.refp = calloc (l->nrefs, sizeof (struct opd_ref *));
+ if (l->u.refp == NULL)
+ goto error_mem;
+ }
+ else
+ l->u.refp = NULL;
+ tabent_htab = htab_try_create (100, opd_tabent_hash, opd_tabent_eq, opd_del);
+ refent_htab = htab_try_create (100, opd_refent_hash, opd_refent_eq, opd_del);
+ l->htab = htab_try_create (100, opd_refent_hash, opd_refent_eq, opd_del);
+ if (tabent_htab == NULL || refent_htab == NULL || l->htab == NULL)
+ goto error_mem;
+
+ for (i = 0; i < info->ent->ndepends; ++i)
+ {
+ struct prelink_entry *ent;
+ struct prelink_conflict *conflict;
+ struct opd_lib *ol;
+ size_t maxidx = 1;
+
+ ent = info->ent->depends[i];
+ ol = ent->opd;
+ if (info->conflicts[i + 1].hash != &info->conflicts[i + 1].first)
+ maxidx = 251;
+ for (j = 0; j < ol->nrefs; ++j)
+ {
+ GElf_Addr symoff = ol->u.refs[j].symoff;
+ refent.val = ol->u.refs[j].ent->val;
+ refent.gp = ol->u.refs[j].ent->gp;
+ for (conflict = info->conflicts[i + 1].hash[symoff % maxidx]; conflict;
+ conflict = conflict->next)
+ {
+ if (conflict->symoff == symoff
+ && conflict->reloc_class != RTYPE_CLASS_COPY
+ && conflict->reloc_class != RTYPE_CLASS_TLS)
+ break;
+ }
+
+ if (conflict)
+ {
+ if (refent.val
+ != conflict->conflict.ent->base + conflict->conflictval
+ || refent.gp != conflict->conflict.ent->pltgot)
+ {
+ error (0, 0, "%s: OPD value changed during prelinking",
+ info->ent->filename);
+ goto error_out;
+ }
+
+ refent.val = conflict->lookup.ent->base + conflict->lookupval;
+ refent.gp = conflict->lookup.ent->pltgot;
+ }
+
+ if (ol->u.refs[j].ent->opd & OPD_ENT_PLT)
+ {
+ struct opd_ent_plt *entp
+ = (struct opd_ent_plt *) ol->u.refs[j].ent;
+ int k;
+ size_t idx = 0;
+
+ for (k = 0; k < info->ent->ndepends; ++k)
+ if (info->ent->depends[k] == entp->lib)
+ break;
+
+ assert (k < info->ent->ndepends);
+
+ if (info->conflicts[k + 1].hash != &info->conflicts[k + 1].first)
+ idx = entp->symoff % 251;
+ for (conflict = info->conflicts[k + 1].hash[idx]; conflict;
+ conflict = conflict->next)
+ {
+ if (conflict->symoff == entp->symoff
+ && conflict->reloc_class == RTYPE_CLASS_PLT)
+ break;
+ }
+
+ if (conflict)
+ {
+ if (ol->u.refs[j].ent->val
+ != conflict->conflict.ent->base + conflict->conflictval
+ || ol->u.refs[j].ent->gp
+ != conflict->conflict.ent->pltgot)
+ {
+ error (0, 0, "%s: OPD value changed during prelinking",
+ info->ent->filename);
+ goto error_out;
+ }
+
+ /* FPTR originally pointed into .plt, but since they
+ now resolve to different values, this cannot be used. */
+ if (refent.val
+ != conflict->lookup.ent->base + conflict->lookupval
+ || refent.gp != conflict->lookup.ent->pltgot)
+ continue;
+ }
+ else if (refent.val != ol->u.refs[j].ent->val
+ || refent.gp != ol->u.refs[j].ent->gp)
+ continue;
+ }
+
+ tabslot = htab_find_slot (refent_htab, &refent, INSERT);
+ if (tabslot == NULL)
+ goto error_mem;
+
+ if (*tabslot != NULL)
+ {
+ for (r = (struct opd_refent *) *tabslot; r; r = r->next)
+ if (r->tabent->ent == ol->u.refs[j].ent)
+ {
+ r->refcnt += ol->u.refs[j].refcnt;
+ break;
+ }
+
+ if (r)
+ continue;
+ }
+
+ r = (struct opd_refent *) calloc (sizeof (struct opd_refent), 1);
+ if (r == NULL)
+ goto error_mem;
+
+ ++nrefent;
+ r->next = (struct opd_refent *) *tabslot;
+ *tabslot = r;
+ r->val = refent.val;
+ r->gp = refent.gp;
+ r->refcnt = ol->u.refs[j].refcnt;
+
+ tabent.ent = ol->u.refs[j].ent;
+
+ tabslot = htab_find_slot (tabent_htab, &tabent, INSERT);
+ if (tabslot == NULL)
+ goto error_mem;
+
+ if (*tabslot != NULL)
+ {
+ t = (struct opd_tabent *) *tabslot;
+ t->ref->nextref = r;
+ r->nextref = t->ref;
+ }
+ else
+ {
+ t = (struct opd_tabent *) calloc (sizeof (struct opd_tabent), 1);
+ if (t == NULL)
+ goto error_mem;
+ t->ent = ol->u.refs[j].ent;
+ *tabslot = t;
+ r->nextref = r;
+ t->ref = r;
+ }
+
+ r->tabent = t;
+ }
+ }
+
+ refarr = alloca (nrefent * sizeof (struct opd_refent *));
+ a = refarr;
+ htab_traverse (refent_htab, opd_gather_refent, &a);
+ assert (a == refarr + nrefent);
+ qsort (refarr, nrefent, sizeof (struct opd_refent *), opd_refent_cmp);
+ for (i = 0; i < nrefent; ++i)
+ {
+ struct opd_fptr *f;
+
+ if (refarr[i]->tabent == NULL)
+ continue;
+
+ f = (struct opd_fptr *) calloc (sizeof (struct opd_fptr), 1);
+ if (f == NULL)
+ goto error_mem;
+
+ f->val = refarr[i]->val;
+ f->gp = refarr[i]->gp;
+ f->ent = refarr[i]->tabent->ent;
+ tabslot = htab_find_slot (l->htab, f, INSERT);
+ if (tabslot == NULL)
+ goto error_mem;
+
+ *tabslot = f;
+ r = refarr[i]->tabent->ref;
+ do
+ {
+ if (r != refarr[i])
+ r->tabent = NULL;
+ r = r->nextref;
+ }
+ while (r != refarr[i]->tabent->ref);
+
+ for (r = refarr[i]->first; r; r = r->next)
+ r->tabent = NULL;
+ }
+
+ htab_delete (tabent_htab);
+ htab_delete (refent_htab);
+ info->ent->opd = l;
+ return 0;
+
+error_mem:
+ error (0, ENOMEM, "%s: Could not create OPD table",
+ info->ent->filename);
+error_out:
+ if (tabent_htab)
+ htab_delete (tabent_htab);
+ if (refent_htab)
+ htab_delete (refent_htab);
+ if (l && l->htab)
+ htab_delete (l->htab);
+ free (l);
+ return 1;
+}
+
+int
+opd_add (struct prelink_info *info, GElf_Word r_sym, int reloc_type)
+{
+ struct opd_fptr *f, fp;
+ void **tabslot;
+ struct opd_lib *l = info->ent->opd;
+
+ if (l->u.refp[r_sym] != NULL)
+ {
+ ++l->u.refp[r_sym]->refcnt;
+ return 0;
+ }
+
+ if (ELF64_ST_BIND (info->symtab [r_sym].st_info)
+ == STB_LOCAL)
+ {
+ fp.val = info->symtab [r_sym].st_value;
+ fp.gp = info->ent->pltgot;
+ }
+ else
+ {
+ fp.val = info->resolve (info, r_sym, reloc_type);
+ if (info->resolveent == NULL)
+ return 0;
+ fp.gp = info->resolveent->pltgot;
+ }
+
+ l->u.refp[r_sym] = malloc (sizeof (struct opd_ref));
+ if (l->u.refp[r_sym] == NULL)
+ goto error_mem;
+ l->u.refp[r_sym]->symoff = r_sym;
+ l->u.refp[r_sym]->refcnt = 1;
+ l->u.refp[r_sym]->ent = NULL;
+
+ tabslot = htab_find_slot (l->htab, &fp, INSERT);
+ if (tabslot == NULL)
+ goto error_mem;
+
+ if (*tabslot == NULL)
+ {
+ f = calloc (sizeof (struct opd_fptr), 1);
+ if (f == NULL)
+ goto error_mem;
+ f->val = fp.val;
+ f->gp = fp.gp;
+ *tabslot = f;
+ }
+
+ l->u.refp[r_sym]->ent = *tabslot;
+ return 0;
+
+error_mem:
+ error (0, ENOMEM, "%s: Could not create OPD table",
+ info->ent->filename);
+ return 1;
+}
+
+void
+opd_note_plt (struct prelink_info *info, GElf_Word r_sym, int reloc_type,
+ GElf_Addr r_offset)
+{
+ struct opd_fptr *f, fp;
+ struct opd_lib *l = info->ent->opd;
+ struct opd_ent_plt *entp;
+
+ if (ELF64_ST_BIND (info->symtab [r_sym].st_info)
+ == STB_LOCAL)
+ {
+ fp.val = info->symtab [r_sym].st_value;
+ fp.gp = info->ent->pltgot;
+ }
+ else
+ {
+ fp.val = info->resolve (info, r_sym, reloc_type);
+ if (info->resolveent == NULL)
+ return;
+ fp.gp = info->resolveent->pltgot;
+ }
+
+ f = (struct opd_fptr *) htab_find (l->htab, &fp);
+ if (f == NULL || f->ent != NULL)
+ return;
+
+ entp = calloc (sizeof (struct opd_ent_plt), 1);
+ if (entp == NULL)
+ return;
+
+ entp->v.val = fp.val;
+ entp->v.gp = fp.gp;
+ entp->v.opd = (r_offset - l->plt_start) | (OPD_ENT_PLT | OPD_ENT_NEW);
+ entp->lib = info->ent;
+ entp->symoff = r_sym;
+ f->ent = &entp->v;
+}
+
+GElf_Addr
+opd_size (struct prelink_info *info, GElf_Word entsize)
+{
+ struct opd_lib *l = info->ent->opd;
+ int i;
+ GElf_Addr ret = 0;
+ struct opd_ent *e;
+ struct opd_fptr *f;
+
+ for (i = 0; i < l->nrefs; ++i)
+ if ((f = (struct opd_fptr *) l->u.refp[i]->ent)->ent == NULL)
+ {
+ e = calloc (sizeof (struct opd_ent), 1);
+ if (e == NULL)
+ {
+ error (0, ENOMEM, "%s: Could not create OPD table",
+ info->ent->filename);
+ return -1;
+ }
+
+ e->val = f->val;
+ e->gp = f->gp;
+ e->opd = ret | OPD_ENT_NEW;
+ ret += entsize;
+ }
+
+ return ret;
+}
diff --git a/src/fptr.h b/src/fptr.h
new file mode 100644
index 0000000..36ef7c6
--- /dev/null
+++ b/src/fptr.h
@@ -0,0 +1,67 @@
+/* Copyright (C) 2001 Red Hat, Inc.
+ Written by Jakub Jelinek <jakub@redhat.com>, 2001.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ifndef FPTR_H
+#define FPTR_H
+
+#include "prelink.h"
+#include "hashtab.h"
+
+struct opd_ent
+{
+ GElf_Addr val;
+ GElf_Addr gp;
+ GElf_Addr opd;
+#define OPD_ENT_PLT 1
+#define OPD_ENT_NEW 2
+};
+
+struct opd_ent_plt
+{
+ struct opd_ent v;
+ struct prelink_entry *lib;
+ GElf_Word symoff;
+};
+
+struct opd_ref
+{
+ GElf_Word symoff;
+ GElf_Word refcnt;
+ struct opd_ent *ent;
+};
+
+struct opd_lib
+{
+ GElf_Addr symtab_start;
+ GElf_Addr opd_start;
+ GElf_Addr plt_start;
+ union
+ {
+ struct opd_ref *refs;
+ struct opd_ref **refp;
+ } u;
+ htab_t htab;
+ int nrefs;
+};
+
+int opd_init (struct prelink_info *info);
+int opd_add (struct prelink_info *info, GElf_Word r_sym, int reloc_type);
+void opd_note_plt (struct prelink_info *info, GElf_Word r_sym, int reloc_type,
+ GElf_Addr r_offset);
+GElf_Addr opd_size (struct prelink_info *info, GElf_Word entsize);
+
+#endif /* FPTR_H */
diff --git a/src/gather.c b/src/gather.c
new file mode 100644
index 0000000..c61626e
--- /dev/null
+++ b/src/gather.c
@@ -0,0 +1,1496 @@
+/* Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007 Red Hat, Inc.
+ Written by Jakub Jelinek <jakub@redhat.com>, 2001.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include <config.h>
+#include <assert.h>
+#include <errno.h>
+#include <error.h>
+#include <fcntl.h>
+#include <fnmatch.h>
+#include <ftw.h>
+#include <glob.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "prelinktab.h"
+#include "reloc.h"
+
+#ifndef HAVE_FTW_ACTIONRETVAL
+# define FTW_ACTIONRETVAL 0
+# define FTW_CONTINUE 0
+# define FTW_STOP 1
+#endif
+
+static int gather_lib (struct prelink_entry *ent);
+static int implicit;
+
+static struct prelink_dir *dirs;
+static struct prelink_dir *blacklist;
+#ifndef HAVE_FTW_ACTIONRETVAL
+static char *blacklist_dir;
+static size_t blacklist_dir_len;
+#endif
+static struct extension
+{
+ const char *ext;
+ size_t len;
+ int is_glob;
+} *blacklist_ext;
+static int blacklist_next;
+
+static int
+gather_deps (DSO *dso, struct prelink_entry *ent)
+{
+ int i, j, seen = 0;
+ FILE *f = NULL;
+ const char *argv[8];
+ const char *envp[5];
+ char *line = NULL, *p, *q = NULL;
+ const char **depends = NULL, **depends_temp;
+ size_t ndepends = 0, ndepends_alloced = 0;
+ size_t len = 0;
+ ssize_t n;
+ Elf_Scn *scn;
+ Elf_Data *data;
+ Elf32_Lib *liblist = NULL;
+ int nliblist = 0;
+ const char *dl;
+ const char *ent_filename;
+ int etype = dso->ehdr.e_type;
+
+ if (check_dso (dso))
+ {
+ if (! undo)
+ ent->type = ET_UNPRELINKABLE;
+ goto error_out;
+ }
+
+ ent->pltgot = dso->info[DT_PLTGOT];
+ ent->soname = strdup (dso->soname);
+ ent->flags = (dso->arch->class == ELFCLASS64 ? PCF_ELF64 : 0)
+ | (dso->arch->machine & PCF_MACHINE);
+ if (ent->soname == NULL)
+ {
+ error (0, ENOMEM, "%s: Could not record SONAME", ent->filename);
+ goto error_out;
+ }
+
+ dl = dynamic_linker ?: dso->arch->dynamic_linker;
+ if (strcmp (dso->filename, dl) == 0
+ || is_ldso_soname (dso->soname))
+ {
+ if (dynamic_info_is_set (dso, DT_GNU_PRELINKED_BIT)
+ && dynamic_info_is_set (dso, DT_CHECKSUM_BIT))
+ {
+ if (! undo && dso->arch->read_opd)
+ dso->arch->read_opd (dso, ent);
+ ent->done = 2;
+ }
+ close_dso (dso);
+ return 0;
+ }
+
+ for (i = 1; i < dso->ehdr.e_shnum; ++i)
+ {
+ const char *name;
+ if (dso->shdr[i].sh_type == SHT_GNU_LIBLIST
+ && (name = strptr (dso, dso->ehdr.e_shstrndx, dso->shdr[i].sh_name))
+ && ! strcmp (name, ".gnu.liblist")
+ && (dso->shdr[i].sh_size % sizeof (Elf32_Lib)) == 0)
+ {
+ nliblist = dso->shdr[i].sh_size / sizeof (Elf32_Lib);
+ liblist = (Elf32_Lib *) alloca (dso->shdr[i].sh_size);
+ scn = dso->scn[i];
+ data = elf_getdata (scn, NULL);
+ if (data == NULL || elf_getdata (scn, data)
+ || data->d_buf == NULL || data->d_off
+ || data->d_size != dso->shdr[i].sh_size)
+ liblist = NULL;
+ else
+ memcpy (liblist, data->d_buf, dso->shdr[i].sh_size);
+ if (! undo)
+ break;
+ }
+ else if (undo
+ && dso->shdr[i].sh_type == SHT_PROGBITS
+ && (name = strptr (dso, dso->ehdr.e_shstrndx,
+ dso->shdr[i].sh_name))
+ && ! strcmp (name, ".gnu.prelink_undo"))
+ ent->done = 2;
+ }
+
+ if (! undo && dso->arch->read_opd)
+ dso->arch->read_opd (dso, ent);
+ close_dso (dso);
+ dso = NULL;
+
+ i = 0;
+ argv[i++] = dl;
+ if (strchr (ent->filename, '/') != NULL)
+ ent_filename = ent->filename;
+ else
+ {
+ size_t flen = strlen (ent->filename);
+ char *tp = alloca (2 + flen + 1);
+ memcpy (tp, "./", 2);
+ memcpy (tp + 2, ent->filename, flen + 1);
+ ent_filename = tp;
+ }
+
+ if (prelink_rtld == NULL)
+ {
+ i = 0;
+ argv[i++] = dl;
+ if (ld_library_path)
+ {
+ argv[i++] = "--library-path";
+ argv[i++] = ld_library_path;
+ }
+ argv[i++] = ent_filename;
+ argv[i] = NULL;
+ envp[0] = "LD_TRACE_LOADED_OBJECTS=1";
+ envp[1] = "LD_TRACE_PRELINKING=1";
+ envp[2] = "LD_WARN=";
+ envp[3] = NULL;
+ f = execve_open (dl, (char * const *)argv, (char * const *)envp);
+ }
+ else
+ {
+ char *path;
+ i = 0;
+ argv[i++] = prelink_rtld;
+ if (ld_library_path)
+ {
+ argv[i++] = "--library-path";
+ argv[i++] = ld_library_path;
+ }
+
+ if(etype == ET_EXEC && ld_preload) {
+ argv[i++] = "--ld-preload";
+ argv[i++] = ld_preload;
+ }
+ argv[i++] = "--target-paths";
+ argv[i++] = ent_filename;
+ argv[i] = NULL;
+ envp[0] = "RTLD_TRACE_PRELINKING=1";
+ envp[1] = "RTLD_WARN=";
+ path = alloca (sizeof "PATH=" + strlen (getenv ("PATH")));
+ sprintf (path, "PATH=%s", getenv ("PATH"));
+ envp[2] = path;
+
+ if (sysroot)
+ {
+ envp[3] = alloca (sizeof "PRELINK_SYSROOT=" + strlen (sysroot));
+ sprintf ((char *) envp[3], "PRELINK_SYSROOT=%s", sysroot);
+ envp[4] = NULL;
+ }
+ else
+ envp[3] = NULL;
+
+ f = execve_open (prelink_rtld, (char * const *)argv, (char * const *)envp);
+ }
+
+ if (f == NULL)
+ goto error_out;
+
+ do
+ {
+ n = getline (&line, &len, f);
+ if (n < 0)
+ break;
+
+ if (line[n - 1] == '\n')
+ line[n - 1] = '\0';
+
+ p = strstr (line, " => ");
+ if (p)
+ {
+ q = strstr (p, " (");
+ if (q == NULL && strcmp (p, " => not found") == 0)
+ {
+ error (0, 0, "%s: Could not find one of the dependencies: %s",
+ ent->filename, line);
+ goto error_out;
+ }
+ }
+ if (p == NULL || q == NULL)
+ {
+ if (strstr (line, "statically linked") != NULL)
+ error (0, 0, "%s: Library without dependencies", ent->filename);
+ else
+ {
+ p = strstr (line, "error while loading shared libraries: ");
+ if (p != NULL)
+ {
+ p += sizeof "error while loading shared libraries: " - 1;
+ q = strstr (line, "cannot open shared object file: "
+ "No such file or directory");
+ if (q != NULL)
+ {
+ error (0, 0,
+ "%s: Could not find one of the dependencies: \n%s",
+ ent->filename, line);
+ goto error_out;
+ }
+ }
+ error (0, 0, "%s: Could not parse `%s'", ent->filename, line);
+ }
+ goto error_out;
+ }
+
+ *p = '\0';
+ p += sizeof " => " - 1;
+ *q = '\0';
+ if (! strcmp (p, ent_filename))
+ {
+ ++seen;
+ continue;
+ }
+ if (ndepends == ndepends_alloced)
+ {
+ ndepends_alloced += 10;
+ depends_temp = depends;
+ depends =
+ (const char **) realloc (depends,
+ ndepends_alloced * sizeof (char *));
+ if (depends == NULL)
+ {
+ free(depends_temp);
+ error (0, ENOMEM, "%s: Could not record dependencies",
+ ent->filename);
+ goto error_out;
+ }
+ }
+
+ depends[ndepends] = strdupa (p);
+ ++ndepends;
+ } while (!feof (f));
+
+ if (execve_close (f))
+ {
+ f = NULL;
+ error (0, 0, "%s: Dependency tracing failed", ent->filename);
+ goto error_out;
+ }
+
+ f = NULL;
+ if (seen != 1)
+ {
+ error (0, 0, "%s seen %d times in LD_TRACE_PRELINKING output, expected once",
+ ent->filename, seen);
+ goto error_out;
+ }
+
+ free (line);
+ line = NULL;
+
+ if (ndepends == 0)
+ ent->depends = NULL;
+ else
+ {
+ ent->depends =
+ (struct prelink_entry **)
+ malloc (ndepends * sizeof (struct prelink_entry *));
+ if (ent->depends == NULL)
+ {
+ error (0, ENOMEM, "%s: Could not record dependencies", ent->filename);
+ goto error_out;
+ }
+ }
+
+ ent->ndepends = ndepends;
+ char *cache_dyn_depends = NULL;
+ if (ndepends)
+ {
+ cache_dyn_depends = alloca (ndepends);
+ memset (cache_dyn_depends, '\0', ndepends);
+ }
+ for (i = 0; i < ndepends; ++i)
+ {
+ ent->depends[i] = prelink_find_entry (depends [i], NULL, 1);
+ if (ent->depends[i] == NULL)
+ goto error_out_free_depends;
+
+ if (ent->depends[i]->type == ET_CACHE_DYN)
+ {
+ ent->depends[i]->type = ET_NONE;
+ free (ent->depends[i]->depends);
+ ent->depends[i]->depends = NULL;
+ ent->depends[i]->ndepends = 0;
+ cache_dyn_depends[i] = 1;
+ }
+
+ if (ent->depends[i]->type != ET_NONE
+ && ent->depends[i]->type != ET_BAD
+ && ent->depends[i]->type != ET_DYN
+ && ent->depends[i]->type != ET_UNPRELINKABLE)
+ {
+ error (0, 0, "%s is not a shared library", depends [i]);
+error_out_regather_libs:
+ for (i = 0; i < ndepends; ++i)
+ {
+ if (cache_dyn_depends[i] && ent->depends[i]->type == ET_NONE)
+ gather_lib (ent->depends[i]);
+ }
+ goto error_out_free_depends;
+ }
+ }
+
+ free (depends);
+ depends = NULL;
+
+ for (i = 0; i < ndepends; ++i)
+ if (ent->depends[i]->type == ET_NONE
+ && gather_lib (ent->depends[i]))
+ {
+ cache_dyn_depends[i] = 0;
+ goto error_out_regather_libs;
+ }
+
+ for (i = 0; i < ndepends; ++i)
+ for (j = 0; j < ent->depends[i]->ndepends; ++j)
+ if (ent->depends[i]->depends[j] == ent)
+ {
+ error (0, 0, "%s has a dependency cycle", ent->canon_filename);
+ goto error_out_free_depends;
+ }
+
+ for (i = 0; i < ndepends; ++i)
+ if (ent->depends[i]->type == ET_UNPRELINKABLE)
+ {
+ error (0, 0, "Could not prelink %s because its dependency %s could not be prelinked",
+ ent->filename, ent->depends[i]->filename);
+ ent->type = ET_UNPRELINKABLE;
+ goto error_out;
+ }
+
+ if (! undo && (!nliblist || liblist) && nliblist == ndepends)
+ {
+ for (i = 0; i < ndepends; ++i)
+ if (liblist[i].l_time_stamp != ent->depends[i]->timestamp
+ || liblist[i].l_checksum != ent->depends[i]->checksum
+ || ! ent->depends[i]->done)
+ break;
+
+ if (i == ndepends)
+ ent->done = 2;
+ }
+
+ return 0;
+
+error_out_free_depends:
+ free (ent->depends);
+ ent->depends = NULL;
+ ent->ndepends = 0;
+error_out:
+ if (f)
+ execve_close (f);
+ free (line);
+ free (depends);
+ if (dso)
+ close_dso (dso);
+ return 1;
+}
+
+static int
+gather_dso (DSO *dso, struct prelink_entry *ent)
+{
+ int prelinked;
+
+ if (verbose > 5)
+ printf ("Checking shared library %s\n", ent->canon_filename);
+
+ if (dso->ehdr.e_type != ET_DYN)
+ {
+ error (0, 0, "%s is not a shared library", ent->filename);
+ close_dso (dso);
+ return 1;
+ }
+
+ prelinked = (dynamic_info_is_set (dso, DT_GNU_PRELINKED_BIT)
+ && dynamic_info_is_set (dso, DT_CHECKSUM_BIT));
+ ent->timestamp = dso->info_DT_GNU_PRELINKED;
+ ent->checksum = dso->info_DT_CHECKSUM;
+ ent->base = dso->base;
+ ent->end = dso->end;
+ if (dso->arch->need_rel_to_rela != NULL && ! prelinked)
+ {
+ /* If the library has not been prelinked yet and we need
+ to convert REL to RELA, then make room for it. */
+ struct reloc_info rinfo;
+ GElf_Addr adjust = 0;
+ int sec = dso->ehdr.e_shnum;
+
+ if (find_reloc_sections (dso, &rinfo))
+ {
+ close_dso (dso);
+ return 1;
+ }
+
+ assert (sizeof (Elf32_Rel) * 3 == sizeof (Elf32_Rela) * 2);
+ assert (sizeof (Elf64_Rel) * 3 == sizeof (Elf64_Rela) * 2);
+ if (rinfo.rel_to_rela)
+ {
+ sec = rinfo.first;
+ adjust = (dso->shdr[rinfo.last].sh_addr
+ + dso->shdr[rinfo.last].sh_size
+ - dso->shdr[rinfo.first].sh_addr) / 2;
+ }
+ if (rinfo.rel_to_rela_plt)
+ {
+ if (rinfo.plt < sec)
+ sec = rinfo.plt;
+ adjust += dso->shdr[rinfo.plt].sh_size / 2;
+ }
+ if (adjust)
+ {
+ int align = 0, i, last;
+ GElf_Addr start;
+
+ for (i = rinfo.plt ? rinfo.plt : rinfo.first;
+ i < dso->ehdr.e_shnum; i++)
+ {
+ if (dso->shdr[i].sh_addralign > align)
+ align = dso->shdr[i].sh_addralign;
+ }
+
+ if (rinfo.plt)
+ start = dso->shdr[rinfo.plt].sh_addr
+ + dso->shdr[rinfo.plt].sh_size;
+ else
+ start = dso->shdr[rinfo.first].sh_addr
+ + dso->shdr[rinfo.first].sh_size;
+
+ /* Need to make sure that all the remaining sections are properly
+ aligned. */
+ if (align)
+ adjust = (adjust + align - 1) & ~(align - 1);
+
+ /* Need to make sure adjust doesn't cause different Phdr segments
+ to overlap on the same page. */
+ last = -1;
+ for (i = 0; i < dso->ehdr.e_phnum; ++i)
+ if (dso->phdr[i].p_type == PT_LOAD
+ && dso->phdr[i].p_vaddr + dso->phdr[i].p_memsz >= start)
+ {
+ if (last != -1
+ && (((dso->phdr[last].p_vaddr + dso->phdr[last].p_memsz
+ - 1) ^ dso->phdr[i].p_vaddr)
+ & ~(dso->arch->max_page_size - 1))
+ && !(((dso->phdr[last].p_vaddr + dso->phdr[last].p_memsz
+ + adjust - 1)
+ ^ (dso->phdr[i].p_vaddr + adjust))
+ & ~(dso->arch->max_page_size - 1)))
+ {
+ if (align >= dso->arch->max_page_size)
+ {
+ error (0, 0, "%s: Cannot grow reloc sections",
+ ent->filename);
+ close_dso (dso);
+ return 1;
+ }
+ adjust = (adjust + dso->arch->max_page_size - 1)
+ & ~(dso->arch->max_page_size - 1);
+ }
+ last = i;
+ }
+
+ ent->end += adjust;
+ }
+ }
+
+ if (gather_deps (dso, ent))
+ return 1;
+
+ if (ent->done && ! prelinked && ! undo)
+ ent->done = 0;
+ ent->type = ET_DYN;
+ return 0;
+}
+
+static int
+gather_lib (struct prelink_entry *ent)
+{
+ DSO *dso;
+
+ ent->type = ET_BAD;
+ dso = open_dso (ent->filename);
+ if (dso == NULL)
+ return 1;
+
+ return gather_dso (dso, ent);
+}
+
+static int
+gather_exec (DSO *dso, const struct stat64 *st)
+{
+ int i, j;
+ Elf_Data *data;
+ const char *dl;
+ struct prelink_entry *ent;
+
+ if (verbose > 5)
+ printf ("Checking executable %s\n", dso->filename);
+
+ for (i = 0; i < dso->ehdr.e_phnum; ++i)
+ if (dso->phdr[i].p_type == PT_INTERP)
+ break;
+
+ /* If there are no PT_INTERP segments, it is statically linked. */
+ if (i == dso->ehdr.e_phnum)
+ {
+make_unprelinkable:
+ if (undo)
+ goto error_out;
+
+ ent = prelink_find_entry (dso->filename, st, 1);
+ if (ent == NULL)
+ goto error_out;
+
+ assert (ent->type == ET_NONE);
+ ent->type = ET_UNPRELINKABLE;
+ close_dso (dso);
+ return 0;
+ }
+
+ j = addr_to_sec (dso, dso->phdr[i].p_vaddr);
+ if (j == -1 || dso->shdr[j].sh_addr != dso->phdr[i].p_vaddr
+ || dso->shdr[j].sh_type != SHT_PROGBITS)
+ {
+ error (0, 0, "%s: PT_INTERP segment not corresponding to .interp section",
+ dso->filename);
+ goto make_unprelinkable;
+ }
+
+ data = elf_getdata (dso->scn[j], NULL);
+ if (data == NULL)
+ {
+ error (0, 0, "%s: Could not read .interp section", dso->filename);
+ goto error_out;
+ }
+
+ i = strnlen (data->d_buf, data->d_size);
+ if (i == data->d_size)
+ {
+ error (0, 0, "%s: .interp section not zero terminated", dso->filename);
+ goto error_out;
+ }
+
+ dl = dynamic_linker ?: dso->arch->dynamic_linker;
+ if (strcmp (dl, data->d_buf) != 0
+ && (dynamic_linker != NULL || dso->arch->dynamic_linker_alt == NULL
+ || strcmp (dso->arch->dynamic_linker_alt, data->d_buf) != 0))
+ {
+ error (0, 0, "%s: Using %s, not %s as dynamic linker", dso->filename,
+ (char *) data->d_buf, dl);
+ goto error_out;
+ }
+
+ if (dso_has_bad_textrel (dso))
+ {
+ error (0, 0, "%s has text relocations", dso->filename);
+ goto make_unprelinkable;
+ }
+
+ ent = prelink_find_entry (dso->filename, st, 1);
+ if (ent == NULL)
+ goto error_out;
+
+ assert (ent->type == ET_NONE);
+ ent->u.explicit = 1;
+
+ if (gather_deps (dso, ent))
+ return 0;
+
+ for (i = 0; i < ent->ndepends; ++i)
+ ++ent->depends[i]->refs;
+
+ ent->type = ET_EXEC;
+ return 0;
+
+error_out:
+ if (dso)
+ close_dso (dso);
+ return 0;
+}
+
+static int
+add_dir_to_dirlist (const char *name, dev_t dev, int flags)
+{
+ const char *canon_name;
+ struct prelink_dir *dir;
+ size_t len;
+
+ canon_name = prelink_canonicalize (name, NULL);
+ if (canon_name == NULL)
+ {
+ if (! all && implicit)
+ return 0;
+ error (0, errno, "Could not record directory %s", name);
+ return 1;
+ }
+
+ len = strlen (canon_name);
+
+ for (dir = blacklist; dir; dir = dir->next)
+ if (((dir->flags != FTW_CHDIR && len >= dir->len)
+ || (dir->flags == FTW_CHDIR && len == dir->len))
+ && strncmp (dir->dir, canon_name, dir->len) == 0)
+ {
+ if (dir->flags == FTW_CHDIR)
+ break;
+ if ((dir->flags & FTW_MOUNT) && dir->dev != dev)
+ continue;
+ break;
+ }
+
+ if (dir != NULL)
+ {
+ free ((char *) canon_name);
+ return 2;
+ }
+
+ dir = malloc (sizeof (struct prelink_dir) + len + 1);
+ if (dir == NULL)
+ {
+ error (0, ENOMEM, "Could not record directory %s", name);
+ free ((char *) canon_name);
+ return 1;
+ }
+
+ dir->next = dirs;
+ dir->flags = flags;
+ dir->dev = dev;
+ dir->len = len;
+ strcpy (dir->dir, canon_name);
+ free ((char *) canon_name);
+ dirs = dir;
+ return 0;
+}
+
+/* Determine if a buffer holding an ELF header and program header
+ table may be that of a position-independent executable. */
+static int
+maybe_pie (unsigned char *e_ident, int big_endian, int sixty_four)
+{
+ uint16_t num_phdrs;
+ uint16_t phdr;
+ size_t p_type_offset;
+ size_t phnum_offset;
+ unsigned char *phdr_table;
+ unsigned char *this_phdr;
+
+ if (sixty_four)
+ {
+ uint64_t phdr_offset;
+
+ p_type_offset = offsetof (Elf64_Phdr, p_type);
+ phnum_offset = offsetof (Elf64_Ehdr, e_phnum);
+ if (big_endian)
+ phdr_offset = buf_read_ube64 (&e_ident [offsetof (Elf64_Ehdr,
+ e_phoff)]);
+ else
+ phdr_offset = buf_read_ule64 (&e_ident [offsetof (Elf64_Ehdr,
+ e_phoff)]);
+ phdr_table = e_ident + phdr_offset;
+ }
+ else
+ {
+ uint32_t phdr_offset;
+
+ p_type_offset = offsetof (Elf32_Phdr, p_type);
+ phnum_offset = offsetof (Elf32_Ehdr, e_phnum);
+ if (big_endian)
+ phdr_offset = buf_read_ube32 (&e_ident [offsetof (Elf32_Ehdr,
+ e_phoff)]);
+ else
+ phdr_offset = buf_read_ule32 (&e_ident [offsetof (Elf32_Ehdr,
+ e_phoff)]);
+ phdr_table = e_ident + phdr_offset;
+ }
+
+ this_phdr = phdr_table;
+
+ if (big_endian)
+ num_phdrs = buf_read_ube16 (&e_ident [phnum_offset]);
+ else
+ num_phdrs = buf_read_ule16 (&e_ident [phnum_offset]);
+
+ for (phdr = 0; phdr < num_phdrs; phdr++)
+ {
+ unsigned char *p_type_start = this_phdr + p_type_offset;
+ uint32_t p_type;
+
+ if (big_endian)
+ p_type = buf_read_ube32 (p_type_start);
+ else
+ p_type = buf_read_ule32 (p_type_start);
+
+ if (p_type == PT_PHDR)
+ return 1;
+
+ /* Any PT_PHDR entry must come before any PT_LOAD entry. */
+ if (p_type == PT_LOAD)
+ return 0;
+
+ this_phdr += sixty_four ? sizeof (Elf64_Phdr) : sizeof (Elf32_Phdr);
+ }
+
+ return 0;
+}
+
+static int
+gather_func (const char *name, const struct stat64 *st, int type,
+ struct FTW *ftwp)
+{
+ unsigned char e_ident [sizeof (Elf64_Ehdr) + sizeof (Elf64_Phdr)];
+
+#ifndef HAVE_FTW_ACTIONRETVAL
+ if (blacklist_dir)
+ {
+ if (strncmp (name, blacklist_dir, blacklist_dir_len) == 0)
+ return FTW_CONTINUE;
+ free (blacklist_dir);
+ blacklist_dir = NULL;
+ }
+#endif
+ if (type == FTW_F && S_ISREG (st->st_mode) && (st->st_mode & 0111))
+ {
+ int fd, i;
+ DSO *dso;
+ struct prelink_entry *ent;
+ size_t len = strlen (name);
+ const char *base = NULL;
+
+ for (i = 0; i < blacklist_next; ++i)
+ if (blacklist_ext[i].is_glob)
+ {
+ if (base == NULL)
+ {
+ base = strrchr (name, '/');
+ if (base == NULL)
+ base = name;
+ else
+ ++base;
+ }
+ if (fnmatch (blacklist_ext[i].ext, base, FNM_PERIOD) == 0)
+ return FTW_CONTINUE;
+ }
+ else if (blacklist_ext[i].len <= len
+ && memcmp (name + len - blacklist_ext[i].len,
+ blacklist_ext[i].ext, blacklist_ext[i].len) == 0)
+ return FTW_CONTINUE;
+
+ ent = prelink_find_entry (name, st, 0);
+ if (ent != NULL && ent->type != ET_NONE)
+ {
+ if (verbose > 5)
+ {
+ if (ent->type == ET_CACHE_EXEC || ent->type == ET_CACHE_DYN)
+ printf ("Assuming prelinked %s\n", name);
+ if (ent->type == ET_UNPRELINKABLE)
+ printf ("Assuming non-prelinkable %s\n", name);
+ }
+ ent->u.explicit = 1;
+ return FTW_CONTINUE;
+ }
+
+ if (st->st_size < sizeof (e_ident))
+ return FTW_CONTINUE;
+
+ fd = wrap_open (name, O_RDONLY);
+ if (fd == -1)
+ return FTW_CONTINUE;
+
+ if (read (fd, e_ident, sizeof (e_ident)) != sizeof (e_ident))
+ {
+close_it:
+ fsync (fd);
+ close (fd);
+ return FTW_CONTINUE;
+ }
+
+ /* Quickly find ET_EXEC ELF binaries and most of PIE binaries. */
+
+ if (memcmp (e_ident, ELFMAG, SELFMAG) != 0)
+ {
+make_unprelinkable:
+ if (! undo)
+ {
+ ent = prelink_find_entry (name, st, 1);
+ if (ent != NULL)
+ {
+ assert (ent->type == ET_NONE);
+ ent->type = ET_UNPRELINKABLE;
+ }
+ }
+ fsync (fd);
+ close (fd);
+ return FTW_CONTINUE;
+ }
+
+ switch (e_ident [EI_DATA])
+ {
+ case ELFDATA2LSB:
+ if (e_ident [EI_NIDENT + 1] != 0)
+ goto make_unprelinkable;
+ if (e_ident [EI_NIDENT] != ET_EXEC)
+ {
+ if (e_ident [EI_NIDENT] != ET_DYN)
+ goto make_unprelinkable;
+ else if (e_ident [EI_CLASS] == ELFCLASS32)
+ {
+ if (maybe_pie (e_ident, 0, 0))
+ {
+maybe_pie:
+ dso = fdopen_dso (fd, name);
+ if (dso == NULL)
+ goto close_it;
+ if (dynamic_info_is_set (dso, DT_DEBUG))
+ {
+ close_dso (dso);
+ goto make_unprelinkable;
+ }
+ close_dso (dso);
+ }
+ goto close_it;
+ }
+ else if (e_ident [EI_CLASS] == ELFCLASS64)
+ {
+ if (maybe_pie (e_ident, 0, 1))
+ goto maybe_pie;
+ goto close_it;
+ }
+ else
+ goto make_unprelinkable;
+ }
+ break;
+ case ELFDATA2MSB:
+ if (e_ident [EI_NIDENT] != 0)
+ goto make_unprelinkable;
+ if (e_ident [EI_NIDENT + 1] != ET_EXEC)
+ {
+ if (e_ident [EI_NIDENT + 1] != ET_DYN)
+ goto make_unprelinkable;
+ else if (e_ident [EI_CLASS] == ELFCLASS32)
+ {
+ if (maybe_pie (e_ident, 1, 0))
+ goto maybe_pie;
+ goto close_it;
+ }
+ else if (e_ident [EI_CLASS] == ELFCLASS64)
+ {
+ if (maybe_pie (e_ident, 1, 1))
+ goto maybe_pie;
+ goto close_it;
+ }
+ else
+ goto make_unprelinkable;
+ }
+ break;
+ default:
+ goto make_unprelinkable;
+ }
+
+ dso = fdopen_dso (fd, name);
+ if (dso == NULL)
+ return FTW_CONTINUE;
+
+ gather_exec (dso, st);
+ }
+ else if (type == FTW_D)
+ switch (add_dir_to_dirlist (name, st->st_dev, FTW_CHDIR))
+ {
+ case 0: return FTW_CONTINUE;
+ default: return FTW_STOP;
+ case 2:
+#ifdef HAVE_FTW_ACTIONRETVAL
+ return FTW_SKIP_SUBTREE;
+#else
+ {
+ blacklist_dir_len = strlen (name) + 1;
+ if (blacklist_dir_len > 1 && name[blacklist_dir_len - 2] == '/')
+ blacklist_dir_len--;
+ blacklist_dir = malloc (blacklist_dir_len + 1);
+ if (blacklist_dir == NULL)
+ {
+ error (0, ENOMEM, "Cannot store blacklisted dir name");
+ return FTW_STOP;
+ }
+ memcpy (blacklist_dir, name, blacklist_dir_len - 1);
+ blacklist_dir[blacklist_dir_len - 1] = '/';
+ blacklist_dir[blacklist_dir_len] = '\0';
+ return FTW_CONTINUE;
+ }
+#endif
+ }
+
+ return FTW_CONTINUE;
+}
+
+static int
+gather_binlib (const char *name, const struct stat64 *st)
+{
+ unsigned char e_ident [EI_NIDENT + 2];
+ int fd, type;
+ DSO *dso;
+ struct prelink_entry *ent;
+
+ if (! S_ISREG (st->st_mode))
+ {
+ error (0, 0, "%s is not a regular file", name);
+ return 1;
+ }
+
+ ent = prelink_find_entry (name, st, 0);
+ if (ent != NULL && ent->type == ET_UNPRELINKABLE)
+ {
+ free (ent->depends);
+ ent->depends = NULL;
+ ent->ndepends = 0;
+ ent->type = ET_NONE;
+ }
+ if (ent != NULL && ent->type != ET_NONE)
+ {
+ ent->u.explicit = 1;
+ return 0;
+ }
+
+ fd = wrap_open (name, O_RDONLY);
+ if (fd == -1)
+ {
+ error (0, errno, "Could not open %s", name);
+ return 1;
+ }
+
+ if (read (fd, e_ident, sizeof (e_ident)) != sizeof (e_ident))
+ {
+ error (0, errno, "Could not read ELF header from %s", name);
+ fsync (fd);
+ close (fd);
+ return 1;
+ }
+
+ /* Quickly find ET_EXEC/ET_DYN ELF binaries/libraries only. */
+
+ if (memcmp (e_ident, ELFMAG, SELFMAG) != 0)
+ {
+ error (0, 0, "%s is not an ELF object", name);
+ fsync (fd);
+ close (fd);
+ return 1;
+ }
+
+ switch (e_ident [EI_DATA])
+ {
+ case ELFDATA2LSB:
+ if (e_ident [EI_NIDENT + 1] != 0)
+ goto unsupported_type;
+ type = e_ident [EI_NIDENT];
+ break;
+ case ELFDATA2MSB:
+ if (e_ident [EI_NIDENT] != 0)
+ goto unsupported_type;
+ type = e_ident [EI_NIDENT + 1];
+ break;
+ default:
+ goto unsupported_type;
+ }
+
+ if (type != ET_EXEC && type != ET_DYN)
+ {
+unsupported_type:
+ error (0, 0, "%s is neither ELF executable nor ELF shared library", name);
+ fsync (fd);
+ close (fd);
+ return 1;
+ }
+
+ dso = fdopen_dso (fd, name);
+ if (dso == NULL)
+ return 0;
+
+ if (type == ET_EXEC)
+ {
+ int i;
+
+ for (i = 0; i < dso->ehdr.e_phnum; ++i)
+ if (dso->phdr[i].p_type == PT_INTERP)
+ break;
+
+ /* If there are no PT_INTERP segments, it is statically linked. */
+ if (i == dso->ehdr.e_phnum)
+ {
+ error (0, 0, "%s is statically linked", name);
+ close_dso (dso);
+ return 1;
+ }
+
+ return gather_exec (dso, st);
+ }
+
+ ent = prelink_find_entry (name, st, 1);
+ if (ent == NULL)
+ {
+ close_dso (dso);
+ return 1;
+ }
+
+ assert (ent->type == ET_NONE);
+ ent->type = ET_BAD;
+ ent->u.explicit = 1;
+ return gather_dso (dso, ent);
+}
+
+int
+gather_object (const char *name, int deref, int onefs)
+{
+ struct stat64 st;
+
+ if (wrap_stat64 (name, &st) < 0)
+ {
+ if (implicit)
+ return 0;
+ error (0, errno, "Could not stat %s", name);
+ return 1;
+ }
+
+ if (S_ISDIR (st.st_mode))
+ {
+ int flags = 0, ret;
+ if (! deref) flags |= FTW_PHYS;
+ if (onefs) flags |= FTW_MOUNT;
+
+ if (implicit && ! deref)
+ {
+ ret = add_dir_to_dirlist (name, st.st_dev, flags);
+ if (ret)
+ return ret == 2 ? 0 : 1;
+ }
+ if (!all && implicit && ! deref)
+ return 0;
+ ++implicit;
+ ret = wrap_nftw64 (name, gather_func, 20, flags | FTW_ACTIONRETVAL);
+ --implicit;
+ if (ret < 0)
+ error (0, errno, "Failed searching %s", name);
+#ifndef HAVE_FTW_ACTIONRETVAL
+ free (blacklist_dir);
+ blacklist_dir = NULL;
+#endif
+ return ret;
+ }
+ else
+ return gather_binlib (name, &st);
+}
+
+static struct config_line
+{
+ struct config_line *next;
+ char line[1];
+} *config_lines, **config_end = &config_lines;
+
+int
+read_config (const char *config)
+{
+ FILE *file = fopen (config, "r");
+ char *line = NULL;
+ size_t len, llen;
+ int ret = 0;
+ struct config_line *c;
+
+ if (file == NULL)
+ {
+ error (0, errno, "Can't open configuration file %s", config);
+ return 1;
+ }
+
+ do
+ {
+ ssize_t i = getline (&line, &len, file);
+ char *p;
+
+ if (i < 0)
+ break;
+
+ if (line[i - 1] == '\n')
+ line[i - 1] = '\0';
+
+ p = strchr (line, '#');
+ if (p != NULL)
+ *p = '\0';
+
+ p = line + strspn (line, " \t");
+ if (p[0] == '-' && p[1] == 'c' && (p[2] == ' ' || p[2] == '\t'))
+ {
+ glob_t g;
+ p += 2 + strspn (p + 2, " \t");
+
+ if (!wrap_glob (p, GLOB_BRACE, NULL, &g))
+ {
+ size_t n;
+
+ for (n = 0; n < g.gl_pathc; ++n)
+ if (read_config (g.gl_pathv[n]))
+ {
+ ret = 1;
+ break;
+ }
+
+ globfree (&g);
+ if (ret)
+ break;
+ }
+ continue;
+ }
+
+ llen = strlen (p);
+ c = malloc (sizeof (*c) + llen);
+ if (c == NULL)
+ {
+ error (0, ENOMEM, "Could not cache config file");
+ ret = 1;
+ break;
+ }
+
+ c->next = NULL;
+ memcpy (c->line, p, llen + 1);
+ *config_end = c;
+ config_end = &c->next;
+ }
+ while (!feof (file));
+
+ free (line);
+ fclose (file);
+ return ret;
+}
+
+int
+gather_config (void)
+{
+ struct config_line *c;
+ int ret = 0;
+
+ implicit = 1;
+ for (c = config_lines; c; c = c->next)
+ {
+ int deref = 0;
+ int onefs = 0;
+ char *p = c->line;
+
+ while (*p == '-')
+ {
+ switch (p[1])
+ {
+ case 'h': deref = 1; break;
+ case 'l': onefs = 1; break;
+ case 'b': p = ""; continue;
+ default:
+ error (0, 0, "Unknown directory option `%s'\n", p);
+ break;
+ }
+ p = p + 2 + strspn (p + 2, " \t");
+ }
+
+ if (*p == '\0')
+ continue;
+
+ if (strpbrk (p, "*?[{") == NULL)
+ {
+ ret = gather_object (p, deref, onefs);
+ if (ret)
+ {
+ ret = 1;
+ break;
+ }
+ }
+ else
+ {
+ glob_t g;
+
+ if (!wrap_glob (p, GLOB_BRACE, NULL, &g))
+ {
+ size_t n;
+
+ for (n = 0; n < g.gl_pathc; ++n)
+ {
+ ret = gather_object (g.gl_pathv[n], deref, onefs);
+ if (ret)
+ {
+ ret = 1;
+ break;
+ }
+ }
+
+ globfree (&g);
+ if (ret)
+ break;
+ }
+ }
+ }
+
+ implicit = 0;
+ return ret;
+}
+
+static int
+gather_check_lib (void **p, void *info)
+{
+ struct prelink_entry *e = * (struct prelink_entry **) p;
+
+ if (e->type != ET_DYN)
+ return 1;
+
+ if (! e->u.explicit)
+ {
+ struct prelink_dir *dir;
+ const char *name;
+ size_t len;
+
+ name = strrchr (e->canon_filename, '/');
+ if (!name)
+ name = e->canon_filename;
+ len = name - e->canon_filename;
+
+ for (dir = blacklist; dir; dir = dir->next)
+ if (((dir->flags != FTW_CHDIR && len >= dir->len)
+ || (dir->flags == FTW_CHDIR && len == dir->len))
+ && strncmp (dir->dir, e->canon_filename, dir->len) == 0)
+ {
+ if (dir->flags == FTW_CHDIR)
+ break;
+ if ((dir->flags & FTW_MOUNT) && dir->dev != e->dev)
+ continue;
+ break;
+ }
+
+ if (dir != NULL)
+ {
+ error (0, 0, "%s is present in a blacklisted directory %s",
+ e->canon_filename, dir->dir);
+ e->type = ET_BAD;
+ return 1;
+ }
+
+ for (dir = dirs; dir; dir = dir->next)
+ if (((dir->flags != FTW_CHDIR && len >= dir->len)
+ || (dir->flags == FTW_CHDIR && len == dir->len))
+ && strncmp (dir->dir, e->canon_filename, dir->len) == 0)
+ {
+ if (dir->flags == FTW_CHDIR)
+ break;
+ if ((dir->flags & FTW_MOUNT) && dir->dev != e->dev)
+ continue;
+ break;
+ }
+
+ if (dir == NULL)
+ {
+ error (0, 0, "%s is not present in any config file directories, nor was specified on command line",
+ e->canon_filename);
+ e->type = ET_BAD;
+ return 1;
+ }
+ }
+
+ return 1;
+}
+
+int
+gather_check_libs (void)
+{
+ struct prelink_dir *dir;
+ void *f;
+
+ htab_traverse (prelink_filename_htab, gather_check_lib, NULL);
+
+ dir = dirs;
+ while (dir != NULL)
+ {
+ f = dir;
+ dir = dir->next;
+ free (f);
+ }
+
+ dir = blacklist;
+ while (dir != NULL)
+ {
+ f = dir;
+ dir = dir->next;
+ free (f);
+ }
+
+ dirs = NULL;
+ blacklist = NULL;
+ return 0;
+}
+
+int
+add_to_blacklist (const char *name, int deref, int onefs)
+{
+ const char *canon_name;
+ struct prelink_dir *path;
+ size_t len;
+ struct stat64 st;
+
+ if (wrap_stat64 (name, &st) < 0)
+ {
+ if (implicit)
+ return 0;
+ error (0, errno, "Could not stat %s", name);
+ return 1;
+ }
+
+ if (!S_ISDIR (st.st_mode))
+ {
+ struct prelink_entry *ent;
+
+ ent = prelink_find_entry (name, &st, 1);
+ if (ent == NULL)
+ return 1;
+
+ ent->type = ET_BAD;
+ ent->u.explicit = 1;
+ return 0;
+ }
+
+ canon_name = prelink_canonicalize (name, NULL);
+ if (canon_name == NULL)
+ {
+ if (implicit)
+ return 0;
+ error (0, errno, "Could not canonicalize %s", name);
+ return 1;
+ }
+
+ len = strlen (canon_name);
+ path = malloc (sizeof (struct prelink_dir) + len + 1);
+ if (path == NULL)
+ {
+ error (0, ENOMEM, "Could not record path %s", name);
+ free ((char *) canon_name);
+ return 1;
+ }
+
+ path->next = blacklist;
+ path->flags = 0;
+ if (! deref) path->flags |= FTW_PHYS;
+ if (onefs) path->flags |= FTW_MOUNT;
+ path->dev = 0;
+ path->len = len;
+ strcpy (path->dir, canon_name);
+ free ((char *) canon_name);
+ blacklist = path;
+ return 0;
+}
+
+void
+add_blacklist_ext (const char *ext)
+{
+ blacklist_ext = realloc (blacklist_ext,
+ (blacklist_next + 1) * sizeof (*blacklist_ext));
+ if (blacklist_ext == NULL)
+ error (EXIT_FAILURE, errno, "can't create blacklist extension list");
+ if (*ext == '*' && strpbrk (ext + 1, "*?[{") == NULL)
+ {
+ blacklist_ext[blacklist_next].is_glob = 0;
+ ext++;
+ }
+ else
+ blacklist_ext[blacklist_next].is_glob = 1;
+ blacklist_ext[blacklist_next].ext = strdup (ext);
+ if (blacklist_ext[blacklist_next].ext == NULL)
+ error (EXIT_FAILURE, errno, "can't create blacklist extension list");
+ blacklist_ext[blacklist_next].len = strlen (ext);
+ blacklist_next++;
+}
+
+int
+blacklist_from_config (void)
+{
+ struct config_line *c;
+ int ret = 0;
+
+ implicit = 1;
+ for (c = config_lines; c; c = c->next)
+ {
+ int deref = 0;
+ int onefs = 0;
+ int blacklist = 0;
+ char *p = c->line;
+
+ while (*p == '-')
+ {
+ switch (p[1])
+ {
+ case 'h': deref = 1; break;
+ case 'l': onefs = 1; break;
+ case 'b': blacklist = 1; break;
+ }
+ p = p + 2 + strspn (p + 2, " \t");
+ }
+
+ if (*p == '\0' || !blacklist)
+ continue;
+
+ if (strchr (p, '/') == NULL)
+ {
+ add_blacklist_ext (p);
+ continue;
+ }
+
+ if (strpbrk (p, "*?[{") == NULL)
+ {
+ ret = add_to_blacklist (p, deref, onefs);
+ if (ret)
+ {
+ ret = 1;
+ break;
+ }
+ }
+ else
+ {
+ glob_t g;
+
+ if (!wrap_glob (p, GLOB_BRACE | GLOB_PERIOD, NULL, &g))
+ {
+ size_t n;
+
+ for (n = 0; n < g.gl_pathc; ++n)
+ {
+ ret = add_to_blacklist (g.gl_pathv[n], deref, onefs);
+ if (ret)
+ {
+ ret = 1;
+ break;
+ }
+ }
+
+ globfree (&g);
+ if (ret)
+ break;
+ }
+ }
+ }
+
+ implicit = 0;
+ return ret;
+}
diff --git a/src/get.c b/src/get.c
new file mode 100644
index 0000000..d10efcc
--- /dev/null
+++ b/src/get.c
@@ -0,0 +1,760 @@
+/* Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007, 2009 Red Hat, Inc.
+ Written by Jakub Jelinek <jakub@redhat.com>, 2001.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include <config.h>
+#include <assert.h>
+#include <errno.h>
+#include <error.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include "prelink.h"
+
+int
+is_ldso_soname (const char *soname)
+{
+ if (! strcmp (soname, "ld-linux.so.2")
+ || ! strcmp (soname, "ld.so.1")
+ || ! strcmp (soname, "ld-linux-ia64.so.2")
+ || ! strcmp (soname, "ld-linux-x86-64.so.2")
+ || ! strcmp (soname, "ld64.so.1")
+ || ! strcmp (soname, "ld-linux.so.3")
+ || ! strcmp (soname, "ld-linux-armhf.so.3"))
+ return 1;
+ return 0;
+}
+
+static void
+conflict_hash_init (struct prelink_conflicts *conflicts)
+{
+ struct prelink_conflict **hash
+ = calloc (sizeof (struct prelink_conflict *), 251);
+ struct prelink_conflict *conflict, *next;
+ size_t idx;
+
+ if (hash == NULL)
+ return;
+
+ for (conflict = conflicts->first; conflict; conflict = next)
+ {
+ next = conflict->next;
+ idx = conflict->symoff % 251;
+ conflict->next = hash[idx];
+ hash[idx] = conflict;
+ }
+ conflicts->hash = hash;
+}
+
+static int
+prelink_record_relocations (struct prelink_info *info, FILE *f,
+ const char *ent_filename)
+{
+ char buffer[8192];
+ DSO *dso = info->dso;
+ struct prelink_entry *ent, *ent2;
+ struct prelink_tls *tls;
+ struct deps
+ {
+ struct prelink_entry *ent;
+ char *soname;
+ GElf_Addr start;
+ GElf_Addr l_addr;
+ GElf_Addr tls_modid;
+ GElf_Addr tls_offset;
+ } deps[info->ent->ndepends + 1];
+ char *r;
+ int i, ndeps = 0, undef = 0, seen = 0, tdeps = 0;
+ int mask_32bit = (info->dso->ehdr.e_ident[EI_CLASS] == ELFCLASS32);
+
+ /* Record the dependencies. */
+ while ((r = fgets (buffer, 8192, f)) != NULL)
+ {
+ char *soname, *filename, *p, *q;
+ GElf_Addr start = 0, l_addr = 0, tls_modid = 0, tls_offset = 0;
+ unsigned long long l;
+
+ if (buffer[0] != '\t' || (filename = strstr (buffer, " => ")) == NULL)
+ break;
+ soname = buffer + 1;
+ p = strstr (filename + sizeof (" => "), " (0x");
+ if (p != NULL)
+ {
+ l = strtoull (p + sizeof (" (0x") - 1, &q, 16);
+ start = (GElf_Addr) l;
+ if (start != l || strncmp (q, ", 0x", sizeof (", 0x") - 1))
+ p = NULL;
+ else
+ {
+ l = strtoull (q + sizeof (", 0x") - 1, &q, 16);
+ l_addr = (GElf_Addr) l;
+ if (l_addr != l || q[-1] == 'x')
+ p = NULL;
+ else if (strncmp (q, ") TLS(0x", sizeof (") TLS(0x") - 1) == 0)
+ {
+ l = strtoull (q + sizeof (") TLS(0x") - 1, &q, 16);
+ tls_modid = (GElf_Addr) l;
+ if (tls_modid != l || q[-1] == 'x'
+ || strncmp (q, ", 0x", sizeof (", 0x") - 1))
+ p = NULL;
+ else
+ {
+ l = strtoull (q + sizeof (", 0x") - 1, &q, 16);
+ tls_offset = (GElf_Addr) l;
+ if (tls_offset != l || q[-1] == 'x')
+ p = NULL;
+ }
+ }
+ if (p && strcmp (q, ")\n"))
+ p = NULL;
+ }
+ }
+ if (p == NULL)
+ {
+ p = strchr (buffer, '\n');
+ if (p != NULL)
+ *p = '\0';
+ error (0, 0, "Could not parse line `%s'", buffer);
+ goto error_out;
+ }
+ *filename = '\0';
+ filename += sizeof (" => ") - 1;
+ *p = '\0';
+
+ if (ndeps > info->ent->ndepends)
+ {
+ error (0, 0, "%s: Recorded %d dependencies, now seeing %d\n",
+ info->ent->filename, info->ent->ndepends, ndeps - 1);
+ goto error_out;
+ }
+
+ tdeps = ndeps - seen + 1;
+ if (! seen
+ && (strcmp (info->ent->filename, filename) == 0
+ || (info->ent->filename != ent_filename
+ && strcmp (ent_filename, filename) == 0)
+ || strcmp (info->ent->canon_filename, filename) == 0))
+ {
+ seen = 1;
+ tdeps = 0;
+ }
+ else if (ent2 = info->ent->depends [tdeps - 1],
+ strcmp (ent2->filename, filename) != 0
+ && strcmp (ent2->canon_filename, filename) != 0)
+ {
+ struct prelink_link *hardlink;
+
+ for (hardlink = ent2->hardlink; hardlink; hardlink = hardlink->next)
+ if (strcmp (hardlink->canon_filename, filename) == 0)
+ break;
+
+ if (hardlink == NULL)
+ {
+ struct stat64 st;
+
+ if (wrap_stat64 (filename, &st) < 0)
+ {
+ error (0, errno, "%s: Could not stat %s",
+ info->ent->filename, filename);
+ goto error_out;
+ }
+
+ if (st.st_dev != ent2->dev || st.st_ino != ent2->ino)
+ {
+ error (0, 0, "%s: %s => %s does not match recorded dependency",
+ info->ent->filename, soname, filename);
+ goto error_out;
+ }
+ }
+ }
+
+ if (! tdeps)
+ deps[0].ent = info->ent;
+ else
+ deps[tdeps].ent = info->ent->depends[tdeps - 1];
+ deps[tdeps].soname = strdup (soname);
+ if (deps[tdeps].soname == NULL)
+ {
+ error (0, ENOMEM, "Could not record `%s' SONAME", soname);
+ goto error_out;
+ }
+ deps[tdeps].start = start;
+ deps[tdeps].l_addr = l_addr;
+ deps[tdeps].tls_modid = tls_modid;
+ deps[tdeps].tls_offset = tls_offset;
+ ++ndeps;
+ }
+
+ if (ndeps != info->ent->ndepends + 1)
+ {
+ error (0, 0, "%s: Recorded %d dependencies, now seeing %d\n",
+ info->ent->filename, info->ent->ndepends, ndeps - 1);
+ goto error_out;
+ }
+
+ if (r == NULL && !ndeps)
+ {
+ error (0, 0, "%s: %s did not print any lookup lines", info->ent->filename,
+ dynamic_linker ?: dso->arch->dynamic_linker);
+ goto error_out;
+ }
+
+ info->tls = malloc (ndeps * sizeof (struct prelink_tls));
+ if (info->tls == NULL)
+ {
+ error (0, ENOMEM, "%s: Could not record dependency TLS information",
+ dso->filename);
+ goto error_out;
+ }
+
+ for (i = 0; i < ndeps; i++)
+ {
+ info->tls[i].modid = deps[i].tls_modid;
+ info->tls[i].offset = deps[i].tls_offset;
+ }
+
+ if (dso->ehdr.e_type == ET_EXEC || dso->arch->create_opd)
+ {
+ info->conflicts = (struct prelink_conflicts *)
+ calloc (sizeof (struct prelink_conflicts), ndeps);
+ if (info->conflicts == NULL)
+ {
+ error (0, ENOMEM, "%s: Can't build list of conflicts", info->ent->filename);
+ goto error_out;
+ }
+ for (i = 0; i < ndeps; i++)
+ info->conflicts[i].hash = &info->conflicts[i].first;
+ }
+ do
+ {
+ unsigned long long symstart, symoff, valstart[3], value[3];
+ int reloc_class, len, type = 1, ifunc = 0;
+ char *symname;
+
+ r = strchr (buffer, '\n');
+ if (r)
+ *r = '\0';
+ if (strncmp (buffer, "lookup ", sizeof ("lookup ") - 1) == 0)
+ {
+ struct prelink_symbol *s;
+
+ if (sscanf (buffer, "lookup 0x%llx 0x%llx -> 0x%llx 0x%llx %n",
+ &symstart, &symoff, &valstart[0], &value[0], &len) != 4)
+ {
+ error (0, 0, "%s: Could not parse `%s'", info->ent->filename, buffer);
+ goto error_out;
+ }
+
+ if (buffer[len] == '/')
+ {
+ ++len;
+ type = 0;
+ }
+
+ reloc_class = strtoul (buffer + len, &symname, 16);
+ if (buffer + len == symname || (reloc_class == 0 && type)
+ || (*symname != ' ' && *symname != '\t'))
+ {
+ error (0, 0, "%s: Could not parse `%s'", info->ent->filename, buffer);
+ goto error_out;
+ }
+
+ if (type)
+ reloc_class = dso->arch->reloc_class (reloc_class);
+ else
+ {
+ if (reloc_class & 8)
+ {
+ reloc_class = ((reloc_class & ~8)
+ | dso->arch->rtype_class_valid);
+ ifunc = 1;
+ }
+ else if ((reloc_class | RTYPE_CLASS_VALID) == RTYPE_CLASS_TLS)
+ reloc_class |= RTYPE_CLASS_VALID;
+ else
+ reloc_class |= dso->arch->rtype_class_valid;
+ }
+
+ while (*symname == ' ' || *symname == '\t') ++symname;
+
+ ent = NULL;
+ tls = NULL;
+ if (symstart == deps[0].start
+ || ((reloc_class == RTYPE_CLASS_TLS || ifunc)
+ && info->conflicts))
+ {
+ for (i = 0; i < ndeps; i++)
+ if (deps[i].start == valstart[0])
+ {
+ if (reloc_class == RTYPE_CLASS_TLS)
+ tls = info->tls + i;
+ else
+ {
+ ent = deps[i].ent;
+ /* If the library the symbol is bound to is already
+ prelinked, adjust the value so that it is relative
+ to library base. */
+ if (mask_32bit)
+ value[0] -= (Elf32_Addr) (deps[i].start - deps[i].l_addr);
+ else
+ value[0] -= deps[i].start - deps[i].l_addr;
+ }
+ break;
+ }
+
+ if (ent == NULL && tls == NULL && valstart[0])
+ {
+ error (0, 0, "Could not find base 0x%08llx in the list of bases `%s'",
+ valstart[0], buffer);
+ goto error_out;
+ }
+ }
+
+ if (symstart == deps[0].start && (!ifunc || info->conflicts == NULL))
+ {
+ /* Only interested in relocations from the current object. */
+ if (symoff < info->symtab_start || symoff >= info->symtab_end)
+ {
+ error (0, 0, "%s: Symbol `%s' offset 0x%08llx does not point into .dynsym section",
+ info->ent->filename, symname, symoff);
+ goto error_out;
+ }
+
+ if (ent == info->ent
+ && reloc_class != RTYPE_CLASS_TLS)
+ value[0] = adjust_old_to_new (info->dso, value[0]);
+
+ s = &info->symbols[(symoff - info->symtab_start)
+ / info->symtab_entsize];
+ if (s->reloc_class)
+ {
+ while (s->reloc_class != reloc_class && s->next != NULL)
+ s = s->next;
+ if (s->reloc_class == reloc_class)
+ {
+ if ((reloc_class != RTYPE_CLASS_TLS && s->u.ent != ent)
+ || (reloc_class == RTYPE_CLASS_TLS
+ && s->u.tls != tls)
+ || s->value != value[0])
+ {
+ error (0, 0, "%s: Symbol `%s' with the same reloc type resolves to different values each time",
+ info->ent->filename, symname);
+ goto error_out;
+ }
+ s = NULL;
+ }
+ else
+ {
+ s->next = (struct prelink_symbol *)
+ malloc (sizeof (struct prelink_symbol));
+ if (s->next == NULL)
+ {
+ error (0, ENOMEM, "Cannot build symbol lookup map");
+ goto error_out;
+ }
+ s = s->next;
+ }
+ }
+ if (s)
+ {
+ if (reloc_class == RTYPE_CLASS_TLS)
+ s->u.tls = tls;
+ else
+ s->u.ent = ent;
+ s->value = value[0];
+ s->reloc_class = reloc_class;
+ s->next = NULL;
+ }
+ }
+ else if ((reloc_class == RTYPE_CLASS_TLS || ifunc)
+ && info->conflicts)
+ {
+ struct prelink_conflict *conflict;
+ int symowner;
+ size_t idx;
+
+ for (symowner = 0; symowner < ndeps; symowner++)
+ if (deps[symowner].start == symstart)
+ break;
+ if (symowner == ndeps)
+ {
+ error (0, 0, "Could not find base 0x%08llx in the list of bases `%s'",
+ symstart, buffer);
+ goto error_out;
+ }
+
+ idx = 0;
+ if (info->conflicts[symowner].hash != &info->conflicts[symowner].first)
+ idx = symoff % 251;
+ for (conflict = info->conflicts[symowner].hash[idx]; conflict;
+ conflict = conflict->next)
+ if (conflict->symoff == symoff
+ && conflict->reloc_class == reloc_class)
+ {
+ if ((reloc_class != RTYPE_CLASS_TLS
+ && (conflict->lookup.ent != ent
+ || conflict->conflict.ent != ent))
+ || (reloc_class == RTYPE_CLASS_TLS
+ && (conflict->lookup.tls != tls
+ || conflict->conflict.tls != tls))
+ || conflict->lookupval != value[0]
+ || conflict->conflictval != value[0])
+ {
+ error (0, 0, "%s: Symbol `%s' with the same reloc type resolves to different values each time",
+ info->ent->filename, symname);
+ goto error_out;
+ }
+ break;
+ }
+ if (conflict == NULL)
+ {
+ conflict = malloc (sizeof (struct prelink_conflict));
+ if (conflict == NULL)
+ {
+ error (0, ENOMEM, "Cannot build list of conflicts");
+ goto error_out;
+ }
+
+ conflict->next = info->conflicts[symowner].hash[idx];
+ conflict->next2 = NULL;
+ info->conflicts[symowner].hash[idx] = conflict;
+ if (reloc_class != RTYPE_CLASS_TLS)
+ {
+ conflict->lookup.ent = ent;
+ conflict->conflict.ent = ent;
+ }
+ else
+ {
+ conflict->lookup.tls = tls;
+ conflict->conflict.tls = tls;
+ }
+ conflict->lookupval = value[0];
+ conflict->conflictval = value[0];
+ conflict->symoff = symoff;
+ conflict->reloc_class = reloc_class;
+ conflict->used = 0;
+ conflict->ifunc = ifunc;
+ conflict->symname = strdup(symname);
+ if (++info->conflicts[symowner].count == 16)
+ conflict_hash_init (&info->conflicts[symowner]);
+ }
+ }
+ }
+ else if (strncmp (buffer, "conflict ", sizeof ("conflict ") - 1) == 0)
+ {
+ if (sscanf (buffer, "conflict 0x%llx 0x%llx -> 0x%llx 0x%llx x 0x%llx 0x%llx %n",
+ &symstart, &symoff, &valstart[0], &value[0],
+ &valstart[1], &value[1], &len) != 6)
+ {
+ error (0, 0, "%s: Could not parse `%s'", info->ent->filename, buffer);
+ goto error_out;
+ }
+
+ if (buffer[len] == '/')
+ {
+ ++len;
+ type = 0;
+ }
+
+ reloc_class = strtoul (buffer + len, &symname, 16);
+ if (buffer + len == symname || (reloc_class == 0 && type)
+ || (*symname != ' ' && *symname != '\t'))
+ {
+ error (0, 0, "%s: Could not parse `%s'", info->ent->filename, buffer);
+ goto error_out;
+ }
+
+ if (type)
+ reloc_class = dso->arch->reloc_class (reloc_class);
+ else
+ {
+ if (reloc_class & 8)
+ {
+ reloc_class = ((reloc_class & ~8)
+ | dso->arch->rtype_class_valid);
+ ifunc = 1;
+ }
+ else if ((reloc_class | RTYPE_CLASS_VALID) == RTYPE_CLASS_TLS)
+ reloc_class |= RTYPE_CLASS_VALID;
+ else
+ reloc_class |= dso->arch->rtype_class_valid;
+ }
+
+ while (*symname == ' ' || *symname == '\t') ++symname;
+
+ if (symstart == deps[0].start)
+ {
+ error (0, 0, "Conflict in _dl_loaded `%s'", buffer);
+ goto error_out;
+ }
+
+ if (info->conflicts)
+ {
+ struct prelink_entry *ents[2];
+ struct prelink_tls *tlss[2];
+ struct prelink_conflict *conflict;
+ int symowner, j;
+ size_t idx;
+
+ for (symowner = 1; symowner < ndeps; symowner++)
+ if (deps[symowner].start == symstart)
+ break;
+ if (symowner == ndeps)
+ {
+ error (0, 0, "Could not find base 0x%08llx in the list of bases `%s'",
+ symstart, buffer);
+ goto error_out;
+ }
+
+ for (j = 0; j < 2; j++)
+ {
+ ents[j] = NULL;
+ tlss[j] = NULL;
+ for (i = 0; i < ndeps; i++)
+ if (deps[i].start == valstart[j])
+ {
+ if (reloc_class == RTYPE_CLASS_TLS)
+ tlss[j] = info->tls + i;
+ else
+ {
+ ents[j] = deps[i].ent;
+ /* If the library the symbol is bound to is already
+ prelinked, adjust the value so that it is relative
+ to library base. */
+ if (mask_32bit)
+ value[j] -= (Elf32_Addr) (deps[i].start - deps[i].l_addr);
+ else
+ value[j] -= deps[i].start - deps[i].l_addr;
+ }
+ break;
+ }
+ if (ents[j] == NULL && tlss[j] == NULL && valstart[j])
+ {
+ error (0, 0, "Could not find base 0x%08llx in the list of bases `%s'",
+ valstart[j], buffer);
+ goto error_out;
+ }
+ }
+
+ idx = 0;
+ if (info->conflicts[symowner].hash
+ != &info->conflicts[symowner].first)
+ idx = symoff % 251;
+ for (conflict = info->conflicts[symowner].hash[idx]; conflict;
+ conflict = conflict->next)
+ if (conflict->symoff == symoff
+ && conflict->reloc_class == reloc_class)
+ {
+ if ((reloc_class != RTYPE_CLASS_TLS
+ && (conflict->lookup.ent != ents[0]
+ || conflict->conflict.ent != ents[1]))
+ || (reloc_class == RTYPE_CLASS_TLS
+ && (conflict->lookup.tls != tlss[0]
+ || conflict->conflict.tls != tlss[1]))
+ || conflict->lookupval != value[0]
+ || conflict->conflictval != value[1])
+ {
+ error (0, 0, "%s: Symbol `%s' with the same reloc type resolves to different values each time",
+ info->ent->filename, symname);
+ goto error_out;
+ }
+ break;
+ }
+ if (conflict == NULL)
+ {
+ conflict = malloc (sizeof (struct prelink_conflict));
+ if (conflict == NULL)
+ {
+ error (0, ENOMEM, "Cannot build list of conflicts");
+ goto error_out;
+ }
+
+ conflict->next = info->conflicts[symowner].hash[idx];
+ conflict->next2 = NULL;
+ info->conflicts[symowner].hash[idx] = conflict;
+ if (reloc_class != RTYPE_CLASS_TLS)
+ {
+ conflict->lookup.ent = ents[0];
+ conflict->conflict.ent = ents[1];
+ }
+ else
+ {
+ conflict->lookup.tls = tlss[0];
+ conflict->conflict.tls = tlss[1];
+ }
+ conflict->lookupval = value[0];
+ conflict->conflictval = value[1];
+ conflict->symoff = symoff;
+ conflict->reloc_class = reloc_class;
+ conflict->used = 0;
+ conflict->ifunc = ifunc;
+ conflict->symname = strdup(symname);
+ if (++info->conflicts[symowner].count == 16)
+ conflict_hash_init (&info->conflicts[symowner]);
+ }
+ }
+ }
+ else if (strncmp (buffer, "undefined symbol: ",
+ sizeof ("undefined symbol: ") - 1) == 0 && ! undef)
+ {
+ undef = 1;
+ if (verbose)
+ error (0, 0, "Warning: %s has undefined non-weak symbols",
+ info->ent->filename);
+ }
+ } while (fgets (buffer, 8192, f) != NULL);
+
+ info->sonames = malloc (ndeps * sizeof (const char *));
+ if (info->sonames == NULL)
+ {
+ error (0, ENOMEM, "%s: Could not record dependency SONAMEs", dso->filename);
+ goto error_out;
+ }
+
+ for (i = 0; i < ndeps; i++)
+ info->sonames[i] = deps[i].soname;
+
+ return 0;
+
+error_out:
+ for (i = 0; i < ndeps; i++)
+ free (deps[i].soname);
+ return 1;
+}
+
+int
+prelink_get_relocations (struct prelink_info *info)
+{
+ FILE *f;
+ DSO *dso = info->dso;
+ const char *argv[8];
+ const char *envp[4];
+ int i, ret, status;
+ char *p;
+ const char *dl = dynamic_linker ?: dso->arch->dynamic_linker;
+ const char *ent_filename;
+ int etype = info->dso->ehdr.e_type;
+
+ if (info->ent->type == ET_DYN)
+ {
+ assert (info->ent->base == dso->base);
+ if (info->ent->end < dso->end)
+ {
+ error (0, 0, "%s: grew since it has been recorded", info->ent->filename);
+ return 0;
+ }
+ }
+ else
+ {
+ info->ent->base = dso->base;
+ info->ent->end = dso->end;
+ }
+
+ if (is_ldso_soname (info->dso->soname))
+ return 1;
+
+ info->symbol_count = (info->symtab_end - info->symtab_start)
+ / info->symtab_entsize;
+ info->symbols = calloc (sizeof (struct prelink_symbol), info->symbol_count);
+
+ if (strchr (info->ent->filename, '/') != NULL)
+ ent_filename = info->ent->filename;
+ else
+ {
+ size_t flen = strlen (info->ent->filename);
+ char *p = alloca (2 + flen + 1);
+ memcpy (p, "./", 2);
+ memcpy (p + 2, info->ent->filename, flen + 1);
+ ent_filename = p;
+ }
+ if (prelink_rtld == NULL)
+ {
+ i = 0;
+ argv[i++] = dl;
+ if (ld_library_path)
+ {
+ argv[i++] = "--library-path";
+ argv[i++] = ld_library_path;
+ }
+ argv[i++] = ent_filename;
+ argv[i] = NULL;
+ envp[0] = "LD_TRACE_LOADED_OBJECTS=1";
+ envp[1] = "LD_BIND_NOW=1";
+ p = alloca (sizeof "LD_TRACE_PRELINKING=" + strlen (info->ent->filename));
+ strcpy (stpcpy (p, "LD_TRACE_PRELINKING="), info->ent->filename);
+ envp[2] = p;
+ envp[3] = NULL;
+ ret = 2;
+ f = execve_open (dl, (char * const *)argv, (char * const *)envp);
+ }
+ else
+ {
+ i = 0;
+ argv[i++] = prelink_rtld;
+ if (ld_library_path)
+ {
+ argv[i++] = "--library-path";
+ argv[i++] = ld_library_path;
+ }
+
+ if(etype == ET_EXEC && ld_preload) {
+ argv[i++] = "--ld-preload";
+ argv[i++] = ld_preload;
+ }
+
+ argv[i++] = "--target-paths";
+ argv[i++] = ent_filename;
+ argv[i] = NULL;
+ p = alloca (sizeof "RTLD_TRACE_PRELINKING=" + strlen (info->ent->filename));
+ strcpy (stpcpy (p, "RTLD_TRACE_PRELINKING="), info->ent->filename);
+ envp[0] = p;
+ p = alloca (sizeof "PATH=" + strlen (getenv ("PATH")));
+ sprintf (p, "PATH=%s", getenv ("PATH"));
+ envp[1] = p;
+ envp[2] = NULL;
+ if (sysroot)
+ {
+ p = alloca (sizeof "PRELINK_SYSROOT=" + strlen (sysroot));
+ sprintf (p, "PRELINK_SYSROOT=%s", sysroot);
+ envp[2] = p;
+ envp[3] = NULL;
+ }
+ ret = 2;
+ f = execve_open (prelink_rtld, (char * const *)argv, (char * const *)envp);
+ }
+
+ if (f == NULL)
+ {
+ error (0, errno, "%s: Could not trace symbol resolving",
+ info->ent->filename);
+ return 0;
+ }
+
+ if (prelink_record_relocations (info, f, ent_filename))
+ ret = 0;
+
+ if ((status = execve_close (f)))
+ {
+ if (ret)
+ error (0, status == -1 ? errno : 0,
+ "%s Could not trace symbol resolving", info->ent->filename);
+ return 0;
+ }
+
+ return ret;
+}
diff --git a/src/hashtab.c b/src/hashtab.c
new file mode 100644
index 0000000..fa27446
--- /dev/null
+++ b/src/hashtab.c
@@ -0,0 +1,609 @@
+/* An expandable hash tables datatype.
+ Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
+ Contributed by Vladimir Makarov (vmakarov@cygnus.com).
+
+This file is part of the libiberty library.
+Libiberty is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+Libiberty is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with libiberty; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+/* This package implements basic hash table functionality. It is possible
+ to search for an entry, create an entry and destroy an entry.
+
+ Elements in the table are generic pointers.
+
+ The size of the table is not fixed; if the occupancy of the table
+ grows too high the hash table will be expanded.
+
+ The abstract data implementation is based on generalized Algorithm D
+ from Knuth's book "The art of computer programming". Hash table is
+ expanded by creation of new hash table and transferring elements from
+ the old table to the new table. */
+
+#include <config.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include "hashtab.h"
+
+/* This macro defines reserved value for empty table entry. */
+
+#define EMPTY_ENTRY ((void *) 0)
+
+/* This macro defines reserved value for table entry which contained
+ a deleted element. */
+
+#define DELETED_ENTRY ((void *) 1)
+
+static unsigned long higher_prime_number (unsigned long);
+static hashval_t hash_pointer (const void *);
+static int eq_pointer (const void *, const void *);
+static int htab_expand (htab_t);
+static void **find_empty_slot_for_expand (htab_t, hashval_t);
+
+/* At some point, we could make these be NULL, and modify the
+ hash-table routines to handle NULL specially; that would avoid
+ function-call overhead for the common case of hashing pointers. */
+htab_hash htab_hash_pointer = hash_pointer;
+htab_eq htab_eq_pointer = eq_pointer;
+
+/* The following function returns a nearest prime number which is
+ greater than N, and near a power of two. */
+
+static unsigned long
+higher_prime_number (n)
+ unsigned long n;
+{
+ /* These are primes that are near, but slightly smaller than, a
+ power of two. */
+ static unsigned long primes[] = {
+ (unsigned long) 2,
+ (unsigned long) 7,
+ (unsigned long) 13,
+ (unsigned long) 31,
+ (unsigned long) 61,
+ (unsigned long) 127,
+ (unsigned long) 251,
+ (unsigned long) 509,
+ (unsigned long) 1021,
+ (unsigned long) 2039,
+ (unsigned long) 4093,
+ (unsigned long) 8191,
+ (unsigned long) 16381,
+ (unsigned long) 32749,
+ (unsigned long) 65521,
+ (unsigned long) 131071,
+ (unsigned long) 262139,
+ (unsigned long) 524287,
+ (unsigned long) 1048573,
+ (unsigned long) 2097143,
+ (unsigned long) 4194301,
+ (unsigned long) 8388593,
+ (unsigned long) 16777213,
+ (unsigned long) 33554393,
+ (unsigned long) 67108859,
+ (unsigned long) 134217689,
+ (unsigned long) 268435399,
+ (unsigned long) 536870909,
+ (unsigned long) 1073741789,
+ (unsigned long) 2147483647,
+ /* 4294967291L */
+ ((unsigned long) 2147483647) + ((unsigned long) 2147483644),
+ };
+
+ unsigned long* low = &primes[0];
+ unsigned long* high = &primes[sizeof(primes) / sizeof(primes[0])];
+
+ while (low != high)
+ {
+ unsigned long* mid = low + (high - low) / 2;
+ if (n > *mid)
+ low = mid + 1;
+ else
+ high = mid;
+ }
+
+ /* If we've run out of primes, abort. */
+ if (n > *low)
+ {
+ fprintf (stderr, "Cannot find prime bigger than %lu\n", n);
+ abort ();
+ }
+
+ return *low;
+}
+
+/* Returns a hash code for P. */
+
+static hashval_t
+hash_pointer (p)
+ const void * p;
+{
+ return (hashval_t) ((long)p >> 3);
+}
+
+/* Returns non-zero if P1 and P2 are equal. */
+
+static int
+eq_pointer (p1, p2)
+ const void * p1;
+ const void * p2;
+{
+ return p1 == p2;
+}
+
+/* This function creates table with length slightly longer than given
+ source length. The created hash table is initiated as empty (all the
+ hash table entries are EMPTY_ENTRY). The function returns the created
+ hash table. Memory allocation may fail; it may return NULL. */
+
+htab_t
+htab_try_create (size, hash_f, eq_f, del_f)
+ size_t size;
+ htab_hash hash_f;
+ htab_eq eq_f;
+ htab_del del_f;
+{
+ htab_t result;
+
+ size = higher_prime_number (size);
+ result = (htab_t) calloc (1, sizeof (struct htab));
+ if (result == NULL)
+ return NULL;
+
+ result->entries = (void **) calloc (size, sizeof (void *));
+ if (result->entries == NULL)
+ {
+ free (result);
+ return NULL;
+ }
+
+ result->size = size;
+ result->hash_f = hash_f;
+ result->eq_f = eq_f;
+ result->del_f = del_f;
+ result->return_allocation_failure = 1;
+ return result;
+}
+
+/* This function frees all memory allocated for given hash table.
+ Naturally the hash table must already exist. */
+
+void
+htab_delete (htab)
+ htab_t htab;
+{
+ int i;
+
+ if (htab->del_f)
+ for (i = htab->size - 1; i >= 0; i--)
+ if (htab->entries[i] != EMPTY_ENTRY
+ && htab->entries[i] != DELETED_ENTRY)
+ (*htab->del_f) (htab->entries[i]);
+
+ free (htab->entries);
+ free (htab);
+}
+
+/* This function clears all entries in the given hash table. */
+
+void
+htab_empty (htab)
+ htab_t htab;
+{
+ int i;
+
+ if (htab->del_f)
+ for (i = htab->size - 1; i >= 0; i--)
+ if (htab->entries[i] != EMPTY_ENTRY
+ && htab->entries[i] != DELETED_ENTRY)
+ (*htab->del_f) (htab->entries[i]);
+
+ memset (htab->entries, 0, htab->size * sizeof (void *));
+}
+
+/* Similar to htab_find_slot, but without several unwanted side effects:
+ - Does not call htab->eq_f when it finds an existing entry.
+ - Does not change the count of elements/searches/collisions in the
+ hash table.
+ This function also assumes there are no deleted entries in the table.
+ HASH is the hash value for the element to be inserted. */
+
+static void **
+find_empty_slot_for_expand (htab, hash)
+ htab_t htab;
+ hashval_t hash;
+{
+ size_t size = htab->size;
+ hashval_t hash2 = 1 + hash % (size - 2);
+ unsigned int index = hash % size;
+
+ for (;;)
+ {
+ void **slot = htab->entries + index;
+
+ if (*slot == EMPTY_ENTRY)
+ return slot;
+ else if (*slot == DELETED_ENTRY)
+ abort ();
+
+ index += hash2;
+ if (index >= size)
+ index -= size;
+ }
+}
+
+/* The following function changes size of memory allocated for the
+ entries and repeatedly inserts the table elements. The occupancy
+ of the table after the call will be about 50%. Naturally the hash
+ table must already exist. Remember also that the place of the
+ table entries is changed. If memory allocation failures are allowed,
+ this function will return zero, indicating that the table could not be
+ expanded. If all goes well, it will return a non-zero value. */
+
+static int
+htab_expand (htab)
+ htab_t htab;
+{
+ void **oentries;
+ void **olimit;
+ void **p;
+
+ oentries = htab->entries;
+ olimit = oentries + htab->size;
+
+ htab->size = higher_prime_number (htab->size * 2);
+
+ if (htab->return_allocation_failure)
+ {
+ void **nentries = (void **) calloc (htab->size, sizeof (void **));
+ if (nentries == NULL)
+ return 0;
+ htab->entries = nentries;
+ }
+
+ htab->n_elements -= htab->n_deleted;
+ htab->n_deleted = 0;
+
+ p = oentries;
+ do
+ {
+ void * x = *p;
+
+ if (x != EMPTY_ENTRY && x != DELETED_ENTRY)
+ {
+ void **q = find_empty_slot_for_expand (htab, (*htab->hash_f) (x));
+
+ *q = x;
+ }
+
+ p++;
+ }
+ while (p < olimit);
+
+ free (oentries);
+ return 1;
+}
+
+/* This function searches for a hash table entry equal to the given
+ element. It cannot be used to insert or delete an element. */
+
+void *
+htab_find_with_hash (htab, element, hash)
+ htab_t htab;
+ const void * element;
+ hashval_t hash;
+{
+ unsigned int index;
+ hashval_t hash2;
+ size_t size;
+ void * entry;
+
+ htab->searches++;
+ size = htab->size;
+ index = hash % size;
+
+ entry = htab->entries[index];
+ if (entry == EMPTY_ENTRY
+ || (entry != DELETED_ENTRY && (*htab->eq_f) (entry, element)))
+ return entry;
+
+ hash2 = 1 + hash % (size - 2);
+
+ for (;;)
+ {
+ htab->collisions++;
+ index += hash2;
+ if (index >= size)
+ index -= size;
+
+ entry = htab->entries[index];
+ if (entry == EMPTY_ENTRY
+ || (entry != DELETED_ENTRY && (*htab->eq_f) (entry, element)))
+ return entry;
+ }
+}
+
+/* Like htab_find_slot_with_hash, but compute the hash value from the
+ element. */
+
+void *
+htab_find (htab, element)
+ htab_t htab;
+ const void * element;
+{
+ return htab_find_with_hash (htab, element, (*htab->hash_f) (element));
+}
+
+/* This function searches for a hash table slot containing an entry
+ equal to the given element. To delete an entry, call this with
+ INSERT = 0, then call htab_clear_slot on the slot returned (possibly
+ after doing some checks). To insert an entry, call this with
+ INSERT = 1, then write the value you want into the returned slot.
+ When inserting an entry, NULL may be returned if memory allocation
+ fails. */
+
+void **
+htab_find_slot_with_hash (htab, element, hash, insert)
+ htab_t htab;
+ const void * element;
+ hashval_t hash;
+ enum insert_option insert;
+{
+ void **first_deleted_slot;
+ unsigned int index;
+ hashval_t hash2;
+ size_t size;
+
+ if (insert == INSERT && htab->size * 3 <= htab->n_elements * 4
+ && htab_expand (htab) == 0)
+ return NULL;
+
+ size = htab->size;
+ hash2 = 1 + hash % (size - 2);
+ index = hash % size;
+
+ htab->searches++;
+ first_deleted_slot = NULL;
+
+ for (;;)
+ {
+ void * entry = htab->entries[index];
+ if (entry == EMPTY_ENTRY)
+ {
+ if (insert == NO_INSERT)
+ return NULL;
+
+ htab->n_elements++;
+
+ if (first_deleted_slot)
+ {
+ *first_deleted_slot = EMPTY_ENTRY;
+ return first_deleted_slot;
+ }
+
+ return &htab->entries[index];
+ }
+
+ if (entry == DELETED_ENTRY)
+ {
+ if (!first_deleted_slot)
+ first_deleted_slot = &htab->entries[index];
+ }
+ else if ((*htab->eq_f) (entry, element))
+ return &htab->entries[index];
+
+ htab->collisions++;
+ index += hash2;
+ if (index >= size)
+ index -= size;
+ }
+}
+
+/* Like htab_find_slot_with_hash, but compute the hash value from the
+ element. */
+
+void **
+htab_find_slot (htab, element, insert)
+ htab_t htab;
+ const void * element;
+ enum insert_option insert;
+{
+ return htab_find_slot_with_hash (htab, element, (*htab->hash_f) (element),
+ insert);
+}
+
+/* This function deletes an element with the given value from hash
+ table. If there is no matching element in the hash table, this
+ function does nothing. */
+
+void
+htab_remove_elt (htab, element)
+ htab_t htab;
+ void * element;
+{
+ void **slot;
+
+ slot = htab_find_slot (htab, element, NO_INSERT);
+ if (*slot == EMPTY_ENTRY)
+ return;
+
+ if (htab->del_f)
+ (*htab->del_f) (*slot);
+
+ *slot = DELETED_ENTRY;
+ htab->n_deleted++;
+}
+
+/* This function clears a specified slot in a hash table. It is
+ useful when you've already done the lookup and don't want to do it
+ again. */
+
+void
+htab_clear_slot (htab, slot)
+ htab_t htab;
+ void **slot;
+{
+ if (slot < htab->entries || slot >= htab->entries + htab->size
+ || *slot == EMPTY_ENTRY || *slot == DELETED_ENTRY)
+ abort ();
+
+ if (htab->del_f)
+ (*htab->del_f) (*slot);
+
+ *slot = DELETED_ENTRY;
+ htab->n_deleted++;
+}
+
+/* This function scans over the entire hash table calling
+ CALLBACK for each live entry. If CALLBACK returns false,
+ the iteration stops. INFO is passed as CALLBACK's second
+ argument. */
+
+void
+htab_traverse (htab, callback, info)
+ htab_t htab;
+ htab_trav callback;
+ void * info;
+{
+ void **slot = htab->entries;
+ void **limit = slot + htab->size;
+
+ do
+ {
+ void * x = *slot;
+
+ if (x != EMPTY_ENTRY && x != DELETED_ENTRY)
+ if (!(*callback) (slot, info))
+ break;
+ }
+ while (++slot < limit);
+}
+
+/* Return the current size of given hash table. */
+
+size_t
+htab_size (htab)
+ htab_t htab;
+{
+ return htab->size;
+}
+
+/* Return the current number of elements in given hash table. */
+
+size_t
+htab_elements (htab)
+ htab_t htab;
+{
+ return htab->n_elements - htab->n_deleted;
+}
+
+/* Return the fraction of fixed collisions during all work with given
+ hash table. */
+
+double
+htab_collisions (htab)
+ htab_t htab;
+{
+ if (htab->searches == 0)
+ return 0.0;
+
+ return (double) htab->collisions / (double) htab->searches;
+}
+
+#ifndef NDEBUG
+void
+htab_dump (htab, name, dumpfn)
+ htab_t htab;
+ const char *name;
+ htab_dumpfn dumpfn;
+{
+ FILE *f = fopen (name, "w");
+ size_t i, j;
+
+ if (f == NULL)
+ abort ();
+ fprintf (f, "size %zd n_elements %zd n_deleted %zd\n",
+ htab->size, htab->n_elements, htab->n_deleted);
+ for (i = 0; i < htab->size; ++i)
+ {
+ if (htab->entries [i] == EMPTY_ENTRY
+ || htab->entries [i] == DELETED_ENTRY)
+ {
+ for (j = i + 1; j < htab->size; ++j)
+ if (htab->entries [j] != htab->entries [i])
+ break;
+ fprintf (f, "%c%zd\n",
+ htab->entries [i] == EMPTY_ENTRY ? 'E' : 'D',
+ j - i);
+ i = j - 1;
+ }
+ else
+ {
+ fputc ('V', f);
+ (*dumpfn) (f, htab->entries [i]);
+ }
+ }
+ fclose (f);
+}
+
+void
+htab_restore (htab, name, restorefn)
+ htab_t htab;
+ const char *name;
+ htab_restorefn restorefn;
+{
+ FILE *f = fopen (name, "r");
+ size_t size, n_elements, n_deleted, i, j, k;
+ int c;
+
+ if (f == NULL)
+ abort ();
+ if (fscanf (f, "size %zd n_elements %zd n_deleted %zd\n",
+ &size, &n_elements, &n_deleted) != 3)
+ abort ();
+ htab_empty (htab);
+ free (htab->entries);
+ htab->entries = (void **) calloc (size, sizeof (void *));
+ if (htab->entries == NULL)
+ abort ();
+ htab->size = size;
+ htab->n_elements = n_elements;
+ htab->n_deleted = n_deleted;
+ for (i = 0; i < htab->size; ++i)
+ {
+ switch ((c = fgetc (f)))
+ {
+ case 'E':
+ case 'D':
+ if (fscanf (f, "%zd\n", &j) != 1)
+ abort ();
+ if (i + j > htab->size)
+ abort ();
+ if (c == 'D')
+ for (k = i; k < i + j; ++k)
+ htab->entries [k] = DELETED_ENTRY;
+ i += j - 1;
+ break;
+ case 'V':
+ htab->entries [i] = (*restorefn) (f);
+ break;
+ default:
+ abort ();
+ }
+ }
+ fclose (f);
+}
+#endif
diff --git a/src/hashtab.h b/src/hashtab.h
new file mode 100644
index 0000000..31e63e0
--- /dev/null
+++ b/src/hashtab.h
@@ -0,0 +1,155 @@
+/* An expandable hash tables datatype.
+ Copyright (C) 1999, 2000 Free Software Foundation, Inc.
+ Contributed by Vladimir Makarov (vmakarov@cygnus.com).
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* This package implements basic hash table functionality. It is possible
+ to search for an entry, create an entry and destroy an entry.
+
+ Elements in the table are generic pointers.
+
+ The size of the table is not fixed; if the occupancy of the table
+ grows too high the hash table will be expanded.
+
+ The abstract data implementation is based on generalized Algorithm D
+ from Knuth's book "The art of computer programming". Hash table is
+ expanded by creation of new hash table and transferring elements from
+ the old table to the new table. */
+
+#ifndef __HASHTAB_H__
+#define __HASHTAB_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/* The type for a hash code. */
+typedef unsigned int hashval_t;
+
+/* Callback function pointer types. */
+
+/* Calculate hash of a table entry. */
+typedef hashval_t (*htab_hash) (const void *);
+
+/* Compare a table entry with a possible entry. The entry already in
+ the table always comes first, so the second element can be of a
+ different type (but in this case htab_find and htab_find_slot
+ cannot be used; instead the variants that accept a hash value
+ must be used). */
+typedef int (*htab_eq) (const void *, const void *);
+
+/* Cleanup function called whenever a live element is removed from
+ the hash table. */
+typedef void (*htab_del) (void *);
+
+/* Function called by htab_traverse for each live element. The first
+ arg is the slot of the element (which can be passed to htab_clear_slot
+ if desired), the second arg is the auxiliary pointer handed to
+ htab_traverse. Return 1 to continue scan, 0 to stop. */
+typedef int (*htab_trav) (void **, void *);
+
+/* Hash tables are of the following type. The structure
+ (implementation) of this type is not needed for using the hash
+ tables. All work with hash table should be executed only through
+ functions mentioned below. */
+
+struct htab
+{
+ /* Pointer to hash function. */
+ htab_hash hash_f;
+
+ /* Pointer to comparison function. */
+ htab_eq eq_f;
+
+ /* Pointer to cleanup function. */
+ htab_del del_f;
+
+ /* Table itself. */
+ void **entries;
+
+ /* Current size (in entries) of the hash table */
+ size_t size;
+
+ /* Current number of elements including also deleted elements */
+ size_t n_elements;
+
+ /* Current number of deleted elements in the table */
+ size_t n_deleted;
+
+ /* The following member is used for debugging. Its value is number
+ of all calls of `htab_find_slot' for the hash table. */
+ unsigned int searches;
+
+ /* The following member is used for debugging. Its value is number
+ of collisions fixed for time of work with the hash table. */
+ unsigned int collisions;
+
+ /* This is non-zero if we are allowed to return NULL for function calls
+ that allocate memory. */
+ int return_allocation_failure;
+};
+
+typedef struct htab *htab_t;
+
+/* An enum saying whether we insert into the hash table or not. */
+enum insert_option {NO_INSERT, INSERT};
+
+/* The prototypes of the package functions. */
+
+/* This function is like htab_create, but may return NULL if memory
+ allocation fails, and also signals that htab_find_slot_with_hash and
+ htab_find_slot are allowed to return NULL when inserting. */
+extern htab_t htab_try_create (size_t, htab_hash, htab_eq, htab_del);
+extern void htab_delete (htab_t);
+extern void htab_empty (htab_t);
+
+extern void *htab_find (htab_t, const void *);
+extern void **htab_find_slot (htab_t, const void *, enum insert_option);
+extern void *htab_find_with_hash (htab_t, const void *, hashval_t);
+extern void **htab_find_slot_with_hash (htab_t, const void *, hashval_t,
+ enum insert_option);
+extern void htab_clear_slot (htab_t, void **);
+extern void htab_remove_elt (htab_t, void *);
+
+extern void htab_traverse (htab_t, htab_trav, void *);
+
+extern size_t htab_size (htab_t);
+extern size_t htab_elements (htab_t);
+extern double htab_collisions (htab_t);
+
+/* A hash function for pointers. */
+extern htab_hash htab_hash_pointer;
+
+/* An equality function for pointers. */
+extern htab_eq htab_eq_pointer;
+
+#ifndef NDEBUG
+
+#include <stdio.h>
+
+typedef void (*htab_dumpfn) (FILE *, const void *);
+typedef void *(*htab_restorefn) (FILE *);
+
+extern void htab_dump (htab_t, const char *, htab_dumpfn);
+extern void htab_restore (htab_t, const char *, htab_restorefn);
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __HASHTAB_H */
diff --git a/src/layout.c b/src/layout.c
new file mode 100644
index 0000000..859ab66
--- /dev/null
+++ b/src/layout.c
@@ -0,0 +1,656 @@
+/* Copyright (C) 2001, 2002, 2003, 2004, 2006, 2011 Red Hat, Inc.
+ Written by Jakub Jelinek <jakub@redhat.com>, 2001.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include <config.h>
+#include <alloca.h>
+#include <errno.h>
+#include <error.h>
+#include <fcntl.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <assert.h>
+#include "prelinktab.h"
+#include "layout.h"
+
+#ifndef NDEBUG
+# define DEBUG_LAYOUT
+#endif
+
+#ifdef DEBUG_LAYOUT
+void
+print_ent (struct prelink_entry *e)
+{
+ printf ("%s: %08x %08x/%08x\n",
+ e->filename, (int)e->base, (int)e->end, (int)e->layend);
+}
+
+void
+print_list (struct prelink_entry *e)
+{
+ for (; e; e = e->next)
+ print_ent (e);
+ printf ("\n");
+}
+#endif
+
+static int
+find_arches (void **p, void *info)
+{
+ struct layout_libs *l = (struct layout_libs *) info;
+ struct prelink_entry *e = * (struct prelink_entry **) p;
+ int i;
+
+ if (e->type == ET_DYN || e->type == ET_EXEC
+ || e->type == ET_CACHE_DYN || e->type == ET_CACHE_EXEC)
+ {
+ for (i = 0; i < l->nbinlibs; ++i)
+ if ((l->binlibs[i]->flags & (PCF_ELF64 | PCF_MACHINE))
+ == (e->flags & (PCF_ELF64 | PCF_MACHINE)))
+ return 1;
+
+ l->binlibs[l->nbinlibs++] = e;
+ }
+
+ return 1;
+}
+
+static int
+find_libs (void **p, void *info)
+{
+ struct layout_libs *l = (struct layout_libs *) info;
+ struct prelink_entry *e = * (struct prelink_entry **) p;
+
+ if ((e->flags & (PCF_ELF64 | PCF_MACHINE)) != l->flags)
+ return 1;
+
+ if (e->type == ET_DYN || e->type == ET_EXEC
+ || e->type == ET_CACHE_DYN || e->type == ET_CACHE_EXEC)
+ l->binlibs[l->nbinlibs++] = e;
+ if (e->type == ET_DYN || e->type == ET_CACHE_DYN)
+ l->libs[l->nlibs++] = e;
+ if (force)
+ e->done = 0;
+ if (e->type == ET_CACHE_DYN || e->type == ET_CACHE_EXEC)
+ e->done = 2;
+ if (e->base & (l->max_page_size - 1))
+ {
+ e->done = 0;
+ e->end -= e->base;
+ e->base = 0;
+ }
+
+ return 1;
+}
+
+static int
+refs_cmp (const void *A, const void *B)
+{
+ struct prelink_entry *a = * (struct prelink_entry **) A;
+ struct prelink_entry *b = * (struct prelink_entry **) B;
+ int i;
+
+ /* Dynamic linkers first. */
+ if (! a->ndepends && b->ndepends)
+ return -1;
+ if (a->ndepends && ! b->ndepends)
+ return 1;
+ /* Most widely used libraries first. */
+ if (a->refs > b->refs)
+ return -1;
+ if (a->refs < b->refs)
+ return 1;
+ /* Largest libraries first. */
+ if (a->layend - a->base > b->layend - b->base)
+ return -1;
+ if (a->layend - a->base < b->layend - b->base)
+ return 1;
+ if (a->refs)
+ {
+ i = strcmp (a->soname, b->soname);
+ if (i)
+ return i;
+ }
+ return strcmp (a->filename, b->filename);
+}
+
+static int
+refs_rnd_cmp (const void *A, const void *B)
+{
+ struct prelink_entry *a = * (struct prelink_entry **) A;
+ struct prelink_entry *b = * (struct prelink_entry **) B;
+ int i, refs;
+
+ /* Dynamic linkers first. */
+ if (! a->ndepends && b->ndepends)
+ return -1;
+ if (a->ndepends && ! b->ndepends)
+ return 1;
+ /* Most widely used libraries first with some randomization. */
+ refs = a->refs < b->refs ? a->refs : b->refs;
+ if (refs < 8)
+ i = 1;
+ else if (refs < 32)
+ i = 2;
+ else if (refs < 128)
+ i = 4;
+ else
+ i = 8;
+ if (a->refs > b->refs && a->refs - b->refs >= i)
+ return -1;
+ if (a->refs < b->refs && b->refs - a->refs >= i)
+ return 1;
+ if (a->u.tmp < b->u.tmp)
+ return -1;
+ if (a->u.tmp > b->u.tmp)
+ return 1;
+ /* Largest libraries first. */
+ if (a->layend - a->base > b->layend - b->base)
+ return -1;
+ if (a->layend - a->base < b->layend - b->base)
+ return 1;
+ if (a->refs && b->refs)
+ {
+ i = strcmp (a->soname, b->soname);
+ if (i)
+ return i;
+ }
+ return strcmp (a->filename, b->filename);
+}
+
+static int
+addr_cmp (const void *A, const void *B)
+{
+ struct prelink_entry *a = * (struct prelink_entry **) A;
+ struct prelink_entry *b = * (struct prelink_entry **) B;
+
+ if (! a->done)
+ return b->done ? 1 : 0;
+ else if (! b->done)
+ return -1;
+ if (a->base < b->base)
+ return -1;
+ else if (a->base > b->base)
+ return 1;
+ if (a->layend < b->layend)
+ return -1;
+ else if (a->layend > b->layend)
+ return 1;
+ return 0;
+}
+
+int deps_cmp (const void *A, const void *B)
+{
+ struct prelink_entry *a = * (struct prelink_entry **) A;
+ struct prelink_entry *b = * (struct prelink_entry **) B;
+
+ if (a->base < b->base)
+ return -1;
+ if (a->base > b->base)
+ return 1;
+ return 0;
+}
+
+int
+layout_libs (void)
+{
+ struct layout_libs l;
+ int arch, *arches, narches;
+ struct prelink_entry **plibs, **pbinlibs;
+
+ memset (&l, 0, sizeof (l));
+ l.libs = plibs =
+ (struct prelink_entry **) alloca (prelink_entry_count
+ * sizeof (struct prelink_entry *));
+ l.binlibs = pbinlibs =
+ (struct prelink_entry **) alloca (prelink_entry_count
+ * sizeof (struct prelink_entry *));
+ htab_traverse (prelink_filename_htab, find_arches, &l);
+ narches = l.nbinlibs;
+ arches = (int *) alloca (narches * sizeof (int));
+ for (arch = 0; arch < narches; ++arch)
+ arches[arch] = l.binlibs[arch]->flags & (PCF_ELF64 | PCF_MACHINE);
+
+ for (arch = 0; arch < narches; ++arch)
+ {
+ struct PLArch *plarch;
+ extern struct PLArch __start_pl_arch[], __stop_pl_arch[];
+ int i, j, k, m, done, class;
+ GElf_Addr mmap_start, mmap_base, mmap_end, mmap_fin, max_page_size;
+ GElf_Addr base, size;
+ struct prelink_entry *list, *e, *fake, **deps;
+ struct prelink_entry fakeent;
+ int fakecnt;
+ int (*layout_libs_pre) (struct layout_libs *l);
+ int (*layout_libs_post) (struct layout_libs *l);
+
+ for (plarch = __start_pl_arch; plarch < __stop_pl_arch; plarch++)
+ if (plarch->class == (arches[arch] & PCF_ELF64 ? ELFCLASS64 : ELFCLASS32)
+ && plarch->machine == (arches[arch] & PCF_MACHINE))
+ break;
+
+ if (plarch == __stop_pl_arch)
+ error (EXIT_FAILURE, 0, "%d-bit ELF e_machine %04x not supported",
+ (arches[arch] & PCF_ELF64) ? 64 : 32, arches[arch] & PCF_MACHINE);
+
+ list = NULL;
+ fake = NULL;
+ fakecnt = 0;
+ memset (&l, 0, sizeof (l));
+ l.flags = arches[arch];
+ l.libs = plibs;
+ l.binlibs = pbinlibs;
+ max_page_size = plarch->max_page_size;
+ if (layout_page_size > max_page_size)
+ max_page_size = layout_page_size;
+ l.max_page_size = max_page_size;
+ htab_traverse (prelink_filename_htab, find_libs, &l);
+
+ /* Make sure there is some room between libraries. */
+ for (i = 0; i < l.nlibs; ++i)
+ l.libs[i]->layend = (l.libs[i]->end + 8192 + max_page_size - 1)
+ & ~(max_page_size - 1);
+
+ if (plarch->layout_libs_init)
+ {
+ plarch->layout_libs_init (&l);
+ mmap_base = l.mmap_base;
+ mmap_end = l.mmap_end;
+ }
+ else
+ {
+ mmap_base = plarch->mmap_base;
+ mmap_end = plarch->mmap_end;
+ }
+ if (mmap_reg_start != ~(GElf_Addr) 0)
+ mmap_base = mmap_reg_start;
+ if (mmap_reg_end != ~(GElf_Addr) 0)
+ mmap_end = mmap_reg_end;
+ if (mmap_base >= mmap_end)
+ error (EXIT_FAILURE, 0,
+ "--mmap-region-start cannot be bigger than --mmap-region-end");
+ if ((mmap_base | mmap_end) & (max_page_size - 1))
+ error (EXIT_FAILURE, 0, "--layout-page-size too large");
+ class = plarch->class;
+ /* The code below relies on having a VA slot as big as <mmap_base,mmap_end)
+ above mmap_end for -R. */
+ if (mmap_end + (mmap_end - mmap_base) <= mmap_end)
+ random_base = 0;
+ layout_libs_pre = plarch->layout_libs_pre;
+ layout_libs_post = plarch->layout_libs_post;
+
+ deps = (struct prelink_entry **)
+ alloca (l.nlibs * sizeof (struct prelink_entry *));
+
+ /* Now see which already prelinked libraries have to be
+ re-prelinked to avoid overlaps. */
+ for (i = 0; i < l.nbinlibs; ++i)
+ {
+ for (j = 0, k = 0; j < l.binlibs[i]->ndepends; ++j)
+ if (l.binlibs[i]->depends[j]->type == ET_DYN
+ && l.binlibs[i]->depends[j]->done)
+ {
+ assert (k < l.nlibs);
+ deps[k++] = l.binlibs[i]->depends[j];
+ }
+ if (k)
+ {
+ qsort (deps, k, sizeof (struct prelink_entry *), deps_cmp);
+ for (j = 1; j < k; ++j)
+ if (deps[j]->base < deps[j - 1]->end
+ && (deps[j]->type == ET_DYN
+ || deps[j - 1]->type == ET_DYN))
+ {
+ if (deps[j - 1]->refs < deps[j]->refs)
+ --j;
+ deps[j]->done = 0;
+ --k;
+ memmove (deps + j, deps + j + 1, (k - j) * sizeof (*deps));
+ if (j > 0)
+ --j;
+ }
+ }
+ }
+
+ /* If layout_libs_init or the for cycle above cleared
+ done flags for some libraries, make sure all libraries
+ that depend on them are re-prelinked as well. */
+ for (i = 0; i < l.nlibs; ++i)
+ if (l.libs[i]->done)
+ for (j = 0; j < l.libs[i]->ndepends; ++j)
+ if (l.libs[i]->depends[j]->done == 0)
+ {
+ l.libs[i]->done = 0;
+ break;
+ }
+
+ /* Put the already prelinked libs into double linked list. */
+ qsort (l.libs, l.nlibs, sizeof (struct prelink_entry *), addr_cmp);
+ for (i = 0; i < l.nlibs; ++i)
+ if (! l.libs[i]->done || l.libs[i]->layend >= mmap_base)
+ break;
+ j = 0;
+ if (i < l.nlibs && l.libs[i]->done)
+ {
+ if (l.libs[i]->base < mmap_base)
+ random_base = 0;
+ for (j = i + 1; j < l.nlibs; ++j)
+ {
+ if (! l.libs[j]->done || l.libs[j]->base >= mmap_end)
+ break;
+
+ if (l.libs[j]->base < mmap_base || l.libs[j]->layend > mmap_end)
+ random_base = 0;
+ l.libs[j]->prev = l.libs[j - 1];
+ l.libs[j - 1]->next = l.libs[j];
+ }
+ list = l.libs[i];
+ list->prev = l.libs[j - 1];
+ while (j < l.nlibs && l.libs[j]->done) ++j;
+ }
+
+ mmap_start = mmap_base;
+ mmap_fin = mmap_end;
+ done = 1;
+ if (random_base & 2)
+ {
+ mmap_start = seed;
+ if (mmap_start < mmap_base || mmap_start >= mmap_end)
+ mmap_start = mmap_base;
+
+ mmap_start = (mmap_start + max_page_size - 1) & ~(max_page_size - 1);
+ }
+ else if (random_base)
+ {
+ int fd = open ("/dev/urandom", O_RDONLY);
+
+ mmap_start = 0;
+ if (fd != -1)
+ {
+ GElf_Addr x;
+
+ if (read (fd, &x, sizeof (x)) == sizeof (x))
+ {
+ mmap_start = x % (mmap_end - mmap_base);
+ mmap_start += mmap_base;
+ }
+
+ fsync (fd);
+ close (fd);
+ }
+
+ if (! mmap_start)
+ {
+ mmap_start = ((mmap_end - mmap_base) >> 16)
+ * (time (NULL) & 0xffff);
+ mmap_start += mmap_base;
+ }
+
+ seed = mmap_start;
+ mmap_start = (mmap_start + max_page_size - 1) & ~(max_page_size - 1);
+ }
+ if (random_base)
+ {
+ srandom (mmap_start >> 12);
+ for (i = 0; i < l.nlibs; ++i)
+ l.libs[i]->u.tmp = random ();
+ qsort (l.libs, l.nlibs, sizeof (struct prelink_entry *), refs_rnd_cmp);
+ }
+ else
+ qsort (l.libs, l.nlibs, sizeof (struct prelink_entry *), refs_cmp);
+
+ if (verbose && l.nlibs > j)
+ {
+ printf ("Laying out %d libraries in virtual address space %0*llx-%0*llx\n",
+ l.nlibs - j, class == ELFCLASS32 ? 8 : 16, (long long) mmap_base,
+ class == ELFCLASS32 ? 8 : 16, (long long) mmap_end);
+ if (mmap_start != mmap_base)
+ printf ("Random base 0x%0*llx\n", class == ELFCLASS32 ? 8 : 16,
+ (long long) mmap_start);
+ }
+
+ if (layout_libs_pre)
+ {
+ l.list = list;
+ l.mmap_base = mmap_base;
+ l.mmap_start = mmap_start;
+ l.mmap_end = mmap_end;
+ layout_libs_pre (&l);
+ list = l.list;
+ mmap_base = l.mmap_base;
+ mmap_start = l.mmap_start;
+ mmap_fin = l.mmap_fin;
+ mmap_end = l.mmap_end;
+ fake = l.fake;
+ fakecnt = l.fakecnt;
+ }
+
+ if (mmap_start != mmap_base && list)
+ {
+ for (e = list; e != NULL; e = e->next)
+ {
+ if (e->base >= mmap_start)
+ break;
+ if (e->layend > mmap_start)
+ mmap_start = (e->layend + max_page_size - 1)
+ & ~(max_page_size - 1);
+ e->base += mmap_end - mmap_base;
+ e->end += mmap_end - mmap_base;
+ e->layend += mmap_end - mmap_base;
+ e->done |= 0x80;
+ }
+
+ if (mmap_start < mmap_end)
+ {
+ if (e && e != list)
+ {
+ memset (&fakeent, 0, sizeof (fakeent));
+ fakeent.u.tmp = -1;
+ fakeent.base = mmap_end;
+ fakeent.end = mmap_end;
+ fakeent.layend = mmap_end;
+ fake = &fakeent;
+ fakecnt = 1;
+ fakeent.prev = list->prev;
+ fakeent.next = list;
+ list->prev = fake;
+ fakeent.prev->next = fake;
+ list = e;
+ e->prev->next = NULL;
+ }
+ }
+ else
+ {
+ mmap_start = mmap_base;
+ for (e = list; e != NULL; e = e->next)
+ if (e->done & 0x80)
+ {
+ e->done &= ~0x80;
+ e->base -= mmap_end - mmap_base;
+ e->end -= mmap_end - mmap_base;
+ e->layend -= mmap_end - mmap_base;
+ }
+ }
+ }
+
+ if (mmap_start != mmap_base)
+ {
+ done |= 0x80;
+ mmap_fin = mmap_end + (mmap_start - mmap_base);
+ }
+
+ for (i = 0; i < l.nlibs; ++i)
+ l.libs[i]->u.tmp = -1;
+ m = -1;
+
+ for (i = 0; i < l.nlibs; ++i)
+ if (! l.libs[i]->done)
+ {
+ if (conserve_memory)
+ {
+ /* If conserving virtual address space, only consider libraries
+ which ever appear together with this one. Otherwise consider
+ all libraries. */
+ m = i;
+ for (j = 0; j < l.nbinlibs; ++j)
+ {
+ for (k = 0; k < l.binlibs[j]->ndepends; ++k)
+ if (l.binlibs[j]->depends[k] == l.libs[i])
+ {
+ for (k = 0; k < l.binlibs[j]->ndepends; ++k)
+ l.binlibs[j]->depends[k]->u.tmp = m;
+ break;
+ }
+ }
+ for (j = 0; j < fakecnt; ++j)
+ fake[j].u.tmp = m;
+ }
+
+ size = l.libs[i]->layend - l.libs[i]->base;
+ base = mmap_start;
+ for (e = list; e; e = e->next)
+ if (e->u.tmp == m)
+ {
+ if (base + size <= e->base)
+ goto found;
+
+ if (base < e->layend)
+ base = e->layend;
+ }
+
+ if (base + size > mmap_fin)
+ goto not_found;
+found:
+ l.libs[i]->end += base - l.libs[i]->base;
+ l.libs[i]->base = base;
+ l.libs[i]->layend = base + size;
+ if (base >= mmap_end)
+ l.libs[i]->done = done;
+ else
+ l.libs[i]->done = 1;
+ if (list == NULL)
+ {
+ list = l.libs[i];
+ list->prev = list;
+ }
+ else
+ {
+ if (e == NULL)
+ e = list->prev;
+ else
+ e = e->prev;
+ while (e != list && e->base > base)
+ e = e->prev;
+ if (e->base > base)
+ {
+ l.libs[i]->next = list;
+ l.libs[i]->prev = list->prev;
+ list->prev = l.libs[i];
+ list = l.libs[i];
+ }
+ else
+ {
+ l.libs[i]->next = e->next;
+ l.libs[i]->prev = e;
+ if (e->next)
+ e->next->prev = l.libs[i];
+ else
+ list->prev = l.libs[i];
+ e->next = l.libs[i];
+ }
+ }
+#ifdef DEBUG_LAYOUT
+ {
+ struct prelink_entry *last = list;
+ base = 0;
+ for (e = list; e; last = e, e = e->next)
+ {
+ if (e->base < base)
+ abort ();
+ base = e->base;
+ if ((e == list && e->prev->next != NULL)
+ || (e != list && e->prev->next != e))
+ abort ();
+ }
+ if (list->prev != last)
+ abort ();
+ }
+#endif
+ continue;
+
+not_found:
+ error (EXIT_FAILURE, 0, "Could not find virtual address slot for %s",
+ l.libs[i]->filename);
+ }
+
+ if (layout_libs_post)
+ {
+ l.list = list;
+ layout_libs_post (&l);
+ }
+
+ if (done & 0x80)
+ for (e = list; e != NULL; e = e->next)
+ if (e->done & 0x80)
+ {
+ e->done &= ~0x80;
+ e->base -= mmap_end - mmap_base;
+ e->end -= mmap_end - mmap_base;
+ e->layend -= mmap_base - mmap_base;
+ }
+
+ if (verbose)
+ {
+ if (narches == 1)
+ printf ("Assigned virtual address space slots for libraries:\n");
+ else
+ printf ("Assigned virtual address space slots for %d-bit %s ELF libraries:\n",
+ class == ELFCLASS32 ? 32 : 64, plarch->name);
+
+ for (i = 0; i < l.nlibs; ++i)
+ if (l.libs[i]->done >= 1)
+ printf ("%-60s %0*llx-%0*llx\n", l.libs[i]->filename,
+ class == ELFCLASS32 ? 8 : 16, (long long) l.libs[i]->base,
+ class == ELFCLASS32 ? 8 : 16, (long long) l.libs[i]->end);
+ }
+
+#ifdef DEBUG_LAYOUT
+ for (i = 0; i < l.nbinlibs; ++i)
+ {
+ for (j = 0; j < l.binlibs[i]->ndepends; ++j)
+ if ((l.binlibs[i]->depends[j]->type != ET_DYN
+ && l.binlibs[i]->depends[j]->type != ET_CACHE_DYN)
+ || l.binlibs[i]->depends[j]->done == 0)
+ break;
+ if (j < l.binlibs[i]->ndepends)
+ continue;
+ memcpy (deps, l.binlibs[i]->depends,
+ l.binlibs[i]->ndepends * sizeof (struct prelink_entry *));
+ qsort (deps, l.binlibs[i]->ndepends, sizeof (struct prelink_entry *),
+ deps_cmp);
+ for (j = 1; j < l.binlibs[i]->ndepends; ++j)
+ if (deps[j]->base
+ < ((deps[j - 1]->end + max_page_size - 1)
+ & ~(max_page_size - 1))
+ && (deps[j]->type == ET_DYN || deps[j - 1]->type == ET_DYN))
+ abort ();
+ }
+#endif
+ }
+
+ return 0;
+}
diff --git a/src/layout.h b/src/layout.h
new file mode 100644
index 0000000..f481d22
--- /dev/null
+++ b/src/layout.h
@@ -0,0 +1,35 @@
+/* Copyright (C) 2001, 2004, 2006 Red Hat, Inc.
+ Written by Jakub Jelinek <jakub@redhat.com>, 2001.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ifndef LAYOUT_H
+#define LAYOUT_H
+
+struct layout_libs
+ {
+ struct prelink_entry **libs;
+ struct prelink_entry **binlibs;
+ struct prelink_entry *list;
+ struct prelink_entry *fake;
+ GElf_Addr mmap_base, mmap_start, mmap_fin, mmap_end, max_page_size;
+ void *arch_data;
+ int flags;
+ int nlibs;
+ int nbinlibs;
+ int fakecnt;
+ };
+
+#endif /* LAYOUT_H */
diff --git a/src/main.c b/src/main.c
new file mode 100644
index 0000000..c879d62
--- /dev/null
+++ b/src/main.c
@@ -0,0 +1,570 @@
+/* Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007, 2010, 2011 Red Hat, Inc.
+ Written by Jakub Jelinek <jakub@redhat.com>, 2001.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include <config.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <locale.h>
+#include <error.h>
+#include <argp.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "prelink.h"
+
+#define PRELINK_CONF "/etc/prelink.conf"
+#define PRELINK_CACHE "/etc/prelink.cache"
+
+int all;
+int force;
+int verbose;
+int print_cache;
+int reloc_only;
+GElf_Addr reloc_base;
+int no_update;
+int random_base;
+int conserve_memory;
+int libs_only;
+int dry_run;
+int dereference;
+int one_file_system;
+int enable_cxx_optimizations = 1;
+int exec_shield;
+int undo, verify;
+enum verify_method_t verify_method;
+int quick;
+int compute_checksum;
+long long seed;
+GElf_Addr mmap_reg_start = ~(GElf_Addr) 0;
+GElf_Addr mmap_reg_end = ~(GElf_Addr) 0;
+GElf_Addr layout_page_size = 0;
+const char *dynamic_linker;
+const char *ld_library_path;
+const char *prelink_conf = PRELINK_CONF;
+const char *prelink_cache = PRELINK_CACHE;
+const char *undo_output;
+char *ld_preload = NULL;
+int noreexecinit;
+time_t initctime;
+
+const char *argp_program_version = PRELINK_PROG PKGVERSION " 1.0";
+
+const char *argp_program_bug_address = REPORT_BUGS_TO;
+
+static char argp_doc[] = PRELINK_PROG " -- program to relocate and prelink ELF shared libraries and programs";
+
+#define OPT_DYNAMIC_LINKER 0x80
+#define OPT_LD_LIBRARY_PATH 0x81
+#define OPT_LIBS_ONLY 0x82
+#define OPT_CXX_DISABLE 0x83
+#define OPT_MMAP_REG_START 0x84
+#define OPT_MMAP_REG_END 0x85
+#define OPT_EXEC_SHIELD 0x86
+#define OPT_NO_EXEC_SHIELD 0x87
+#define OPT_SEED 0x88
+#define OPT_MD5 0x89
+#define OPT_SHA 0x8a
+#define OPT_COMPUTE_CHECKSUM 0x8b
+#define OPT_LAYOUT_PAGE_SIZE 0x8c
+#define OPT_SYSROOT 0x8d
+#define OPT_RTLD 0x8e
+#define OPT_ALLOW_TEXTREL 0x8f
+#define OPT_LD_PRELOAD 0x90
+
+static struct argp_option options[] = {
+ {"all", 'a', 0, 0, "Prelink all binaries" },
+ {"black-list", 'b', "PATH", 0, "Blacklist path" },
+ {"cache-file", 'C', "CACHE", 0, "Use CACHE as cache file" },
+ {"config-file", 'c', "CONF", 0, "Use CONF as configuration file" },
+ {"force", 'f', 0, 0, "Force prelinking" },
+ {"dereference", 'h', 0, 0, "Follow symlinks when processing directory trees from command line" },
+ {"one-file-system", 'l', 0, 0, "Stay in local file system when processing directories from command line" },
+ {"conserve-memory", 'm', 0, 0, "Allow libraries to overlap as long as they never appear in the same program" },
+ {"no-update-cache", 'N', 0, 0, "Don't update prelink cache" },
+ {"dry-run", 'n', 0, 0, "Don't actually prelink anything" },
+ {"undo-output", 'o', "FILE", 0, "Undo output file" },
+ {"print-cache", 'p', 0, 0, "Print prelink cache" },
+ {"quick", 'q', 0, 0, "Quick scan" },
+ {"random", 'R', 0, 0, "Choose random base for libraries" },
+ {"reloc-only", 'r', "BASE_ADDRESS", 0, "Relocate library to given address, don't prelink" },
+ {"root", OPT_SYSROOT, "ROOT_PATH", 0, "Prefix all paths with ROOT_PATH" },
+ {"undo", 'u', 0, 0, "Undo prelink" },
+ {"verbose", 'v', 0, 0, "Produce verbose output" },
+ {"verify", 'y', 0, 0, "Verify file consistency by undoing and redoing prelink and printing original to standard output" },
+ {"md5", OPT_MD5, 0, 0, "For verify print MD5 sum of original to standard output instead of content" },
+ {"sha", OPT_SHA, 0, 0, "For verify print SHA sum of original to standard output instead of content" },
+ {"dynamic-linker", OPT_DYNAMIC_LINKER, "DYNAMIC_LINKER",
+ 0, "Special dynamic linker path" },
+ {"exec-shield", OPT_EXEC_SHIELD, 0, 0, "Lay out libraries for exec-shield on IA-32" },
+ {"no-exec-shield", OPT_NO_EXEC_SHIELD, 0, 0, "Don't lay out libraries for exec-shield on IA-32" },
+ {"ld-library-path", OPT_LD_LIBRARY_PATH, "PATHLIST",
+ 0, "What LD_LIBRARY_PATH should be used" },
+ {"ld-preload", OPT_LD_PRELOAD, "PATHLIST", 0, "What LD_PRELOAD should be used" },
+ {"libs-only", OPT_LIBS_ONLY, 0, 0, "Prelink only libraries, no binaries" },
+ {"layout-page-size", OPT_LAYOUT_PAGE_SIZE, "SIZE", 0, "Layout start of libraries at given boundary" },
+ {"disable-c++-optimizations", OPT_CXX_DISABLE, 0, OPTION_HIDDEN, "" },
+ {"mmap-region-start", OPT_MMAP_REG_START, "BASE_ADDRESS", OPTION_HIDDEN, "" },
+ {"mmap-region-end", OPT_MMAP_REG_END, "BASE_ADDRESS", OPTION_HIDDEN, "" },
+ {"seed", OPT_SEED, "SEED", OPTION_HIDDEN, "" },
+ {"compute-checksum", OPT_COMPUTE_CHECKSUM, 0, OPTION_HIDDEN, "" },
+ {"rtld", OPT_RTLD, "RTLD", OPTION_HIDDEN, "" },
+ {"init", 'i', 0, 0, "Do not re-execute init" },
+ {"allow-textrel", OPT_ALLOW_TEXTREL, 0, 0, "Allow text relocations even on architectures where they may not work" },
+ { 0 }
+};
+
+static error_t
+parse_opt (int key, char *arg, struct argp_state *state)
+{
+ char *endarg;
+
+ switch (key)
+ {
+ case 'a':
+ all = 1;
+ break;
+ case 'b':
+ if (add_to_blacklist (arg, dereference, one_file_system))
+ exit (EXIT_FAILURE);
+ break;
+ case 'f':
+ force = 1;
+ break;
+ case 'p':
+ print_cache = 1;
+ break;
+ case 'q':
+ quick = 1;
+ break;
+ case 'v':
+ ++verbose;
+ break;
+ case 'R':
+ random_base |= 1;
+ break;
+ case OPT_SEED:
+ random_base |= 2;
+ seed = strtoull (arg, &endarg, 0);
+ if (endarg != strchr (arg, '\0'))
+ error (EXIT_FAILURE, 0, "--seed option requires numberic argument");
+ break;
+ case 'r':
+ reloc_only = 1;
+ reloc_base = strtoull (arg, &endarg, 0);
+ if (endarg != strchr (arg, '\0'))
+ error (EXIT_FAILURE, 0, "-r option requires numberic argument");
+ break;
+ case 'h':
+ dereference = 1;
+ break;
+ case 'l':
+ one_file_system = 1;
+ break;
+ case 'm':
+ conserve_memory = 1;
+ break;
+ case 'N':
+ no_update = 1;
+ break;
+ case 'n':
+ dry_run = 1;
+ break;
+ case 'C':
+ prelink_cache = arg;
+ break;
+ case 'c':
+ prelink_conf = arg;
+ break;
+ case 'u':
+ undo = 1;
+ break;
+ case 'y':
+ verify = 1;
+ break;
+ case 'o':
+ undo_output = arg;
+ break;
+ case OPT_DYNAMIC_LINKER:
+ dynamic_linker = arg;
+ break;
+ case OPT_LD_LIBRARY_PATH:
+ ld_library_path = arg;
+ break;
+ case OPT_LIBS_ONLY:
+ libs_only = 1;
+ break;
+ case OPT_MD5:
+ verify_method = VERIFY_MD5;
+ break;
+ case OPT_SHA:
+ verify_method = VERIFY_SHA;
+ break;
+ case OPT_CXX_DISABLE:
+ enable_cxx_optimizations = 0;
+ break;
+ case OPT_MMAP_REG_START:
+ mmap_reg_start = strtoull (arg, &endarg, 0);
+ if (endarg != strchr (arg, '\0'))
+ error (EXIT_FAILURE, 0, "--mmap-region-start option requires numberic argument");
+ break;
+ case OPT_MMAP_REG_END:
+ mmap_reg_end = strtoull (arg, &endarg, 0);
+ if (endarg != strchr (arg, '\0'))
+ error (EXIT_FAILURE, 0, "--mmap-region-end option requires numberic argument");
+ break;
+ case OPT_EXEC_SHIELD:
+ exec_shield = 1;
+ break;
+ case OPT_NO_EXEC_SHIELD:
+ exec_shield = 0;
+ break;
+ case OPT_COMPUTE_CHECKSUM:
+ compute_checksum = 1;
+ break;
+ case OPT_LAYOUT_PAGE_SIZE:
+ layout_page_size = strtoull (arg, &endarg, 0);
+ if (endarg != strchr (arg, '\0') || (layout_page_size & (layout_page_size - 1)))
+ error (EXIT_FAILURE, 0, "--layout-page-size option requires numberic power-of-two argument");
+ case OPT_SYSROOT:
+ sysroot = arg;
+ break;
+ case OPT_RTLD:
+ prelink_rtld = arg;
+ break;
+ case 'i':
+ noreexecinit=1;
+ break;
+ case OPT_ALLOW_TEXTREL:
+ allow_bad_textrel = 1;
+ break;
+ case OPT_LD_PRELOAD:
+ ld_preload = arg;
+ break;
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+}
+
+time_t get_ctime(const char *file) {
+ struct stat st;
+ if(stat(file,&st) == 0)
+ return st.st_ctime;
+ return 0;
+}
+
+void checkinit() {
+ if(initctime != get_ctime("/sbin/init")) {
+ printf("Executing /sbin/init U\n");
+ system("/sbin/init U");
+ }
+}
+
+static struct argp argp = { options, parse_opt, "[FILES]", argp_doc };
+
+const char *prelink_rtld = NULL;
+
+/* Disable detection, this is not appropriate when cross prelinking. */
+#if 0 && (defined (__i386__) || defined (__x86_64__)) && defined (__GNUC__)
+static void
+set_default_layout_page_size (void)
+{
+ /* From gcc.dg/20020523-1.c test in gcc 3.2 testsuite. */
+ int fl1, fl2;
+
+#ifndef __x86_64__
+ /* See if we can use cpuid. */
+ __asm__ ("pushfl; pushfl; popl %0; movl %0,%1; xorl %2,%0;"
+ "pushl %0; popfl; pushfl; popl %0; popfl"
+ : "=&r" (fl1), "=&r" (fl2)
+ : "i" (0x00200000));
+ if (((fl1 ^ fl2) & 0x00200000) == 0)
+ return;
+#define cpuid(fl1, fl2, fn) \
+ __asm__ ("movl %%ebx, %1; cpuid; xchgl %%ebx, %1" \
+ : "=a" (fl1), "=r" (fl2) : "0" (fn) : "ecx", "edx")
+#else
+#define cpuid(fl1, fl2, fn) \
+ __asm__ ("cpuid" : "=a" (fl1), "=b" (fl2) : "0" (fn) : "ecx", "edx")
+#endif
+
+ /* See if CPUID gives capabilities. */
+ cpuid (fl1, fl2, 0);
+ if (fl1 < 1 || fl2 != 0x68747541 /* Auth - AMD */)
+ return;
+
+ /* CPUID 1. */
+ cpuid (fl1, fl2, 1);
+ if (((fl1 >> 8) & 0x0f) + ((fl1 >> 20) & 0xff) == 0x15 /* Family */)
+ /* On AMD Bulldozer CPUs default to --layout-page-size=0x8000. */
+ layout_page_size = 0x8000;
+}
+#else
+# define set_default_layout_page_size()
+#endif
+
+int
+main (int argc, char *argv[])
+{
+ int remaining, failures = 0;
+
+ setlocale (LC_ALL, "");
+
+ exec_shield = 2;
+
+ set_default_layout_page_size ();
+
+ prelink_init_cache ();
+
+ elf_version (EV_CURRENT);
+
+ argp_parse (&argp, argc, argv, 0, &remaining, 0);
+
+ if(!noreexecinit) {
+ initctime = get_ctime("/sbin/init");
+ atexit(checkinit);
+ }
+
+ if (ld_library_path == NULL)
+ ld_library_path = getenv ("LD_LIBRARY_PATH");
+
+ if (all && reloc_only)
+ error (EXIT_FAILURE, 0, "--all and --reloc-only options are incompatible");
+ if ((undo || verify) && reloc_only)
+ error (EXIT_FAILURE, 0, "--undo and --reloc-only options are incompatible");
+ if (verify && (undo || all))
+ error (EXIT_FAILURE, 0, "--verify and either --undo or --all options are incompatible");
+ if (dry_run && verify)
+ error (EXIT_FAILURE, 0, "--dry-run and --verify options are incompatible");
+ if ((undo || verify) && quick)
+ error (EXIT_FAILURE, 0, "--undo and --quick options are incompatible");
+
+ /* Set the default for exec_shield. */
+ if (exec_shield == 2)
+ {
+ if (sysroot == NULL && ! access ("/proc/sys/kernel/exec-shield", F_OK))
+ exec_shield = 1;
+ else
+ exec_shield = 0;
+ }
+
+#ifdef DEFAULT_SYSROOT
+ if (sysroot == NULL)
+ {
+ extern char *make_relative_prefix (const char *, const char *, const char *);
+ sysroot = make_relative_prefix (argv[0], BINDIR, DEFAULT_SYSROOT);
+ }
+#endif
+
+ if (sysroot)
+ {
+ sysroot = canonicalize_file_name (sysroot);
+ if (sysroot == NULL)
+ error (EXIT_FAILURE, 0, "Could not canonicalize --root argument");
+ asprintf ((char **) &prelink_conf, "%s%s", sysroot, prelink_conf);
+ }
+ if (prelink_rtld != NULL && prelink_rtld[0] == 0)
+ prelink_rtld = NULL;
+ else
+ if (prelink_rtld == NULL)
+ {
+ extern char *make_relative_prefix (const char *, const char *, const char *);
+ const char *path = make_relative_prefix (argv[0], BINDIR, BINDIR);
+ asprintf ((char **) &prelink_rtld, "%s/%s", path,
+ PRELINK_RTLD_PROG EXEEXT);
+ }
+
+ if (print_cache)
+ {
+ prelink_load_cache ();
+ prelink_print_cache ();
+ return 0;
+ }
+
+ if (remaining == argc && ! all)
+ error (EXIT_FAILURE, 0, "no files given and --all not used");
+
+ if (undo_output && (!undo || all))
+ error (EXIT_FAILURE, 0, "-o can be only specified together with -u and without -a");
+
+ if (undo_output && remaining + 1 != argc)
+ error (EXIT_FAILURE, 0, "-o can only be used when undoing a single object");
+
+ if (compute_checksum)
+ {
+ while (remaining < argc)
+ {
+ DSO *dso = open_dso (argv[remaining++]);
+
+ if (dso == NULL || reopen_dso (dso, NULL, NULL)
+ || prelink_set_checksum (dso))
+ error (0, 0, "could not recompute checksum of %s", dso->filename);
+ close_dso (dso);
+ error (0, 0, "%08x %s\n", (unsigned int) dso->info_DT_CHECKSUM, dso->filename);
+ }
+ exit (0);
+ }
+
+ if (verify)
+ {
+ if (remaining + 1 != argc)
+ error (EXIT_FAILURE, 0, "only one library or binary can be verified in a single command");
+ return prelink_verify (argv[remaining]);
+ }
+
+ if (reloc_only || (undo && ! all))
+ {
+ while (remaining < argc)
+ {
+ DSO *dso = open_dso (argv[remaining++]);
+ int ret;
+
+ if (dso == NULL)
+ {
+ ++failures;
+ continue;
+ }
+
+ if (dso->ehdr.e_type != ET_DYN
+ && (reloc_only || dso->ehdr.e_type != ET_EXEC))
+ {
+ ++failures;
+ error (0, 0, "%s is not a shared library", dso->filename);
+ continue;
+ }
+
+ if (undo)
+ ret = prelink_undo (dso);
+ else
+ ret = relocate_dso (dso, reloc_base);
+
+ if (ret)
+ {
+ ++failures;
+ close_dso (dso);
+ continue;
+ }
+
+ if (dynamic_info_is_set (dso, DT_CHECKSUM_BIT)
+ && dso_is_rdwr (dso)
+ && prelink_set_checksum (dso))
+ {
+ ++failures;
+ close_dso (dso);
+ continue;
+ }
+
+ if (dry_run)
+ {
+ close_dso (dso);
+ continue;
+ }
+
+ if (reloc_only)
+ dso->permissive = 1;
+ else if (undo_output)
+ {
+ const char *output, *orig_filename;
+
+ if (!dso_is_rdwr (dso))
+ {
+ struct stat64 st;
+ int err;
+
+ if (fstat64 (dso->fd, &st) < 0)
+ {
+ error (0, errno, "Could not stat %s", dso->filename);
+ ++failures;
+ close_dso (dso);
+ continue;
+ }
+ err = copy_fd_to_file (dso->fd, undo_output, &st);
+ if (err)
+ {
+ error (0, err, "Could not undo %s to %s", dso->filename,
+ undo_output);
+ ++failures;
+ }
+ close_dso (dso);
+ continue;
+ }
+
+ output = strdup (undo_output);
+ if (!output)
+ {
+ ++failures;
+ close_dso (dso);
+ continue;
+ }
+ if (dso->filename != dso->soname)
+ orig_filename = dso->filename;
+ else
+ orig_filename = strdup (dso->filename);
+ if (!orig_filename)
+ {
+ ++failures;
+ close_dso (dso);
+ continue;
+ }
+ dso->filename = output;
+ if (update_dso (dso, orig_filename))
+ ++failures;
+ free ((char *) orig_filename);
+ continue;
+ }
+
+ if (update_dso (dso, NULL))
+ ++failures;
+ }
+
+ return failures;
+ }
+
+ if (read_config (prelink_conf))
+ return EXIT_FAILURE;
+
+ if (blacklist_from_config ())
+ return EXIT_FAILURE;
+
+ if (quick)
+ prelink_load_cache ();
+
+ if (gather_config ())
+ return EXIT_FAILURE;
+
+ while (remaining < argc)
+ if (gather_object (argv[remaining++], dereference, one_file_system))
+ return EXIT_FAILURE;
+
+ if (gather_check_libs ())
+ return EXIT_FAILURE;
+
+ if (undo)
+ return undo_all ();
+
+ if (! all && ! quick)
+ prelink_load_cache ();
+
+ layout_libs ();
+ prelink_all ();
+
+ if (! no_update && ! dry_run)
+ prelink_save_cache (all);
+ return 0;
+}
diff --git a/src/makecrc.c b/src/makecrc.c
new file mode 100644
index 0000000..db52013
--- /dev/null
+++ b/src/makecrc.c
@@ -0,0 +1,63 @@
+/* Not copyrighted 1990 Mark Adler */
+
+#ifndef lint
+static char rcsid[] = "$Id: makecrc.c,v 0.6 1993/05/28 07:42:59 jloup Exp $";
+#endif
+
+#include <stdio.h>
+
+main()
+/*
+ Generate a table for a byte-wise 32-bit CRC calculation on the polynomial:
+ x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1.
+
+ Polynomials over GF(2) are represented in binary, one bit per coefficient,
+ with the lowest powers in the most significant bit. Then adding polynomials
+ is just exclusive-or, and multiplying a polynomial by x is a right shift by
+ one. If we call the above polynomial p, and represent a byte as the
+ polynomial q, also with the lowest power in the most significant bit (so the
+ byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p,
+ where a mod b means the remainder after dividing a by b.
+
+ This calculation is done using the shift-register method of multiplying and
+ taking the remainder. The register is initialized to zero, and for each
+ incoming bit, x^32 is added mod p to the register if the bit is a one (where
+ x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by
+ x (which is shifting right by one and adding x^32 mod p if the bit shifted
+ out is a one). We start with the highest power (least significant bit) of
+ q and repeat for all eight bits of q.
+
+ The table is simply the CRC of all possible eight bit values. This is all
+ the information needed to generate CRC's on data a byte at a time for all
+ combinations of CRC register values and incoming bytes. The table is
+ written to stdout as 256 long hexadecimal values in C language format.
+*/
+{
+ unsigned long c; /* crc shift register */
+ unsigned long e; /* polynomial exclusive-or pattern */
+ int i; /* counter for all possible eight bit values */
+ int k; /* byte being shifted into crc apparatus */
+
+ /* terms of polynomial defining this crc (except x^32): */
+ static int p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26};
+
+ /* Make exclusive-or pattern from polynomial (0xedb88320) */
+ e = 0;
+ for (i = 0; i < sizeof(p)/sizeof(int); i++)
+ e |= 1L << (31 - p[i]);
+
+ /* Compute and print table of CRC's, five per line */
+ printf(" 0x00000000");
+ for (i = 1; i < 256; i++)
+ {
+ c = i;
+ /* The idea to initialize the register with the byte instead of
+ * zero was stolen from Haruhiko Okumura's ar002
+ */
+ for (k = 8; k; k--)
+ c = c & 1 ? (c >> 1) ^ e : c >> 1;
+ printf(i % 5 ? ", 0x%08lx" : ",\n 0x%08lx", c);
+ }
+ putchar('\n');
+ return 0;
+}
diff --git a/src/md5.c b/src/md5.c
new file mode 100644
index 0000000..0d2fdef
--- /dev/null
+++ b/src/md5.c
@@ -0,0 +1,362 @@
+/* md5.c - Functions to compute MD5 message digest of files or memory blocks
+ according to the definition of MD5 in RFC 1321 from April 1992.
+ Copyright (C) 1995, 1996, 2001, 2003 Free Software Foundation, Inc.
+ NOTE: The canonical source of this file is maintained with the GNU C
+ Library. Bugs can be reported to bug-glibc@prep.ai.mit.edu.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995. */
+
+#include <sys/types.h>
+#include <stdlib.h>
+#include <string.h>
+#include <endian.h>
+#include <byteswap.h>
+#include "md5.h"
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+# define SWAP(n) bswap_32 (n)
+#else
+# define SWAP(n) (n)
+#endif
+
+/* This array contains the bytes used to pad the buffer to the next
+ 64-byte boundary. (RFC 1321, 3.1: Step 1) */
+static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ };
+
+
+/* Initialize structure containing state of computation.
+ (RFC 1321, 3.3: Step 3) */
+void
+md5_init_ctx (ctx)
+ struct md5_ctx *ctx;
+{
+ ctx->A = 0x67452301;
+ ctx->B = 0xefcdab89;
+ ctx->C = 0x98badcfe;
+ ctx->D = 0x10325476;
+
+ ctx->total[0] = ctx->total[1] = 0;
+ ctx->buflen = 0;
+}
+
+/* Put result from CTX in first 16 bytes following RESBUF. The result
+ must be in little endian byte order.
+
+ IMPORTANT: On some systems it is required that RESBUF is correctly
+ aligned for a 32 bits value. */
+void *
+md5_read_ctx (ctx, resbuf)
+ const struct md5_ctx *ctx;
+ void *resbuf;
+{
+ ((md5_uint32 *) resbuf)[0] = SWAP (ctx->A);
+ ((md5_uint32 *) resbuf)[1] = SWAP (ctx->B);
+ ((md5_uint32 *) resbuf)[2] = SWAP (ctx->C);
+ ((md5_uint32 *) resbuf)[3] = SWAP (ctx->D);
+
+ return resbuf;
+}
+
+/* Process the remaining bytes in the internal buffer and the usual
+ prolog according to the standard and write the result to RESBUF.
+
+ IMPORTANT: On some systems it is required that RESBUF is correctly
+ aligned for a 32 bits value. */
+void *
+md5_finish_ctx (ctx, resbuf)
+ struct md5_ctx *ctx;
+ void *resbuf;
+{
+ /* Take yet unprocessed bytes into account. */
+ md5_uint32 bytes = ctx->buflen;
+ size_t pad;
+
+ /* Now count remaining bytes. */
+ ctx->total[0] += bytes;
+ if (ctx->total[0] < bytes)
+ ++ctx->total[1];
+
+ pad = bytes >= 56 ? 64 + 56 - bytes : 56 - bytes;
+ memcpy (&ctx->buffer[bytes], fillbuf, pad);
+
+ /* Put the 64-bit file length in *bits* at the end of the buffer. */
+ *(md5_uint32 *) &ctx->buffer[bytes + pad] = SWAP (ctx->total[0] << 3);
+ *(md5_uint32 *) &ctx->buffer[bytes + pad + 4] = SWAP ((ctx->total[1] << 3) |
+ (ctx->total[0] >> 29));
+
+ /* Process last bytes. */
+ md5_process_block (ctx->buffer, bytes + pad + 8, ctx);
+
+ return md5_read_ctx (ctx, resbuf);
+}
+
+/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The
+ result is always in little endian byte order, so that a byte-wise
+ output yields to the wanted ASCII representation of the message
+ digest. */
+void *
+md5_buffer (buffer, len, resblock)
+ const char *buffer;
+ size_t len;
+ void *resblock;
+{
+ struct md5_ctx ctx;
+
+ /* Initialize the computation context. */
+ md5_init_ctx (&ctx);
+
+ /* Process whole buffer but last len % 64 bytes. */
+ md5_process_bytes (buffer, len, &ctx);
+
+ /* Put result in desired memory area. */
+ return md5_finish_ctx (&ctx, resblock);
+}
+
+
+void
+md5_process_bytes (buffer, len, ctx)
+ const void *buffer;
+ size_t len;
+ struct md5_ctx *ctx;
+{
+ /* When we already have some bits in our internal buffer concatenate
+ both inputs first. */
+ if (ctx->buflen != 0)
+ {
+ size_t left_over = ctx->buflen;
+ size_t add = 128 - left_over > len ? len : 128 - left_over;
+
+ memcpy (&ctx->buffer[left_over], buffer, add);
+ ctx->buflen += add;
+
+ if (ctx->buflen > 64)
+ {
+ md5_process_block (ctx->buffer, ctx->buflen & ~63, ctx);
+
+ ctx->buflen &= 63;
+ /* The regions in the following copy operation cannot overlap. */
+ memcpy (ctx->buffer, &ctx->buffer[(left_over + add) & ~63],
+ ctx->buflen);
+ }
+
+ buffer = (const char *) buffer + add;
+ len -= add;
+ }
+
+ /* Process available complete blocks. */
+ if (len >= 64)
+ {
+#define UNALIGNED_P(p) (((md5_uintptr) p) % __alignof__ (md5_uint32) != 0)
+ if (UNALIGNED_P (buffer))
+ while (len > 64)
+ {
+ md5_process_block (memcpy (ctx->buffer, buffer, 64), 64, ctx);
+ buffer = (const char *) buffer + 64;
+ len -= 64;
+ }
+ else
+ {
+ md5_process_block (buffer, len & ~63, ctx);
+ buffer = (const char *) buffer + (len & ~63);
+ len &= 63;
+ }
+ }
+
+ /* Move remaining bytes in internal buffer. */
+ if (len > 0)
+ {
+ size_t left_over = ctx->buflen;
+
+ memcpy (&ctx->buffer[left_over], buffer, len);
+ left_over += len;
+ if (left_over >= 64)
+ {
+ md5_process_block (ctx->buffer, 64, ctx);
+ left_over -= 64;
+ memcpy (ctx->buffer, &ctx->buffer[64], left_over);
+ }
+ ctx->buflen = left_over;
+ }
+}
+
+
+/* These are the four functions used in the four steps of the MD5 algorithm
+ and defined in the RFC 1321. The first function is a little bit optimized
+ (as found in Colin Plumbs public domain implementation). */
+/* #define FF(b, c, d) ((b & c) | (~b & d)) */
+#define FF(b, c, d) (d ^ (b & (c ^ d)))
+#define FG(b, c, d) FF (d, b, c)
+#define FH(b, c, d) (b ^ c ^ d)
+#define FI(b, c, d) (c ^ (b | ~d))
+
+/* Process LEN bytes of BUFFER, accumulating context into CTX.
+ It is assumed that LEN % 64 == 0. */
+
+void
+md5_process_block (buffer, len, ctx)
+ const void *buffer;
+ size_t len;
+ struct md5_ctx *ctx;
+{
+ md5_uint32 correct_words[16];
+ const md5_uint32 *words = buffer;
+ size_t nwords = len / sizeof (md5_uint32);
+ const md5_uint32 *endp = words + nwords;
+ md5_uint32 A = ctx->A;
+ md5_uint32 B = ctx->B;
+ md5_uint32 C = ctx->C;
+ md5_uint32 D = ctx->D;
+
+ /* First increment the byte count. RFC 1321 specifies the possible
+ length of the file up to 2^64 bits. Here we only compute the
+ number of bytes. Do a double word increment. */
+ ctx->total[0] += len;
+ if (ctx->total[0] < len)
+ ++ctx->total[1];
+
+ /* Process all bytes in the buffer with 64 bytes in each round of
+ the loop. */
+ while (words < endp)
+ {
+ md5_uint32 *cwp = correct_words;
+ md5_uint32 A_save = A;
+ md5_uint32 B_save = B;
+ md5_uint32 C_save = C;
+ md5_uint32 D_save = D;
+
+ /* First round: using the given function, the context and a constant
+ the next context is computed. Because the algorithms processing
+ unit is a 32-bit word and it is determined to work on words in
+ little endian byte order we perhaps have to change the byte order
+ before the computation. To reduce the work for the next steps
+ we store the swapped words in the array CORRECT_WORDS. */
+
+#define OP(a, b, c, d, s, T) \
+ do \
+ { \
+ a += FF (b, c, d) + (*cwp++ = SWAP (*words)) + T; \
+ ++words; \
+ a = rol (a, s); \
+ a += b; \
+ } \
+ while (0)
+
+ /* Before we start, one word to the strange constants.
+ They are defined in RFC 1321 as
+
+ T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64, or
+ perl -e 'foreach(1..64){printf "0x%08x\n", int (4294967296 * abs (sin $_))}'
+ */
+
+ /* Round 1. */
+ OP (A, B, C, D, 7, 0xd76aa478);
+ OP (D, A, B, C, 12, 0xe8c7b756);
+ OP (C, D, A, B, 17, 0x242070db);
+ OP (B, C, D, A, 22, 0xc1bdceee);
+ OP (A, B, C, D, 7, 0xf57c0faf);
+ OP (D, A, B, C, 12, 0x4787c62a);
+ OP (C, D, A, B, 17, 0xa8304613);
+ OP (B, C, D, A, 22, 0xfd469501);
+ OP (A, B, C, D, 7, 0x698098d8);
+ OP (D, A, B, C, 12, 0x8b44f7af);
+ OP (C, D, A, B, 17, 0xffff5bb1);
+ OP (B, C, D, A, 22, 0x895cd7be);
+ OP (A, B, C, D, 7, 0x6b901122);
+ OP (D, A, B, C, 12, 0xfd987193);
+ OP (C, D, A, B, 17, 0xa679438e);
+ OP (B, C, D, A, 22, 0x49b40821);
+
+ /* For the second to fourth round we have the possibly swapped words
+ in CORRECT_WORDS. Redefine the macro to take an additional first
+ argument specifying the function to use. */
+#undef OP
+#define OP(f, a, b, c, d, k, s, T) \
+ do \
+ { \
+ a += f (b, c, d) + correct_words[k] + T; \
+ a = rol (a, s); \
+ a += b; \
+ } \
+ while (0)
+
+ /* Round 2. */
+ OP (FG, A, B, C, D, 1, 5, 0xf61e2562);
+ OP (FG, D, A, B, C, 6, 9, 0xc040b340);
+ OP (FG, C, D, A, B, 11, 14, 0x265e5a51);
+ OP (FG, B, C, D, A, 0, 20, 0xe9b6c7aa);
+ OP (FG, A, B, C, D, 5, 5, 0xd62f105d);
+ OP (FG, D, A, B, C, 10, 9, 0x02441453);
+ OP (FG, C, D, A, B, 15, 14, 0xd8a1e681);
+ OP (FG, B, C, D, A, 4, 20, 0xe7d3fbc8);
+ OP (FG, A, B, C, D, 9, 5, 0x21e1cde6);
+ OP (FG, D, A, B, C, 14, 9, 0xc33707d6);
+ OP (FG, C, D, A, B, 3, 14, 0xf4d50d87);
+ OP (FG, B, C, D, A, 8, 20, 0x455a14ed);
+ OP (FG, A, B, C, D, 13, 5, 0xa9e3e905);
+ OP (FG, D, A, B, C, 2, 9, 0xfcefa3f8);
+ OP (FG, C, D, A, B, 7, 14, 0x676f02d9);
+ OP (FG, B, C, D, A, 12, 20, 0x8d2a4c8a);
+
+ /* Round 3. */
+ OP (FH, A, B, C, D, 5, 4, 0xfffa3942);
+ OP (FH, D, A, B, C, 8, 11, 0x8771f681);
+ OP (FH, C, D, A, B, 11, 16, 0x6d9d6122);
+ OP (FH, B, C, D, A, 14, 23, 0xfde5380c);
+ OP (FH, A, B, C, D, 1, 4, 0xa4beea44);
+ OP (FH, D, A, B, C, 4, 11, 0x4bdecfa9);
+ OP (FH, C, D, A, B, 7, 16, 0xf6bb4b60);
+ OP (FH, B, C, D, A, 10, 23, 0xbebfbc70);
+ OP (FH, A, B, C, D, 13, 4, 0x289b7ec6);
+ OP (FH, D, A, B, C, 0, 11, 0xeaa127fa);
+ OP (FH, C, D, A, B, 3, 16, 0xd4ef3085);
+ OP (FH, B, C, D, A, 6, 23, 0x04881d05);
+ OP (FH, A, B, C, D, 9, 4, 0xd9d4d039);
+ OP (FH, D, A, B, C, 12, 11, 0xe6db99e5);
+ OP (FH, C, D, A, B, 15, 16, 0x1fa27cf8);
+ OP (FH, B, C, D, A, 2, 23, 0xc4ac5665);
+
+ /* Round 4. */
+ OP (FI, A, B, C, D, 0, 6, 0xf4292244);
+ OP (FI, D, A, B, C, 7, 10, 0x432aff97);
+ OP (FI, C, D, A, B, 14, 15, 0xab9423a7);
+ OP (FI, B, C, D, A, 5, 21, 0xfc93a039);
+ OP (FI, A, B, C, D, 12, 6, 0x655b59c3);
+ OP (FI, D, A, B, C, 3, 10, 0x8f0ccc92);
+ OP (FI, C, D, A, B, 10, 15, 0xffeff47d);
+ OP (FI, B, C, D, A, 1, 21, 0x85845dd1);
+ OP (FI, A, B, C, D, 8, 6, 0x6fa87e4f);
+ OP (FI, D, A, B, C, 15, 10, 0xfe2ce6e0);
+ OP (FI, C, D, A, B, 6, 15, 0xa3014314);
+ OP (FI, B, C, D, A, 13, 21, 0x4e0811a1);
+ OP (FI, A, B, C, D, 4, 6, 0xf7537e82);
+ OP (FI, D, A, B, C, 11, 10, 0xbd3af235);
+ OP (FI, C, D, A, B, 2, 15, 0x2ad7d2bb);
+ OP (FI, B, C, D, A, 9, 21, 0xeb86d391);
+
+ /* Add the starting values of the context. */
+ A += A_save;
+ B += B_save;
+ C += C_save;
+ D += D_save;
+ }
+
+ /* Put checksum in context given as argument. */
+ ctx->A = A;
+ ctx->B = B;
+ ctx->C = C;
+ ctx->D = D;
+}
diff --git a/src/md5.h b/src/md5.h
new file mode 100644
index 0000000..55f6195
--- /dev/null
+++ b/src/md5.h
@@ -0,0 +1,105 @@
+/* md5.h - Declaration of functions and data types used for MD5 sum
+ computing library functions.
+ Copyright (C) 1995, 1996, 1999 Free Software Foundation, Inc.
+ NOTE: The canonical source of this file is maintained with the GNU C
+ Library. Bugs can be reported to bug-glibc@prep.ai.mit.edu.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ifndef _MD5_H
+#define _MD5_H 1
+
+#include <limits.h>
+#include <stdint.h>
+typedef uint32_t md5_uint32;
+typedef uintptr_t md5_uintptr;
+
+/* Structure to save state of computation between the single steps. */
+struct md5_ctx
+{
+ md5_uint32 A;
+ md5_uint32 B;
+ md5_uint32 C;
+ md5_uint32 D;
+
+ md5_uint32 total[2];
+ md5_uint32 buflen;
+ char buffer[128];
+};
+
+/*
+ * The following three functions are build up the low level used in
+ * the function `md5_buffer'.
+ */
+
+/* Initialize structure containing state of computation.
+ (RFC 1321, 3.3: Step 3) */
+extern void md5_init_ctx (struct md5_ctx *ctx);
+
+/* Starting with the result of former calls of this function (or the
+ initialization function update the context for the next LEN bytes
+ starting at BUFFER.
+ It is necessary that LEN is a multiple of 64!!! */
+extern void md5_process_block __P ((const void *buffer, size_t len,
+ struct md5_ctx *ctx));
+
+/* Starting with the result of former calls of this function (or the
+ initialization function update the context for the next LEN bytes
+ starting at BUFFER.
+ It is NOT required that LEN is a multiple of 64. */
+extern void md5_process_bytes __P ((const void *buffer, size_t len,
+ struct md5_ctx *ctx));
+
+/* Process the remaining bytes in the buffer and put result from CTX
+ in first 16 bytes following RESBUF. The result is always in little
+ endian byte order, so that a byte-wise output yields to the wanted
+ ASCII representation of the message digest.
+
+ IMPORTANT: On some systems it is required that RESBUF be correctly
+ aligned for a 32 bits value. */
+extern void *md5_finish_ctx (struct md5_ctx *ctx, void *resbuf);
+
+
+/* Put result from CTX in first 16 bytes following RESBUF. The result is
+ always in little endian byte order, so that a byte-wise output yields
+ to the wanted ASCII representation of the message digest.
+
+ IMPORTANT: On some systems it is required that RESBUF is correctly
+ aligned for a 32 bits value. */
+extern void *md5_read_ctx (const struct md5_ctx *ctx, void *resbuf);
+
+
+/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The
+ result is always in little endian byte order, so that a byte-wise
+ output yields to the wanted ASCII representation of the message
+ digest. */
+extern void *md5_buffer (const char *buffer, size_t len, void *resblock);
+
+/* The following is from gnupg-1.0.2's cipher/bithelp.h. */
+/* Rotate a 32 bit integer by n bytes */
+#if defined __GNUC__ && defined __i386__
+static inline md5_uint32
+rol(md5_uint32 x, int n)
+{
+ __asm__("roll %%cl,%0"
+ :"=r" (x)
+ :"0" (x),"c" (n));
+ return x;
+}
+#else
+# define rol(x,n) ( ((x) << (n)) | ((x) >> (32-(n))) )
+#endif
+
+#endif
diff --git a/src/mdebug.c b/src/mdebug.c
new file mode 100644
index 0000000..4c22d2f
--- /dev/null
+++ b/src/mdebug.c
@@ -0,0 +1,692 @@
+/* Copyright (C) 2001 Red Hat, Inc.
+ Written by Jakub Jelinek <jakub@redhat.com>, 2001.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include <config.h>
+#include <assert.h>
+#include <byteswap.h>
+#include <endian.h>
+#include <error.h>
+#include <stddef.h>
+
+#include "prelink.h"
+
+#define F8(x) unsigned char x[1];
+#define F16(x) unsigned char x[2];
+#define F24(x) unsigned char x[3];
+#define F32(x) unsigned char x[4];
+#define F64(x) unsigned char x[8];
+
+typedef struct
+{
+ F16(magic)
+ F16(vstamp)
+ F32(ilineMax)
+ F32(cbLine)
+ F32(cbLineOffset)
+ F32(idnMax)
+ F32(cbDnOffset)
+ F32(ipdMax)
+ F32(cbPdOffset)
+ F32(isymMax)
+ F32(cbSymOffset)
+ F32(ioptMax)
+ F32(cbOptOffset)
+ F32(iauxMax)
+ F32(cbAuxOffset)
+ F32(issMax)
+ F32(cbSsOffset)
+ F32(issExtMax)
+ F32(cbSsExtOffset)
+ F32(ifdMax)
+ F32(cbFdOffset)
+ F32(crfd)
+ F32(cbRfdOffset)
+ F32(iextMax)
+ F32(cbExtOffset)
+} mdebug_hdr_32;
+
+typedef struct
+{
+ F16(magic)
+ F16(vstamp)
+ F32(ilineMax)
+ F32(idnMax)
+ F32(ipdMax)
+ F32(isymMax)
+ F32(ioptMax)
+ F32(iauxMax)
+ F32(issMax)
+ F32(issExtMax)
+ F32(ifdMax)
+ F32(crfd)
+ F32(iextMax)
+ F64(cbLine)
+ F64(cbLineOffset)
+ F64(cbDnOffset)
+ F64(cbPdOffset)
+ F64(cbSymOffset)
+ F64(cbOptOffset)
+ F64(cbAuxOffset)
+ F64(cbSsOffset)
+ F64(cbSsExtOffset)
+ F64(cbFdOffset)
+ F64(cbRfdOffset)
+ F64(cbExtOffset)
+} mdebug_hdr_64;
+
+typedef struct
+{
+ F32(adr)
+ F32(rss)
+ F32(issBase)
+ F32(cbSs)
+ F32(isymBase)
+ F32(csym)
+ F32(ilineBase)
+ F32(cline)
+ F32(ioptBase)
+ F32(copt)
+ F16(ipdFirst)
+ F16(cpd)
+ F32(iauxBase)
+ F32(caux)
+ F32(rfdBase)
+ F32(crfd)
+ F8(bits1)
+ F24(bits2)
+ F32(cbLineOffset)
+ F32(cbLine)
+} mdebug_fdr_32;
+
+typedef struct
+{
+ F64(adr)
+ F64(cbLineOffset)
+ F64(cbLine)
+ F64(cbSs)
+ F32(rss)
+ F32(issBase)
+ F32(isymBase)
+ F32(csym)
+ F32(ilineBase)
+ F32(cline)
+ F32(ioptBase)
+ F32(copt)
+ F32(ipdFirst)
+ F32(cpd)
+ F32(iauxBase)
+ F32(caux)
+ F32(rfdBase)
+ F32(crfd)
+ F8(bits1)
+ F24(bits2)
+ F32(padding)
+} mdebug_fdr_64;
+
+typedef struct
+{
+ F32(iss)
+ F32(value)
+ F8(bits1)
+ F8(bits2)
+ F8(bits3)
+ F8(bits4)
+} mdebug_sym_32;
+
+typedef struct
+{
+ F64(value)
+ F32(iss)
+ F8(bits1)
+ F8(bits2)
+ F8(bits3)
+ F8(bits4)
+} mdebug_sym_64;
+
+typedef struct
+{
+ F8(bits1)
+ F8(bits2)
+ F16(fd)
+ mdebug_sym_32 asym;
+} mdebug_ext_32;
+
+typedef struct
+{
+ mdebug_sym_64 asym;
+ F8(bits1)
+ F24(bits2)
+ F32(fd)
+} mdebug_ext_64;
+
+typedef struct
+{
+ F32(adr)
+ F32(isym)
+ F32(iline)
+ F32(regmask)
+ F32(regoffset)
+ F32(iopt)
+ F32(fregmask)
+ F32(fregoffset)
+ F32(frameoffset)
+ F16(framereg)
+ F16(pcreg)
+ F32(lnLow)
+ F32(lnHigh)
+ F32(cbLineOffset)
+} mdebug_pdr_32;
+
+typedef struct
+{
+ F64(adr)
+ F64(cbLineOffset)
+ F32(isym)
+ F32(iline)
+ F32(regmask)
+ F32(regoffset)
+ F32(iopt)
+ F32(fregmask)
+ F32(fregoffset)
+ F32(frameoffset)
+ F32(lnLow)
+ F32(lnHigh)
+ F8(gp_prologue)
+ F8(bits1)
+ F8(bits2)
+ F8(localoff)
+ F16(framereg)
+ F16(pcreg)
+} mdebug_pdr_64;
+
+typedef struct
+{
+ F32(bits);
+} mdebug_rndx;
+
+typedef struct
+{
+ F8(bits1)
+ F8(bits2)
+ F8(bits3)
+ F8(bits4)
+ mdebug_rndx rndx;
+ F32(offset)
+} mdebug_opt;
+
+typedef struct
+{
+ F32(rfd)
+ F32(index)
+} mdebug_dnr;
+
+typedef struct
+{
+ F32(rfd)
+} mdebug_rfd;
+
+#define scNil 0
+#define scText 1
+#define scData 2
+#define scBss 3
+#define scRegister 4
+#define scAbs 5
+#define scUndefined 6
+#define scCdbLocal 7
+#define scBits 8
+#define scCdbSystem 9
+#define scDbx 9
+#define scRegImage 10
+#define scInfo 11
+#define scUserStruct 12
+#define scSData 13
+#define scSBss 14
+#define scRData 15
+#define scVar 16
+#define scCommon 17
+#define scSCommon 18
+#define scVarRegister 19
+#define scVariant 20
+#define scSUndefined 21
+#define scInit 22
+#define scBasedVar 23
+#define scXData 24
+#define scPData 25
+#define scFini 26
+#define scRConst 27
+#define scMax 32
+
+#define stNil 0
+#define stGlobal 1
+#define stStatic 2
+#define stParam 3
+#define stLocal 4
+#define stLabel 5
+#define stProc 6
+#define stBlock 7
+#define stEnd 8
+#define stMember 9
+#define stTypedef 10
+#define stFile 11
+#define stRegReloc 12
+#define stForward 13
+#define stStaticProc 14
+#define stConstant 15
+#define stStaParam 16
+#define stStruct 26
+#define stUnion 27
+#define stEnum 28
+#define stIndirect 34
+#define stMax 64
+
+struct mdebug
+{
+ uint32_t (*read_32) (char *);
+ GElf_Addr (*read_ptr) (char *);
+ void (*write_ptr) (char *, GElf_Addr);
+ void (*adjust_sym) (struct mdebug *, unsigned char *, GElf_Addr, GElf_Addr);
+ unsigned char *buf;
+ DSO *dso;
+};
+
+static uint32_t
+read_native_32 (char *p)
+{
+ return *(uint32_t *)p;
+}
+
+static uint32_t
+read_swap_32 (char *p)
+{
+ return bswap_32 (*(uint32_t *)p);
+}
+
+static GElf_Addr
+read_native_ptr32 (char *p)
+{
+ return *(uint32_t *)p;
+}
+
+static GElf_Addr
+read_swap_ptr32 (char *p)
+{
+ return bswap_32 (*(uint32_t *)p);
+}
+
+static void
+write_native_ptr32 (char *p, GElf_Addr v)
+{
+ *(uint32_t *)p = v;
+}
+
+static void
+write_swap_ptr32 (char *p, GElf_Addr v)
+{
+ *(uint32_t *)p = bswap_32 (v);
+}
+
+static GElf_Addr
+read_native_ptr64 (char *p)
+{
+ return *(uint64_t *)p;
+}
+
+static GElf_Addr
+read_swap_ptr64 (char *p)
+{
+ return bswap_64 (*(uint64_t *)p);
+}
+
+static void
+write_native_ptr64 (char *p, GElf_Addr v)
+{
+ *(uint64_t *)p = v;
+}
+
+static void
+write_swap_ptr64 (char *p, GElf_Addr v)
+{
+ *(uint64_t *)p = bswap_64 (v);
+}
+
+static inline int
+mdebug_sym_relocate (unsigned int st, unsigned int sc)
+{
+ switch (sc)
+ {
+ case scData:
+ case scBss:
+ case scAbs:
+ case scSData:
+ case scSBss:
+ case scRData:
+ case scXData:
+ case scPData:
+ return 1;
+ case scText:
+ case scInit:
+ case scFini:
+ case scRConst:
+ if (st != stBlock && st != stEnd && st != stFile)
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+static void
+adjust_mdebug_sym_le32 (struct mdebug *mdebug, mdebug_sym_32 *symptr,
+ GElf_Addr start, GElf_Addr adjust)
+{
+ unsigned int st, sc;
+ GElf_Addr addr;
+
+ st = symptr->bits1[0] & 0x3f;
+ sc = (symptr->bits1[0] >> 6) | ((symptr->bits2[0] & 7) << 2);
+ if (mdebug_sym_relocate (st, sc))
+ {
+ addr = mdebug->read_ptr (symptr->value);
+ if (addr >= start && (addr || sc != scAbs))
+ mdebug->write_ptr (symptr->value, addr + adjust);
+ }
+}
+
+static void
+adjust_mdebug_sym_be32 (struct mdebug *mdebug, mdebug_sym_32 *symptr,
+ GElf_Addr start, GElf_Addr adjust)
+{
+ unsigned int st, sc;
+ GElf_Addr addr;
+
+ st = symptr->bits1[0] >> 2;
+ sc = ((symptr->bits1[0] & 3) << 3) | (symptr->bits2[0] >> 5);
+ if (mdebug_sym_relocate (st, sc))
+ {
+ addr = mdebug->read_ptr (symptr->value);
+ if (addr >= start && (addr || sc != scAbs))
+ mdebug->write_ptr (symptr->value, addr + adjust);
+ }
+}
+
+static void
+adjust_mdebug_sym_le64 (struct mdebug *mdebug, mdebug_sym_64 *symptr,
+ GElf_Addr start, GElf_Addr adjust)
+{
+ unsigned int st, sc;
+ GElf_Addr addr;
+
+ st = symptr->bits1[0] & 0x3f;
+ sc = (symptr->bits1[0] >> 6) | ((symptr->bits2[0] & 7) << 2);
+ if (mdebug_sym_relocate (st, sc))
+ {
+ addr = mdebug->read_ptr (symptr->value);
+ if (addr >= start && (addr || sc != scAbs))
+ mdebug->write_ptr (symptr->value, addr + adjust);
+ }
+}
+
+static void
+adjust_mdebug_sym_be64 (struct mdebug *mdebug, mdebug_sym_64 *symptr,
+ GElf_Addr start, GElf_Addr adjust)
+{
+ unsigned int st, sc;
+ GElf_Addr addr;
+
+ st = symptr->bits1[0] >> 2;
+ sc = ((symptr->bits1[0] & 3) << 3) | (symptr->bits2[0] >> 5);
+ if (mdebug_sym_relocate (st, sc))
+ {
+ addr = mdebug->read_ptr (symptr->value);
+ if (addr >= start && (addr || sc != scAbs))
+ mdebug->write_ptr (symptr->value, addr + adjust);
+ }
+}
+
+#define SIZEOf(x) \
+ (dso->arch->class == ELFCLASS32 ? sizeof (x##_32) : sizeof (x##_64))
+#define SIZEOF(x) SIZEOf(x)
+#define OFFSETOf(x,y) \
+ (dso->arch->class == ELFCLASS32 ? offsetof (x##_32, y) : offsetof (x##_64, y))
+#define OFFSETOF(x,y) OFFSETOf(x,y)
+
+static int
+start_mdebug (DSO *dso, int n, struct mdebug *mdebug)
+{
+ Elf_Data *data = NULL;
+ Elf_Scn *scn = dso->scn[n];
+
+ data = elf_getdata (scn, NULL);
+ mdebug->buf = data->d_buf;
+ mdebug->dso = dso;
+ assert (data != NULL && data->d_buf != NULL);
+ assert (elf_getdata (scn, data) == NULL);
+ assert (data->d_off == 0 && data->d_size == dso->shdr[n].sh_size);
+ if (dso->mdebug_orig_offset == 0)
+ dso->mdebug_orig_offset = dso->shdr[n].sh_offset;
+#if __BYTE_ORDER == __BIG_ENDIAN
+ if (dso->ehdr.e_ident[EI_DATA] == ELFDATA2MSB)
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
+ if (dso->ehdr.e_ident[EI_DATA] == ELFDATA2LSB)
+#else
+# error Not supported host endianess
+#endif
+ {
+ mdebug->read_32 = read_native_32;
+ if (dso->arch->class == ELFCLASS32)
+ {
+ mdebug->read_ptr = read_native_ptr32;
+ mdebug->write_ptr = write_native_ptr32;
+ }
+ else
+ {
+ mdebug->read_ptr = read_native_ptr64;
+ mdebug->write_ptr = write_native_ptr64;
+ }
+ }
+#if __BYTE_ORDER == __BIG_ENDIAN
+ else if (dso->ehdr.e_ident[EI_DATA] == ELFDATA2LSB)
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
+ else if (dso->ehdr.e_ident[EI_DATA] == ELFDATA2MSB)
+#endif
+ {
+ mdebug->read_32 = read_swap_32;
+ if (dso->arch->class == ELFCLASS32)
+ {
+ mdebug->read_ptr = read_swap_ptr32;
+ mdebug->write_ptr = write_swap_ptr32;
+ }
+ else
+ {
+ mdebug->read_ptr = read_swap_ptr64;
+ mdebug->write_ptr = write_swap_ptr64;
+ }
+ }
+ else
+ {
+ error (0, 0, "%s: Wrong ELF data enconding", dso->filename);
+ return 1;
+ }
+ if (dso->ehdr.e_ident[EI_DATA] == ELFDATA2LSB)
+ {
+ if (dso->arch->class == ELFCLASS32)
+ mdebug->adjust_sym = (void *) adjust_mdebug_sym_le32;
+ else
+ mdebug->adjust_sym = (void *) adjust_mdebug_sym_le64;
+ }
+ else
+ {
+ if (dso->arch->class == ELFCLASS32)
+ mdebug->adjust_sym = (void *) adjust_mdebug_sym_be32;
+ else
+ mdebug->adjust_sym = (void *) adjust_mdebug_sym_be64;
+ }
+
+ if (dso->shdr[n].sh_size < SIZEOF (mdebug_hdr))
+ {
+ error (0, 0, "%s: .mdebug section too small", dso->filename);
+ return 1;
+ }
+ return 0;
+}
+
+int
+adjust_mdebug (DSO *dso, int n, GElf_Addr start, GElf_Addr adjust)
+{
+ struct mdebug mdebug;
+ struct { GElf_Off offset; GElf_Off size; size_t entsize; } regions [11];
+ int i = 0;
+ unsigned char *symptr, *endptr;
+
+ if (start_mdebug (dso, n, &mdebug))
+ return 1;
+
+#define READ(x, y, longsize, sz) \
+do { \
+ unsigned char *tmp; \
+ tmp = mdebug.buf + OFFSETOF (mdebug_hdr, x); \
+ regions[i].offset = mdebug.read_ptr (tmp); \
+ tmp = mdebug.buf + OFFSETOF (mdebug_hdr, y); \
+ if (longsize) \
+ regions[i].size = mdebug.read_ptr (tmp); \
+ else \
+ regions[i].size = mdebug.read_32 (tmp); \
+ regions[i].entsize = sz; \
+ ++i; \
+} while (0)
+
+ READ (cbLineOffset, cbLine, 1, sizeof (char));
+ READ (cbDnOffset, idnMax, 0, sizeof (mdebug_dnr));
+ READ (cbPdOffset, ipdMax, 0, SIZEOF (mdebug_pdr));
+ READ (cbSymOffset, isymMax, 0, SIZEOF (mdebug_sym));
+ READ (cbOptOffset, ioptMax, 0, sizeof (mdebug_opt));
+ READ (cbAuxOffset, iauxMax, 0, 4 * sizeof (char));
+ READ (cbSsOffset, issMax, 0, sizeof (char));
+ READ (cbSsExtOffset, issExtMax, 0, sizeof (char));
+ READ (cbFdOffset, ifdMax, 0, SIZEOF (mdebug_fdr));
+ READ (cbRfdOffset, crfd, 0, sizeof (mdebug_rfd));
+ READ (cbExtOffset, iextMax, 0, SIZEOF (mdebug_ext));
+
+#undef READ
+
+ for (i = 0; i < 11; ++i)
+ {
+ if (regions[i].offset)
+ regions[i].offset -= dso->mdebug_orig_offset;
+ regions[i].size *= regions[i].entsize;
+ if (regions[i].offset >= dso->shdr[n].sh_size
+ || regions[i].offset + regions[i].size > dso->shdr[n].sh_size)
+ {
+ error (0, 0, "%s: File offsets in .mdebug header point outside of .mdebug section",
+ dso->filename);
+ return 1;
+ }
+ }
+
+ /* Adjust symbols. */
+ if (regions[3].offset)
+ for (symptr = mdebug.buf + regions[3].offset,
+ endptr = symptr + regions[3].size;
+ symptr < endptr;
+ symptr += regions[3].entsize)
+ mdebug.adjust_sym (&mdebug, symptr, start, adjust);
+
+ /* Adjust file descriptor's addresses. */
+ if (regions[8].offset)
+ for (symptr = mdebug.buf + regions[8].offset,
+ endptr = symptr + regions[8].size;
+ symptr < endptr;
+ symptr += regions[8].entsize)
+ {
+ GElf_Addr addr;
+
+ assert (offsetof (mdebug_fdr_32, adr) == 0);
+ assert (offsetof (mdebug_fdr_64, adr) == 0);
+ addr = mdebug.read_ptr (symptr);
+ if (addr >= start)
+ mdebug.write_ptr (symptr, addr + adjust);
+ }
+
+ /* Adjust extended symbols. */
+ if (regions[10].offset)
+ for (symptr = mdebug.buf + regions[10].offset
+ + OFFSETOF (mdebug_ext, asym),
+ endptr = symptr + regions[10].size;
+ symptr < endptr;
+ symptr += regions[10].entsize)
+ mdebug.adjust_sym (&mdebug, symptr, start, adjust);
+
+ return 0;
+}
+
+int
+finalize_mdebug (DSO *dso)
+{
+ int i;
+ struct mdebug mdebug;
+ GElf_Addr adj;
+
+ for (i = 1; i < dso->ehdr.e_shnum; i++)
+ if ((dso->arch->machine == EM_ALPHA
+ && dso->shdr[i].sh_type == SHT_ALPHA_DEBUG)
+ || (dso->arch->machine == EM_MIPS
+ && dso->shdr[i].sh_type == SHT_MIPS_DEBUG))
+ break;
+
+ assert (i < dso->ehdr.e_shnum);
+
+ /* If .mdebug's file position did not change, there is nothing to do. */
+ adj = dso->shdr[i].sh_offset - dso->mdebug_orig_offset;
+ if (! adj)
+ return 0;
+
+ if (start_mdebug (dso, i, &mdebug))
+ return 1;
+
+#define ADJUST(x) \
+do { \
+ unsigned char *tmp; \
+ GElf_Addr val; \
+ tmp = mdebug.buf + OFFSETOF (mdebug_hdr, x); \
+ val = mdebug.read_ptr (tmp); \
+ if (! val) \
+ break; \
+ val += adj; \
+ if (val < dso->shdr[i].sh_offset \
+ || val >= dso->shdr[i].sh_offset + dso->shdr[i].sh_size) \
+ { \
+ error (0, 0, "%s: File offsets in .mdebug header point outside of .mdebug section", \
+ dso->filename); \
+ return 1; \
+ } \
+ mdebug.write_ptr (tmp, val); \
+} while (0)
+
+ ADJUST (cbLineOffset);
+ ADJUST (cbDnOffset);
+ ADJUST (cbPdOffset);
+ ADJUST (cbSymOffset);
+ ADJUST (cbOptOffset);
+ ADJUST (cbAuxOffset);
+ ADJUST (cbSsOffset);
+ ADJUST (cbSsExtOffset);
+ ADJUST (cbFdOffset);
+ ADJUST (cbRfdOffset);
+ ADJUST (cbExtOffset);
+
+#undef ADJUST
+ return 0;
+}
diff --git a/src/prelink.c b/src/prelink.c
new file mode 100644
index 0000000..0798811
--- /dev/null
+++ b/src/prelink.c
@@ -0,0 +1,995 @@
+/* Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007 Red Hat, Inc.
+ Written by Jakub Jelinek <jakub@redhat.com>, 2001.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include <config.h>
+#include <assert.h>
+#include <endian.h>
+#include <errno.h>
+#include <error.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include "prelink.h"
+#include "reloc.h"
+
+static GElf_Addr
+resolve_ldso (struct prelink_info *info, GElf_Word r_sym,
+ int reloc_type __attribute__((unused)))
+{
+ /* Dynamic linker does not depend on any other library,
+ all symbols resolve to themselves with the exception
+ of SHN_UNDEF symbols which resolve to 0. */
+ if (info->symtab[r_sym].st_shndx == SHN_UNDEF)
+ {
+ info->resolveent = NULL;
+ info->resolvetls = NULL;
+ return 0;
+ }
+ else
+ {
+ /* As the dynamic linker is relocated first,
+ l_addr will be 0. */
+ info->resolveent = info->ent;
+ info->resolvetls = NULL;
+ return 0 + info->symtab[r_sym].st_value;
+ }
+}
+
+static GElf_Addr
+resolve_dso (struct prelink_info *info, GElf_Word r_sym,
+ int reloc_type)
+{
+ struct prelink_symbol *s;
+ int reloc_class = info->dso->arch->reloc_class (reloc_type);
+
+ for (s = & info->symbols[r_sym]; s; s = s->next)
+ if (s->reloc_class == reloc_class)
+ break;
+
+ info->resolveent = NULL;
+ info->resolvetls = NULL;
+
+ if (s == NULL || s->u.ent == NULL)
+ return 0;
+
+ if (reloc_class == RTYPE_CLASS_TLS)
+ {
+ info->resolvetls = s->u.tls;
+ return s->value;
+ }
+
+ info->resolveent = s->u.ent;
+ return s->u.ent->base + s->value;
+}
+
+static int
+prelink_rel (DSO *dso, int n, struct prelink_info *info)
+{
+ Elf_Data *data = NULL;
+ Elf_Scn *scn = dso->scn[n];
+ GElf_Rel rel;
+ int sec;
+
+ while ((data = elf_getdata (scn, data)) != NULL)
+ {
+ int ndx, maxndx;
+ GElf_Addr addr = dso->shdr[n].sh_addr + data->d_off;
+
+ maxndx = data->d_size / dso->shdr[n].sh_entsize;
+ for (ndx = 0; ndx < maxndx;
+ ++ndx, addr += dso->shdr[n].sh_entsize)
+ {
+ gelfx_getrel (dso->elf, data, ndx, &rel);
+ sec = addr_to_sec (dso, rel.r_offset);
+ if (sec == -1)
+ continue;
+
+ switch (dso->arch->prelink_rel (info, &rel, addr))
+ {
+ case 2:
+ gelfx_update_rel (dso->elf, data, ndx, &rel);
+ break;
+ case 0:
+ break;
+ default:
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+static int
+prelink_rela (DSO *dso, int n, struct prelink_info *info)
+{
+ Elf_Data *data = NULL;
+ Elf_Scn *scn = dso->scn[n];
+ GElf_Rela rela;
+ int sec;
+
+ while ((data = elf_getdata (scn, data)) != NULL)
+ {
+ int ndx, maxndx;
+ GElf_Addr addr = dso->shdr[n].sh_addr + data->d_off;
+
+ maxndx = data->d_size / dso->shdr[n].sh_entsize;
+ for (ndx = 0; ndx < maxndx;
+ ++ndx, addr += dso->shdr[n].sh_entsize)
+ {
+ gelfx_getrela (dso->elf, data, ndx, &rela);
+ sec = addr_to_sec (dso, rela.r_offset);
+ if (sec == -1)
+ continue;
+
+ switch (dso->arch->prelink_rela (info, &rela, addr))
+ {
+ case 2:
+ gelfx_update_rela (dso->elf, data, ndx, &rela);
+ break;
+ case 0:
+ break;
+ default:
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+int
+prelink_prepare (DSO *dso)
+{
+ struct reloc_info rinfo;
+ int liblist = 0, libstr = 0, newlibstr = 0, undo = 0, newundo = 0;
+ int i;
+
+ for (i = 1; i < dso->ehdr.e_shnum; ++i)
+ {
+ const char *name
+ = strptr (dso, dso->ehdr.e_shstrndx, dso->shdr[i].sh_name);
+ if (! strcmp (name, ".gnu.liblist"))
+ liblist = i;
+ else if (! strcmp (name, ".gnu.libstr"))
+ libstr = i;
+ else if (! strcmp (name, ".gnu.prelink_undo"))
+ undo = i;
+ }
+
+ if (undo == 0)
+ {
+ Elf32_Shdr *shdr32;
+ Elf64_Shdr *shdr64;
+ Elf_Data src, dst;
+
+ dso->undo.d_size = gelf_fsize (dso->elf, ELF_T_EHDR, 1, EV_CURRENT)
+ + gelf_fsize (dso->elf, ELF_T_PHDR,
+ dso->ehdr.e_phnum, EV_CURRENT)
+ + gelf_fsize (dso->elf, ELF_T_SHDR,
+ dso->ehdr.e_shnum - 1, EV_CURRENT);
+ dso->undo.d_buf = malloc (dso->undo.d_size);
+ if (dso->undo.d_buf == NULL)
+ {
+ error (0, ENOMEM, "%s: Could not create .gnu.prelink_undo section",
+ dso->filename);
+ return 1;
+ }
+ dso->undo.d_type = ELF_T_BYTE;
+ dso->undo.d_off = 0;
+ dso->undo.d_align = gelf_fsize (dso->elf, ELF_T_ADDR, 1, EV_CURRENT);
+ dso->undo.d_version = EV_CURRENT;
+ src = dso->undo;
+ src.d_type = ELF_T_EHDR;
+ src.d_size = gelf_fsize (dso->elf, ELF_T_EHDR, 1, EV_CURRENT);
+ dst = src;
+ switch (gelf_getclass (dso->elf))
+ {
+ case ELFCLASS32:
+ src.d_buf = elf32_getehdr (dso->elf);
+ if (elf32_xlatetof (&dst, &src, dso->ehdr.e_ident[EI_DATA]) == NULL)
+ {
+ error (0, 0, "%s: Failed to create .gnu.prelink_undo section",
+ dso->filename);
+ return 1;
+ }
+ break;
+ case ELFCLASS64:
+ src.d_buf = elf64_getehdr (dso->elf);
+ if (elf64_xlatetof (&dst, &src, dso->ehdr.e_ident[EI_DATA]) == NULL)
+ {
+ error (0, 0, "%s: Failed to create .gnu.prelink_undo section",
+ dso->filename);
+ return 1;
+ }
+ break;
+ default:
+ return 1;
+ }
+ src.d_buf = dst.d_buf + src.d_size;
+ src.d_type = ELF_T_PHDR;
+ src.d_size = gelf_fsize (dso->elf, ELF_T_PHDR, dso->ehdr.e_phnum,
+ EV_CURRENT);
+ dst = src;
+ switch (gelf_getclass (dso->elf))
+ {
+ case ELFCLASS32:
+ src.d_buf = elf32_getphdr (dso->elf);
+ if (elf32_xlatetof (&dst, &src, dso->ehdr.e_ident[EI_DATA]) == NULL)
+ {
+ error (0, 0, "%s: Failed to create .gnu.prelink_undo section",
+ dso->filename);
+ return 1;
+ }
+ break;
+ case ELFCLASS64:
+ src.d_buf = elf64_getphdr (dso->elf);
+ if (elf64_xlatetof (&dst, &src, dso->ehdr.e_ident[EI_DATA]) == NULL)
+ {
+ error (0, 0, "%s: Failed to create .gnu.prelink_undo section",
+ dso->filename);
+ return 1;
+ }
+ break;
+ }
+ src.d_buf = dst.d_buf + src.d_size;
+ src.d_type = ELF_T_SHDR;
+ src.d_size = gelf_fsize (dso->elf, ELF_T_SHDR,
+ dso->ehdr.e_shnum - 1, EV_CURRENT);
+ dst = src;
+ switch (gelf_getclass (dso->elf))
+ {
+ case ELFCLASS32:
+ shdr32 = (Elf32_Shdr *) src.d_buf;
+ /* Note: cannot use dso->scn[i] below, since we want to save the
+ original section order before non-alloced sections were
+ sorted by sh_offset. */
+ for (i = 1; i < dso->ehdr.e_shnum; ++i)
+ shdr32[i - 1] = *elf32_getshdr (elf_getscn (dso->elf, i));
+ if (elf32_xlatetof (&dst, &src, dso->ehdr.e_ident[EI_DATA]) == NULL)
+ {
+ error (0, 0, "%s: Failed to create .gnu.prelink_undo section",
+ dso->filename);
+ return 1;
+ }
+ break;
+ case ELFCLASS64:
+ shdr64 = (Elf64_Shdr *) src.d_buf;
+ /* Note: cannot use dso->scn[i] below, since we want to save the
+ original section order before non-alloced sections were
+ sorted by sh_offset. */
+ for (i = 1; i < dso->ehdr.e_shnum; ++i)
+ shdr64[i - 1] = *elf64_getshdr (elf_getscn (dso->elf, i));
+ if (elf64_xlatetof (&dst, &src, dso->ehdr.e_ident[EI_DATA]) == NULL)
+ {
+ error (0, 0, "%s: Failed to create .gnu.prelink_undo section",
+ dso->filename);
+ return 1;
+ }
+ break;
+ }
+ }
+
+ if (dso->ehdr.e_type != ET_DYN)
+ return 0;
+
+ if (find_reloc_sections (dso, &rinfo))
+ return 1;
+
+ if (is_ldso_soname (dso->soname))
+ {
+ liblist = -1;
+ libstr = -1;
+ }
+
+ if (liblist && libstr && undo
+ && ! rinfo.rel_to_rela && ! rinfo.rel_to_rela_plt)
+ return 0;
+
+ if (! liblist || ! libstr || ! undo)
+ {
+ struct section_move *move;
+
+ move = init_section_move (dso);
+ if (move == NULL)
+ return 1;
+
+ if (! liblist)
+ {
+ liblist = move->old_to_new [dso->ehdr.e_shstrndx];
+ add_section (move, liblist);
+ }
+ else
+ liblist = 0;
+
+ if (! libstr)
+ {
+ add_section (move, liblist + 1);
+ libstr = liblist + 1;
+ newlibstr = 1;
+ }
+ else if (libstr != -1)
+ libstr = move->old_to_new[libstr];
+
+ if (! undo)
+ {
+ if (libstr == -1)
+ {
+ undo = move->old_to_new [dso->ehdr.e_shstrndx];
+ add_section (move, undo);
+ }
+ else
+ {
+ add_section (move, libstr + 1);
+ undo = libstr + 1;
+ }
+ newundo = 1;
+ }
+ else
+ undo = move->old_to_new[undo];
+
+ if (reopen_dso (dso, move, NULL))
+ {
+ free (move);
+ return 1;
+ }
+
+ free (move);
+ if (liblist)
+ {
+ memset (&dso->shdr[liblist], 0, sizeof (GElf_Shdr));
+ dso->shdr[liblist].sh_name = shstrtabadd (dso, ".gnu.liblist");
+ if (dso->shdr[liblist].sh_name == 0)
+ return 1;
+ dso->shdr[liblist].sh_type = SHT_GNU_LIBLIST;
+ dso->shdr[liblist].sh_offset = dso->shdr[liblist - 1].sh_offset;
+ if (dso->shdr[liblist - 1].sh_type != SHT_NOBITS)
+ dso->shdr[liblist].sh_offset += dso->shdr[liblist - 1].sh_size;
+ dso->shdr[liblist].sh_link = libstr;
+ dso->shdr[liblist].sh_addralign = sizeof (GElf_Word);
+ dso->shdr[liblist].sh_entsize = sizeof (Elf32_Lib);
+ }
+
+ if (newlibstr)
+ {
+ memset (&dso->shdr[libstr], 0, sizeof (GElf_Shdr));
+ dso->shdr[libstr].sh_name = shstrtabadd (dso, ".gnu.libstr");
+ if (dso->shdr[libstr].sh_name == 0)
+ return 1;
+ dso->shdr[libstr].sh_type = SHT_STRTAB;
+ dso->shdr[libstr].sh_offset = dso->shdr[libstr - 1].sh_offset;
+ if (dso->shdr[libstr - 1].sh_type != SHT_NOBITS)
+ dso->shdr[libstr].sh_offset += dso->shdr[libstr - 1].sh_size;
+ dso->shdr[libstr].sh_addralign = 1;
+ }
+
+ if (newundo)
+ {
+ Elf_Scn *scn;
+ Elf_Data *data;
+ GElf_Addr newoffset;
+
+ memset (&dso->shdr[undo], 0, sizeof (GElf_Shdr));
+ dso->shdr[undo].sh_name = shstrtabadd (dso, ".gnu.prelink_undo");
+ if (dso->shdr[undo].sh_name == 0)
+ return 1;
+ dso->shdr[undo].sh_type = SHT_PROGBITS;
+ dso->shdr[undo].sh_offset = dso->shdr[undo - 1].sh_offset;
+ if (dso->shdr[undo - 1].sh_type != SHT_NOBITS)
+ dso->shdr[undo].sh_offset += dso->shdr[undo - 1].sh_size;
+ dso->shdr[undo].sh_addralign = dso->undo.d_align;
+ dso->shdr[undo].sh_entsize = 1;
+ dso->shdr[undo].sh_size = dso->undo.d_size;
+ newoffset = dso->shdr[undo].sh_offset + dso->undo.d_align - 1;
+ newoffset &= ~(dso->shdr[undo].sh_addralign - 1);
+ if (adjust_dso_nonalloc (dso, undo + 1, dso->shdr[undo].sh_offset,
+ dso->undo.d_size + newoffset
+ - dso->shdr[undo].sh_offset))
+ return 1;
+ dso->shdr[undo].sh_offset = newoffset;
+ scn = dso->scn[undo];
+ data = elf_getdata (scn, NULL);
+ assert (data != NULL && elf_getdata (scn, data) == NULL);
+ free (data->d_buf);
+ *data = dso->undo;
+ dso->undo.d_buf = NULL;
+ }
+ }
+ else if (reopen_dso (dso, NULL, NULL))
+ return 1;
+
+ if (rinfo.rel_to_rela || rinfo.rel_to_rela_plt)
+ {
+ /* On REL architectures, we might need to convert some REL
+ relocations to RELA relocs. */
+
+ int safe = 1, align = 0, last;
+ GElf_Addr start, adjust, adjust1, adjust2;
+
+ for (i = 1; i < (rinfo.plt ? rinfo.plt : rinfo.first); i++)
+ switch (dso->shdr[i].sh_type)
+ {
+ case SHT_HASH:
+ case SHT_GNU_HASH:
+ case SHT_DYNSYM:
+ case SHT_REL:
+ case SHT_RELA:
+ case SHT_STRTAB:
+ case SHT_NOTE:
+ case SHT_GNU_verdef:
+ case SHT_GNU_verneed:
+ case SHT_GNU_versym:
+ /* These sections are safe, no relocations should point
+ to it, therefore enlarging a section after sections
+ from this set only (and SHT_REL) in ET_DYN just needs
+ adjusting the rest of the library. */
+ break;
+ case SHT_DYNAMIC:
+ case SHT_MIPS_REGINFO:
+ case SHT_MIPS_OPTIONS:
+ /* The same applies to these sections on MIPS. The convention
+ is to put .dynamic and .reginfo near the beginning of the
+ read-only segment, before the program text. No relocations
+ may refer to them. */
+ if (dso->ehdr.e_machine == EM_MIPS)
+ break;
+ /* FALLTHROUGH */
+ default:
+ /* The rest of sections are not safe. */
+ safe = 0;
+ break;
+ }
+
+ if (! safe)
+ {
+ error (0, 0, "%s: Cannot safely convert %s' section from REL to RELA",
+ dso->filename, strptr (dso, dso->ehdr.e_shstrndx,
+ dso->shdr[rinfo.rel_to_rela
+ ? rinfo.first : rinfo.plt].sh_name));
+ return 1;
+ }
+
+ for (i = rinfo.plt ? rinfo.plt : rinfo.first; i < dso->ehdr.e_shnum; i++)
+ {
+ if (dso->shdr[i].sh_addralign > align)
+ align = dso->shdr[i].sh_addralign;
+ }
+
+ if (rinfo.plt)
+ start = dso->shdr[rinfo.plt].sh_addr + dso->shdr[rinfo.plt].sh_size;
+ else
+ start = dso->shdr[rinfo.last].sh_addr + dso->shdr[rinfo.last].sh_size;
+
+ adjust1 = 0;
+ adjust2 = 0;
+ assert (sizeof (Elf32_Rel) * 3 == sizeof (Elf32_Rela) * 2);
+ assert (sizeof (Elf64_Rel) * 3 == sizeof (Elf64_Rela) * 2);
+ if (rinfo.rel_to_rela)
+ {
+ for (i = rinfo.first; i <= rinfo.last; ++i)
+ {
+ GElf_Addr size = dso->shdr[i].sh_size / 2 * 3;
+ adjust1 += size - dso->shdr[i].sh_size;
+ if (convert_rel_to_rela (dso, i))
+ return 1;
+ }
+ }
+ if (rinfo.rel_to_rela_plt)
+ {
+ GElf_Addr size = dso->shdr[rinfo.plt].sh_size / 2 * 3;
+ adjust2 = size - dso->shdr[rinfo.plt].sh_size;
+ if (convert_rel_to_rela (dso, rinfo.plt))
+ return 1;
+ }
+
+ adjust = adjust1 + adjust2;
+
+ /* Need to make sure that all the remaining sections are properly
+ aligned. */
+ if (align)
+ adjust = (adjust + align - 1) & ~(align - 1);
+
+ /* Need to make sure adjust doesn't cause different Phdr segments
+ to overlap on the same page. */
+ last = -1;
+ for (i = 0; i < dso->ehdr.e_phnum; ++i)
+ if (dso->phdr[i].p_type == PT_LOAD
+ && dso->phdr[i].p_vaddr + dso->phdr[i].p_memsz >= start)
+ {
+ if (last != -1
+ && (((dso->phdr[last].p_vaddr + dso->phdr[last].p_memsz - 1)
+ ^ dso->phdr[i].p_vaddr)
+ & ~(dso->arch->max_page_size - 1))
+ && !(((dso->phdr[last].p_vaddr + dso->phdr[last].p_memsz
+ + adjust - 1)
+ ^ (dso->phdr[i].p_vaddr + adjust))
+ & ~(dso->arch->max_page_size - 1)))
+ {
+ if (align >= dso->arch->max_page_size)
+ {
+ error (0, 0, "%s: Cannot grow reloc sections", dso->filename);
+ return 1;
+ }
+ adjust = (adjust + dso->arch->max_page_size - 1)
+ & ~(dso->arch->max_page_size - 1);
+ }
+ last = i;
+ }
+
+ /* Adjust all addresses pointing into remaining sections. */
+ if (adjust_dso (dso, start - 1, adjust))
+ return 1;
+
+ if (rinfo.rel_to_rela)
+ {
+ GElf_Addr adjust3 = 0;
+ for (i = rinfo.first; i <= rinfo.last; ++i)
+ {
+ GElf_Addr size = dso->shdr[i].sh_size / 2 * 3;
+
+ dso->shdr[i].sh_addr += adjust3;
+ dso->shdr[i].sh_offset += adjust3;
+ adjust3 += size - dso->shdr[i].sh_size;
+ dso->shdr[i].sh_size = size;
+ }
+ assert (adjust1 == adjust3);
+ if (rinfo.plt)
+ {
+ dso->shdr[rinfo.plt].sh_addr += adjust1;
+ dso->shdr[rinfo.plt].sh_offset += adjust1;
+ }
+ }
+ if (rinfo.rel_to_rela_plt)
+ dso->shdr[rinfo.plt].sh_size += adjust2;
+
+ if (update_dynamic_rel (dso, &rinfo))
+ return 1;
+ }
+
+ return 0;
+}
+
+static int
+prelink_dso (struct prelink_info *info)
+{
+ int liblist = 0, libstr = 0, nobits_plt = 0;
+ int i, ndeps = info->ent->ndepends + 1;
+ DSO *dso = info->dso;
+ Elf32_Lib *list = NULL;
+ Elf_Scn *scn;
+ Elf_Data *data;
+ GElf_Addr oldsize, oldoffset;
+ size_t strsize;
+
+ if (dso->ehdr.e_type != ET_DYN)
+ return 0;
+
+ for (i = 1; i < dso->ehdr.e_shnum; ++i)
+ {
+ const char *name
+ = strptr (dso, dso->ehdr.e_shstrndx, dso->shdr[i].sh_name);
+ if (! strcmp (name, ".gnu.liblist"))
+ liblist = i;
+ else if (! strcmp (name, ".gnu.libstr"))
+ libstr = i;
+ else if (! strcmp (name, ".plt") && dso->shdr[i].sh_type == SHT_NOBITS)
+ nobits_plt = i;
+#if 0
+ else if (dso->arch->create_opd && ! strcmp (name, ".opd"))
+ opd = i;
+#endif
+ }
+
+ if (nobits_plt)
+ {
+ int j, first;
+ GElf_Addr adj, last_offset;
+
+ for (i = 0; i < dso->ehdr.e_phnum; ++i)
+ if (dso->phdr[i].p_type == PT_LOAD
+ && dso->phdr[i].p_vaddr <= dso->shdr[nobits_plt].sh_addr
+ && dso->phdr[i].p_vaddr + dso->phdr[i].p_memsz
+ >= dso->shdr[nobits_plt].sh_addr
+ + dso->shdr[nobits_plt].sh_size)
+ break;
+
+ if (i == dso->ehdr.e_phnum)
+ {
+ error (0, 0, "%s: .plt section not contained within a segment",
+ dso->filename);
+ return 1;
+ }
+
+ for (j = i + 1; j < dso->ehdr.e_phnum; ++j)
+ if (dso->phdr[j].p_type == PT_LOAD)
+ {
+ error (0, 0, "%s: library's NOBITS .plt section not in loadable last segment",
+ dso->filename);
+ return 1;
+ }
+
+ for (j = nobits_plt - 1; j > 0; --j)
+ if (dso->shdr[j].sh_addr < dso->phdr[i].p_vaddr
+ || dso->shdr[j].sh_type != SHT_NOBITS)
+ break;
+ first = j + 1;
+
+ for (j = first; j <= nobits_plt; ++j)
+ {
+ Elf_Data *data = elf_getdata (dso->scn[j], NULL);
+
+ assert (data->d_buf == NULL);
+ assert (data->d_size == dso->shdr[j].sh_size);
+ if (data->d_size)
+ {
+ data->d_buf = calloc (data->d_size, 1);
+ if (data->d_buf == NULL)
+ {
+ error (0, ENOMEM, "%s: Could not convert NOBITS section into PROGBITS",
+ dso->filename);
+ return 1;
+ }
+ }
+ data->d_type = ELF_T_BYTE;
+ dso->shdr[j].sh_type = SHT_PROGBITS;
+ dso->shdr[j].sh_offset = dso->phdr[i].p_offset + dso->shdr[j].sh_addr
+ - dso->phdr[i].p_vaddr;
+ }
+
+ adj = dso->shdr[nobits_plt].sh_offset + dso->shdr[nobits_plt].sh_size
+ - dso->phdr[i].p_offset;
+ assert (adj <= dso->phdr[i].p_memsz);
+ if (adj > dso->phdr[i].p_filesz)
+ {
+ adj -= dso->phdr[i].p_filesz;
+ dso->phdr[i].p_filesz += adj;
+ if (adjust_dso_nonalloc (dso, nobits_plt + 1,
+ dso->shdr[first].sh_offset, adj))
+ return 1;
+ }
+
+ last_offset = dso->shdr[nobits_plt].sh_offset
+ + dso->shdr[nobits_plt].sh_size;
+ for (j = nobits_plt + 1; j < dso->ehdr.e_shnum; ++j)
+ if (!(dso->shdr[j].sh_flags & (SHF_ALLOC | SHF_WRITE | SHF_EXECINSTR)))
+ break;
+ else
+ {
+ last_offset += dso->shdr[j].sh_addralign - 1;
+ last_offset &= ~(dso->shdr[j].sh_addralign - 1);
+ if (last_offset > dso->phdr[i].p_offset + dso->phdr[i].p_filesz)
+ last_offset = dso->phdr[i].p_offset + dso->phdr[i].p_filesz;
+ dso->shdr[j].sh_offset = last_offset;
+ }
+ }
+
+ if (ndeps <= 1)
+ return 0;
+
+ assert (liblist != 0);
+ assert (libstr != 0);
+
+ list = calloc (ndeps - 1, sizeof (Elf32_Lib));
+ if (list == NULL)
+ {
+ error (0, ENOMEM, "%s: Cannot build .gnu.liblist section",
+ dso->filename);
+ goto error_out;
+ }
+
+ strsize = 1;
+ for (i = 0; i < ndeps - 1; ++i)
+ {
+ struct prelink_entry *ent = info->ent->depends[i];
+
+ strsize += strlen (info->sonames[i + 1]) + 1;
+ list[i].l_time_stamp = ent->timestamp;
+ list[i].l_checksum = ent->checksum;
+ }
+
+ scn = dso->scn[libstr];
+ data = elf_getdata (scn, NULL);
+ if (data == NULL)
+ data = elf_newdata (scn);
+ assert (elf_getdata (scn, data) == NULL);
+
+ data->d_type = ELF_T_BYTE;
+ data->d_size = 1;
+ data->d_off = 0;
+ data->d_align = 1;
+ data->d_version = EV_CURRENT;
+ data->d_buf = realloc (data->d_buf, strsize);
+ if (data->d_buf == NULL)
+ {
+ error (0, ENOMEM, "%s: Could not build .gnu.libstr section",
+ dso->filename);
+ goto error_out;
+ }
+
+ oldsize = dso->shdr[libstr].sh_size;
+ dso->shdr[libstr].sh_size = 1;
+ *(char *)data->d_buf = '\0';
+ for (i = 0; i < ndeps - 1; ++i)
+ {
+ const char *name = info->sonames[i + 1];
+
+ list[i].l_name = strtabfind (dso, liblist, name);
+ if (list[i].l_name == 0)
+ {
+ size_t len = strlen (name) + 1;
+
+ memcpy (data->d_buf + data->d_size, name, len);
+ list[i].l_name = data->d_size;
+ data->d_size += len;
+ dso->shdr[libstr].sh_size += len;
+ }
+ }
+ if (oldsize != dso->shdr[libstr].sh_size)
+ {
+ GElf_Addr adjust = dso->shdr[libstr].sh_size - oldsize;
+
+ oldoffset = dso->shdr[libstr].sh_offset;
+ if (adjust_dso_nonalloc (dso, libstr + 1, oldoffset, adjust))
+ goto error_out;
+ }
+
+ scn = dso->scn[liblist];
+ data = elf_getdata (scn, NULL);
+ if (data == NULL)
+ data = elf_newdata (scn);
+ assert (elf_getdata (scn, data) == NULL);
+
+ data->d_type = ELF_T_WORD;
+ data->d_size = (ndeps - 1) * sizeof (Elf32_Lib);
+ data->d_off = 0;
+ data->d_align = sizeof (GElf_Word);
+ data->d_version = EV_CURRENT;
+ free (data->d_buf);
+ data->d_buf = list;
+ list = NULL;
+
+ if (data->d_size != dso->shdr[liblist].sh_size)
+ {
+ GElf_Addr adjust = data->d_size - dso->shdr[liblist].sh_size;
+ GElf_Addr newoffset;
+
+ oldoffset = dso->shdr[liblist].sh_offset;
+ newoffset = oldoffset;
+ if (newoffset & (data->d_align - 1))
+ {
+ newoffset = (newoffset + data->d_align - 1) & ~(data->d_align - 1);
+ adjust += newoffset - dso->shdr[liblist].sh_offset;
+ }
+ if (adjust_dso_nonalloc (dso, liblist + 1, oldoffset, adjust))
+ goto error_out;
+ dso->shdr[liblist].sh_offset = newoffset;
+ dso->shdr[liblist].sh_size = data->d_size;
+ }
+
+ recompute_nonalloc_offsets (dso);
+ return 0;
+
+error_out:
+ free (list);
+ return 1;
+}
+
+static int
+prelink_set_timestamp (struct prelink_info *info)
+{
+ DSO *dso = info->dso;
+
+ if (! verify)
+ info->ent->timestamp = getenv ("PRELINK_TIMESTAMP") ?
+ atoi (getenv ("PRELINK_TIMESTAMP"))
+ : (GElf_Word) time (NULL);
+ dso->info_DT_GNU_PRELINKED = info->ent->timestamp;
+ if (prelink_set_checksum (dso))
+ return 1;
+ info->ent->checksum = dso->info_DT_CHECKSUM;
+ return 0;
+}
+
+static void
+free_info (struct prelink_info *info)
+{
+ int i;
+
+ free (info->symtab);
+ free (info->dynbss);
+ free (info->sdynbss);
+ free (info->conflict_rela);
+ if (info->conflicts)
+ {
+ for (i = 0; i < info->ent->ndepends + 1; ++i)
+ {
+ if (info->conflicts[i].hash == &info->conflicts[i].first)
+ {
+ struct prelink_conflict *c = info->conflicts[i].first;
+ void *f;
+
+ while (c != NULL)
+ {
+ f = c;
+ c = c->next;
+ free (f);
+ }
+ }
+ else
+ {
+ int j;
+ for (j = 0; j < 251; j++)
+ {
+ struct prelink_conflict *c = info->conflicts[i].hash[j];
+ void *f;
+
+ while (c != NULL)
+ {
+ f = c;
+ c = c->next;
+ free (f);
+ }
+ }
+ free (info->conflicts[i].hash);
+ }
+ if (info->conflicts[i].hash2 != NULL)
+ free (info->conflicts[i].hash2);
+ }
+ free (info->conflicts);
+ }
+ if (info->sonames)
+ {
+ for (i = 0; i < info->ent->ndepends + 1; ++i)
+ free ((char *) info->sonames[i]);
+ free (info->sonames);
+ }
+ free (info->tls);
+ if (info->symbols)
+ {
+ for (i = 0; i < info->symbol_count; ++i)
+ {
+ struct prelink_symbol *s = info->symbols[i].next;
+ void *f;
+
+ while (s != NULL)
+ {
+ f = s;
+ s = s->next;
+ free (f);
+ }
+ }
+ free (info->symbols);
+ }
+}
+
+int
+prelink (DSO *dso, struct prelink_entry *ent)
+{
+ int i;
+ Elf_Scn *scn;
+ Elf_Data *data;
+ struct prelink_info info;
+
+ ent->pltgot = dso->info[DT_PLTGOT];
+
+ if (! dso->info[DT_SYMTAB])
+ return 0;
+
+ if (! dso_is_rdwr (dso) && dso->ehdr.e_type == ET_DYN)
+ {
+ if (reopen_dso (dso, NULL, NULL))
+ return 1;
+ }
+
+ i = addr_to_sec (dso, dso->info[DT_SYMTAB]);
+ /* DT_SYMTAB should be found and should point to
+ start of .dynsym section. */
+ if (i == -1
+ || dso->info[DT_SYMTAB] != dso->shdr[i].sh_addr)
+ {
+ error (0, 0, "%s: Bad symtab", dso->filename);
+ return 1;
+ }
+
+ memset (&info, 0, sizeof (info));
+ info.ent = ent;
+ info.symtab_entsize = dso->shdr[i].sh_entsize;
+ info.symtab = calloc (dso->shdr[i].sh_size / dso->shdr[i].sh_entsize,
+ sizeof (GElf_Sym));
+ if (info.symtab == NULL)
+ {
+ error (0, ENOMEM, "%s: Cannot convert .dynsym section", dso->filename);
+ return 1;
+ }
+
+ scn = dso->scn[i];
+ data = NULL;
+ while ((data = elf_getdata (scn, data)) != NULL)
+ {
+ int ndx, maxndx, loc;
+
+ loc = data->d_off / info.symtab_entsize;
+ maxndx = data->d_size / info.symtab_entsize;
+ for (ndx = 0; ndx < maxndx; ++ndx)
+ gelfx_getsym (dso->elf, data, ndx, info.symtab + loc + ndx);
+ }
+ info.symtab_start =
+ adjust_new_to_old (dso, dso->shdr[i].sh_addr - dso->base);
+ info.symtab_end = info.symtab_start + dso->shdr[i].sh_size;
+ info.dso = dso;
+ switch (prelink_get_relocations (&info))
+ {
+ case 0:
+ goto error_out;
+ case 1:
+ info.resolve = resolve_ldso;
+ break;
+ case 2:
+ info.resolve = resolve_dso;
+ break;
+ }
+
+ if (dso->arch->arch_pre_prelink && dso->arch->arch_pre_prelink (dso))
+ goto error_out;
+
+ if (dso->ehdr.e_type == ET_EXEC)
+ {
+ if (prelink_exec (&info))
+ goto error_out;
+ }
+ else if (prelink_dso (&info))
+ goto error_out;
+
+ for (i = 1; i < dso->ehdr.e_shnum; i++)
+ {
+ if (! (dso->shdr[i].sh_flags & SHF_ALLOC))
+ continue;
+ if (! strcmp (strptr (dso, dso->ehdr.e_shstrndx,
+ dso->shdr[i].sh_name),
+ ".gnu.conflict"))
+ continue;
+ switch (dso->shdr[i].sh_type)
+ {
+ case SHT_REL:
+ if (prelink_rel (dso, i, &info))
+ goto error_out;
+ break;
+ case SHT_RELA:
+ if (prelink_rela (dso, i, &info))
+ goto error_out;
+ break;
+ }
+ }
+
+ if (dso->arch->arch_prelink && dso->arch->arch_prelink (&info))
+ goto error_out;
+
+ if (dso->arch->read_opd && dso->arch->read_opd (dso, ent))
+ goto error_out;
+
+ /* Must be last. */
+ if (dso->ehdr.e_type == ET_DYN
+ && prelink_set_timestamp (&info))
+ goto error_out;
+
+ free_info (&info);
+ return 0;
+
+error_out:
+ free_info (&info);
+ return 1;
+}
diff --git a/src/prelink.h b/src/prelink.h
new file mode 100644
index 0000000..299f1fa
--- /dev/null
+++ b/src/prelink.h
@@ -0,0 +1,632 @@
+/* Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2009, 2010, 2011,
+ 2013 Red Hat, Inc.
+ Copyright (C) 2008 CodeSourcery.
+ Written by Jakub Jelinek <jakub@redhat.com>, 2001.
+ Updated by Maciej W. Rozycki <macro@codesourcery.com>, 2008.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ifndef PRELINK_H
+#define PRELINK_H
+
+#include <elf.h>
+#include <libelf.h>
+#include <gelfx.h>
+#include <ftw.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <utime.h>
+#include <glob.h>
+
+#ifndef HAVE_ELF64_BYTE
+typedef uint8_t Elf64_Byte;
+#endif
+
+#ifndef DT_GNU_LIBLIST
+#define DT_GNU_LIBLIST 0x6ffffef9
+#define DT_GNU_LIBLISTSZ 0x6ffffdf7
+#define DT_GNU_CONFLICT 0x6ffffef8
+#define DT_GNU_CONFLICTSZ 0x6ffffdf6
+#define DT_GNU_PRELINKED 0x6ffffdf5
+#define SHT_GNU_LIBLIST 0x6ffffff7
+#endif
+
+#if DT_GNU_LIBLIST == 0x6ffffef7
+#undef DT_GNU_LIBLIST
+#undef DT_GNU_CONFLICT
+#undef SHT_GNU_LIBLIST
+#define DT_GNU_LIBLIST 0x6ffffef9
+#define DT_GNU_CONFLICT 0x6ffffef8
+#define SHT_GNU_LIBLIST 0x6ffffff7
+#endif
+
+#ifndef DT_GNU_HASH
+#define DT_GNU_HASH 0x6ffffef5
+#define SHT_GNU_HASH 0x6ffffff6
+#endif
+
+#ifndef DT_TLSDESC_PLT
+#define DT_TLSDESC_PLT 0x6ffffef6
+#endif
+
+#ifndef DT_MIPS_RLD_VERSION
+#define DT_MIPS_RLD_VERSION 0x70000001
+#define DT_MIPS_TIME_STAMP 0x70000002
+#define DT_MIPS_ICHECKSUM 0x70000003
+#define DT_MIPS_IVERSION 0x70000004
+#define DT_MIPS_FLAGS 0x70000005
+#define DT_MIPS_BASE_ADDRESS 0x70000006
+#define DT_MIPS_CONFLICT 0x70000008
+#define DT_MIPS_LIBLIST 0x70000009
+#define DT_MIPS_LOCAL_GOTNO 0x7000000a
+#define DT_MIPS_CONFLICTNO 0x7000000b
+#define DT_MIPS_LIBLISTNO 0x70000010
+#define DT_MIPS_SYMTABNO 0x70000011
+#define DT_MIPS_UNREFEXTNO 0x70000012
+#define DT_MIPS_GOTSYM 0x70000013
+#define DT_MIPS_HIPAGENO 0x70000014
+#define DT_MIPS_RLD_MAP 0x70000016
+#endif
+
+#ifndef R_MIPS_TLS_DTPMOD32
+#define R_MIPS_TLS_DTPMOD32 38
+#define R_MIPS_TLS_DTPREL32 39
+#define R_MIPS_TLS_TPREL32 47
+#endif
+
+#ifndef R_MIPS_TLS_DTPMOD64
+#define R_MIPS_TLS_DTPMOD64 40
+#define R_MIPS_TLS_DTPREL64 41
+#define R_MIPS_TLS_TPREL64 48
+#endif
+
+#ifndef R_MIPS_GLOB_DAT
+#define R_MIPS_GLOB_DAT 51
+#endif
+
+#ifndef R_MIPS_COPY
+#define R_MIPS_COPY 126
+#define R_MIPS_JUMP_SLOT 127
+#define STO_MIPS_PLT 0x8
+#define DT_MIPS_PLTGOT 0x70000032
+#define DT_MIPS_RWPLT 0x70000034
+#endif
+
+#ifndef SHT_MIPS_DWARF
+#define SHT_MIPS_DWARF 0x7000001e
+#endif
+
+#ifndef RSS_UNDEF
+#define RSS_UNDEF 0
+#endif
+
+#ifndef R_ARM_TLS_DESC
+#define R_ARM_TLS_DESC 13
+#endif
+
+#ifndef R_ARM_TLS_DTPMOD32
+#define R_ARM_TLS_DTPMOD32 17
+#define R_ARM_TLS_DTPOFF32 18
+#define R_ARM_TLS_TPOFF32 19
+#endif
+
+#ifndef R_386_IRELATIVE
+#define R_386_IRELATIVE 42
+#endif
+
+#ifndef R_X86_64_IRELATIVE
+#define R_X86_64_IRELATIVE 37
+#endif
+
+#ifndef R_PPC_IRELATIVE
+#define R_PPC_IRELATIVE 248
+#endif
+
+#ifndef R_PPC64_JMP_IREL
+#define R_PPC64_JMP_IREL 247
+#define R_PPC64_IRELATIVE 248
+#endif
+
+#ifndef R_390_IRELATIVE
+#define R_390_IRELATIVE 61
+#endif
+
+#ifndef R_ARM_IRELATIVE
+#define R_ARM_IRELATIVE 160
+#endif
+
+struct prelink_entry;
+struct prelink_info;
+struct PLArch;
+struct opd_lib;
+
+struct PLAdjust
+{
+ GElf_Addr start;
+ GElf_Addr adjust;
+};
+
+struct section_move
+{
+ int old_shnum;
+ int new_shnum;
+ int *old_to_new;
+ int *new_to_old;
+};
+
+typedef struct
+{
+ Elf *elf, *elfro;
+ GElf_Ehdr ehdr;
+ GElf_Phdr *phdr;
+ Elf_Scn **scn;
+ GElf_Addr base, end, align;
+ GElf_Addr mask;
+ GElf_Addr info[DT_NUM];
+ GElf_Addr info_DT_GNU_PRELINKED;
+ GElf_Addr info_DT_CHECKSUM;
+ GElf_Addr info_DT_VERNEED, info_DT_VERDEF, info_DT_VERSYM;
+ GElf_Addr info_DT_GNU_HASH;
+ GElf_Addr info_DT_TLSDESC_PLT;
+ GElf_Addr info_DT_MIPS_LOCAL_GOTNO;
+ GElf_Addr info_DT_MIPS_GOTSYM;
+ GElf_Addr info_DT_MIPS_SYMTABNO;
+ GElf_Addr info_DT_MIPS_PLTGOT;
+#define DT_GNU_PRELINKED_BIT 50
+#define DT_CHECKSUM_BIT 51
+#define DT_VERNEED_BIT 52
+#define DT_VERDEF_BIT 53
+#define DT_VERSYM_BIT 54
+#define DT_FILTER_BIT 55
+#define DT_AUXILIARY_BIT 56
+#define DT_LOPROC_BIT 57
+#define DT_GNU_HASH_BIT 58
+#define DT_TLSDESC_PLT_BIT 59
+ uint64_t info_set_mask;
+ int fd, fdro;
+ int lastscn, dynamic;
+ const char *soname;
+ const char *filename, *temp_filename;
+ struct PLArch *arch;
+ struct PLAdjust *adjust;
+ /* .mdebug has absolute file offsets in it. */
+ GElf_Off mdebug_orig_offset;
+ Elf_Data undo;
+ int nadjust;
+ int permissive;
+ struct section_move *move;
+ GElf_Shdr shdr[0];
+} DSO;
+
+static inline int
+dynamic_info_is_set (DSO *dso, int bit)
+{
+ return ((dso)->info_set_mask & (1ULL << (bit))) != 0;
+}
+
+struct layout_libs;
+
+struct PLArch
+{
+ const char *name;
+ int class;
+ int machine;
+ int alternate_machine[3];
+ int max_reloc_size;
+ const char *dynamic_linker;
+ const char *dynamic_linker_alt;
+ int R_COPY;
+ int R_JMP_SLOT;
+ int R_RELATIVE;
+ int rtype_class_valid;
+ int (*arch_adjust) (DSO *dso, GElf_Addr start, GElf_Addr adjust);
+ int (*adjust_section) (DSO *dso, int n, GElf_Addr start, GElf_Addr adjust);
+ int (*adjust_dyn) (DSO *dso, int n, GElf_Dyn *dyn, GElf_Addr start,
+ GElf_Addr adjust);
+ int (*adjust_rel) (DSO *dso, GElf_Rel *rel, GElf_Addr start,
+ GElf_Addr adjust);
+ int (*adjust_rela) (DSO *dso, GElf_Rela *rela, GElf_Addr start,
+ GElf_Addr adjust);
+ int (*prelink_rel) (struct prelink_info *info, GElf_Rel *rel,
+ GElf_Addr reladdr);
+ int (*prelink_rela) (struct prelink_info *info, GElf_Rela *rela,
+ GElf_Addr relaaddr);
+ int (*prelink_conflict_rel) (DSO *dso, struct prelink_info *info,
+ GElf_Rel *rel, GElf_Addr reladdr);
+ int (*prelink_conflict_rela) (DSO *dso, struct prelink_info *info,
+ GElf_Rela *rela, GElf_Addr relaaddr);
+ int (*arch_prelink_conflict) (DSO *dso, struct prelink_info *info);
+ int (*apply_conflict_rela) (struct prelink_info *info, GElf_Rela *rela,
+ char *buf, GElf_Addr dest_addr);
+ int (*apply_rel) (struct prelink_info *info, GElf_Rel *rel, char *buf);
+ int (*apply_rela) (struct prelink_info *info, GElf_Rela *rela, char *buf);
+ int (*rel_to_rela) (DSO *dso, GElf_Rel *rel, GElf_Rela *rela);
+ int (*rela_to_rel) (DSO *dso, GElf_Rela *rela, GElf_Rel *rel);
+ int (*need_rel_to_rela) (DSO *dso, int first, int last);
+ GElf_Addr (*create_opd) (struct prelink_info *info, int first, int last,
+ int plt);
+ int (*read_opd) (DSO *dso, struct prelink_entry *ent);
+ int (*free_opd) (struct prelink_entry *ent);
+ /* Return reloc size in bytes for given non-COPY reloc type. */
+ int (*reloc_size) (int);
+#define RTYPE_CLASS_VALID 8
+#define RTYPE_CLASS_PLT (8|1)
+#define RTYPE_CLASS_COPY (8|2)
+#define RTYPE_CLASS_TLS (8|4)
+ int (*reloc_class) (int);
+ int (*arch_pre_prelink) (DSO *dso);
+ int (*arch_prelink) (struct prelink_info *info);
+ int (*arch_undo_prelink) (DSO *dso);
+ int (*undo_prelink_rel) (DSO *dso, GElf_Rel *rel, GElf_Addr reladdr);
+ int (*undo_prelink_rela) (DSO *dso, GElf_Rela *rela, GElf_Addr relaaddr);
+ int (*layout_libs_init) (struct layout_libs *l);
+ int (*layout_libs_pre) (struct layout_libs *l);
+ int (*layout_libs_post) (struct layout_libs *l);
+ GElf_Addr mmap_base, mmap_end;
+ /* max_page_size is the ELF page size (ELF_MAXPAGESIZE in bfd),
+ page_size is PAGE_SIZE the architecture typically has,
+ or if there are more typical sizes, the smallest one.
+ It doesn't need to be the absolutely smallest supported one,
+ prelink only optimizes for such page_size. */
+ GElf_Addr max_page_size, page_size;
+} __attribute__((aligned(64)));
+
+DSO * open_dso (const char *name);
+DSO * fdopen_dso (int fd, const char *name);
+struct section_move *init_section_move (DSO *dso);
+void add_section (struct section_move *move, int sec);
+void remove_section (struct section_move *move, int sec);
+int reopen_dso (DSO *dso, struct section_move *move, const char *);
+int adjust_symbol_p (DSO *dso, GElf_Sym *sym);
+int check_dso (DSO *dso);
+int dso_is_rdwr (DSO *dso);
+void read_dynamic (DSO *dso);
+int set_dynamic (DSO *dso, GElf_Word tag, GElf_Addr value, int fatal);
+int addr_to_sec (DSO *dso, GElf_Addr addr);
+int adjust_dso (DSO *dso, GElf_Addr start, GElf_Addr adjust);
+int adjust_nonalloc (DSO *dso, GElf_Ehdr *ehdr, GElf_Shdr *shdr, int first,
+ GElf_Addr start, GElf_Addr adjust);
+int adjust_dso_nonalloc (DSO *dso, int first, GElf_Addr start,
+ GElf_Addr adjust);
+int recompute_nonalloc_offsets (DSO *dso);
+int adjust_stabs (DSO *dso, int n, GElf_Addr start, GElf_Addr adjust);
+int adjust_dwarf2 (DSO *dso, int n, GElf_Addr start, GElf_Addr adjust);
+int adjust_mdebug (DSO *dso, int n, GElf_Addr start, GElf_Addr adjust);
+int finalize_mdebug (DSO *dso);
+int relocate_dso (DSO *dso, GElf_Addr base);
+int copy_fd_to_file (int fdin, const char *name, struct stat64 *st);
+int update_dso (DSO *dso, const char *);
+int prepare_write_dso (DSO *dso);
+int write_dso (DSO *dso);
+int close_dso (DSO *dso);
+GElf_Addr adjust_old_to_new (DSO *dso, GElf_Addr addr);
+GElf_Addr adjust_new_to_old (DSO *dso, GElf_Addr addr);
+int strtabfind (DSO *dso, int strndx, const char *name);
+int shstrtabadd (DSO *dso, const char *name);
+int dso_has_bad_textrel (DSO *dso);
+
+/* data.c */
+
+/* Used for reading consecutive blocks of data from a DSO. */
+struct data_iterator {
+ /* The DSO that is being read. */
+ DSO *dso;
+
+ /* The data block that contained the last byte to be read.
+ NULL if no data has been read yet or if the end of the
+ DSO has been reached. */
+ Elf_Data *data;
+
+ /* The section that contains DATA, when DATA is nonnull. */
+ int sec;
+
+ /* The address of the next byte. */
+ GElf_Addr addr;
+
+ /* The offset of the next byte from the start of SEC, when DATA
+ is nonnull. */
+ GElf_Addr sec_offset;
+};
+
+unsigned char * get_data (DSO *dso, GElf_Addr addr, int *scnp, Elf_Type *typep);
+#define READWRITEPROTO(le,nn) \
+uint##nn##_t buf_read_u##le##nn (unsigned char *data); \
+uint##nn##_t read_u##le##nn (DSO *dso, GElf_Addr addr); \
+void buf_write_##le##nn (unsigned char *data, uint##nn##_t val);\
+int write_##le##nn (DSO *dso, GElf_Addr addr, uint##nn##_t val);
+#define READWRITEPROTOSIZE(nn) \
+READWRITEPROTO(le,nn) \
+READWRITEPROTO(be,nn) \
+uint##nn##_t buf_read_une##nn (DSO *dso, unsigned char *data); \
+uint##nn##_t read_une##nn (DSO *dso, GElf_Addr addr); \
+void buf_write_ne##nn (DSO *dso, unsigned char *data, \
+ uint##nn##_t val); \
+void write_ne##nn (DSO *dso, GElf_Addr addr, uint##nn##_t val);
+READWRITEPROTO(,8)
+READWRITEPROTOSIZE(16)
+READWRITEPROTOSIZE(32)
+READWRITEPROTOSIZE(64)
+#undef READWRITEPROTO
+#undef READWRITEPROTOSIZE
+const char * strptr (DSO *dso, int sec, off_t offset);
+void init_data_iterator (struct data_iterator *it, DSO *dso, GElf_Addr addr);
+unsigned char *get_data_from_iterator (struct data_iterator *it,
+ GElf_Addr size);
+int get_sym_from_iterator (struct data_iterator *it, GElf_Sym *sym);
+
+#define PL_ARCH(F) \
+static struct PLArch plarch_##F __attribute__((section("pl_arch"),used))
+
+#define addr_adjust(addr, start, adjust) \
+ do { \
+ if (addr >= start) \
+ addr += adjust; \
+ } while (0)
+
+struct prelink_cache_entry
+{
+ uint32_t filename;
+ uint32_t depends;
+ uint32_t checksum;
+#define PCF_UNPRELINKABLE 0x40000
+#define PCF_PRELINKED 0x20000
+#define PCF_ELF64 0x10000
+#define PCF_MACHINE 0x0ffff
+ uint32_t flags;
+ uint32_t ctime;
+ uint32_t mtime;
+ uint64_t base;
+ uint64_t end;
+};
+
+struct prelink_cache
+{
+#define PRELINK_CACHE_NAME "prelink-ELF"
+#define PRELINK_CACHE_VER "0.3.2"
+#define PRELINK_CACHE_MAGIC PRELINK_CACHE_NAME PRELINK_CACHE_VER
+ const char magic [sizeof (PRELINK_CACHE_MAGIC) - 1];
+ uint32_t nlibs;
+ uint32_t ndeps;
+ uint32_t len_strings;
+ uint32_t unused[9];
+ struct prelink_cache_entry entry[0];
+ /* uint32_t depends [ndeps]; */
+ /* const char strings [len_strings]; */
+};
+
+struct prelink_link
+{
+ struct prelink_link *next;
+ const char *canon_filename;
+};
+
+struct prelink_entry
+{
+ const char *filename;
+ const char *canon_filename;
+ const char *soname;
+ struct prelink_link *hardlink;
+ GElf_Word timestamp;
+ GElf_Word checksum;
+ GElf_Addr base, end, layend, pltgot;
+ dev_t dev;
+ ino64_t ino;
+#define ET_BAD (ET_NUM)
+#define ET_CACHE_EXEC (ET_NUM + 1)
+#define ET_CACHE_DYN (ET_NUM + 2)
+#define ET_UNPRELINKABLE (ET_NUM + 3)
+ int type, done, ndepends, refs, flags;
+ union
+ {
+ int explicit;
+ int tmp;
+ } u;
+ uint32_t ctime, mtime;
+ struct prelink_entry **depends;
+ struct prelink_entry *prev, *next;
+ struct opd_lib *opd;
+};
+
+struct prelink_dir
+{
+ dev_t dev;
+ struct prelink_dir *next;
+ size_t len;
+ int flags;
+ char dir[0];
+};
+
+struct prelink_tls
+{
+ GElf_Addr modid;
+ GElf_Addr offset;
+};
+
+struct prelink_symbol
+{
+ union
+ {
+ struct prelink_entry *ent;
+ struct prelink_tls *tls;
+ } u;
+ struct prelink_symbol *next;
+ GElf_Addr value;
+ int reloc_class;
+};
+
+struct prelink_conflict
+{
+ struct prelink_conflict *next;
+ struct prelink_conflict *next2;
+ /* Object which it was relocated to. */
+ union
+ {
+ struct prelink_entry *ent;
+ struct prelink_tls *tls;
+ } lookup,
+ /* Object which the relocation was prelinked to. */
+ conflict;
+ /* Offset from start of owner to owner's symbol. */
+ GElf_Addr symoff;
+ /* Value it has in lookup.ent. */
+ GElf_Addr lookupval;
+ /* Value it has in conflict.ent. */
+ GElf_Addr conflictval;
+ int reloc_class;
+ unsigned char used;
+ unsigned char ifunc;
+ char * symname;
+};
+
+struct prelink_conflicts
+{
+ struct prelink_conflict *first;
+ struct prelink_conflict **hash;
+ struct prelink_conflict **hash2;
+ size_t count;
+};
+
+#define conflict_lookup_value(cfl) \
+ (((cfl)->reloc_class != RTYPE_CLASS_TLS ? (cfl)->lookup.ent->base : 0) \
+ + (cfl)->lookupval)
+
+struct prelink_info
+{
+ DSO *dso;
+ DSO **dsos;
+ struct prelink_entry *ent;
+ struct prelink_symbol *symbols;
+ struct prelink_conflicts *conflicts;
+ struct prelink_conflicts *curconflicts;
+ struct prelink_tls *tls, *curtls;
+ const char **sonames;
+ char *dynbss, *sdynbss;
+ GElf_Addr dynbss_base, sdynbss_base;
+ size_t dynbss_size, sdynbss_size, symtab_entsize;
+ int symbol_count;
+ GElf_Sym *symtab;
+ GElf_Rela *conflict_rela;
+ size_t conflict_rela_alloced, conflict_rela_size;
+ GElf_Addr symtab_start, symtab_end;
+ GElf_Addr (*resolve) (struct prelink_info *info, GElf_Word r_sym,
+ int reloc_type);
+ struct prelink_entry *resolveent;
+ struct prelink_tls *resolvetls;
+};
+
+int prelink_prepare (DSO *dso);
+int prelink (DSO *dso, struct prelink_entry *ent);
+int prelink_init_cache (void);
+int prelink_load_cache (void);
+int prelink_print_cache (void);
+int prelink_save_cache (int do_warn);
+struct prelink_entry *
+ prelink_find_entry (const char *filename, const struct stat64 *stp,
+ int insert);
+struct prelink_conflict *
+ prelink_conflict (struct prelink_info *info, GElf_Word r_sym,
+ int reloc_type);
+GElf_Rela *prelink_conflict_add_rela (struct prelink_info *info);
+int prelink_get_relocations (struct prelink_info *info);
+int prelink_build_conflicts (struct prelink_info *info);
+int update_dynamic_tags (DSO *dso, GElf_Shdr *shdr, GElf_Shdr *old_shdr,
+ struct section_move *move);
+int prelink_exec (struct prelink_info *info);
+int prelink_set_checksum (DSO *dso);
+int is_ldso_soname (const char *soname);
+
+int prelink_undo (DSO *dso);
+
+int prelink_verify (const char *filename);
+ssize_t send_file (int outfd, int infd, off_t *poff, size_t count);
+
+int gather_object (const char *dir, int deref, int onefs);
+int read_config (const char *config);
+int gather_config (void);
+int gather_check_libs (void);
+int add_to_blacklist (const char *name, int deref, int onefs);
+int blacklist_from_config (void);
+
+FILE *execve_open (const char *path, char *const argv[], char *const envp[]);
+int execve_close (FILE *f);
+
+int remove_redundant_cxx_conflicts (struct prelink_info *info);
+int get_relocated_mem (struct prelink_info *info, DSO *dso, GElf_Addr addr,
+ char *buf, GElf_Word size, GElf_Addr dest_addr);
+
+int layout_libs (void);
+
+void prelink_all (void);
+
+int undo_all (void);
+
+char *prelink_canonicalize (const char *name, struct stat64 *stp);
+
+extern const char *dynamic_linker;
+extern const char *ld_library_path;
+extern const char *prelink_cache;
+extern const char *prelink_conf;
+extern const char *undo_output;
+extern int all;
+extern int force;
+extern int random_base;
+extern int conserve_memory;
+extern int verbose;
+extern int dry_run;
+extern int libs_only;
+extern int enable_cxx_optimizations;
+extern int exec_shield;
+extern int undo;
+extern int verify;
+extern int print_cache;
+enum verify_method_t { VERIFY_CONTENT, VERIFY_MD5, VERIFY_SHA };
+extern enum verify_method_t verify_method;
+extern int quick;
+extern long long seed;
+extern GElf_Addr mmap_reg_start, mmap_reg_end, layout_page_size;
+extern char *ld_preload;
+
+extern const char *sysroot;
+
+extern int allow_bad_textrel;
+
+int wrap_readlink (const char *path, char *buf, int len);
+int wrap_lstat64 (const char *file, struct stat64 *buf);
+int wrap_stat64 (const char *file, struct stat64 *buf);
+int wrap_open (const char *file, int mode, ...);
+int wrap_access (const char *file, int mode);
+int wrap_rename (const char *old, const char *new);
+int wrap_link (const char *old, const char *new);
+int wrap_nftw64 (const char *dir, __nftw64_func_t func,
+ int descriptors, int flag);
+int wrap_utime (const char *file, struct utimbuf *file_times);
+int wrap_mkstemp (char *filename);
+int wrap_unlink (const char *filename);
+ssize_t wrap_listxattr (const char *path, char *list, size_t size);
+ssize_t wrap_getxattr (const char *path, const char *name, void *value,
+ size_t size);
+int wrap_setxattr (const char *path, const char *name, const void *value,
+ size_t size, int flags);
+int wrap_glob (const char *pattern, int flags,
+ int (*errfunc) (const char *epath, int eerrno),
+ glob_t *pglob);
+
+char *sysroot_file_name (const char *name, int allow_last_link);
+
+extern const char *prelink_rtld;
+
+#endif /* PRELINK_H */
diff --git a/src/prelinktab.h b/src/prelinktab.h
new file mode 100644
index 0000000..f41c79c
--- /dev/null
+++ b/src/prelinktab.h
@@ -0,0 +1,27 @@
+/* Copyright (C) 2001 Red Hat, Inc.
+ Written by Jakub Jelinek <jakub@redhat.com>, 2001.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ifndef PRELINKTAB_H
+#define PRELINKTAB_H
+
+#include "hashtab.h"
+#include "prelink.h"
+
+extern htab_t prelink_devino_htab, prelink_filename_htab;
+extern int prelink_entry_count;
+
+#endif /* PRELINKTAB_H */
diff --git a/src/reloc-info.c b/src/reloc-info.c
new file mode 100644
index 0000000..4ce333c
--- /dev/null
+++ b/src/reloc-info.c
@@ -0,0 +1,215 @@
+/* Copyright (C) 2008 CodeSourcery
+ Written by Maciej W. Rozycki <macro@codesourcery.com>, 2008.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include <config.h>
+
+#include "prelink.h"
+#include "reloc-info.h"
+
+/* A structure to lay out generic relocation information
+ * in a way specific to 64-bit MIPS. */
+union mips64_r_info
+{
+ /* Generic r_info interpretation. */
+ Elf64_Xword r_info;
+
+ /* 64-bit MIPS r_info interpretation. */
+ struct
+ {
+ /* Symbol index for the first relocation. */
+ Elf64_Word r_sym;
+
+ /* Special symbol for the second relocation. */
+ Elf64_Byte r_ssym;
+
+ /* Third relocation. */
+ Elf64_Byte r_type3;
+
+ /* Second relocation. */
+ Elf64_Byte r_type2;
+
+ /* First relocation. */
+ Elf64_Byte r_type;
+ }
+ s_info;
+};
+
+/* Extract the symbol index from 64-bit MIPS reloc info. */
+
+static GElf_Xword
+mips64_r_sym (DSO *dso, GElf_Xword r_info)
+{
+ union mips64_r_info mips64_r_info;
+
+ buf_write_ne64 (dso, (unsigned char *) &mips64_r_info.r_info, r_info);
+ return buf_read_une32 (dso, (unsigned char *) &mips64_r_info.s_info.r_sym);
+}
+
+/* Extract the special symbol index from 64-bit MIPS reloc info. */
+
+static GElf_Xword
+mips64_r_ssym (DSO *dso, GElf_Xword r_info)
+{
+ union mips64_r_info mips64_r_info;
+
+ buf_write_ne64 (dso, (unsigned char *) &mips64_r_info.r_info, r_info);
+ return mips64_r_info.s_info.r_ssym;
+}
+
+/* Extract the first reloc type from 64-bit MIPS reloc info. */
+
+static GElf_Xword
+mips64_r_type (DSO *dso, GElf_Xword r_info)
+{
+ union mips64_r_info mips64_r_info;
+
+ buf_write_ne64 (dso, (unsigned char *) &mips64_r_info.r_info, r_info);
+ return mips64_r_info.s_info.r_type;
+}
+
+/* Extract the second reloc type from 64-bit MIPS reloc info. */
+
+static GElf_Xword
+mips64_r_type2 (DSO *dso, GElf_Xword r_info)
+{
+ union mips64_r_info mips64_r_info;
+
+ buf_write_ne64 (dso, (unsigned char *) &mips64_r_info.r_info, r_info);
+ return mips64_r_info.s_info.r_type2;
+}
+
+/* Extract the third reloc type from 64-bit MIPS reloc info. */
+
+static GElf_Xword
+mips64_r_type3 (DSO *dso, GElf_Xword r_info)
+{
+ union mips64_r_info mips64_r_info;
+
+ buf_write_ne64 (dso, (unsigned char *) &mips64_r_info.r_info, r_info);
+ return mips64_r_info.s_info.r_type3;
+}
+
+/* Construct 64-bit MIPS reloc info from symbol indices and reloc types. */
+
+static GElf_Xword
+mips64_r_info_ext (DSO *dso, GElf_Word r_sym, Elf64_Byte r_ssym,
+ Elf64_Byte r_type, Elf64_Byte r_type2, Elf64_Byte r_type3)
+{
+ union mips64_r_info mips64_r_info;
+
+ buf_write_ne32 (dso, (unsigned char *) &mips64_r_info.s_info.r_sym, r_sym);
+ mips64_r_info.s_info.r_ssym = r_ssym;
+ mips64_r_info.s_info.r_type = r_type;
+ mips64_r_info.s_info.r_type2 = r_type2;
+ mips64_r_info.s_info.r_type3 = r_type3;
+ return buf_read_une64 (dso, (unsigned char *) &mips64_r_info.r_info);
+}
+
+
+/* Extract the symbol index from reloc info. */
+
+GElf_Xword
+reloc_r_sym (DSO *dso, GElf_Xword r_info)
+{
+ if (dso->ehdr.e_ident[EI_CLASS] == ELFCLASS64
+ && dso->ehdr.e_machine == EM_MIPS)
+ return mips64_r_sym (dso, r_info);
+ else
+ return GELF_R_SYM (r_info);
+}
+
+/* Extract the special symbol index from reloc info. */
+
+GElf_Xword
+reloc_r_ssym (DSO *dso, GElf_Xword r_info)
+{
+ if (dso->ehdr.e_ident[EI_CLASS] == ELFCLASS64
+ && dso->ehdr.e_machine == EM_MIPS)
+ return mips64_r_ssym (dso, r_info);
+ else
+ return RSS_UNDEF;
+}
+
+/* Extract the first reloc type from reloc info. */
+
+GElf_Xword
+reloc_r_type (DSO *dso, GElf_Xword r_info)
+{
+ if (dso->ehdr.e_ident[EI_CLASS] == ELFCLASS64
+ && dso->ehdr.e_machine == EM_MIPS)
+ return mips64_r_type (dso, r_info);
+ else
+ return GELF_R_TYPE (r_info);
+}
+
+/* Extract the second reloc type from reloc info. */
+
+GElf_Xword
+reloc_r_type2 (DSO *dso, GElf_Xword r_info)
+{
+ if (dso->ehdr.e_ident[EI_CLASS] == ELFCLASS64
+ && dso->ehdr.e_machine == EM_MIPS)
+ return mips64_r_type2 (dso, r_info);
+ else
+ return 0;
+}
+
+/* Extract the third reloc type from reloc info. */
+
+GElf_Xword
+reloc_r_type3 (DSO *dso, GElf_Xword r_info)
+{
+ if (dso->ehdr.e_ident[EI_CLASS] == ELFCLASS64
+ && dso->ehdr.e_machine == EM_MIPS)
+ return mips64_r_type3 (dso, r_info);
+ else
+ return 0;
+}
+
+/* Construct reloc info from symbol index and reloc type. */
+
+GElf_Xword
+reloc_r_info (DSO *dso, GElf_Word r_sym, GElf_Word r_type)
+{
+ if (dso->ehdr.e_ident[EI_CLASS] == ELFCLASS64
+ && dso->ehdr.e_machine == EM_MIPS)
+ switch (r_type)
+ {
+ case R_MIPS_REL32:
+ case R_MIPS_GLOB_DAT:
+ return mips64_r_info_ext (dso, r_sym, RSS_UNDEF,
+ r_type, R_MIPS_64, R_MIPS_NONE);
+ default:
+ return mips64_r_info_ext (dso, r_sym, RSS_UNDEF,
+ r_type, R_MIPS_NONE, R_MIPS_NONE);
+ }
+ else
+ return GELF_R_INFO (r_sym, r_type);
+}
+
+/* Construct reloc info from symbol index and reloc type. */
+
+GElf_Xword
+reloc_r_info_ext (DSO *dso, GElf_Word r_sym, Elf64_Byte r_ssym,
+ Elf64_Byte r_type, Elf64_Byte r_type2, Elf64_Byte r_type3)
+{
+ if (dso->ehdr.e_ident[EI_CLASS] == ELFCLASS64
+ && dso->ehdr.e_machine == EM_MIPS)
+ return mips64_r_info_ext (dso, r_sym, r_ssym, r_type, r_type2, r_type3);
+ else
+ return GELF_R_INFO (r_sym, r_type);
+}
diff --git a/src/reloc-info.h b/src/reloc-info.h
new file mode 100644
index 0000000..a8f8b7c
--- /dev/null
+++ b/src/reloc-info.h
@@ -0,0 +1,35 @@
+/* Copyright (C) 2008 CodeSourcery
+ Written by Maciej W. Rozycki <macro@codesourcery.com>, 2008.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ifndef RELOC_INFO_H
+#define RELOC_INFO_H
+
+#include "prelink.h"
+
+/* Reloc info primitives. */
+GElf_Xword reloc_r_sym (DSO *dso, GElf_Xword r_info);
+GElf_Xword reloc_r_ssym (DSO *dso, GElf_Xword r_info);
+GElf_Xword reloc_r_type (DSO *dso, GElf_Xword r_info);
+GElf_Xword reloc_r_type2 (DSO *dso, GElf_Xword r_info);
+GElf_Xword reloc_r_type3 (DSO *dso, GElf_Xword r_info);
+
+GElf_Xword reloc_r_info (DSO *dso, GElf_Word r_sym, GElf_Word r_type);
+GElf_Xword reloc_r_info_ext (DSO *dso, GElf_Word r_sym, Elf64_Byte r_ssym,
+ Elf64_Byte r_type, Elf64_Byte r_type2,
+ Elf64_Byte r_type3);
+
+#endif /* RELOC_INFO_H */
diff --git a/src/reloc.c b/src/reloc.c
new file mode 100644
index 0000000..deb0abe
--- /dev/null
+++ b/src/reloc.c
@@ -0,0 +1,427 @@
+/* Copyright (C) 2001, 2002, 2003, 2005 Red Hat, Inc.
+ Written by Jakub Jelinek <jakub@redhat.com>, 2001.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include <config.h>
+#include <assert.h>
+#include <errno.h>
+#include <error.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include "prelink.h"
+#include "reloc.h"
+
+int
+find_reloc_sections (DSO *dso, struct reloc_info *rinfo)
+{
+ int first, last, rela, i, pltfirst;
+ GElf_Addr start, end, pltstart, pltend;
+
+ memset (rinfo, 0, sizeof (*rinfo));
+
+ if (dynamic_info_is_set (dso, DT_REL)
+ && dynamic_info_is_set (dso, DT_RELA))
+ {
+ error (0, 0, "%s: Cannot prelink object with both DT_REL and DT_RELA tags",
+ dso->filename);
+ return 1;
+ }
+
+ rela = dynamic_info_is_set (dso, DT_RELA);
+
+ if (rela)
+ {
+ start = dso->info[DT_RELA];
+ end = dso->info[DT_RELA] + dso->info[DT_RELASZ];
+ }
+ else
+ {
+ start = dso->info[DT_REL];
+ end = dso->info[DT_REL] + dso->info[DT_RELSZ];
+ }
+ rinfo->reldyn_rela = rela;
+
+ if (dso->info[DT_JMPREL])
+ {
+ pltstart = dso->info[DT_JMPREL];
+ pltend = dso->info[DT_JMPREL] + dso->info[DT_PLTRELSZ];
+ pltfirst = first = addr_to_sec (dso, pltstart);
+ last = addr_to_sec (dso, pltend - 1);
+ if (first == -1
+ || last == -1
+ || first != last
+ || dso->shdr[first].sh_addr != pltstart
+ || dso->shdr[first].sh_addr + dso->shdr[first].sh_size != pltend
+ || (dso->info[DT_PLTREL] != DT_REL
+ && dso->info[DT_PLTREL] != DT_RELA)
+ || dso->shdr[first].sh_type
+ != (dso->info[DT_PLTREL] == DT_RELA ? SHT_RELA : SHT_REL)
+ || strcmp (strptr (dso, dso->ehdr.e_shstrndx,
+ dso->shdr[first].sh_name),
+ dso->info[DT_PLTREL] == DT_RELA
+ ? ".rela.plt" : ".rel.plt"))
+ {
+ error (0, 0, "%s: DT_JMPREL tags don't surround .rel%s.plt section",
+ dso->filename, dso->info[DT_PLTREL] == DT_RELA ? "a" : "");
+ return 1;
+ }
+ rinfo->plt = first;
+ rinfo->plt_rela = (dso->shdr[first].sh_type == SHT_RELA);
+ if (dso->shdr[first].sh_type == SHT_REL
+ && dso->arch->need_rel_to_rela != NULL
+ && dso->arch->need_rel_to_rela (dso, first, first))
+ rinfo->rel_to_rela_plt = 1;
+ }
+ else
+ {
+ pltstart = end;
+ pltend = end;
+ pltfirst = 0;
+ }
+
+ if (start == 0 && end == 0)
+ {
+ /* No non-PLT relocations. */
+ return 0;
+ }
+
+ if (start == end)
+ {
+ first = 0;
+ last = 0;
+ }
+ else
+ {
+ first = addr_to_sec (dso, start);
+ last = addr_to_sec (dso, end - 1);
+
+ if (first == -1
+ || last == -1
+ || dso->shdr[first].sh_addr != start
+ || dso->shdr[last].sh_addr + dso->shdr[last].sh_size != end)
+ {
+ error (0, 0, "%s: DT_REL%s tags don't surround whole relocation sections",
+ dso->filename, rela ? "A" : "");
+ return 1;
+ }
+
+ for (i = first; i <= last; i++)
+ if (dso->shdr[i].sh_type != (rela ? SHT_RELA : SHT_REL))
+ {
+ error (0, 0, "%s: DT_REL%s tags don't surround relocation sections of expected type",
+ dso->filename, rela ? "A" : "");
+ return 1;
+ }
+ }
+
+ if (pltstart != end && pltend != end
+ /* There is a gap between .rel(a).dyn and .rel(a).plt sections.
+ The gap may be due to a linker optimization, in which case
+ the sections are still adjacent, with a zero-filled gap in-between. */
+ && last + 1 != pltfirst)
+ {
+ error (0, 0, "%s: DT_JMPREL tag not adjacent to DT_REL%s relocations",
+ dso->filename, rela ? "A" : "");
+ return 1;
+ }
+
+ if (pltstart == start && pltend == end)
+ {
+ /* No non-PLT relocations. */
+ rinfo->overlap = 1;
+ return 0;
+ }
+
+ if (pltstart != end && pltend == end)
+ {
+ rinfo->overlap = 1;
+ --last;
+ }
+
+ rinfo->first = first;
+ rinfo->last = last;
+ if (! rela
+ && first
+ && dso->arch->need_rel_to_rela != NULL
+ && dso->arch->need_rel_to_rela (dso, first, last))
+ rinfo->rel_to_rela = 1;
+ return 0;
+}
+
+int
+convert_rel_to_rela (DSO *dso, int i)
+{
+ Elf_Data d1, d2, *d;
+ Elf_Scn *scn;
+ GElf_Rel rel;
+ GElf_Rela rela;
+ int ndx, maxndx;
+
+ scn = dso->scn[i];
+ d = elf_getdata (scn, NULL);
+ assert (elf_getdata (scn, d) == NULL);
+ assert (d->d_off == 0);
+ assert (d->d_size == dso->shdr[i].sh_size);
+ d1 = *d;
+ d2 = *d;
+ assert (sizeof (Elf32_Rel) * 3 == sizeof (Elf32_Rela) * 2);
+ assert (sizeof (Elf64_Rel) * 3 == sizeof (Elf64_Rela) * 2);
+ d1.d_size = d->d_size / 2 * 3;
+ d1.d_buf = malloc (d1.d_size);
+ d1.d_type = ELF_T_RELA;
+ if (d1.d_buf == NULL)
+ {
+ error (0, ENOMEM, "Cannot convert REL section to RELA");
+ return 1;
+ }
+
+ maxndx = d->d_size / dso->shdr[i].sh_entsize;
+ for (ndx = 0; ndx < maxndx; ndx++)
+ {
+ if (gelfx_getrel (dso->elf, d, ndx, &rel) == 0
+ || dso->arch->rel_to_rela (dso, &rel, &rela))
+ {
+ free (d1.d_buf);
+ return 1;
+ }
+ /* gelf_update_rel etc. should have Elf * argument, so that
+ we don't have to do this crap. */
+ *d = d1;
+ if (gelfx_update_rela (dso->elf, d, ndx, &rela) == 0)
+ {
+ *d = d2;
+ free (d1.d_buf);
+ return 1;
+ }
+ *d = d2;
+ }
+
+ free (d2.d_buf);
+ *d = d1;
+ dso->shdr[i].sh_entsize
+ = gelf_fsize (dso->elf, ELF_T_RELA, 1, EV_CURRENT);
+ dso->shdr[i].sh_type = SHT_RELA;
+ return 0;
+}
+
+int
+convert_rela_to_rel (DSO *dso, int i)
+{
+ Elf_Data d1, d2, *d;
+ Elf_Scn *scn;
+ GElf_Rel rel;
+ GElf_Rela rela;
+ int ndx, maxndx;
+
+ scn = dso->scn[i];
+ d = elf_getdata (scn, NULL);
+ assert (elf_getdata (scn, d) == NULL);
+ assert (d->d_off == 0);
+ assert (d->d_size == dso->shdr[i].sh_size);
+ d1 = *d;
+ d2 = *d;
+ assert (sizeof (Elf32_Rel) * 3 == sizeof (Elf32_Rela) * 2);
+ assert (sizeof (Elf64_Rel) * 3 == sizeof (Elf64_Rela) * 2);
+ d1.d_size = d->d_size / 3 * 2;
+ d1.d_buf = malloc (d1.d_size);
+ d1.d_type = ELF_T_REL;
+ if (d1.d_buf == NULL)
+ {
+ error (0, ENOMEM, "Cannot convert RELA section to REL");
+ return 1;
+ }
+
+ maxndx = d->d_size / dso->shdr[i].sh_entsize;
+ for (ndx = 0; ndx < maxndx; ndx++)
+ {
+ if (gelfx_getrela (dso->elf, d, ndx, &rela) == 0
+ || dso->arch->rela_to_rel (dso, &rela, &rel))
+ {
+ free (d1.d_buf);
+ return 1;
+ }
+ /* gelf_update_rela etc. should have Elf * argument, so that
+ we don't have to do this crap. */
+ *d = d1;
+ if (gelfx_update_rel (dso->elf, d, ndx, &rel) == 0)
+ {
+ *d = d2;
+ free (d1.d_buf);
+ return 1;
+ }
+ *d = d2;
+ }
+
+ free (d2.d_buf);
+ *d = d1;
+ dso->shdr[i].sh_entsize
+ = gelf_fsize (dso->elf, ELF_T_REL, 1, EV_CURRENT);
+ dso->shdr[i].sh_type = SHT_REL;
+ return 0;
+}
+
+int
+update_dynamic_rel (DSO *dso, struct reloc_info *rinfo)
+{
+ GElf_Dyn *info[DT_NUM], *info_DT_RELCOUNT, *info_DT_RELACOUNT;
+ GElf_Dyn *dynamic = NULL;
+ int rel = rinfo->first, plt = rinfo->plt, overlap = rinfo->overlap;
+ int dynsec, count = 0, loc;
+ Elf_Data *data;
+ Elf_Scn *scn = NULL;
+
+ memset (&info, 0, sizeof (info));
+ info_DT_RELCOUNT = NULL;
+ info_DT_RELACOUNT = NULL;
+ for (dynsec = 0; dynsec < dso->ehdr.e_shnum; dynsec++)
+ if (dso->shdr[dynsec].sh_type == SHT_DYNAMIC)
+ {
+ scn = dso->scn[dynsec];
+ dynamic = alloca (dso->shdr[dynsec].sh_size
+ / dso->shdr[dynsec].sh_entsize * sizeof (GElf_Dyn));
+ loc = 0;
+ data = NULL;
+ while ((data = elf_getdata (scn, data)) != NULL)
+ {
+ int ndx, maxndx;
+
+ maxndx = data->d_size / dso->shdr[dynsec].sh_entsize;
+ for (ndx = 0; ndx < maxndx; ++ndx, ++loc)
+ {
+ gelfx_getdyn (dso->elf, data, ndx, dynamic + loc);
+ if (dynamic[loc].d_tag == DT_NULL)
+ break;
+ else if ((GElf_Xword) dynamic[loc].d_tag < DT_NUM)
+ info[dynamic[loc].d_tag] = dynamic + loc;
+ else if (dynamic[loc].d_tag == DT_RELCOUNT)
+ info_DT_RELCOUNT = dynamic + loc;
+ else if (dynamic[loc].d_tag == DT_RELACOUNT)
+ info_DT_RELACOUNT = dynamic + loc;
+ }
+ if (ndx < maxndx)
+ break;
+ }
+ count = loc;
+ break;
+ }
+
+ if (rel && plt && overlap)
+ {
+ if (dso->shdr[rel].sh_type != dso->shdr[plt].sh_type)
+ overlap = 0;
+ }
+
+ if (rel || (plt && overlap))
+ {
+ int dt_RELENT, dt_REL, dt_RELSZ;
+
+ if (rinfo->reldyn_rela)
+ {
+ dt_RELENT = DT_RELAENT;
+ dt_REL = DT_RELA;
+ dt_RELSZ = DT_RELASZ;
+ }
+ else
+ {
+ dt_RELENT = DT_RELENT;
+ dt_REL = DT_REL;
+ dt_RELSZ = DT_RELSZ;
+ }
+
+ assert (dso->info[dt_RELENT]
+ == gelf_fsize (dso->elf, rinfo->reldyn_rela
+ ? ELF_T_RELA : ELF_T_REL, 1, EV_CURRENT));
+ assert (dso->info[dt_REL] != 0);
+ assert (dso->info[dt_RELSZ] != 0);
+
+ info[dt_REL]->d_un.d_ptr = dso->shdr[rel ?: plt].sh_addr;
+ if (plt && overlap)
+ info[dt_RELSZ]->d_un.d_val =
+ dso->shdr[plt].sh_addr + dso->shdr[plt].sh_size;
+ else
+ info[dt_RELSZ]->d_un.d_val =
+ dso->shdr[rinfo->last].sh_addr + dso->shdr[rinfo->last].sh_size;
+ info[dt_RELSZ]->d_un.d_val -= info[dt_REL]->d_un.d_ptr;
+
+ if (!rinfo->reldyn_rela && dso->shdr[rel ?: plt].sh_type == SHT_RELA)
+ {
+ info[DT_RELENT]->d_un.d_val =
+ gelf_fsize (dso->elf, ELF_T_RELA, 1, EV_CURRENT);
+ info[DT_REL]->d_tag = DT_RELA;
+ info[DT_RELSZ]->d_tag = DT_RELASZ;
+ info[DT_RELENT]->d_tag = DT_RELAENT;
+ if (info_DT_RELCOUNT)
+ info_DT_RELCOUNT->d_tag = DT_RELACOUNT;
+ }
+ else if (rinfo->reldyn_rela && dso->shdr[rel ?: plt].sh_type == SHT_REL)
+ {
+ info[DT_RELAENT]->d_un.d_val =
+ gelf_fsize (dso->elf, ELF_T_REL, 1, EV_CURRENT);
+ info[DT_RELA]->d_tag = DT_REL;
+ info[DT_RELASZ]->d_tag = DT_RELSZ;
+ info[DT_RELAENT]->d_tag = DT_RELENT;
+ if (info_DT_RELACOUNT)
+ info_DT_RELACOUNT->d_tag = DT_RELCOUNT;
+ }
+ }
+
+ if (plt)
+ {
+ assert (dso->info[DT_JMPREL] != 0);
+ assert (dso->info[DT_PLTREL] == rinfo->plt_rela ? DT_RELA : DT_REL);
+
+ info[DT_JMPREL]->d_un.d_ptr = dso->shdr[plt].sh_addr;
+ if (!rinfo->plt_rela && dso->shdr[plt].sh_type == SHT_RELA)
+ {
+ info[DT_PLTREL]->d_un.d_val = DT_RELA;
+ info[DT_PLTRELSZ]->d_un.d_val = dso->shdr[plt].sh_size;
+ }
+ else if (rinfo->plt_rela && dso->shdr[plt].sh_type == SHT_REL)
+ {
+ info[DT_PLTREL]->d_un.d_val = DT_REL;
+ info[DT_PLTRELSZ]->d_un.d_val = dso->shdr[plt].sh_size;
+ }
+
+ if (!rel && !overlap)
+ {
+ int dt_REL = rinfo->reldyn_rela ? DT_RELA : DT_REL;
+
+ if (info[dt_REL] && info[dt_REL]->d_un.d_ptr)
+ info[dt_REL]->d_un.d_ptr = info[DT_JMPREL]->d_un.d_ptr;
+ }
+ }
+
+ loc = 0;
+ data = NULL;
+ while ((data = elf_getdata (scn, data)) != NULL)
+ {
+ int ndx, maxndx;
+
+ maxndx = data->d_size / dso->shdr[dynsec].sh_entsize;
+ for (ndx = 0; ndx < maxndx && loc < count; ++ndx, ++loc)
+ if ((GElf_Xword) dynamic[loc].d_tag < DT_NUM
+ || dynamic[loc].d_tag == DT_RELCOUNT
+ || dynamic[loc].d_tag == DT_RELACOUNT)
+ gelfx_update_dyn (dso->elf, data, ndx, dynamic + loc);
+ if (ndx < maxndx)
+ break;
+ }
+
+ read_dynamic (dso);
+ return 0;
+}
diff --git a/src/reloc.h b/src/reloc.h
new file mode 100644
index 0000000..a2ceff9
--- /dev/null
+++ b/src/reloc.h
@@ -0,0 +1,44 @@
+/* Copyright (C) 2001, 2002 Red Hat, Inc.
+ Written by Jakub Jelinek <jakub@redhat.com>, 2001.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ifndef RELOC_H
+#define RELOC_H
+
+#include "prelink.h"
+
+struct reloc_info
+{
+ int first; /* First dynamic SHT_REL* section. */
+ int last; /* Last dynamic SHT_REL* section not counting .rel*.plt. */
+ int plt; /* .rel*.plt section. */
+ int overlap; /* 1 if DT_REL{,A}SZ range includes DT_PLTRELSZ range. */
+ int reldyn_rela; /* first..last sections were originally RELA. */
+ int plt_rela; /* plt section was originally RELA. */
+ int rel_to_rela; /* first..last sections have to be converted REL->RELA. */
+ int rel_to_rela_plt; /* plt section has to be converted REL->RELA. */
+ int relcount; /* DT_RELCOUNT resp. DT_RELACOUNT. */
+};
+
+int find_reloc_sections (DSO *dso, struct reloc_info *rinfo);
+int convert_rel_to_rela (DSO *dso, int i);
+int convert_rela_to_rel (DSO *dso, int i);
+int update_dynamic_rel (DSO *dso, struct reloc_info *rinfo);
+int undo_sections (DSO *dso, int undo, struct section_move *move,
+ struct reloc_info *rinfo, GElf_Ehdr *ehdr,
+ GElf_Phdr *phdr, GElf_Shdr *shdr);
+
+#endif /* RELOC_H */
diff --git a/src/rtld/COPYING b/src/rtld/COPYING
new file mode 100644
index 0000000..d159169
--- /dev/null
+++ b/src/rtld/COPYING
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/src/rtld/COPYING.LIB b/src/rtld/COPYING.LIB
new file mode 100644
index 0000000..4362b49
--- /dev/null
+++ b/src/rtld/COPYING.LIB
@@ -0,0 +1,502 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/src/rtld/ChangeLog b/src/rtld/ChangeLog
new file mode 100644
index 0000000..ae208d7
--- /dev/null
+++ b/src/rtld/ChangeLog
@@ -0,0 +1,267 @@
+2015-10-21 Mark Hatle <mark.hatle@windriver.com>
+ * rtld/: Resync to glibc-2.22
+ * rtld/*: Update copyright dates to match glibc-2.22
+ * rtld/rtld.c: Update the elf_machine_type class entries
+ Add support for ELF_RTYPE_CLASS_EXTERN_PROTECTED_DATA via
+ new extern_protected_data function.
+ rename reloc_typeclass to elf_machine_type_class
+ add machine_no_rela, machine_no_rel funcs
+ Update debug msg
+ Fix missing dso_list->map = NULL
+ * rtld/dl-tls.c: (rtld_determine_tlsoffsets) add NIOS2 definition
+ * rtld/dl-lookup.c: Add EXTERN_PROTECTED_DATA support
+ * rtld/dl-lookupX.h: Add EXTERN_PROTECTED_DATA support
+ update debug msgs
+ * rtld/dl-load.c: (create_map_object_from_dso_ent) Add ld.so like debug
+ When an executable sets a load address use it
+ Update the load address calculation, prevents visual overlaps
+ * rtld/dl-version.c: update debug msgs
+ * rtld/rtld.h: define _dl_debug_printf to act like ld.so debug
+ define RTLD_DEBUG_PID to set the debug prefix
+
+ * glibc changes directly affecting the implementation:
+
+ 2013-12-04 Ulrich Weigand <Ulrich.Weigand@de.ibm.com>
+ Alan Modra <amodra@gmail.com>
+ * libc/sysdeps/powerpc/powerpc64/dl-machine.h
+ (elf_machine_type_class): Use SHN_UNDEF PLT handling for ELFv2 ABI.
+
+ 2015-01-18 Chung-Lin Tang <cltang@codesourcery.com>
+ Sandra Loosemore <sandra@codesourcery.com>
+ Andrew Jenner <andrew@codesourcery.com>
+ Joseph Myers <joseph@codesourcery.com>
+ Nathan Sidwell <nathan@codesourcery.com>
+ * sysdeps/nios2/dl-machine.h: New file.
+
+ 2015-03-31 H.J. Lu <hongjiu.lu@intel.com>
+ * elf/dl-lookup.c (do_lookup_x): When UNDEF_MAP is NULL, which
+ indicates it is called from do_lookup_x on relocation against
+ protected data, skip the data definion in the executable from
+ copy reloc.
+ (_dl_lookup_symbol_x): Pass ELF_RTYPE_CLASS_EXTERN_PROTECTED_DATA,
+ instead of ELF_RTYPE_CLASS_PLT, to do_lookup_x for
+ EXTERN_PROTECTED_DATA relocation against STT_OBJECT symbol.
+ * sysdeps/i386/dl-machine.h (elf_machine_type_class): Set class
+ to ELF_RTYPE_CLASS_EXTERN_PROTECTED_DATA for R_386_GLOB_DAT.
+ * sysdeps/x86_64/dl-machine.h (elf_machine_type_class): Set class
+ to ELF_RTYPE_CLASS_EXTERN_PROTECTED_DATA for R_X86_64_GLOB_DAT.
+
+ 2015-07-24 Szabolcs Nagy <szabolcs.nagy@arm.com>
+ * sysdeps/aarch64/dl-machine.h (elf_machine_type_class): Handle
+ ELF_RTYPE_CLASS_EXTERN_PROTECTED_DATA.
+ * sysdeps/arm/dl-machine.h (elf_machine_type_class): Handle
+ ELF_RTYPE_CLASS_EXTERN_PROTECTED_DATA.
+
+2015-09-11 Vaneet Narang <v.narang@samsung.com>
+ * rtld/rtld.c: Add ability to specify preloaded libraries
+
+2015-09-09 Maninder Singh <maninder1.s@samsung.com>
+ Mark Hatle <mark.hatle@windriver.com>
+ * rtld/rtld.c: dso null pointer check fix
+
+2015-04-06 Mark Hatle <mark.hatle@windriver.com>
+ Maninder Singh <maninder1.s@samsung.com>
+ * rtld/dl-version.c: Add debug for mising ld-linux or libc.so
+
+2014-12-10 Mark Hatle <mark.hatle@windriver.com>
+ * rtld/rtld.c: Sync aarch64 elf_machine_type_class (dl-machine.h)
+ (do_relocs): fix comparison pltrel_end >= rel_end
+ * rtld/dl-tls.c: Add basic aarch64 support
+
+2014-12-10 Mark Hatle <mark.hatle@windriver.com>
+ * rtld/: Resync to glibc-2.20
+ Replace referenced to GLRO_dl_debug_mask to
+ GLRO(dl_debug_mask)
+
+ * rtld/rtld.h: Sync DL_DEBUG_* defines from ldsodefs.h
+ add DSO_FILENAME and RTLD_PROGNAME definitions
+ Move to __glibc_unlikely/likely instead of __builtin_expect
+ rename link_map and update unique_sym_table to match glibc
+
+ * rtld/dl-hash.h:
+ Apply glibc changes:
+ 2011-12-03 Ulrich Drepper <drepper@gmail.com>
+ Fix more warnings
+
+ 2011-12-04 Ulrich Drepper <drepper@gmail.com>
+ Fix attreibute for _dl_elf_hash
+
+ 2011-12-04 Ulrich Drepper <drepper@gmail.com>
+ Small optimization of generic ELF hash function
+
+ 2011-12-10 Ulrich Drepper <drepper@gmail.com>
+ Optimize generic ELF hash function a bit more
+
+ 2012-02-09 Paul Eggert <eggert@cs.ucla.edu>
+ Replace FSF snail mail address with URLs.
+
+ 2013-01-02 Joseph Myers <joseph@codesourcery.com>
+ Update copyright notices with scripts/update-copyrights.
+
+ 2014-01-01 Allan McRae <allan@archlinux.org>
+ Update copyright notices with scripts/update-copyrights
+
+ * rtld/dl-load.c: split (_dl_new_object) move to dl-object
+ Remove VERSYMIDX, already defined in rtld.h
+
+ Apply glibc changes:
+ 2012-02-09 Paul Eggert <eggert@cs.ucla.edu>
+ Replace FSF snail mail address with URLs.
+
+ 2012-04-04 Siddhesh Poyarekar <siddhesh@redhat.com>
+ (Updated copyright date)
+
+ 2013-01-02 Joseph Myers <joseph@codesourcery.com>
+ Update copyright notices with scripts/update-copyrights.
+
+ 2014-01-01 Allan McRae <allan@archlinux.org>
+ Update copyright notices with scripts/update-copyrights
+
+ 2014-02-10 Ond<C5><99>ej B<C3><AD>lka <neleai@seznam.cz>
+ Use glibc_likely instead __builtin_expect.
+
+ * rtld/dl-object.c:
+ Apply glibc changes:
+ 2013-11-11 Jan Kratochvil <jan.kratochvil@redhat.com>
+ [BZ #387]
+ * elf/dl-object.c (_dl_new_object): Initialize L_NAME from NEWNAME if
+ it is empty.
+
+ * rtld/dl-lookup.c, rtld/dl-lookupX.h:
+ Apply glibc changes:
+ 2012-02-09 Paul Eggert <eggert@cs.ucla.edu>
+ Replace FSF snail mail address with URLs.
+
+ 2012-04-05 David S. Miller <davem@davemloft.net>
+ * elf/dl-lookup (_dl_lookup_symbol_x): If DL_DEBUG_UNUSED, ignore
+ undefined symbol errors.
+
+ 2012-08-14 Roland McGrath <roland@hack.frob.com>
+ (Updated copyright date)
+
+ 2013-01-02 Joseph Myers <joseph@codesourcery.com>
+ Update copyright notices with scripts/update-copyrights.
+
+ 2013-05-29 Siddhesh Poyarekar <siddhesh@redhat.com>
+ Avoid crashing in LD_DEBUG when program name is unavailable
+
+ 2013-11-13 Marcus Shawcroft <marcus.shawcroft@linaro.org>
+ Avoid passing NULL to DSO_FILENAME.
+
+ 2014-01-01 Allan McRae <allan@archlinux.org>
+ Update copyright notices with scripts/update-copyrights
+
+ 2014-02-10 Ond<C5><99>ej B<C3><AD>lka <neleai@seznam.cz>
+ Use glibc_likely instead __builtin_expect.
+
+ 2014-02-11 Joseph Myers <joseph@codesourcery.com>
+ Merge MIPS dl-lookup.c into generic file.
+ * elf/dl-lookup.c (ELF_MACHINE_SYM_NO_MATCH): Define if not
+ already defined.
+ (do_lookup_x): Use ELF_MACHINE_SYM_NO_MATCH.
+ * sysdeps/mips/dl-lookup.c: Remove.
+ * sysdeps/mips/dl-machine.h (ELF_MACHINE_SYM_NO_MATCH): New macro.
+
+ 2014-02-28 Carlos O'Donell <carlos@redhat.com>
+ Promote do_lookup_x:check_match to a full function.
+
+ 2014-04-02 Will Newton <will.newton@linaro.org>
+ elf/dl-lookup.c: Remove obsolete comment about nested function
+ * elf/dl-lookup.c (do_lookup_x): Remove comment
+ referring to nested function and move variable
+ declarations down to before first use.
+
+ 2014-04-04 Will Newton <will.newton@linaro.org>
+ elf/dl-lookup.c: Remove unnecessary static variable
+ * elf/dl-lookup.c (undefined_msg): Remove variable.
+ (_dl_lookup_symbol_x): Replace undefined_msg with string
+ literal.
+
+ 2014-04-11 Will Newton <will.newton@linaro.org>
+ elf/dl-lookup.c: Use __glibc_likely and __glibc_unlikely
+
+ * rtld/dl-misc.c:
+ Apply glibc changes:
+ 2012-02-09 Paul Eggert <eggert@cs.ucla.edu>
+ Replace FSF snail mail address with URLs.
+
+ 2013-01-02 Joseph Myers <joseph@codesourcery.com>
+ Update copyright notices with scripts/update-copyrights.
+
+ 2014-01-01 Allan McRae <allan@archlinux.org>
+ Update copyright notices with scripts/update-copyrights
+
+ * rtld/dl-tls.c:
+ Sync spacing with glibc for easier diffs (content remained the same)
+
+ Apply glibc changes:
+ 2012-02-09 Paul Eggert <eggert@cs.ucla.edu>
+ Replace FSF snail mail address with URLs.
+
+ 2014-01-01 Allan McRae <allan@archlinux.org>
+ Update copyright notices with scripts/update-copyrights
+
+ * rtld/dl-version:
+ Apply glibc changes:
+ 2012-02-09 Paul Eggert <eggert@cs.ucla.edu>
+ Replace FSF snail mail address with URLs.
+
+ 2013-01-02 Joseph Myers <joseph@codesourcery.com>
+ Update copyright notices with scripts/update-copyrights.
+
+ 2013-05-29 Siddhesh Poyarekar <siddhesh@redhat.com>
+ Avoid crashing in LD_DEBUG when program name is unavailable
+
+ 2014-01-01 Allan McRae <allan@archlinux.org>
+ Update copyright notices with scripts/update-copyrights
+
+ 2014-02-10 Ond<C5><99>ej B<C3><AD>lka <neleai@seznam.cz>
+ Use glibc_likely instead __builtin_expect.
+
+2014-12-10 Mark Hatle <mark.hatle@windriver.com>
+ * rtld/COPYING, rtld/COPYING.LIB,
+ rtld/ChangeLog, rtld/README-rtld: Add local history
+ information to setup for a resync to glibc-2.20
+
+2012-09-12 Joseph Myers <joseph@codesourcery.com>
+ * rtld/dl-lookup.c: Fix variable copy reloc when host/target
+ byte size is different
+
+2012-04-10 Maxim Kuvyrkov <maxim@codesourcery.com>
+ * rtld/rtld.c (find_lib_by_soname): Follow ld.so's behavior of
+ pulling its name from PT_INTERP.
+
+2012-01-26 Mark Hatle <mark.hatle@windriver.com>
+ * elf.h, rtld/dl-lookupX.h, rtld/rtld.c: Sync to eglibc 2.15
+
+2011-12-08 Mark Hatle <mark.hatle@windriver.com>
+ * rtld/rtld.c: Add support for $ORIGIN, $PLATFORM and $LIB.
+ Note: $PLATFORM = ""
+
+2011-12-08 Mark Hatle <mark.hatle@windriver.com>
+ * rtld/rtld.c: Fix an issue where missing objects would trigger
+ an assert in dl-version.c
+ * rtld/rtld.h: Add _dl_new_object prototype
+
+2011-09-13 Mark Hatle <mark.hatle@windriver.com>
+ * Fix printf problem causing prelink-rtld issues on x86 (32-bit)
+ and arm
+
+2011-08-26 Mark Hatle <mark.hatle@windriver.com>
+ * Add a special check for invalid GNU_HASH entries
+
+2011-08-26 Mark Hatle <mark.hatle@windriver.com>
+ * Sync to eglibc 2.13 ld.so code
+ * sync elf_machine_type_class macros for supports archs
+
+2011-08-26 Mark Hatle <mark.hatle@windriver.com>
+ * Sync to eglibc 2.13 ld.so code
+ * mips specific items from ports
+
+2011-08-26 Mark Hatle <mark.hatle@windriver.com>
+ * Rename ld-libs.c to rtld.c
+ * Sync to eglibc 2.13 ld.so code
+
+2011-08-18 Mark Hatle <mark.hatle@windriver.com>
+ * Move prelink-rtld specific components to rtld
+
diff --git a/src/rtld/Makefile.am b/src/rtld/Makefile.am
new file mode 100644
index 0000000..b02c745
--- /dev/null
+++ b/src/rtld/Makefile.am
@@ -0,0 +1,32 @@
+## Process this file with automake to create Makefile.in
+
+AUTOMAKE_OPTIONS = 1.4 gnu
+
+PKGVERSION = "\"@PKGVERSION@\""
+REPORT_BUGS_TO = "\"@REPORT_BUGS_TO@\""
+
+DEFS = -D_GNU_SOURCE -DHAVE_CONFIG_H -Wall -Wno-pointer-sign
+AM_CFLAGS = -Wall -Wno-pointer-sign
+AM_CPPFLAGS = -DSBINDIR='"@sbindir@"' -DBINDIR='"@bindir@"' \
+ -DEXECSTACK_PROG="\"`echo execstack | sed '$(transform)'`\"" \
+ -DPRELINK_PROG="\"`echo prelink | sed '$(transform)'`\"" \
+ -DPRELINK_RTLD_PROG="\"`echo prelink-rtld | \
+ sed '$(transform)'`\"" \
+ -DEXEEXT='"$(EXEEXT)"' \
+ -DPKGVERSION=$(PKGVERSION) \
+ -DREPORT_BUGS_TO=$(REPORT_BUGS_TO)
+INCLUDES = -I$(top_srcdir)/src @GELFINCLUDE@
+
+sbin_PROGRAMS = prelink-rtld
+
+prelink_rtld_SOURCES = $(top_srcdir)/src/data.c $(top_srcdir)/src/dso.c \
+ $(top_srcdir)/src/canonicalize.c $(top_srcdir)/src/wrap-file.c \
+ $(top_srcdir)/src/reloc-info.c $(top_srcdir)/src/reloc-info.h \
+ rtld.c ld-libs.h \
+ dl-hash.h dl-object.c dl-load.c \
+ dl-tls.c dl-version.c dl-misc.c \
+ dl-lookup.c dl-lookupX.h
+
+prelink_rtld_LDADD = @LIBGELF@ -liberty
+prelink_rtld_CFLAGS = -DDSO_READONLY
+prelink_rtld_LDFLAGS =
diff --git a/src/rtld/README-rtld b/src/rtld/README-rtld
new file mode 100644
index 0000000..fa737dc
--- /dev/null
+++ b/src/rtld/README-rtld
@@ -0,0 +1,18 @@
+The rtld emulation is based on the system libc ld.so code.
+
+The original version of this code was written by Daniel Jacobowitz in
+2003. It needed little modification/updating until recently (2011) when
+new constructs, such as STB_GNU_UNIQUE, were introduced into the dynamic
+linking.
+
+The 2011 work was done by Mark Hatle and based on eglibc-2.13. I
+attempted to document all of the code that had origins in eglibc and where
+the code originated from.
+
+As eglibc continues to advance, similar resyncs will be needed over time.
+Hopefully not such a dramatic resync will be required in the future.
+
+Mark Hatle <mark.hatle@windriver.com>,
+August 2011
+
+See the ChangeLog for additional changes.
diff --git a/src/rtld/dl-hash.h b/src/rtld/dl-hash.h
new file mode 100644
index 0000000..2b1f0b7
--- /dev/null
+++ b/src/rtld/dl-hash.h
@@ -0,0 +1,77 @@
+/* glibc-2.22: sysdeps/generic/dl-hash.h */
+
+/* Compute hash value for given string according to ELF standard.
+ Copyright (C) 1995-2015 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef _DL_HASH_H
+#define _DL_HASH_H 1
+
+#define _dl_elf_hash rtld_elf_hash
+
+/* This is the hashing function specified by the ELF ABI. In the
+ first five operations no overflow is possible so we optimized it a
+ bit. */
+static unsigned int
+_dl_elf_hash (const char *name_arg)
+{
+ const unsigned char *name = (const unsigned char *) name_arg;
+ unsigned long int hash = *name;
+ if (hash != 0 && name[1] != '\0')
+ {
+ hash = (hash << 4) + name[1];
+ if (name[2] != '\0')
+ {
+ hash = (hash << 4) + name[2];
+ if (name[3] != '\0')
+ {
+ hash = (hash << 4) + name[3];
+ if (name[4] != '\0')
+ {
+ hash = (hash << 4) + name[4];
+ name += 5;
+ while (*name != '\0')
+ {
+ unsigned long int hi;
+ hash = (hash << 4) + *name++;
+ hi = hash & 0xf0000000;
+
+ /* The algorithm specified in the ELF ABI is as
+ follows:
+
+ if (hi != 0)
+ hash ^= hi >> 24;
+
+ hash &= ~hi;
+
+ But the following is equivalent and a lot
+ faster, especially on modern processors. */
+
+ hash ^= hi >> 24;
+ }
+
+ /* Second part of the modified formula. This
+ operation can be lifted outside the loop. */
+ hash &= 0x0fffffff;
+ }
+ }
+ }
+ }
+ return hash;
+}
+
+#endif /* dl-hash.h */
diff --git a/src/rtld/dl-load.c b/src/rtld/dl-load.c
new file mode 100644
index 0000000..5dc913e
--- /dev/null
+++ b/src/rtld/dl-load.c
@@ -0,0 +1,279 @@
+/* Restructure code containing the original statement:
+ Copyright (C) 2003 MontaVista Software, Inc.
+ Written by Daniel Jacobowitz <drow@mvista.com>, 2003
+
+ Restructed and synced to latest eglibc 2.13 by
+ Mark Hatle <mark.hatle@windriver.com>, 2011
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* glibc-2.20: elf/dl-load.c */
+
+/* Map in a shared object's segments from the file.
+ Copyright (C) 1995-2014 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <assert.h>
+#include <error.h>
+#include <errno.h>
+#include <string.h>
+#include "rtld.h"
+
+/* Add `name' to the list of names for a particular shared object.
+ `name' is expected to have been allocated with malloc and will
+ be freed if the shared object already has this name.
+ Returns false if the object already had this name. */
+static void
+add_name_to_object (struct link_map *l, const char *name)
+{
+ struct libname_list *lnp, *lastp;
+ struct libname_list *newname;
+ size_t name_len;
+
+ lastp = NULL;
+ for (lnp = l->l_libname; lnp != NULL; lastp = lnp, lnp = lnp->next)
+ if (strcmp (name, lnp->name) == 0)
+ return;
+
+ name_len = strlen (name) + 1;
+ newname = (struct libname_list *) malloc (sizeof *newname + name_len);
+ if (newname == NULL)
+ {
+ /* No more memory. */
+ _dl_signal_error (ENOMEM, name, NULL, ("cannot allocate name record"));
+ return;
+ }
+ /* The object should have a libname set from _dl_new_object. */
+ assert (lastp != NULL);
+
+ newname->name = memcpy (newname + 1, name, name_len);
+ newname->next = NULL;
+ lastp->next = newname;
+}
+
+const char *rtld_progname;
+
+static Elf64_Addr load_addr = 0xdead0000;
+static Elf64_Addr dynamic_addr = 0xfeed0000;
+
+/* mimic behavior of _dl_map_object_from_fd(...)
+ Note: this is not a copy of the function! */
+void
+create_map_object_from_dso_ent (struct dso_list *cur_dso_ent)
+{
+ struct link_map *l = NULL;
+ DSO *dso = cur_dso_ent->dso;
+
+ int i;
+ Elf_Data *data;
+
+
+ const char * realname, * name, *soname;
+ int l_type;
+
+ soname = dso->soname;
+ realname = dso->filename;
+ name = dso->filename;
+
+ l_type = (dso->ehdr.e_type == ET_EXEC ? lt_executable : lt_library);
+
+
+ /* Print debug message. */
+ if ((l_type == lt_library && !is_ldso_soname(soname)) &&
+ __glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES))
+ _dl_debug_printf("file=%s [0]; generating link map\n", soname);
+
+
+ l = _dl_new_object (realname, name, l_type);
+ if (l == NULL)
+ {
+ _dl_signal_error(errno, name, NULL, "cannot create shared object descriptor");
+ }
+
+ if (soname)
+ add_name_to_object(l, soname);
+
+ if (name)
+ add_name_to_object(l, name);
+
+ l->filename = dso->filename;
+
+ /* Set the elfclass */
+ l->elfclass = gelf_getclass (dso->elf);
+
+ /*** Setup the l_info as if this had been loaded into memory ***/
+
+ /* FIXME: gelfify, endianness issues */
+ /* and leaks? */
+ i = addr_to_sec (dso, dso->info[DT_SYMTAB]);
+ if (i != -1)
+ {
+ data = elf_getdata (dso->scn[i], NULL);
+ l->l_info[DT_SYMTAB] = data->d_buf;
+ }
+
+ i = addr_to_sec (dso, dso->info[DT_STRTAB]);
+ if (i != -1)
+ {
+ data = elf_getdata (dso->scn[i], NULL);
+ l->l_info[DT_STRTAB] = data->d_buf;
+ }
+
+ if (dynamic_info_is_set (dso, DT_GNU_HASH_BIT))
+ {
+ i = addr_to_sec (dso, dso->info_DT_GNU_HASH);
+ if (i != -1)
+ {
+ data = elf_getdata (dso->scn[i], NULL);
+
+#if 0
+ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES))
+ printf("l_info DT_GNU_HASH: offset %d -- addr %p (0x%lx) - type %d\n",
+ (DT_ADDRTAGIDX(DT_GNU_HASH) + DT_NUM
+ + DT_THISPROCNUM + DT_VERSIONTAGNUM
+ + DT_EXTRANUM + DT_VALNUM),
+ data->d_buf, (unsigned long) data->d_size);
+#endif
+
+ l->l_info[DT_ADDRTAGIDX(DT_GNU_HASH) + DT_NUM
+ + DT_THISPROCNUM + DT_VERSIONTAGNUM
+ + DT_EXTRANUM + DT_VALNUM] = data->d_buf;
+
+ /* PPC64 workaround */
+ l->l_buckets_start = data->d_buf;
+ l->l_buckets_end = (char *)data->d_buf + data->d_size;
+ /* end workaround */
+ }
+ }
+
+ i = addr_to_sec (dso, dso->info[DT_HASH]);
+ if (i != -1)
+ {
+ data = elf_getdata (dso->scn[i], NULL);
+ l->l_info[DT_HASH] = data->d_buf;
+ }
+
+ if (dynamic_info_is_set (dso, DT_VERNEED_BIT))
+ {
+ i = addr_to_sec (dso, dso->info_DT_VERNEED);
+ if (i != -1)
+ {
+ data = elf_getdata (dso->scn[i], NULL);
+ l->l_info[VERSYMIDX (DT_VERNEED)] = data->d_buf;
+ }
+ }
+
+ if (dynamic_info_is_set (dso, DT_VERDEF_BIT))
+ {
+ i = addr_to_sec (dso, dso->info_DT_VERDEF);
+ if (i != -1)
+ {
+ data = elf_getdata (dso->scn[i], NULL);
+ l->l_info[VERSYMIDX (DT_VERDEF)] = data->d_buf;
+ }
+ }
+
+ if (dynamic_info_is_set (dso, DT_VERSYM_BIT))
+ {
+ i = addr_to_sec (dso, dso->info_DT_VERSYM);
+ if (i != -1)
+ {
+ data = elf_getdata (dso->scn[i], NULL);
+ l->l_info[VERSYMIDX (DT_VERSYM)] = data->d_buf;
+ }
+ }
+
+ if (dso->base) {
+ l->l_map_start = dso->base;
+
+ /* We need to ensure that we don't have two DSOs loading at the same place! */
+ struct dso_list * dso_list_ptr;
+ for (dso_list_ptr = cur_dso_ent->prev; dso_list_ptr; dso_list_ptr = dso_list_ptr->prev)
+ {
+ /* This looks for fairly obvious overlaps... */
+ if ((dso_list_ptr->dso->base <= dso->base && dso->base <= dso_list_ptr->dso->end) || \
+ (dso->base <= dso_list_ptr->dso->base && dso_list_ptr->dso->base <= dso->end))
+ {
+ l->l_map_start = (Elf64_Addr)NULL;
+ break;
+ }
+ }
+ }
+
+ if (l->l_map_start == (Elf64_Addr)NULL)
+ {
+ l->l_map_start = load_addr;
+ load_addr += ( ((dso->end - dso->base) + (0x1000 - 1)) & (~(0x1000-1)) );
+ }
+
+ l->sym_base = dso->info[DT_SYMTAB] - dso->base;
+
+ if ((l_type == lt_library && !is_ldso_soname(soname))
+ && (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES))) {
+ _dl_debug_printf ("\
+ dynamic: 0x%0*lx base: 0x%0*lx size: 0x%0*Zx\n",
+ (int) sizeof (void *) * (gelf_getclass (dso->elf) == ELFCLASS64 ? 2 : 1),
+ (unsigned long int) dynamic_addr,
+ (int) sizeof (void *) * (gelf_getclass (dso->elf) == ELFCLASS64 ? 2 : 1),
+ (unsigned long int) l->l_map_start,
+ (int) sizeof (void *) * (gelf_getclass (dso->elf) == ELFCLASS64 ? 2 : 1),
+ (dso->end - dso->base));
+ _dl_debug_printf ("\
+ entry: 0x%0*lx phdr: 0x%0*lx phnum: %*u\n",
+ (int) sizeof (void *) * (gelf_getclass (dso->elf) == ELFCLASS64 ? 2 : 1),
+ (unsigned long int) l->l_map_start + dso->ehdr.e_entry,
+ (int) sizeof (void *) * (gelf_getclass (dso->elf) == ELFCLASS64 ? 2 : 1),
+ (unsigned long int) l->l_map_start + dso->ehdr.e_ehsize,
+ (int) sizeof (void *) * (gelf_getclass (dso->elf) == ELFCLASS64 ? 2 : 1),
+ dso->ehdr.e_phnum);
+ _dl_debug_printf ("\n");
+
+ /* Only used for debugging output */
+ dynamic_addr += ( ((dso->end - dso->base) + (0x1000 - 1)) & (~(0x1000-1)) );
+ }
+
+ /* Set up the symbol hash table. */
+ _dl_setup_hash (l);
+
+ for (i = 0; i < dso->ehdr.e_phnum; ++i)
+ if (dso->phdr[i].p_type == PT_TLS)
+ {
+ l->l_tls_blocksize = dso->phdr[i].p_memsz;
+ l->l_tls_align = dso->phdr[i].p_align;
+ if (l->l_tls_align == 0)
+ l->l_tls_firstbyte_offset = 0;
+ else
+ l->l_tls_firstbyte_offset = dso->phdr[i].p_vaddr & (l->l_tls_align - 1);
+ break;
+ }
+
+ l->machine = dso->ehdr.e_machine;
+
+ cur_dso_ent->map = l;
+}
diff --git a/src/rtld/dl-lookup.c b/src/rtld/dl-lookup.c
new file mode 100644
index 0000000..6688966
--- /dev/null
+++ b/src/rtld/dl-lookup.c
@@ -0,0 +1,131 @@
+/* glibc-2.22: elf/dl-lookup.c */
+
+/* Look up a symbol in the loaded objects.
+ Copyright (C) 1995-2015 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+/* This file is based on the original eglibc-2.13 libc/elf/dl-lookup.c
+ code.
+
+ It has been split into two pieces dl-lookup.c and dl-lookupX.c,
+ the purpose of the split is to enable both 32-bit and 64-bit ELF
+ processing in the same application. This file contains the ELF
+ size neutral routines.
+ */
+
+#include <config.h>
+#include <alloca.h>
+#include <libintl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <dl-hash.h>
+
+#include <assert.h>
+
+#include <errno.h>
+
+#include <elf.h>
+
+#include <inttypes.h>
+
+#include "prelinktab.h"
+#include "reloc.h"
+
+#include "rtld.h"
+
+/* Return nonzero if check_match should consider SYM to fail to match a
+ symbol reference for some machine-specific reason. */
+#ifndef ELF_MACHINE_SYM_NO_MATCH
+/* glibc-2.20: sysdeps/mips/dl-machine.h */
+/* The semantics of zero/non-zero values of undefined symbols differs
+ depending on whether the non-PIC ABI is in use. Under the non-PIC
+ ABI, a non-zero value indicates that there is an address reference
+ to the symbol and thus it must always be resolved (except when
+ resolving a jump slot relocation) to the PLT entry whose address is
+ provided as the symbol's value; a zero value indicates that this
+ canonical-address behaviour is not required. Yet under the classic
+ MIPS psABI, a zero value indicates that there is an address
+ reference to the function and the dynamic linker must resolve the
+ symbol immediately upon loading. To avoid conflict, symbols for
+ which the dynamic linker must assume the non-PIC ABI semantics are
+ marked with the STO_MIPS_PLT flag. */
+#define ELF_MACHINE_SYM_NO_MATCH(sym) \
+ (map->machine == EM_MIPS && \
+ ((sym)->st_shndx == SHN_UNDEF && !((sym)->st_other & STO_MIPS_PLT)) \
+ )
+#endif
+
+struct unique_sym_table * _ns_unique_sym_table = NULL;
+
+/* This file is from eglibc 2.13, libc/elf/dl-lookup.c
+ It has been split into two pieces dl-lookup.c and dl-lookupX.c,
+ the purpose of the split is to enable both 32-bit and 64-bit ELF
+ processing in the same application. This file contains the common
+ routines ... and is the entry to the overall set of files.
+ */
+
+#define make_string(string, rest...) \
+ ({ \
+ const char *all[] = { string, ## rest }; \
+ size_t len, cnt; \
+ char *result, *cp; \
+ \
+ len = 1; \
+ for (cnt = 0; cnt < sizeof (all) / sizeof (all[0]); ++cnt) \
+ len += strlen (all[cnt]); \
+ \
+ cp = result = alloca (len); \
+ for (cnt = 0; cnt < sizeof (all) / sizeof (all[0]); ++cnt) \
+ cp = __stpcpy (cp, all[cnt]); \
+ \
+ result; \
+ })
+
+static uint_fast32_t
+dl_new_hash (const char *s)
+{
+ uint_fast32_t h = 5381;
+ unsigned char c = *s;
+ for (c = *s; c != '\0'; c = *++s)
+ h = h * 33 + c;
+ return h & 0xffffffff;
+}
+
+#undef RTLD_ELF_SIZE
+#define RTLD_ELF_SIZE 32
+#include "dl-lookupX.h"
+
+#undef RTLD_ELF_SIZE
+#define RTLD_ELF_SIZE 64
+#include "dl-lookupX.h"
+
+#undef RTLD_ELF_SIZE
+
+void
+_dl_setup_hash (struct link_map *map)
+{
+ if (map)
+ {
+ if (map->elfclass == ELFCLASS32)
+ rtld_setup_hash32(map);
+ else if (map->elfclass == ELFCLASS64)
+ rtld_setup_hash64(map);
+ else
+ _dl_signal_error(EINVAL, map->l_name, NULL, "elfclass is not defined 32-bit or 64-bit!");
+ }
+}
diff --git a/src/rtld/dl-lookupX.h b/src/rtld/dl-lookupX.h
new file mode 100644
index 0000000..dc6d4bf
--- /dev/null
+++ b/src/rtld/dl-lookupX.h
@@ -0,0 +1,896 @@
+/* glibc-2.22: elf/dl-lookup.c */
+
+/* Look up a symbol in the loaded objects.
+ Copyright (C) 1995-2015 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+/* This file is from eglibc 2.15, libc/elf/dl-lookup.c
+ It has been split into two pieces dl-lookup.c and dl-lookupX.c,
+ the purpose of the split is to enable both 32-bit and 64-bit ELF
+ processing in the same application. This file contains the ELF
+ size specific routines. It must be included from dl-lookup.c and
+ not used directly!
+ */
+
+#if RTLD_ELF_SIZE == 32
+ #define enter_unique_sym enter_unique_sym_val32
+ #define sym_val sym_val32
+ #define check_match check_match32
+ #define do_lookup_unique do_lookup_unique32
+ #define do_lookup_x do_lookup_x32
+ #undef _dl_setup_hash
+ #define _dl_setup_hash rtld_setup_hash32
+ #define _dl_debug_bindings rtld_debug_bindings32
+ #define _dl_lookup_symbol_x rtld_lookup_symbol_x32
+ #define rtld_size_t uint32_t
+ #define rtld_size_fmtx PRIx32
+
+#elif RTLD_ELF_SIZE == 64
+ #define enter_unique_sym enter_unique_sym_val64
+ #define sym_val sym_val64
+ #define check_match check_match64
+ #define do_lookup_unique do_lookup_unique64
+ #define do_lookup_x do_lookup_x64
+ #undef _dl_setup_hash
+ #define _dl_setup_hash rtld_setup_hash64
+ #define _dl_debug_bindings rtld_debug_bindings64
+ #define _dl_lookup_symbol_x rtld_lookup_symbol_x64
+ #define rtld_size_t uint64_t
+ #define rtld_size_fmtx PRIx64
+
+#else
+ #error "You must declare RTLD_ELF_SIZE to be either 32 or 64"
+#endif
+
+#define __ELF_NATIVE_CLASS RTLD_ELF_SIZE
+
+/* From eglibc 2.15 - elf/link.h */
+
+/* We use this macro to refer to ELF types independent of the native wordsize.
+ `ElfW(TYPE)' is used in place of `Elf32_TYPE' or `Elf64_TYPE'. */
+#define ELFW(type) _ElfW (ELF, __ELF_NATIVE_CLASS, type)
+#define ElfW(type) _ElfW (Elf, __ELF_NATIVE_CLASS, type)
+#define _ElfW(e,w,t) _ElfW_1 (e, w, _##t)
+#define _ElfW_1(e,w,t) e##w##t
+
+struct sym_val
+ {
+ const ElfW(Sym) *s;
+ struct link_map *m;
+ };
+
+/* Utility function for do_lookup_x. The caller is called with undef_name,
+ ref, version, flags and type_class, and those are passed as the first
+ five arguments. The caller then computes sym, symidx, strtab, and map
+ and passes them as the next four arguments. Lastly the caller passes in
+ versioned_sym and num_versions which are modified by check_match during
+ the checking process. */
+static const ElfW(Sym) *
+check_match (const char *const undef_name,
+ const ElfW(Sym) *const ref,
+ const struct r_found_version *const version,
+ const int flags,
+ const int type_class,
+ const ElfW(Sym) *const sym,
+ const Elf_Symndx symidx,
+ const char *const strtab,
+ const struct link_map *const map,
+ const ElfW(Sym) **const versioned_sym,
+ int *const num_versions)
+{
+ unsigned int stt = ELFW(ST_TYPE) (sym->st_info);
+ assert (ELF_RTYPE_CLASS_PLT == 1);
+ if (__glibc_unlikely ((sym->st_value == 0 /* No value. */
+ && stt != STT_TLS)
+ || ELF_MACHINE_SYM_NO_MATCH (sym)
+ || (type_class & (sym->st_shndx == SHN_UNDEF))))
+ return NULL;
+
+ /* Ignore all but STT_NOTYPE, STT_OBJECT, STT_FUNC,
+ STT_COMMON, STT_TLS, and STT_GNU_IFUNC since these are no
+ code/data definitions. */
+#define ALLOWED_STT \
+ ((1 << STT_NOTYPE) | (1 << STT_OBJECT) | (1 << STT_FUNC) \
+ | (1 << STT_COMMON) | (1 << STT_TLS) | (1 << STT_GNU_IFUNC))
+ if (__glibc_unlikely (((1 << stt) & ALLOWED_STT) == 0))
+ return NULL;
+
+ if (sym != ref && strcmp (strtab + sym->st_name, undef_name))
+ /* Not the symbol we are looking for. */
+ return NULL;
+
+ const ElfW(Half) *verstab = map->l_versyms;
+ if (version != NULL)
+ {
+ if (__glibc_unlikely (verstab == NULL))
+ {
+ /* We need a versioned symbol but haven't found any. If
+ this is the object which is referenced in the verneed
+ entry it is a bug in the library since a symbol must
+ not simply disappear.
+
+ It would also be a bug in the object since it means that
+ the list of required versions is incomplete and so the
+ tests in dl-version.c haven't found a problem.*/
+ assert (version->filename == NULL
+ || ! _dl_name_match_p (version->filename, map));
+
+ /* Otherwise we accept the symbol. */
+ }
+ else
+ {
+ /* We can match the version information or use the
+ default one if it is not hidden. */
+ ElfW(Half) ndx = verstab[symidx] & 0x7fff;
+ if ((map->l_versions[ndx].hash != version->hash
+ || strcmp (map->l_versions[ndx].name, version->name))
+ && (version->hidden || map->l_versions[ndx].hash
+ || (verstab[symidx] & 0x8000)))
+ /* It's not the version we want. */
+ return NULL;
+ }
+ }
+ else
+ {
+ /* No specific version is selected. There are two ways we
+ can got here:
+
+ - a binary which does not include versioning information
+ is loaded
+
+ - dlsym() instead of dlvsym() is used to get a symbol which
+ might exist in more than one form
+
+ If the library does not provide symbol version information
+ there is no problem at all: we simply use the symbol if it
+ is defined.
+
+ These two lookups need to be handled differently if the
+ library defines versions. In the case of the old
+ unversioned application the oldest (default) version
+ should be used. In case of a dlsym() call the latest and
+ public interface should be returned. */
+ if (verstab != NULL)
+ {
+ if ((verstab[symidx] & 0x7fff)
+ >= ((flags & DL_LOOKUP_RETURN_NEWEST) ? 2 : 3))
+ {
+ /* Don't accept hidden symbols. */
+ if ((verstab[symidx] & 0x8000) == 0
+ && (*num_versions)++ == 0)
+ /* No version so far. */
+ *versioned_sym = sym;
+
+ return NULL;
+ }
+ }
+ }
+
+ /* There cannot be another entry for this symbol so stop here. */
+ return sym;
+}
+
+/* Utility function for do_lookup_unique. Add a symbol to TABLE. */
+static void
+enter_unique_sym (struct unique_sym *table, size_t size,
+ unsigned int hash, const char *name,
+ const ElfW(Sym) *sym, const struct link_map *map)
+{
+ size_t idx = hash % size;
+ size_t hash2 = 1 + hash % (size - 2);
+ while (table[idx].name != NULL)
+ {
+ idx += hash2;
+ if (idx >= size)
+ idx -= size;
+ }
+
+ table[idx].hashval = hash;
+ table[idx].name = name;
+ table[idx].sym = sym;
+ table[idx].map = map;
+}
+
+/* Utility function for do_lookup_x. Lookup an STB_GNU_UNIQUE symbol
+ in the unique symbol table, creating a new entry if necessary.
+ Return the matching symbol in RESULT. */
+static void
+do_lookup_unique (const char *undef_name, uint_fast32_t new_hash,
+ const struct link_map *map, struct sym_val *result,
+ int type_class, const ElfW(Sym) *sym, const char *strtab,
+ const ElfW(Sym) *ref, const struct link_map *undef_map)
+{
+ /* We have to determine whether we already found a symbol with this
+ name before. If not then we have to add it to the search table.
+ If we already found a definition we have to use it. */
+
+ struct unique_sym_table *tab
+ = _ns_unique_sym_table;
+
+ __rtld_lock_lock_recursive (tab->lock);
+
+ struct unique_sym *entries = tab->entries;
+ size_t size = tab->size;
+ if (entries != NULL)
+ {
+ size_t idx = new_hash % size;
+ size_t hash2 = 1 + new_hash % (size - 2);
+ while (1)
+ {
+ if (entries[idx].hashval == new_hash
+ && strcmp (entries[idx].name, undef_name) == 0)
+ {
+ if ((type_class & ELF_RTYPE_CLASS_COPY) != 0)
+ {
+ /* We possibly have to initialize the central
+ copy from the copy addressed through the
+ relocation. */
+ result->s = sym;
+ result->m = (struct link_map *) map;
+ }
+ else
+ {
+ result->s = entries[idx].sym;
+ result->m = (struct link_map *) entries[idx].map;
+ }
+ __rtld_lock_unlock_recursive (tab->lock);
+ return;
+ }
+
+ if (entries[idx].name == NULL)
+ break;
+
+ idx += hash2;
+ if (idx >= size)
+ idx -= size;
+ }
+
+ if (size * 3 <= tab->n_elements * 4)
+ {
+ /* Expand the table. */
+#ifdef RTLD_CHECK_FOREIGN_CALL
+ /* This must not happen during runtime relocations. */
+ assert (!RTLD_CHECK_FOREIGN_CALL);
+#endif
+ size_t newsize = _dl_higher_prime_number (size + 1);
+ struct unique_sym *newentries
+ = calloc (sizeof (struct unique_sym), newsize);
+ if (newentries == NULL)
+ {
+ nomem:
+ __rtld_lock_unlock_recursive (tab->lock);
+ _dl_fatal_printf ("out of memory\n");
+ }
+
+ for (idx = 0; idx < size; ++idx)
+ if (entries[idx].name != NULL)
+ enter_unique_sym (newentries, newsize, entries[idx].hashval,
+ entries[idx].name, entries[idx].sym,
+ entries[idx].map);
+
+ tab->free (entries);
+ tab->size = newsize;
+ size = newsize;
+ entries = tab->entries = newentries;
+ tab->free = free;
+ }
+ }
+ else
+ {
+#ifdef RTLD_CHECK_FOREIGN_CALL
+ /* This must not happen during runtime relocations. */
+ assert (!RTLD_CHECK_FOREIGN_CALL);
+#endif
+
+#if 1
+ /* If tab->entries is NULL, but tab->size is not, it means
+ this is the second, conflict finding, lookup for
+ LD_TRACE_PRELINKING in _dl_debug_bindings. Don't
+ allocate anything and don't enter anything into the
+ hash table. */
+ if (__glibc_unlikely (tab->size))
+ {
+ assert (GLRO(dl_debug_mask) & DL_DEBUG_PRELINK);
+ goto success;
+ }
+#endif
+
+#define INITIAL_NUNIQUE_SYM_TABLE 31
+ size = INITIAL_NUNIQUE_SYM_TABLE;
+ entries = calloc (sizeof (struct unique_sym), size);
+ if (entries == NULL)
+ goto nomem;
+
+ tab->entries = entries;
+ tab->size = size;
+ tab->free = free;
+ }
+
+ if ((type_class & ELF_RTYPE_CLASS_COPY) != 0)
+ enter_unique_sym (entries, size, new_hash, strtab + sym->st_name, ref,
+ undef_map);
+ else
+ {
+ enter_unique_sym (entries, size,
+ new_hash, strtab + sym->st_name, sym, map);
+
+#if 0
+ if (map->l_type == lt_loaded)
+ /* Make sure we don't unload this object by
+ setting the appropriate flag. */
+ ((struct link_map *) map)->l_flags_1 |= DF_1_NODELETE;
+#endif
+ }
+ ++tab->n_elements;
+
+#if 1
+ success:
+#endif
+
+ result->s = sym;
+ result->m = (struct link_map *) map;
+}
+
+/* Inner part of the lookup functions. We return a value > 0 if we
+ found the symbol, the value 0 if nothing is found and < 0 if
+ something bad happened. */
+static int
+do_lookup_x (const char *undef_name, uint_fast32_t new_hash,
+ unsigned long int *old_hash, const ElfW(Sym) *ref,
+ struct sym_val *result, struct r_scope_elem *scope, size_t i,
+ const struct r_found_version *const version, int flags,
+ struct link_map *skip, int type_class, struct link_map *undef_map)
+{
+ size_t n = scope->r_nlist;
+ /* Make sure we read the value before proceeding. Otherwise we
+ might use r_list pointing to the initial scope and r_nlist being
+ the value after a resize. That is the only path in dl-open.c not
+ protected by GSCOPE. A read barrier here might be to expensive. */
+ __asm volatile ("" : "+r" (n), "+m" (scope->r_list));
+ struct link_map **list = scope->r_list;
+
+ do
+ {
+ const struct link_map *map = list[i];
+
+ /* Here come the extra test needed for `_dl_lookup_symbol_skip'. */
+ if (map == skip)
+ continue;
+
+ /* Don't search the executable when resolving a copy reloc. */
+ if ((type_class & ELF_RTYPE_CLASS_COPY) && map->l_type == lt_executable)
+ continue;
+
+ /* Print some debugging info if wanted. */
+ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_SYMBOLS))
+ _dl_debug_printf ("symbol=%s; lookup in file=%s [%lu]\n",
+ undef_name, DSO_FILENAME (map->l_name),
+ 0UL);
+
+ /* If the hash table is empty there is nothing to do here. */
+ if (map->l_nbuckets == 0)
+ continue;
+
+ Elf_Symndx symidx;
+ int num_versions = 0;
+ const ElfW(Sym) *versioned_sym = NULL;
+
+ /* The tables for this map. */
+ const ElfW(Sym) *symtab = (const void *) D_PTR (map, l_info[DT_SYMTAB]);
+ const char *strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
+
+ const ElfW(Sym) *sym;
+ const ElfW(Addr) *bitmask = map->l_gnu_bitmask;
+ if (__glibc_likely (bitmask != NULL))
+ {
+ ElfW(Addr) bitmask_word
+ = bitmask[(new_hash / __ELF_NATIVE_CLASS)
+ & map->l_gnu_bitmask_idxbits];
+
+ unsigned int hashbit1 = new_hash & (__ELF_NATIVE_CLASS - 1);
+ unsigned int hashbit2 = ((new_hash >> map->l_gnu_shift)
+ & (__ELF_NATIVE_CLASS - 1));
+
+ if (__glibc_unlikely ((bitmask_word >> hashbit1)
+ & (bitmask_word >> hashbit2) & 1))
+ {
+ Elf32_Word bucket = map->l_gnu_buckets[new_hash
+ % map->l_nbuckets];
+
+/* PPC64 workaround */
+ /* There is a bad hash entry and it's pointing beyond
+ the end of the bucket list. */
+ assert ((void *)&map->l_gnu_chain_zero[bucket] < map->l_buckets_end);
+/* END PPC64 workaround */
+ if (bucket != 0)
+ {
+ const Elf32_Word *hasharr = &map->l_gnu_chain_zero[bucket];
+
+ do
+ if (((*hasharr ^ new_hash) >> 1) == 0)
+ {
+ symidx = hasharr - map->l_gnu_chain_zero;
+ sym = check_match (undef_name, ref, version, flags,
+ type_class, &symtab[symidx], symidx,
+ strtab, map, &versioned_sym,
+ &num_versions);
+ if (sym != NULL)
+ goto found_it;
+ }
+ while ((*hasharr++ & 1u) == 0);
+ }
+ }
+ /* No symbol found. */
+ symidx = SHN_UNDEF;
+ }
+ else
+ {
+ if (*old_hash == 0xffffffff)
+ *old_hash = _dl_elf_hash (undef_name);
+
+ /* Use the old SysV-style hash table. Search the appropriate
+ hash bucket in this object's symbol table for a definition
+ for the same symbol name. */
+ for (symidx = map->l_buckets[*old_hash % map->l_nbuckets];
+ symidx != STN_UNDEF;
+ symidx = map->l_chain[symidx])
+ {
+ sym = check_match (undef_name, ref, version, flags,
+ type_class, &symtab[symidx], symidx,
+ strtab, map, &versioned_sym,
+ &num_versions);
+ if (sym != NULL)
+ goto found_it;
+ }
+ }
+
+ /* If we have seen exactly one versioned symbol while we are
+ looking for an unversioned symbol and the version is not the
+ default version we still accept this symbol since there are
+ no possible ambiguities. */
+ sym = num_versions == 1 ? versioned_sym : NULL;
+
+ if (sym != NULL)
+ {
+ found_it:
+ /* When UNDEF_MAP is NULL, which indicates we are called from
+ do_lookup_x on relocation against protected data, we skip
+ the data definion in the executable from copy reloc. */
+ if (ELF_RTYPE_CLASS_EXTERN_PROTECTED_DATA(map->machine)
+ && undef_map == NULL
+ && map->l_type == lt_executable
+ && type_class == ELF_RTYPE_CLASS_EXTERN_PROTECTED_DATA(map->machine))
+ {
+ const ElfW(Sym) *s;
+ unsigned int i;
+
+if (!ELF_MACHINE_NO_RELA(map->machine)) { /* #if ! ELF_MACHINE_NO_RELA */
+ if (map->l_info[DT_RELA] != NULL
+ && map->l_info[DT_RELASZ] != NULL
+ && ((ElfW(Dyn) *)(map->l_info[DT_RELASZ]))->d_un.d_val != 0)
+ {
+ const ElfW(Rela) *rela
+ = (const ElfW(Rela) *) D_PTR (map, l_info[DT_RELA]);
+ unsigned int rela_count
+ = ((ElfW(Dyn) *)(map->l_info[DT_RELASZ]))->d_un.d_val / sizeof (*rela);
+
+ for (i = 0; i < rela_count; i++, rela++)
+ if (elf_machine_type_class (ELFW(R_TYPE) (rela->r_info), map->machine)
+ == ELF_RTYPE_CLASS_COPY)
+ {
+ s = &symtab[ELFW(R_SYM) (rela->r_info)];
+ if (!strcmp (strtab + s->st_name, undef_name))
+ goto skip;
+ }
+ }
+} /* #endif */
+if (!ELF_MACHINE_NO_REL(map->machine)) { /* #if ! ELF_MACHINE_NO_REL */
+ if (map->l_info[DT_REL] != NULL
+ && map->l_info[DT_RELSZ] != NULL
+ && ((ElfW(Dyn) *)(map->l_info[DT_RELSZ]))->d_un.d_val != 0)
+ {
+ const ElfW(Rel) *rel
+ = (const ElfW(Rel) *) D_PTR (map, l_info[DT_REL]);
+ unsigned int rel_count
+ = ((ElfW(Dyn) *)(map->l_info[DT_RELSZ]))->d_un.d_val / sizeof (*rel);
+
+ for (i = 0; i < rel_count; i++, rel++)
+ if (elf_machine_type_class (ELFW(R_TYPE) (rel->r_info), map->machine)
+ == ELF_RTYPE_CLASS_COPY)
+ {
+ s = &symtab[ELFW(R_SYM) (rel->r_info)];
+ if (!strcmp (strtab + s->st_name, undef_name))
+ goto skip;
+ }
+ }
+} /* #endif */
+ }
+
+ switch (ELFW(ST_BIND) (sym->st_info))
+ {
+ case STB_WEAK:
+ /* Weak definition. Use this value if we don't find another. */
+ if (__glibc_unlikely (GLRO(dl_dynamic_weak)))
+ {
+ if (! result->s)
+ {
+ result->s = sym;
+ result->m = (struct link_map *) map;
+ }
+ break;
+ }
+ /* FALLTHROUGH */
+ case STB_GLOBAL:
+ /* Global definition. Just what we need. */
+ result->s = sym;
+ result->m = (struct link_map *) map;
+ return 1;
+
+ case STB_GNU_UNIQUE:;
+ do_lookup_unique (undef_name, new_hash, map, result, type_class,
+ sym, strtab, ref, undef_map);
+ return 1;
+
+ default:
+ /* Local symbols are ignored. */
+ break;
+ }
+ }
+
+skip:
+ /* If this current map is the one mentioned in the verneed entry
+ and we have not found a weak entry, it is a bug. */
+ if (symidx == STN_UNDEF && version != NULL && version->filename != NULL
+ && __glibc_unlikely (_dl_name_match_p (version->filename, map)))
+ return -1;
+ }
+ while (++i < n);
+
+ /* We have not found anything until now. */
+ return 0;
+}
+
+
+static void
+_dl_debug_bindings (const char *undef_name, struct link_map *undef_map,
+ const ElfW(Sym) **ref, struct sym_val *value,
+ const struct r_found_version *version, int type_class,
+ int protected);
+
+
+/* Search loaded objects' symbol tables for a definition of the symbol
+ UNDEF_NAME, perhaps with a requested version for the symbol.
+
+ We must never have calls to the audit functions inside this function
+ or in any function which gets called. If this would happen the audit
+ code might create a thread which can throw off all the scope locking. */
+lookup_t
+_dl_lookup_symbol_x (const char *undef_name, struct link_map *undef_map,
+ const ElfW(Sym) **ref,
+ struct r_scope_elem *symbol_scope[],
+ const struct r_found_version *version,
+ int type_class, int flags, struct link_map *skip_map)
+{
+ const uint_fast32_t new_hash = dl_new_hash (undef_name);
+ unsigned long int old_hash = 0xffffffff;
+ struct sym_val current_value = { NULL, NULL };
+ struct r_scope_elem **scope = symbol_scope;
+
+ /* No other flag than DL_LOOKUP_ADD_DEPENDENCY or DL_LOOKUP_GSCOPE_LOCK
+ is allowed if we look up a versioned symbol. */
+ assert (version == NULL
+ || (flags & ~(DL_LOOKUP_ADD_DEPENDENCY | DL_LOOKUP_GSCOPE_LOCK))
+ == 0);
+
+ size_t i = 0;
+ if (__glibc_unlikely (skip_map != NULL))
+ /* Search the relevant loaded objects for a definition. */
+ while ((*scope)->r_list[i] != skip_map)
+ ++i;
+
+ /* Search the relevant loaded objects for a definition. */
+ size_t start; /* requires C99 to put it into the loop */
+ for (start = i; *scope != NULL; start = 0, ++scope)
+ {
+ int res = do_lookup_x (undef_name, new_hash, &old_hash, *ref,
+ &current_value, *scope, start, version, flags,
+ skip_map, type_class, undef_map);
+ if (res > 0)
+ break;
+
+ if (__glibc_unlikely (res < 0) && skip_map == NULL)
+ {
+ /* Oh, oh. The file named in the relocation entry does not
+ contain the needed symbol. This code is never reached
+ for unversioned lookups. */
+ assert (version != NULL);
+ const char *reference_name = undef_map ? undef_map->l_name : "";
+
+ /* XXX We cannot translate the message. */
+ _dl_signal_cerror (0, DSO_FILENAME (reference_name),
+ "relocation error",
+ make_string ("symbol ", undef_name, ", version ",
+ version->name,
+ " not defined in file ",
+ version->filename,
+ " with link time reference",
+ res == -2
+ ? " (no version symbols)" : ""));
+ *ref = NULL;
+ return 0;
+ }
+ }
+
+ if (__glibc_unlikely (current_value.s == NULL))
+ {
+ if ((*ref == NULL || ELFW(ST_BIND) ((*ref)->st_info) != STB_WEAK)
+ && skip_map == NULL
+ && !(GLRO(dl_debug_mask) & DL_DEBUG_UNUSED))
+ {
+ /* We could find no value for a strong reference. */
+ const char *reference_name = undef_map ? undef_map->l_name : "";
+ const char *versionstr = version ? ", version " : "";
+ const char *versionname = (version && version->name
+ ? version->name : "");
+
+ /* XXX We cannot translate the message. */
+ _dl_signal_cerror (0, DSO_FILENAME (reference_name),
+ ("symbol lookup error"),
+ make_string ("undefined symbol: ", undef_name,
+ versionstr, versionname));
+ }
+ *ref = NULL;
+ return 0;
+ }
+
+ int protected = (*ref
+ && ELFW(ST_VISIBILITY) ((*ref)->st_other) == STV_PROTECTED);
+ if (__glibc_unlikely (protected != 0))
+ {
+ /* It is very tricky. We need to figure out what value to
+ return for the protected symbol. */
+ if (type_class == ELF_RTYPE_CLASS_PLT)
+ {
+ if (current_value.s != NULL && current_value.m != undef_map)
+ {
+ current_value.s = *ref;
+ current_value.m = undef_map;
+ }
+ }
+ else
+ {
+ struct sym_val protected_value = { NULL, NULL };
+
+ for (scope = symbol_scope; *scope != NULL; i = 0, ++scope)
+ if (do_lookup_x (undef_name, new_hash, &old_hash, *ref,
+ &protected_value, *scope, i, version, flags,
+ skip_map,
+ (ELF_RTYPE_CLASS_EXTERN_PROTECTED_DATA(skip_map->machine)
+ && ELFW(ST_TYPE) ((*ref)->st_info) == STT_OBJECT
+ && type_class == ELF_RTYPE_CLASS_EXTERN_PROTECTED_DATA(skip_map->machine))
+ ? ELF_RTYPE_CLASS_EXTERN_PROTECTED_DATA(skip_map->machine)
+ : ELF_RTYPE_CLASS_PLT, NULL) != 0)
+ break;
+
+ if (protected_value.s != NULL && protected_value.m != undef_map)
+ {
+ current_value.s = *ref;
+ current_value.m = undef_map;
+ }
+ }
+ }
+
+#if 0
+ /* We have to check whether this would bind UNDEF_MAP to an object
+ in the global scope which was dynamically loaded. In this case
+ we have to prevent the latter from being unloaded unless the
+ UNDEF_MAP object is also unloaded. */
+ if (__glibc_unlikely (current_value.m->l_type == lt_loaded)
+ /* Don't do this for explicit lookups as opposed to implicit
+ runtime lookups. */
+ && (flags & DL_LOOKUP_ADD_DEPENDENCY) != 0
+ /* Add UNDEF_MAP to the dependencies. */
+ && add_dependency (undef_map, current_value.m, flags) < 0)
+ /* Something went wrong. Perhaps the object we tried to reference
+ was just removed. Try finding another definition. */
+ return _dl_lookup_symbol_x (undef_name, undef_map, ref,
+ symbol_scope,
+ version, type_class, flags, skip_map);
+#endif
+
+ if (__glibc_unlikely (GLRO(dl_debug_mask)
+ & (DL_DEBUG_BINDINGS|DL_DEBUG_PRELINK)))
+ _dl_debug_bindings (undef_name, undef_map, ref,
+ &current_value, version, type_class, protected);
+
+ *ref = current_value.s;
+ return LOOKUP_VALUE (current_value.m);
+}
+
+
+/* Cache the location of MAP's hash table. */
+
+void
+_dl_setup_hash (struct link_map *map)
+{
+ Elf_Symndx *hash;
+
+ if (__glibc_likely (map->l_info[DT_ADDRTAGIDX (DT_GNU_HASH) + DT_NUM
+ + DT_THISPROCNUM + DT_VERSIONTAGNUM
+ + DT_EXTRANUM + DT_VALNUM] != NULL))
+ {
+ Elf32_Word *hash32
+ = (void *) D_PTR (map, l_info[DT_ADDRTAGIDX (DT_GNU_HASH) + DT_NUM
+ + DT_THISPROCNUM + DT_VERSIONTAGNUM
+ + DT_EXTRANUM + DT_VALNUM]);
+ map->l_nbuckets = *hash32++;
+ Elf32_Word symbias = *hash32++;
+ Elf32_Word bitmask_nwords = *hash32++;
+ /* Must be a power of two. */
+ assert ((bitmask_nwords & (bitmask_nwords - 1)) == 0);
+ map->l_gnu_bitmask_idxbits = bitmask_nwords - 1;
+ map->l_gnu_shift = *hash32++;
+
+ map->l_gnu_bitmask = (ElfW(Addr) *) hash32;
+ hash32 += __ELF_NATIVE_CLASS / 32 * bitmask_nwords;
+
+ map->l_gnu_buckets = hash32;
+ hash32 += map->l_nbuckets;
+ map->l_gnu_chain_zero = hash32 - symbias;
+ return;
+ }
+
+ if (!map->l_info[DT_HASH])
+ return;
+ hash = (void *) D_PTR (map, l_info[DT_HASH]);
+
+ map->l_nbuckets = *hash++;
+ /* Skip nchain. */
+ hash++;
+ map->l_buckets = hash;
+ hash += map->l_nbuckets;
+ map->l_chain = hash;
+}
+
+
+static void
+_dl_debug_bindings (const char *undef_name, struct link_map *undef_map,
+ const ElfW(Sym) **ref, struct sym_val *value,
+ const struct r_found_version *version, int type_class,
+ int protected)
+{
+ const char *reference_name = undef_map->l_name;
+
+ if (GLRO(dl_debug_mask) & DL_DEBUG_BINDINGS)
+ {
+ _dl_debug_printf ("binding file %s [%lu] to %s [%lu]: %s symbol `%s'",
+ DSO_FILENAME (reference_name),
+ 0UL,
+ DSO_FILENAME (value->m->l_name),
+ 0UL,
+ protected ? "protected" : "normal", undef_name);
+ if (version)
+ printf (" [%s]\n", version->name);
+ else
+ printf ("\n");
+ }
+#if 1
+ if (GLRO(dl_debug_mask) & DL_DEBUG_PRELINK)
+ {
+ int conflict = 0;
+ struct sym_val val = { NULL, NULL };
+
+ /* We need to always process these or we can miss conflict symbols when
+ RTLD_TRACE_PRELINKING=<library> */
+ if (1)
+ {
+ const uint_fast32_t new_hash = dl_new_hash (undef_name);
+ unsigned long int old_hash = 0xffffffff;
+ struct unique_sym *saved_entries
+ = _ns_unique_sym_table->entries;
+
+ _ns_unique_sym_table->entries = NULL;
+ do_lookup_x (undef_name, new_hash, &old_hash, *ref, &val,
+ undef_map->l_local_scope[0], 0, version, 0, NULL,
+ type_class, undef_map);
+ if (val.s != value->s || val.m != value->m)
+ conflict = 1;
+ else if (1
+ && val.s
+ && __glibc_unlikely (ELFW(ST_BIND) (val.s->st_info)
+ == STB_GNU_UNIQUE))
+ {
+ /* If it is STB_GNU_UNIQUE and undef_map's l_local_scope
+ contains any DT_SYMBOLIC libraries, unfortunately there
+ can be conflicts even if the above is equal. As symbol
+ resolution goes from the last library to the first and
+ if a STB_GNU_UNIQUE symbol is found in some late DT_SYMBOLIC
+ library, it would be the one that is looked up. */
+ struct sym_val val2 = { NULL, NULL };
+ size_t n;
+ struct r_scope_elem *scope = undef_map->l_local_scope[0];
+
+ for (n = 0; n < scope->r_nlist; n++)
+ if (scope->r_list[n] == val.m)
+ break;
+
+ for (n++; n < scope->r_nlist; n++)
+ if (scope->r_list[n]->l_info[DT_SYMBOLIC] != NULL
+ && do_lookup_x (undef_name, new_hash, &old_hash, *ref,
+ &val2,
+ scope,
+ 0, version, 0, NULL, type_class,
+ undef_map) > 0)
+ {
+ conflict = 1;
+ val = val2;
+ break;
+ }
+ }
+ _ns_unique_sym_table->entries = saved_entries;
+ }
+
+ if (value->s)
+ {
+ if (__glibc_unlikely (ELFW(ST_TYPE) (value->s->st_info)
+ == STT_TLS))
+ type_class = 4;
+ else if (__glibc_unlikely (ELFW(ST_TYPE) (value->s->st_info)
+ == STT_GNU_IFUNC))
+ type_class |= 8;
+ }
+
+ if (conflict
+ || GLRO(dl_trace_prelink_map) == undef_map
+ || GLRO(dl_trace_prelink_map) == NULL
+ || type_class >= 4)
+ {
+ printf ("%s 0x%0*"rtld_size_fmtx" 0x%0*"rtld_size_fmtx" -> 0x%0*"rtld_size_fmtx" 0x%0*"rtld_size_fmtx" ",
+ conflict ? "conflict" : "lookup",
+ (int) sizeof (ElfW(Addr)) * 2,
+ (rtld_size_t) undef_map->l_map_start,
+ (int) sizeof (ElfW(Addr)) * 2,
+ (rtld_size_t) (((char *)*ref) - ((char *)undef_map->l_info[DT_SYMTAB]) + (char *)undef_map->sym_base),
+ (int) sizeof (ElfW(Addr)) * 2,
+ (rtld_size_t) (value->s ? value->m->l_map_start : 0),
+ (int) sizeof (ElfW(Addr)) * 2,
+ (rtld_size_t) (value->s ? value->s->st_value : 0));
+
+ if (conflict)
+ printf ("x 0x%0*"rtld_size_fmtx" 0x%0*"rtld_size_fmtx" ",
+ (int) sizeof (ElfW(Addr)) * 2,
+ (rtld_size_t) (val.s ? val.m->l_map_start : 0),
+ (int) sizeof (ElfW(Addr)) * 2,
+ (rtld_size_t) (val.s ? val.s->st_value : 0));
+
+ printf ("/%x %s\n", type_class, undef_name);
+ }
+ }
+#endif
+}
+
+#undef enter_unique_sym
+#undef sym_val
+#undef check_match
+#undef do_lookup_unique
+#undef do_lookup_x
+#undef _dl_setup_hash
+#define _dl_setup_hash rtld_setup_hash
+#undef _dl_debug_bindings
+#undef _dl_lookup_symbol_x
+#undef rtld_size_t
+#undef rtld_size_fmtx
diff --git a/src/rtld/dl-misc.c b/src/rtld/dl-misc.c
new file mode 100644
index 0000000..c70956d
--- /dev/null
+++ b/src/rtld/dl-misc.c
@@ -0,0 +1,106 @@
+/* glibc 2.22, elf/dl-misc.c */
+
+/* Miscellaneous support functions for dynamic linker
+ Copyright (C) 1997-2015 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <assert.h>
+#include <error.h>
+#include <errno.h>
+#include <string.h>
+#include "rtld.h"
+
+/* Test whether given NAME matches any of the names of the given object. */
+int
+_dl_name_match_p (const char *name, const struct link_map *map)
+{
+ if (strcmp (name, map->l_name) == 0)
+ return 1;
+
+ struct libname_list *runp = map->l_libname;
+
+ while (runp != NULL)
+ if (strcmp (name, runp->name) == 0)
+ return 1;
+ else
+ runp = runp->next;
+
+ return 0;
+}
+
+unsigned long int
+_dl_higher_prime_number (unsigned long int n)
+{
+ /* These are primes that are near, but slightly smaller than, a
+ power of two. */
+ static const uint32_t primes[] = {
+ UINT32_C (7),
+ UINT32_C (13),
+ UINT32_C (31),
+ UINT32_C (61),
+ UINT32_C (127),
+ UINT32_C (251),
+ UINT32_C (509),
+ UINT32_C (1021),
+ UINT32_C (2039),
+ UINT32_C (4093),
+ UINT32_C (8191),
+ UINT32_C (16381),
+ UINT32_C (32749),
+ UINT32_C (65521),
+ UINT32_C (131071),
+ UINT32_C (262139),
+ UINT32_C (524287),
+ UINT32_C (1048573),
+ UINT32_C (2097143),
+ UINT32_C (4194301),
+ UINT32_C (8388593),
+ UINT32_C (16777213),
+ UINT32_C (33554393),
+ UINT32_C (67108859),
+ UINT32_C (134217689),
+ UINT32_C (268435399),
+ UINT32_C (536870909),
+ UINT32_C (1073741789),
+ UINT32_C (2147483647),
+ /* 4294967291L */
+ UINT32_C (2147483647) + UINT32_C (2147483644)
+ };
+
+ const uint32_t *low = &primes[0];
+ const uint32_t *high = &primes[sizeof (primes) / sizeof (primes[0])];
+
+ while (low != high)
+ {
+ const uint32_t *mid = low + (high - low) / 2;
+ if (n > *mid)
+ low = mid + 1;
+ else
+ high = mid;
+ }
+
+#if 0
+ /* If we've run out of primes, abort. */
+ if (n > *low)
+ {
+ fprintf (stderr, "Cannot find prime bigger than %lu\n", n);
+ abort ();
+ }
+#endif
+
+ return *low;
+}
diff --git a/src/rtld/dl-object.c b/src/rtld/dl-object.c
new file mode 100644
index 0000000..19f0265
--- /dev/null
+++ b/src/rtld/dl-object.c
@@ -0,0 +1,57 @@
+/* glibc-2.22: elf/dl-object.c */
+
+/* Storage management for the chain of loaded shared objects.
+ Copyright (C) 1995-2015 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <assert.h>
+#include <error.h>
+#include <errno.h>
+#include <string.h>
+#include "rtld.h"
+
+/* Allocate a `struct link_map' for a new object being loaded,
+ and enter it into the _dl_loaded list. */
+struct link_map *
+_dl_new_object (const char *realname, const char *libname, int type)
+{
+ size_t libname_len = strlen (libname) + 1;
+ struct link_map *new;
+ struct libname_list *newname;
+
+ new = (struct link_map *) calloc (sizeof (*new) +
+ + sizeof (*newname) + libname_len, 1);
+
+ if (new == NULL)
+ return NULL;
+
+ new->l_libname = newname
+ = (struct libname_list *) ((char *) (new + 1));
+ newname->name = (char *) memcpy (newname + 1, libname, libname_len);
+ /* newname->next = NULL; We use calloc therefore not necessary. */
+
+ /* When we create the executable link map, or a VDSO link map, we start
+ with "" for the l_name. In these cases "" points to ld.so rodata
+ and won't get dumped during core file generation. Therefore to assist
+ gdb and to create more self-contained core files we adjust l_name to
+ point at the newly allocated copy (which will get dumped) instead of
+ the ld.so rodata copy. */
+ new->l_name = *realname ? realname : (char *) newname->name + libname_len - 1;
+ new->l_type = type;
+
+ return new;
+}
diff --git a/src/rtld/dl-tls.c b/src/rtld/dl-tls.c
new file mode 100644
index 0000000..8b972ff
--- /dev/null
+++ b/src/rtld/dl-tls.c
@@ -0,0 +1,287 @@
+/* Copyright (C) 2011 Wind River Systems, Inc.
+
+ Code reorganized from original code bearing the following copyright:
+ Copyright (C) 2003 MontaVista Software, Inc.
+ Written by Daniel Jacobowitz <drow@mvista.com>, 2003
+
+ Code updated by Mark Hatle <mark.hatle@windriver.com>, 2011
+ to sync to eglibc 2.13 tls behavior...
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* glibc 2.22: elf/dl-tls.c */
+
+/* Thread-local storage handling in the ELF dynamic linker. Generic version.
+ Copyright (C) 2002-2015 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <config.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "rtld.h"
+
+/* Assign TLS offsets for every loaded library. This code is taken
+ almost directly from glibc! */
+
+#define roundup(x, y) ((((x) + ((y) - 1)) / (y)) * (y))
+
+/* The following function needs to mimic the _dl_determine_tlsoffset in eglibc */
+void
+rtld_determine_tlsoffsets (int e_machine, struct r_scope_elem *search_list)
+{
+ uint64_t modid = 1;
+
+ uint64_t i;
+
+ /* skip max_align */
+ uint64_t freetop = 0;
+ uint64_t freebottom = 0;
+
+ /* This comes from each architecture's ABI. If TLS_TCB_AT_TP, then
+ set offset to -1; if TLS_DTV_AT_TP, then set offset to
+ TLS_TCB_SIZE. */
+
+ int tls_tcb_at_tp = 0;
+ int tls_dtv_at_tp = 0;
+ uint64_t tls_tcb_size;
+
+ switch (e_machine)
+ {
+ case EM_X86_64:
+ tls_tcb_at_tp = 1;
+ tls_tcb_size = -1;
+ break;
+
+ case EM_386:
+ tls_tcb_at_tp = 1;
+ tls_tcb_size = -1;
+ break;
+
+ case EM_SH:
+ tls_dtv_at_tp = 1;
+ tls_tcb_size = 8;
+ break;
+
+ case EM_PPC:
+ tls_dtv_at_tp = 1;
+ tls_tcb_size = 0;
+ break;
+
+ case EM_PPC64:
+ tls_dtv_at_tp = 1;
+ tls_tcb_size = 0;
+ break;
+
+ case EM_ARM:
+ tls_dtv_at_tp = 1;
+ tls_tcb_size = 8;
+ break;
+
+ case EM_AARCH64:
+ tls_dtv_at_tp = 1;
+ tls_tcb_size = 16;
+ break;
+
+ case EM_MIPS:
+ tls_dtv_at_tp = 1;
+ tls_tcb_size = 0;
+ break;
+
+ case EM_SPARC:
+ case EM_SPARC32PLUS:
+ tls_tcb_at_tp = 1;
+ tls_tcb_size = -1;
+ break;
+
+ case EM_SPARCV9:
+ tls_tcb_at_tp = 1;
+ tls_tcb_size = -1;
+ break;
+
+ case EM_ALTERA_NIOS2:
+ tls_dtv_at_tp = 1;
+ tls_tcb_size = 0;
+ break;
+
+ default:
+ /* Hope there's no TLS! */
+ for (i = 0; i < search_list->r_nlist; i++)
+ {
+ struct link_map *map = search_list->r_list[i];
+
+ if (map->l_tls_blocksize > 0)
+ _dl_signal_error(0, map->l_name, NULL, "cannot handle TLS data");
+ }
+
+ return;
+ }
+
+ /* eglibc 2.20: elf/dl-tls.c: _dl_determine_tlsoffset (void) */
+ /* Determining the offset of the various parts of the static TLS
+ block has several dependencies. In addition we have to work
+ around bugs in some toolchains.
+
+ Each TLS block from the objects available at link time has a size
+ and an alignment requirement. The GNU ld computes the alignment
+ requirements for the data at the positions *in the file*, though.
+ I.e, it is not simply possible to allocate a block with the size
+ of the TLS program header entry. The data is layed out assuming
+ that the first byte of the TLS block fulfills
+
+ p_vaddr mod p_align == &TLS_BLOCK mod p_align
+
+ This means we have to add artificial padding at the beginning of
+ the TLS block. These bytes are never used for the TLS data in
+ this module but the first byte allocated must be aligned
+ according to mod p_align == 0 so that the first byte of the TLS
+ block is aligned according to p_vaddr mod p_align. This is ugly
+ and the linker can help by computing the offsets in the TLS block
+ assuming the first byte of the TLS block is aligned according to
+ p_align.
+
+ The extra space which might be allocated before the first byte of
+ the TLS block need not go unused. The code below tries to use
+ that memory for the next TLS block. This can work if the total
+ memory requirement for the next TLS block is smaller than the
+ gap. */
+
+ /* Loop over the loaded DSOs. We use the symbol search order; this
+ should be the same as glibc's ordering, which traverses l_next.
+ It's somewhat important that we use both the same ordering to
+ assign module IDs and the same algorithm to assign offsets,
+ because the prelinker will resolve all relocations using these
+ offsets... and then glibc will recalculate them. Future dynamic
+ relocations in any loaded modules will use glibc's values. Also
+ if we take too much space here, glibc won't allocate enough
+ static TLS area to hold it. */
+
+/* #if TLS_TCB_AT_TP */ if (tls_tcb_at_tp == 1) {
+ /* We simply start with zero. */
+ uint64_t offset = 0;
+
+ for (i = 0; i < search_list->r_nlist; i++)
+ {
+ struct link_map *map = search_list->r_list[i];
+
+ uint64_t firstbyte = (-map->l_tls_firstbyte_offset
+ & (map->l_tls_align - 1));
+ uint64_t off;
+
+ /* elf/rtld.c would have caused us to skip this block.. so emulate this */
+ if (map->l_tls_blocksize == 0)
+ continue;
+
+ /* allocate_tls_init would nomrally Increment the module id */
+ map->l_tls_modid = modid++;
+
+ if (freebottom - freetop >= map->l_tls_blocksize)
+ {
+ off = roundup (freetop + map->l_tls_blocksize
+ - firstbyte, map->l_tls_align)
+ + firstbyte;
+ if (off <= freebottom)
+ {
+ freetop = off;
+
+ /* XXX For some architectures we perhaps should store the
+ negative offset. */
+ map->l_tls_offset = off;
+ continue;
+ }
+ }
+
+ off = roundup (offset + map->l_tls_blocksize - firstbyte,
+ map->l_tls_align) + firstbyte;
+ if (off > offset + map->l_tls_blocksize
+ + (freebottom - freetop))
+ {
+ freetop = offset;
+ freebottom = off - map->l_tls_blocksize;
+ }
+ offset = off;
+
+ /* XXX For some architectures we perhaps should store the
+ negative offset. */
+ map->l_tls_offset = off;
+ }
+/* #elif TLS_DTV_AT_TP */ } else if (tls_dtv_at_tp == 1) {
+ /* The TLS blocks start right after the TCB. */
+ uint64_t offset = tls_tcb_size;
+
+ for (i = 0; i < search_list->r_nlist; i++)
+ {
+ struct link_map *map = search_list->r_list[i];
+
+ uint64_t firstbyte = (-map->l_tls_firstbyte_offset
+ & (map->l_tls_align - 1));
+ uint64_t off;
+
+ /* elf/rtld.c would have caused us to skip this block.. so emulate this */
+ if (map->l_tls_blocksize == 0)
+ continue;
+
+ /* allocate_tls_init would nomrally Increment the module id */
+ map->l_tls_modid = modid++;
+
+ if (map->l_tls_blocksize <= freetop - freebottom)
+ {
+ off = roundup (freebottom, map->l_tls_align);
+ if (off - freebottom < firstbyte)
+ off += map->l_tls_align;
+ if (off + map->l_tls_blocksize - firstbyte <= freetop)
+ {
+ map->l_tls_offset = off - firstbyte;
+ freebottom = (off + map->l_tls_blocksize
+ - firstbyte);
+ continue;
+ }
+ }
+
+ off = roundup (offset, map->l_tls_align);
+ if (off - offset < firstbyte)
+ off += map->l_tls_align;
+
+ map->l_tls_offset = off - firstbyte;
+ if (off - firstbyte - offset > freetop - freebottom)
+ {
+ freebottom = offset;
+ freetop = off - firstbyte;
+ }
+
+ offset = off + map->l_tls_blocksize - firstbyte;
+ }
+/* #else */ } else {
+ /* Should never happen... */
+ _dl_signal_error(0, NULL, NULL, "Neither TLS_TCB_AT_TP nor TLS_DTV_AT_TP is defined for this architecture");
+/* #endif */ }
+}
diff --git a/src/rtld/dl-version.c b/src/rtld/dl-version.c
new file mode 100644
index 0000000..042a70f
--- /dev/null
+++ b/src/rtld/dl-version.c
@@ -0,0 +1,369 @@
+/* Based on code originally in eglibc 2.13, libc/elf/dl-version.c */
+
+/* Handle symbol and library versioning.
+ Copyright (C) 1997-2015 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <assert.h>
+#include <error.h>
+#include <errno.h>
+#include <string.h>
+#include "rtld.h"
+
+#define make_string(string, rest...) \
+ ({ \
+ const char *all[] = { string, ## rest }; \
+ size_t len, cnt; \
+ char *result, *cp; \
+ \
+ len = 1; \
+ for (cnt = 0; cnt < sizeof (all) / sizeof (all[0]); ++cnt) \
+ len += strlen (all[cnt]); \
+ \
+ cp = result = alloca (len); \
+ for (cnt = 0; cnt < sizeof (all) / sizeof (all[0]); ++cnt) \
+ cp = __stpcpy (cp, all[cnt]); \
+ \
+ result; \
+ })
+
+
+static inline struct link_map *
+find_needed (const char *name, struct link_map *map)
+{
+ struct link_map *tmap = map;
+ unsigned int n = 0;
+
+ for (n = 0; n < map->l_local_scope[0]->r_nlist; n++)
+ {
+ tmap = map->l_local_scope[0]->r_list[n];
+ if (_dl_name_match_p (name, tmap))
+ return tmap;
+ }
+
+ if (_dl_name_match_p (name, map))
+ return map;
+
+ /* Should never happen. */
+ return NULL;
+}
+
+
+static int
+match_symbol (const char *name, Elf64_Word hash, const char *string,
+ struct link_map *map, int verbose, int weak)
+{
+ const char *strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
+ Elf64_Verdef *def;
+ /* Initialize to make the compiler happy. */
+ const char *errstring = NULL;
+ int result = 0;
+
+ /* Display information about what we are doing while debugging. */
+ if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_VERSIONS))
+ _dl_debug_printf ("\
+checking for version `%s' in file %s [0] required by file %s [0]\n",
+ string, DSO_FILENAME (map->l_name),
+ name);
+
+ if (__glibc_unlikely (map->l_info[VERSYMIDX (DT_VERDEF)] == NULL))
+ {
+ /* The file has no symbol versioning. I.e., the dependent
+ object was linked against another version of this file. We
+ only print a message if verbose output is requested. */
+ if (verbose)
+ {
+ /* XXX We cannot translate the messages. */
+ errstring = make_string ("\
+no version information available (required by ", name, ")");
+ goto call_cerror;
+ }
+ return 0;
+ }
+
+ def = (Elf64_Verdef *) ((char *) map->l_info[VERSYMIDX (DT_VERDEF)]);
+ while (1)
+ {
+ /* Currently the version number of the definition entry is 1.
+ Make sure all we see is this version. */
+ if (__builtin_expect (def->vd_version, 1) != 1)
+ {
+ char buf[20];
+ buf[sizeof (buf) - 1] = '\0';
+ /* XXX We cannot translate the message. */
+ /* _itoa (def->vd_version,
+ &buf[sizeof (buf) - 1], 10, 0), */
+ errstring = make_string ("unsupported version ",
+ " of Verdef record");
+ result = 1;
+ goto call_cerror;
+ }
+
+ /* Compare the hash values. */
+ if (hash == def->vd_hash)
+ {
+ Elf64_Verdaux *aux = (Elf64_Verdaux *) ((char *) def + def->vd_aux);
+
+ /* To be safe, compare the string as well. */
+ if (__builtin_expect (strcmp (string, strtab + aux->vda_name), 0)
+ == 0)
+ /* Bingo! */
+ return 0;
+ }
+
+ /* If no more definitions we failed to find what we want. */
+ if (def->vd_next == 0)
+ break;
+
+ /* Next definition. */
+ def = (Elf64_Verdef *) ((char *) def + def->vd_next);
+ }
+
+ /* Symbol not found. If it was a weak reference it is not fatal. */
+ if (__glibc_likely (weak))
+ {
+ if (verbose)
+ {
+ /* XXX We cannot translate the message. */
+ errstring = make_string ("weak version `", string,
+ "' not found (required by ", name, ")");
+ goto call_cerror;
+ }
+ return 0;
+ }
+
+ /* XXX We cannot translate the message. */
+ errstring = make_string ("version `", string, "' not found (required by ",
+ name, ")");
+ result = 1;
+ call_cerror:
+ _dl_signal_cerror (0, DSO_FILENAME (map->l_name),
+ ("version lookup error"), errstring);
+ return result;
+}
+
+
+int
+_dl_check_map_versions (struct link_map *map, int verbose, int trace_mode)
+{
+ int result = 0;
+ const char *strtab;
+ /* Pointer to section with needed versions. */
+ Elf64_Verneed *dyn;
+ /* This file may require special versions from its dependencies. */
+ Elf64_Verneed *ent;
+ /* Pointer to dynamic section with definitions. */
+ Elf64_Verdef *def;
+ /* We need to find out which is the highest version index used
+ in a dependecy. */
+ unsigned int ndx_high = 0;
+ /* Initialize to make the compiler happy. */
+ const char *errstring = NULL;
+ int errval = 0;
+
+ /* If we don't have a string table, we must be ok. */
+ if (map->l_info[DT_STRTAB] == NULL)
+ return 0;
+ strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]);
+
+ dyn = map->l_info[VERSYMIDX (DT_VERNEED)];
+ def = map->l_info[VERSYMIDX (DT_VERDEF)];
+ ent = (Elf64_Verneed *) (dyn);
+
+ if (dyn != NULL)
+ {
+
+ /* Currently the version number of the needed entry is 1.
+ Make sure all we see is this version. */
+ if (__builtin_expect (ent->vn_version, 1) != 1)
+ {
+ char buf[20];
+ buf[sizeof (buf) - 1] = '\0';
+ /* XXX We cannot translate the message. */
+ /* _itoa (def->vn_version,
+ &buf[sizeof (buf) - 1], 10, 0), */
+ errstring = make_string ("unsupported version ",
+ " of Verneed record\n");
+ call_error:
+ _dl_signal_error (errval, DSO_FILENAME (map->l_name),
+ NULL, errstring);
+ }
+
+ while (1)
+ {
+ Elf64_Vernaux *aux;
+ struct link_map *needed = find_needed (strtab + ent->vn_file, map);
+
+ /* If NEEDED is NULL this means a dependency was not found
+ and no stub entry was created. This should never happen. */
+ if (needed == NULL)
+ {
+ _dl_signal_error (errval, NULL, NULL, strtab + ent->vn_file);
+ printf("error while loading shared libraries: %s", strtab + ent->vn_file);
+ exit (1);
+ }
+ assert (needed != NULL);
+
+ /* Make sure this is no stub we created because of a missing
+ dependency. */
+ if (__builtin_expect (! trace_mode, 1))
+ {
+ /* NEEDED is the map for the file we need. Now look for the
+ dependency symbols. */
+ aux = (Elf64_Vernaux *) ((char *) ent + ent->vn_aux);
+ while (1)
+ {
+ /* Match the symbol. */
+ result |= match_symbol (DSO_FILENAME (map->l_name),
+ aux->vna_hash,
+ strtab + aux->vna_name,
+ needed, verbose,
+ aux->vna_flags & VER_FLG_WEAK);
+
+ /* Compare the version index. */
+ if ((unsigned int) (aux->vna_other & 0x7fff) > ndx_high)
+ ndx_high = aux->vna_other & 0x7fff;
+
+ if (aux->vna_next == 0)
+ /* No more symbols. */
+ break;
+
+ /* Next symbol. */
+ aux = (Elf64_Vernaux *) ((char *) aux + aux->vna_next);
+ }
+ }
+
+ if (ent->vn_next == 0)
+ /* No more dependencies. */
+ break;
+
+ /* Next dependency. */
+ ent = (Elf64_Verneed *) ((char *) ent + ent->vn_next);
+ }
+ }
+
+ /* We also must store the names of the defined versions. Determine
+ the maximum index here as well.
+
+ XXX We could avoid the loop by just taking the number of definitions
+ as an upper bound of new indeces. */
+ if (def != NULL)
+ {
+ Elf64_Verdef *ent;
+ ent = (Elf64_Verdef *) (def);
+ while (1)
+ {
+ if ((unsigned int) (ent->vd_ndx & 0x7fff) > ndx_high)
+ ndx_high = ent->vd_ndx & 0x7fff;
+
+ if (ent->vd_next == 0)
+ /* No more definitions. */
+ break;
+
+ ent = (Elf64_Verdef *) ((char *) ent + ent->vd_next);
+ }
+ }
+
+ if (ndx_high > 0)
+ {
+ /* Now we are ready to build the array with the version names
+ which can be indexed by the version index in the VERSYM
+ section. */
+ map->l_versions = (struct r_found_version *)
+ calloc (ndx_high + 1, sizeof (*map->l_versions));
+ if (__glibc_unlikely (map->l_versions == NULL))
+ {
+ errstring = ("cannot allocate version reference table");
+ errval = ENOMEM;
+ goto call_error;
+ }
+
+ /* Store the number of available symbols. */
+ map->l_nversions = ndx_high + 1;
+
+ /* Compute the pointer to the version symbols. */
+ map->l_versyms = (void *) D_PTR (map, l_info[VERSYMIDX (DT_VERSYM)]);
+
+ if (dyn != NULL)
+ {
+ Elf64_Verneed *ent;
+ ent = (Elf64_Verneed *) (dyn);
+ while (1)
+ {
+ Elf64_Vernaux *aux;
+ aux = (Elf64_Vernaux *) ((char *) ent + ent->vn_aux);
+ while (1)
+ {
+ Elf64_Half ndx = aux->vna_other & 0x7fff;
+ /* In trace mode, dependencies may be missing. */
+ if (__glibc_likely (ndx < map->l_nversions))
+ {
+ map->l_versions[ndx].hash = aux->vna_hash;
+ map->l_versions[ndx].hidden = aux->vna_other & 0x8000;
+ map->l_versions[ndx].name = &strtab[aux->vna_name];
+ map->l_versions[ndx].filename = &strtab[ent->vn_file];
+ }
+
+ if (aux->vna_next == 0)
+ /* No more symbols. */
+ break;
+
+ /* Advance to next symbol. */
+ aux = (Elf64_Vernaux *) ((char *) aux + aux->vna_next);
+ }
+
+ if (ent->vn_next == 0)
+ /* No more dependencies. */
+ break;
+
+ /* Advance to next dependency. */
+ ent = (Elf64_Verneed *) ((char *) ent + ent->vn_next);
+ }
+ }
+
+ /* And insert the defined versions. */
+ if (def != NULL)
+ {
+ Elf64_Verdef *ent;
+ ent = (Elf64_Verdef *) (def);
+ while (1)
+ {
+ Elf64_Verdaux *aux;
+ aux = (Elf64_Verdaux *) ((char *) ent + ent->vd_aux);
+
+ if ((ent->vd_flags & VER_FLG_BASE) == 0)
+ {
+ /* The name of the base version should not be
+ available for matching a versioned symbol. */
+ Elf64_Half ndx = ent->vd_ndx & 0x7fff;
+ map->l_versions[ndx].hash = ent->vd_hash;
+ map->l_versions[ndx].name = &strtab[aux->vda_name];
+ map->l_versions[ndx].filename = NULL;
+ }
+
+ if (ent->vd_next == 0)
+ /* No more definitions. */
+ break;
+
+ ent = (Elf64_Verdef *) ((char *) ent + ent->vd_next);
+ }
+ }
+ }
+
+ return result;
+}
diff --git a/src/rtld/rtld.c b/src/rtld/rtld.c
new file mode 100644
index 0000000..82ba4b2
--- /dev/null
+++ b/src/rtld/rtld.c
@@ -0,0 +1,1425 @@
+/* Copyright (C) 2003 MontaVista Software, Inc.
+ Written by Daniel Jacobowitz <drow@mvista.com>, 2003
+
+ Copyright (C) 2011 Wind River Systems, Inc.
+ Significantly updated by Mark Hatle <mark.hatle@windriver.com>, 2011
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include <config.h>
+#include <assert.h>
+#include <ctype.h>
+#include <error.h>
+#include <errno.h>
+#include <argp.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <libgen.h>
+
+#include <inttypes.h>
+
+#include "prelinktab.h"
+#include "reloc.h"
+#include "reloc-info.h"
+
+#include "rtld.h"
+
+unsigned int static_binary = 0;
+
+unsigned int _dl_debug_mask = 0;
+
+/* LD_DYNAMIC_WEAK option. Default is off, changing to 1
+ is equivalent to setting LD_DYNAMIC_WEAK. */
+unsigned int _dl_dynamic_weak = 0;
+#define MAX_PRELOADED_LIBS 20
+
+struct search_path
+{
+ int maxlen, count, allocated;
+ char **dirs;
+};
+
+struct search_path ld_dirs, ld_library_search_path;
+int host_paths;
+
+char * dst_ORIGIN;
+char * dst_PLATFORM = ""; /* undefined */
+char * dst_LIB = "lib";
+char * ld_preload = NULL;
+
+
+void string_to_path (struct search_path *path, const char *string);
+
+const char *argp_program_version = PRELINK_RTLD_PROG PKGVERSION " 1.0";
+
+const char *argp_program_bug_address = REPORT_BUGS_TO;
+
+static char argp_doc[] = PRELINK_RTLD_PROG " -- program to simulate the runtime linker";
+
+#define OPT_SYSROOT 0x8c
+#define OPT_LIBRARY_PATH 0x8e
+#define OPT_TARGET_PATHS 0x8f
+#define OPT_LD_PRELOAD 0x90
+
+static struct argp_option options[] = {
+ {"library-path", OPT_LIBRARY_PATH, "LIBRARY_PATH", 0, "Set library search path to LIBRARY_PATH" },
+ {"root", OPT_SYSROOT, "ROOT_PATH", 0, "Prefix all paths with ROOT_PATH" },
+ {"target-paths", OPT_TARGET_PATHS, 0, 0, "Specified paths are based on ROOT_PATH" },
+ {"ld-preload", OPT_LD_PRELOAD, "PATHLIST", 0, "List of LD_PRELOAD libraries"},
+ { 0 }
+};
+
+static error_t
+parse_opt (int key, char *arg, struct argp_state *state)
+{
+ switch (key)
+ {
+ case OPT_SYSROOT:
+ sysroot = arg;
+ break;
+ case OPT_LIBRARY_PATH:
+ string_to_path(&ld_library_search_path, arg);
+ break;
+ case OPT_TARGET_PATHS:
+ host_paths = 0;
+ break;
+ case OPT_LD_PRELOAD:
+ ld_preload = arg;
+ break;
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+}
+
+/* This function returns the same constants expected by glibc's
+ symbol lookup routines. This is slightly different from the
+ equivalent routines in prelink. It should return PLT for any
+ relocation where an undefined symbol in the application should
+ be ignored: typically, this means any jump slot or TLS relocations,
+ but not copy relocations. Don't return the prelinker's
+ RTYPE_CLASS_TLS. */
+
+/* The following needs to be kept in sync with the
+ sysdeps/.../dl-machine.h: elf_machine_type_class macro */
+
+/* From glibc-2.22: sysdeps/i386/dl-machine.h */
+# define i386_elf_machine_type_class(type) \
+ ((((type) == R_386_JMP_SLOT || (type) == R_386_TLS_DTPMOD32 \
+ || (type) == R_386_TLS_DTPOFF32 || (type) == R_386_TLS_TPOFF32 \
+ || (type) == R_386_TLS_TPOFF || (type) == R_386_TLS_DESC) \
+ * ELF_RTYPE_CLASS_PLT) \
+ | (((type) == R_386_COPY) * ELF_RTYPE_CLASS_COPY) \
+ | (((type) == R_386_GLOB_DAT) * ELF_RTYPE_CLASS_EXTERN_PROTECTED_DATA(EM_386)))
+
+/* From glibc-2.22: sysdeps/x86_64/dl-machine.h */
+# define x86_64_elf_machine_type_class(type) \
+ ((((type) == R_X86_64_JUMP_SLOT \
+ || (type) == R_X86_64_DTPMOD64 \
+ || (type) == R_X86_64_DTPOFF64 \
+ || (type) == R_X86_64_TPOFF64 \
+ || (type) == R_X86_64_TLSDESC) \
+ * ELF_RTYPE_CLASS_PLT) \
+ | (((type) == R_X86_64_COPY) * ELF_RTYPE_CLASS_COPY) \
+ | (((type) == R_X86_64_GLOB_DAT) * ELF_RTYPE_CLASS_EXTERN_PROTECTED_DATA(EM_X86_64)))
+
+/* From glibc-2.22: ports/sysdeps/arm/dl-machine.h */
+# define arm_elf_machine_type_class(type) \
+ ((((type) == R_ARM_JUMP_SLOT || (type) == R_ARM_TLS_DTPMOD32 \
+ || (type) == R_ARM_TLS_DTPOFF32 || (type) == R_ARM_TLS_TPOFF32 \
+ || (type) == R_ARM_TLS_DESC) \
+ * ELF_RTYPE_CLASS_PLT) \
+ | (((type) == R_ARM_COPY) * ELF_RTYPE_CLASS_COPY) \
+ | (((type) == R_ARM_GLOB_DAT) * ELF_RTYPE_CLASS_EXTERN_PROTECTED_DATA(EM_ARM)))
+
+/* From glibc-2.22: ports/sysdeps/aarch64/dl-machine.h */
+# define aarch64_elf_machine_type_class(type) \
+ ((((type) == R_AARCH64_JUMP_SLOT || \
+ (type) == R_AARCH64_TLS_DTPMOD || \
+ (type) == R_AARCH64_TLS_DTPREL || \
+ (type) == R_AARCH64_TLS_TPREL || \
+ (type) == R_AARCH64_TLSDESC) * ELF_RTYPE_CLASS_PLT) \
+ | (((type) == R_AARCH64_COPY) * ELF_RTYPE_CLASS_COPY) \
+ | (((type) == R_AARCH64_GLOB_DAT) * ELF_RTYPE_CLASS_EXTERN_PROTECTED_DATA(EM_AARCH64)))
+
+/* From glibc-2.22: sysdeps/sh/dl-machine.h */
+# define sh_elf_machine_type_class(type) \
+ ((((type) == R_SH_JMP_SLOT || (type) == R_SH_TLS_DTPMOD32 \
+ || (type) == R_SH_TLS_DTPOFF32 || (type) == R_SH_TLS_TPOFF32) \
+ * ELF_RTYPE_CLASS_PLT) \
+ | (((type) == R_SH_COPY) * ELF_RTYPE_CLASS_COPY))
+
+/* From glibc-2.22: sysdeps/powerpc/powerpc32/dl-machine.h */
+#define powerpc32_elf_machine_type_class(type) \
+ ((((type) == R_PPC_JMP_SLOT \
+ || (type) == R_PPC_REL24 \
+ || ((type) >= R_PPC_DTPMOD32 /* contiguous TLS */ \
+ && (type) <= R_PPC_DTPREL32) \
+ || (type) == R_PPC_ADDR24) * ELF_RTYPE_CLASS_PLT) \
+ | (((type) == R_PPC_COPY) * ELF_RTYPE_CLASS_COPY))
+
+/* From glibc-2.22: sysdeps/powerpc/powerpc64/dl-machine.h */
+/* we only support ELFv2 at this point */
+#define IS_PPC64_TLS_RELOC(R) \
+ (((R) >= R_PPC64_TLS && (R) <= R_PPC64_DTPREL16_HIGHESTA) \
+ || ((R) >= R_PPC64_TPREL16_HIGH && (R) <= R_PPC64_DTPREL16_HIGHA))
+
+#define powerpc64_elf_machine_type_class(type) \
+ ((((type) == R_PPC64_JMP_SLOT \
+ || (type) == R_PPC64_ADDR24 \
+ || IS_PPC64_TLS_RELOC (type)) * ELF_RTYPE_CLASS_PLT) \
+ | (((type) == R_PPC64_COPY) * ELF_RTYPE_CLASS_COPY))
+
+/* From glibc-2.22: sysdeps/mips/dl-machine.h */
+#define ELF_MACHINE_JMP_SLOT R_MIPS_JUMP_SLOT
+#define mips_elf_machine_type_class(type) \
+ ((((type) == ELF_MACHINE_JMP_SLOT) * ELF_RTYPE_CLASS_PLT) \
+ | (((type) == R_MIPS_COPY) * ELF_RTYPE_CLASS_COPY))
+
+/* From glibc-2.22: sysdeps/sparc/sparc32/dl-machine.h */
+#define sparc_elf_machine_type_class(type) \
+ ((((type) == R_SPARC_JMP_SLOT \
+ || ((type) >= R_SPARC_TLS_GD_HI22 && (type) <= R_SPARC_TLS_TPOFF64)) \
+ * ELF_RTYPE_CLASS_PLT) \
+ | (((type) == R_SPARC_COPY) * ELF_RTYPE_CLASS_COPY))
+
+/* From glibc-2.22: sysdeps/sparc/sparc64/dl-machine.h */
+# define sparc64_elf_machine_type_class(type) \
+ ((((type) == R_SPARC_JMP_SLOT \
+ || ((type) >= R_SPARC_TLS_GD_HI22 && (type) <= R_SPARC_TLS_TPOFF64)) \
+ * ELF_RTYPE_CLASS_PLT) \
+ | (((type) == R_SPARC_COPY) * ELF_RTYPE_CLASS_COPY))
+
+/* From glibc-2.22: sysdeps/nios2/dl-machine.h */
+# define nios2_elf_machine_type_class(type) \
+ ((((type) == R_NIOS2_JUMP_SLOT \
+ || (type) == R_NIOS2_TLS_DTPMOD \
+ || (type) == R_NIOS2_TLS_DTPREL \
+ || (type) == R_NIOS2_TLS_TPREL) * ELF_RTYPE_CLASS_PLT) \
+ | (((type) == R_NIOS2_COPY) * ELF_RTYPE_CLASS_COPY) \
+ | (((type) == R_NIOS2_GLOB_DAT) * ELF_RTYPE_CLASS_EXTERN_PROTECTED_DATA(EM_ALTERA_NIOS2)))
+
+int
+elf_machine_type_class (int type, int machine)
+{
+ switch (machine)
+ {
+ case EM_386:
+ return i386_elf_machine_type_class(type);
+ case EM_X86_64:
+ return x86_64_elf_machine_type_class(type);
+ case EM_ARM:
+ return arm_elf_machine_type_class(type);
+ case EM_AARCH64:
+ return aarch64_elf_machine_type_class(type);
+ case EM_SH:
+ return sh_elf_machine_type_class(type);
+ case EM_PPC:
+ return powerpc32_elf_machine_type_class(type);
+ case EM_PPC64:
+ return powerpc64_elf_machine_type_class(type);
+ case EM_MIPS:
+ return mips_elf_machine_type_class(type);
+ case EM_SPARC:
+ case EM_SPARC32PLUS:
+ return sparc_elf_machine_type_class(type);
+ case EM_SPARCV9:
+ return sparc64_elf_machine_type_class(type);
+ case EM_ALTERA_NIOS2:
+ return nios2_elf_machine_type_class(type);
+
+ default:
+ printf ("Unknown architecture!\n");
+ exit (1);
+ return 0;
+ }
+}
+
+int
+extern_protected_data(int machine)
+{
+ switch (machine)
+ {
+ case EM_386:
+ case EM_X86_64:
+ case EM_ARM:
+ case EM_AARCH64:
+ case EM_ALTERA_NIOS2:
+ return 4;
+ default:
+ return 0;
+ }
+}
+
+int
+machine_no_rela (int machine)
+{
+ switch (machine)
+ {
+ case EM_386:
+ case EM_X86_64:
+ case EM_ARM:
+ case EM_AARCH64:
+ case EM_SH:
+ case EM_PPC:
+ case EM_PPC64:
+ case EM_MIPS:
+ case EM_SPARC:
+ case EM_SPARC32PLUS:
+ case EM_SPARCV9:
+ case EM_ALTERA_NIOS2:
+ return 0;
+ default:
+ return 1;
+ }
+}
+
+int
+machine_no_rel (int machine)
+{
+ switch (machine)
+ {
+ case EM_386:
+ case EM_MIPS:
+ case EM_ARM:
+ return 0;
+ default:
+ return 1;
+ }
+}
+
+int
+is_ldso_soname (const char *soname)
+{
+ if ( ! strcmp (soname, "ld-linux.so.2")
+ || ! strcmp (soname, "ld-linux.so.3")
+ || ! strcmp (soname, "ld.so.1")
+ || ! strcmp (soname, "ld-linux-ia64.so.2")
+ || ! strcmp (soname, "ld-linux-x86-64.so.2")
+ || ! strcmp (soname, "ld64.so.2")
+ || ! strcmp (soname, "ld-linux-armhf.so.3")
+ || ! strcmp (soname, "ld-linux-aarch64.so.1")
+ || ! strcmp (soname, "ld-linux-aarch64_be.so.1")
+ || ! strcmp (soname, "ld-linux-nios2.so.1")
+ )
+ return 1;
+ return 0;
+}
+
+static int dso_open_error = 0;
+
+static void
+free_needed (struct needed_list *p)
+{
+ struct needed_list *old_p = p;
+ while (old_p)
+ {
+ old_p = p->next;
+ free (p);
+ p = old_p;
+ }
+}
+
+static struct dso_list *
+in_dso_list (struct dso_list *dso_list, const char *soname, const char *filename)
+{
+ while (dso_list != NULL)
+ {
+ if (dso_list->dso != NULL)
+ {
+ if (strcmp (dso_list->dso->soname, soname) == 0)
+ return dso_list;
+ }
+
+ if (strcmp (dso_list->name, soname) == 0)
+ return dso_list;
+
+ if (filename && dso_list->canon_filename
+ && strcmp (dso_list->canon_filename, filename) == 0)
+ return dso_list;
+
+ dso_list = dso_list->next;
+ }
+ return NULL;
+}
+
+static int
+in_needed_list (struct needed_list *needed_list, const char *soname)
+{
+ while (needed_list != NULL)
+ {
+ if (needed_list->ent->dso != NULL
+ && strcmp (needed_list->ent->dso->soname, soname) == 0)
+ return 1;
+ needed_list = needed_list->next;
+ }
+ return 0;
+}
+
+
+/****/
+
+void
+add_dir (struct search_path *path, const char *dir, int dirlen)
+{
+ if (path->allocated == 0)
+ {
+ path->allocated = 5;
+ path->dirs = malloc (sizeof (char *) * 5);
+ }
+ else if (path->count == path->allocated)
+ {
+ path->allocated *= 2;
+ path->dirs = realloc (path->dirs, sizeof (char *) * path->allocated);
+ }
+ path->dirs[path->count] = malloc (dirlen + 1);
+ memcpy (path->dirs[path->count], dir, dirlen);
+ path->dirs[path->count++][dirlen] = 0;
+
+ if (path->maxlen < dirlen)
+ path->maxlen = dirlen;
+}
+
+void
+free_path (struct search_path *path)
+{
+ if (path->allocated)
+ {
+ int i;
+ for (i = 0; i < path->count; i++)
+ free (path->dirs[i]);
+ free (path->dirs);
+ }
+}
+
+void
+load_ld_so_conf (int use_64bit, int use_mipsn32)
+{
+ int fd;
+ FILE *conf;
+ char buf[1024];
+
+ memset (&ld_dirs, 0, sizeof (ld_dirs));
+
+ /* Only use the correct machine, to prevent mismatches if we
+ have both /lib/ld.so and /lib64/ld.so on x86-64. */
+ if (use_64bit)
+ {
+ dst_LIB = "lib64";
+ add_dir (&ld_dirs, "/lib64/tls", strlen ("/lib64/tls"));
+ add_dir (&ld_dirs, "/lib64", strlen ("/lib64"));
+ add_dir (&ld_dirs, "/usr/lib64/tls", strlen ("/usr/lib64/tls"));
+ add_dir (&ld_dirs, "/usr/lib64", strlen ("/usr/lib64"));
+ }
+ else if (use_mipsn32)
+ {
+ dst_LIB = "lib32";
+ add_dir (&ld_dirs, "/lib32/tls", strlen ("/lib32/tls"));
+ add_dir (&ld_dirs, "/lib32", strlen ("/lib32"));
+ add_dir (&ld_dirs, "/usr/lib32/tls", strlen ("/usr/lib32/tls"));
+ add_dir (&ld_dirs, "/usr/lib32", strlen ("/usr/lib32"));
+ }
+ else
+ {
+ dst_LIB = "lib";
+ add_dir (&ld_dirs, "/lib/tls", strlen ("/lib/tls"));
+ add_dir (&ld_dirs, "/lib", strlen ("/lib"));
+ add_dir (&ld_dirs, "/usr/lib/tls", strlen ("/usr/lib/tls"));
+ add_dir (&ld_dirs, "/usr/lib", strlen ("/usr/lib"));
+ }
+
+ fd = wrap_open ("/etc/ld.so.conf", O_RDONLY);
+ if (fd == -1)
+ return;
+ conf = fdopen (fd, "r");
+ while (fgets (buf, 1024, conf) != NULL)
+ {
+ int len;
+ char *p;
+
+ p = strchr (buf, '#');
+ if (p)
+ *p = 0;
+ len = strlen (buf);
+ while (len > 0 && isspace (buf[len - 1]))
+ buf[--len] = 0;
+
+ if (len > 0)
+ add_dir (&ld_dirs, buf, len);
+ }
+ fclose (conf);
+}
+
+void
+string_to_path (struct search_path *path, const char *string)
+{
+ const char *start, *end, *end_tmp;
+
+ start = string;
+ while (1) {
+ end = start;
+ while (*end && *end != ':' && *end != ';')
+ end ++;
+
+ /* Eliminate any trailing '/' characters, but be sure to leave a
+ leading slash if someeone wants / in their RPATH. */
+ end_tmp = end;
+ while (end_tmp > start + 1 && end_tmp[-1] == '/')
+ end_tmp --;
+
+ add_dir (path, start, end_tmp - start);
+
+ if (*end == 0)
+ break;
+
+ /* Skip the separator. */
+ start = end + 1;
+ }
+}
+
+char *
+find_lib_in_path (struct search_path *path, const char *soname,
+ int elfclass, int machine)
+{
+ char *ret = NULL;
+ int i;
+ int alt_machine;
+
+ switch (machine)
+ {
+ case EM_SPARC:
+ alt_machine = EM_SPARC32PLUS;
+ break;
+ case EM_SPARC32PLUS:
+ alt_machine = EM_SPARC;
+ break;
+ default:
+ alt_machine = machine;
+ break;
+ }
+
+ for (i = 0; i < path->count; i++)
+ {
+ char * fixup_path, * path_string;
+
+ path_string = fixup_path = strdup(path->dirs[i]);
+
+ while ((path_string = strchr (path_string, '$')))
+ {
+ char * replace = NULL;
+ size_t len = 0;
+
+ if (strncmp("$ORIGIN", path_string, 7) == 0) {
+ replace = dst_ORIGIN;
+ len = 7;
+ } else if (strncmp("${ORIGIN}", path_string, 9) == 0) {
+ replace = dst_ORIGIN;
+ len = 9;
+ } else if (strncmp("$PLATFORM", path_string, 9) == 0) {
+ replace = dst_PLATFORM;
+ len = 9;
+ } else if (strncmp("${PLATFORM}", path_string, 11) == 0) {
+ replace = dst_PLATFORM;
+ len = 11;
+ } else if (strncmp("$LIB", path_string, 4) == 0) {
+ replace = dst_LIB;
+ len = 4;
+ } else if (strncmp("${LIB}", path_string, 6) == 0) {
+ replace = dst_LIB;
+ len = 6;
+ } else {
+ /* Not a defined item, so we skip to the next character */
+ path_string += 1;
+ }
+
+ if (replace) {
+ size_t new_path_len = strlen(fixup_path) - len + strlen(replace) + 1;
+ char * new_path = malloc(new_path_len);
+
+ /* Calculate the new path_string position based on the old position */
+ size_t new_path_pos = (path_string - fixup_path) + strlen(replace);
+
+ snprintf(new_path, new_path_len, "%.*s%s%s", (int)(path_string-fixup_path),
+ fixup_path, replace, path_string + len);
+
+ free(fixup_path);
+
+ fixup_path = new_path;
+ path_string = fixup_path + new_path_pos;
+ }
+ }
+
+ ret = malloc (strlen (soname) + 2 + strlen(fixup_path));
+ sprintf (ret, "%s/%s", fixup_path, soname);
+
+ if (wrap_access (ret, F_OK) == 0)
+ {
+ DSO *dso = open_dso (ret);
+ int dso_class, dso_machine;
+
+ if (dso == NULL)
+ continue;
+
+ dso_class = gelf_getclass (dso->elf);
+ dso_machine = (dso_class == ELFCLASS32) ?
+ elf32_getehdr (dso->elf)->e_machine :
+ elf64_getehdr (dso->elf)->e_machine;
+
+ /* Skip 32-bit libraries when looking for 64-bit. Also
+ skip libraries for alternative machines. */
+ if (gelf_getclass (dso->elf) != elfclass
+ || (dso_machine != machine && dso_machine != alt_machine))
+ {
+ close_dso (dso);
+ continue;
+ }
+
+ close_dso (dso);
+ return ret;
+ }
+ }
+
+ free (ret);
+ return NULL;
+}
+
+char *
+find_lib_by_soname (const char *soname, struct dso_list *loader,
+ int elfclass, int machine)
+{
+ char *ret;
+
+ if (strchr (soname, '/'))
+ return strdup (soname);
+
+ if (is_ldso_soname (soname))
+ /* For dynamic linker, pull the path out of PT_INTERP header.
+ When loading an executable the dynamic linker creates an entry for
+ itself under the name stored in PT_INTERP, and the name that we
+ record in .gnu.liblist should match that exactly. */
+ {
+ struct dso_list *loader_p = loader;
+
+ while (loader_p)
+ {
+ if (loader_p->dso->ehdr.e_type == ET_EXEC)
+ {
+ int i;
+
+ for (i = 0; i < loader_p->dso->ehdr.e_phnum; ++i)
+ if (loader_p->dso->phdr[i].p_type == PT_INTERP)
+ {
+ const char *interp;
+ interp = get_data (loader_p->dso,
+ loader_p->dso->phdr[i].p_vaddr,
+ NULL, NULL);
+ return strdup (interp);
+ }
+ }
+ loader_p = loader_p->loader;
+ }
+ }
+
+ if (loader->dso->info[DT_RUNPATH] == 0)
+ {
+ /* Search DT_RPATH all the way up. */
+ struct dso_list *loader_p = loader;
+ while (loader_p)
+ {
+ if (loader_p->dso->info[DT_RPATH])
+ {
+ struct search_path r_path;
+ const char *rpath = get_data (loader_p->dso,
+ loader_p->dso->info[DT_STRTAB]
+ + loader_p->dso->info[DT_RPATH],
+ NULL, NULL);
+ memset (&r_path, 0, sizeof (r_path));
+ string_to_path (&r_path, rpath);
+ ret = find_lib_in_path (&r_path, soname, elfclass, machine);
+ free_path (&r_path);
+ if (ret)
+ return ret;
+ }
+ loader_p = loader_p->loader;
+ }
+ }
+
+ ret = find_lib_in_path (&ld_library_search_path, soname, elfclass, machine);
+ if (ret)
+ return ret;
+
+ if (loader->dso->info[DT_RUNPATH])
+ {
+ struct search_path r_path;
+ const char *rpath = get_data (loader->dso,
+ loader->dso->info[DT_STRTAB]
+ + loader->dso->info[DT_RUNPATH],
+ NULL, NULL);
+ memset (&r_path, 0, sizeof (r_path));
+ string_to_path (&r_path, rpath);
+ ret = find_lib_in_path (&r_path, soname, elfclass, machine);
+ free_path (&r_path);
+ if (ret)
+ return ret;
+ }
+
+ ret = find_lib_in_path (&ld_dirs, soname, elfclass, machine);
+ if (ret)
+ return ret;
+
+ return NULL;
+}
+
+static struct dso_list *
+load_dsos (DSO *dso, int host_paths)
+{
+ struct dso_list *dso_list, *dso_list_tail, *cur_dso_ent, *new_dso_ent;
+ struct stat64 st;
+ int total_preload = 0;
+ char * libname[MAX_PRELOADED_LIBS] = {NULL};
+
+ /* Assume it's static unless we find DT_NEEDED entries */
+ static_binary = 1;
+
+ dso_list = malloc (sizeof (struct dso_list));
+ dso_list->dso = dso;
+ dso_list->map = NULL;
+ dso_list->next = NULL;
+ dso_list->prev = NULL;
+ dso_list->needed = NULL;
+ dso_list->name = dso->filename;
+ dso_list->loader = NULL;
+
+ if (host_paths)
+ dso_list->canon_filename = canonicalize_file_name (dso->filename);
+ else
+ dso_list->canon_filename = prelink_canonicalize (dso->filename, &st);
+
+ if (dso_list->canon_filename == NULL)
+ dso_list->canon_filename = strdup (dso->filename);
+
+ cur_dso_ent = dso_list_tail = dso_list;
+
+ if(dso->ehdr.e_type == ET_EXEC && ld_preload) {
+ char *next_lib = ld_preload;
+ libname[total_preload] = ld_preload;
+ total_preload++;
+ next_lib=strchr(ld_preload,':');
+ while(next_lib!=NULL){
+ *next_lib = '\0';
+ next_lib++;
+ libname[total_preload] = next_lib;
+ total_preload++;
+ next_lib=strchr(next_lib,':');
+ }
+ }
+ else {
+ total_preload = 0;
+ }
+ while (cur_dso_ent != NULL)
+ {
+ DSO *cur_dso, *new_dso;
+ Elf_Scn *scn;
+ Elf_Data *data;
+ GElf_Dyn dyn;
+
+ cur_dso = cur_dso_ent->dso;
+ if (cur_dso == NULL)
+ {
+ cur_dso_ent = cur_dso_ent->next;
+ continue;
+ }
+
+ scn = cur_dso->scn[cur_dso->dynamic];
+ data = NULL;
+ while ((data = elf_getdata (scn, data)) != NULL)
+ {
+ int ndx, maxndx;
+ maxndx = data->d_size / cur_dso->shdr[cur_dso->dynamic].sh_entsize;
+ for (ndx = 0; ndx < maxndx + total_preload; ++ndx)
+ {
+
+ if(ndx - total_preload >= 0) {
+ gelfx_getdyn (cur_dso->elf, data, ndx - total_preload, &dyn);
+ }
+ else {
+ dyn.d_tag = DT_NEEDED;
+ }
+
+ if (dyn.d_tag == DT_NULL)
+ break;
+ if (dyn.d_tag == DT_NEEDED)
+ {
+ /* Not static... */
+ static_binary = 0;
+
+ char *new_name=NULL, *new_canon_name=NULL;
+ const char * soname = NULL;
+ if(ndx - total_preload >= 0) {
+ soname = get_data (cur_dso,
+ cur_dso->info[DT_STRTAB]
+ + dyn.d_un.d_val,
+ NULL, NULL);
+ }
+ else {
+ soname = libname[ndx];
+ }
+
+ new_dso_ent = in_dso_list (dso_list, soname, NULL);
+ if (new_dso_ent == NULL)
+ {
+ if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_FILES, 0))
+ _dl_debug_printf ("file=%s [0]; needed by %s [0]\n",
+ soname, cur_dso->filename);
+
+ int machine;
+ int class = gelf_getclass (dso->elf);
+ machine = (class == ELFCLASS32) ?
+ elf32_getehdr (dso->elf)->e_machine :
+ elf64_getehdr (dso->elf)->e_machine;
+ new_name = find_lib_by_soname (soname, cur_dso_ent,
+ class, machine);
+ if (new_name == 0 || wrap_access (new_name, R_OK) < 0)
+ {
+ dso_open_error ++;
+
+ new_dso_ent = malloc (sizeof (struct dso_list));
+ dso_list_tail->next = new_dso_ent;
+ dso_list_tail->next->prev = dso_list_tail;
+ dso_list_tail = dso_list_tail->next;
+ dso_list_tail->next = NULL;
+ dso_list_tail->dso = NULL;
+ dso_list_tail->map = NULL;
+ dso_list_tail->needed = NULL;
+ dso_list_tail->name = soname;
+ dso_list_tail->loader = NULL;
+ dso_list_tail->canon_filename = strdup(soname);
+ dso_list_tail->err_no = errno;
+
+ continue;
+ }
+
+ /* See if the filename we found has already been
+ opened (possibly under a different SONAME via
+ some symlink). */
+ new_canon_name = prelink_canonicalize (new_name, NULL);
+ if (new_canon_name == NULL)
+ new_canon_name = strdup (new_name);
+ new_dso_ent = in_dso_list (dso_list, soname, new_canon_name);
+ }
+ else if (new_dso_ent->dso == NULL)
+ continue;
+
+ if (new_dso_ent == NULL)
+ {
+ new_dso = open_dso (new_name);
+ free (new_name);
+ new_dso_ent = malloc (sizeof (struct dso_list));
+ dso_list_tail->next = new_dso_ent;
+ dso_list_tail->next->prev = dso_list_tail;
+ dso_list_tail = dso_list_tail->next;
+ dso_list_tail->next = NULL;
+ dso_list_tail->dso = new_dso;
+ dso_list_tail->map = NULL;
+ dso_list_tail->needed = NULL;
+ dso_list_tail->loader = cur_dso_ent;
+ dso_list_tail->canon_filename = new_canon_name;
+ dso_list_tail->err_no = 0;
+
+ if (is_ldso_soname (new_dso->soname))
+ dso_list_tail->name = new_dso->filename;
+ else if (strcmp (new_dso->soname, new_dso->filename) == 0)
+ /* new_dso->soname might be a full path if the library
+ had no SONAME. Use the original SONAME instead. */
+ dso_list_tail->name = soname;
+ else
+ /* Use the new SONAME if possible, in case some library
+ links to this one using an incorrect SONAME. */
+ dso_list_tail->name = new_dso->soname;
+ }
+
+ if (!cur_dso_ent->needed)
+ {
+ cur_dso_ent->needed = malloc (sizeof (struct needed_list));
+ cur_dso_ent->needed_tail = cur_dso_ent->needed;
+ cur_dso_ent->needed_tail->ent = new_dso_ent;
+ cur_dso_ent->needed_tail->next = NULL;
+ }
+ else if (!in_needed_list (cur_dso_ent->needed, soname))
+ {
+ cur_dso_ent->needed_tail->next = malloc (sizeof (struct needed_list));
+ cur_dso_ent->needed_tail = cur_dso_ent->needed_tail->next;
+ cur_dso_ent->needed_tail->ent = new_dso_ent;
+ cur_dso_ent->needed_tail->next = NULL;
+ }
+
+ continue;
+ }
+ if (dyn.d_tag == DT_FILTER || dyn.d_tag == DT_AUXILIARY)
+ {
+ // big fat warning;
+ }
+ }
+ }
+ cur_dso_ent = cur_dso_ent->next;
+ }
+ return dso_list;
+}
+
+struct
+{
+ void *symptr;
+ int rtypeclass;
+} cache;
+
+void
+do_reloc (DSO *dso, struct link_map *map, struct r_scope_elem *scope[],
+ GElf_Word sym, GElf_Word type)
+{
+ struct r_found_version *ver;
+ int rtypeclass;
+ void *symptr;
+ const char *name;
+ Elf64_Word st_name;
+
+ if (map->l_versyms)
+ {
+ int vernum = map->l_versyms[sym] & 0x7fff;
+ ver = &map->l_versions[vernum];
+
+ /* Memory was allocated for the hash table, but it's empty! */
+ if (ver && (ver->name == NULL || ver->hash == 0))
+ ver = NULL;
+ }
+ else
+ ver = NULL;
+
+ rtypeclass = elf_machine_type_class (type, dso->ehdr.e_machine);
+
+ if (gelf_getclass (dso->elf) == ELFCLASS32)
+ {
+ Elf32_Sym *sym32 = &((Elf32_Sym *)map->l_info[DT_SYMTAB])[sym];
+
+ if (ELF32_ST_BIND (sym32->st_info) == STB_LOCAL)
+ return;
+ symptr = sym32;
+ st_name = sym32->st_name;
+ }
+ else
+ {
+ Elf64_Sym *sym64 = &((Elf64_Sym *)map->l_info[DT_SYMTAB])[sym];
+
+ if (ELF64_ST_BIND (sym64->st_info) == STB_LOCAL)
+ return;
+ symptr = sym64;
+ st_name = sym64->st_name;
+ }
+
+ if (cache.symptr == symptr && cache.rtypeclass == rtypeclass)
+ return;
+ cache.symptr = symptr;
+ cache.rtypeclass = rtypeclass;
+
+ name = ((const char *)map->l_info[DT_STRTAB]) + st_name;
+
+ if (gelf_getclass (dso->elf) == ELFCLASS32)
+ {
+ const Elf32_Sym *sym32 = symptr;
+ rtld_lookup_symbol_x32 (name, map, &sym32, scope, ver, rtypeclass,
+ 0, NULL);
+ symptr = (void *) sym32;
+ }
+ else
+ {
+ const Elf64_Sym *sym64 = symptr;
+ rtld_lookup_symbol_x64 (name, map, &sym64, scope, ver, rtypeclass,
+ 0, NULL);
+ symptr = (void *) sym64;
+ }
+}
+
+void
+do_rel_section (DSO *dso, struct link_map *map,
+ struct r_scope_elem *scope[],
+ int tag, int section)
+{
+ Elf_Data *data;
+ int ndx, maxndx, sym, type;
+
+ data = elf_getdata (dso->scn[section], NULL);
+ maxndx = data->d_size / dso->shdr[section].sh_entsize;
+ for (ndx = 0; ndx < maxndx; ndx++)
+ {
+ if (tag == DT_REL)
+ {
+ GElf_Rel rel;
+ gelfx_getrel (dso->elf, data, ndx, &rel);
+ sym = reloc_r_sym (dso, rel.r_info);
+ type = reloc_r_type (dso, rel.r_info);
+ }
+ else
+ {
+ GElf_Rela rela;
+ gelfx_getrela (dso->elf, data, ndx, &rela);
+ sym = reloc_r_sym (dso, rela.r_info);
+ type = reloc_r_type (dso, rela.r_info);
+ }
+ if (sym != 0)
+ do_reloc (dso, map, scope, sym, type);
+ }
+}
+
+void
+do_relocs (DSO *dso, struct link_map *map, struct r_scope_elem *scope[], int tag)
+{
+ GElf_Addr rel_start, rel_end;
+ GElf_Addr pltrel_start, pltrel_end;
+ int first, last;
+
+ /* Load the DT_REL or DT_RELA section. */
+ if (dso->info[tag] != 0)
+ {
+ rel_start = dso->info[tag];
+ rel_end = rel_start + dso->info[tag == DT_REL ? DT_RELSZ : DT_RELASZ];
+ first = addr_to_sec (dso, rel_start);
+ last = addr_to_sec (dso, rel_end - 1);
+ while (first <= last)
+ do_rel_section (dso, map, scope, tag, first++);
+
+ /* If the DT_JMPREL relocs are of the same type and not included,
+ load them too. Assume they overlap completely or not at all,
+ and are in at most a single section. They also need to be adjacent. */
+ if (dso->info[DT_PLTREL] == tag)
+ {
+ pltrel_start = dso->info[DT_JMPREL];
+ pltrel_end = pltrel_start + dso->info[DT_PLTRELSZ];
+ if (pltrel_start < rel_start || pltrel_end >= rel_end)
+ do_rel_section (dso, map, scope, tag, addr_to_sec (dso, pltrel_start));
+ }
+ }
+ else if (dso->info[DT_PLTREL] == tag)
+ do_rel_section (dso, map, scope, tag, addr_to_sec (dso, dso->info[DT_JMPREL]));
+}
+
+/* MIPS GOTs are not handled by normal relocations. Instead, entry X
+ in the global GOT is associated with symbol DT_MIPS_GOTSYM + X.
+ For the purposes of symbol lookup and conflict resolution, we need
+ to act as though entry X had a dynamic relocation against symbol
+ DT_MIPS_GOTSYM + X. */
+
+void
+do_mips_global_got_relocs (DSO *dso, struct link_map *map,
+ struct r_scope_elem *scope[])
+{
+ GElf_Word i;
+
+ for (i = dso->info_DT_MIPS_GOTSYM; i < dso->info_DT_MIPS_SYMTABNO; i++)
+ do_reloc (dso, map, scope, i, R_MIPS_REL32);
+}
+
+void
+handle_relocs_in_entry (struct dso_list *entry, struct dso_list *dso_list)
+{
+ do_relocs (entry->dso, entry->map, dso_list->map->l_local_scope, DT_REL);
+ do_relocs (entry->dso, entry->map, dso_list->map->l_local_scope, DT_RELA);
+ if (entry->dso->ehdr.e_machine == EM_MIPS)
+ do_mips_global_got_relocs (entry->dso, entry->map,
+ dso_list->map->l_local_scope);
+}
+
+void
+handle_relocs (DSO *dso, struct dso_list *dso_list)
+{
+ struct dso_list *ldso, *tail;
+
+ /* do them all last to first.
+ skip the dynamic linker; then do it last
+ in glibc this is conditional on the opencount; but every binary
+ should be linked to libc and thereby have an opencount for ld.so...
+ besides, that's the only way it would get on our dso list. */
+
+ tail = dso_list;
+ while (tail->next)
+ tail = tail->next;
+
+ ldso = NULL;
+ while (tail)
+ {
+ if (is_ldso_soname (tail->dso->soname))
+ ldso = tail;
+ else
+ handle_relocs_in_entry (tail, dso_list);
+ tail = tail->prev;
+ }
+
+ if (ldso)
+ handle_relocs_in_entry (ldso, dso_list);
+}
+
+void
+add_to_scope (struct r_scope_elem *scope[], struct dso_list *ent)
+{
+ struct needed_list *n;
+ int i;
+
+ for (i = 0; i < scope[0]->r_nlist; i++)
+ if (scope[0]->r_list[i] == ent->map)
+ return;
+
+ scope[0]->r_list[scope[0]->r_nlist++] = ent->map;
+ n = ent->needed;
+ while (n)
+ {
+ add_to_scope (scope, n->ent);
+ n = n->next;
+ }
+}
+
+void
+build_local_scope (struct dso_list *ent, int max)
+{
+ ent->map->l_local_scope[0] = malloc (sizeof (struct r_scope_elem));
+ ent->map->l_local_scope[0]->r_list = malloc (sizeof (struct link_map *) * max);
+ ent->map->l_local_scope[0]->r_nlist = 0;
+ add_to_scope (ent->map->l_local_scope, ent);
+}
+
+static struct argp argp = { options, parse_opt, "[FILES]", argp_doc };
+
+struct link_map *requested_map = NULL;
+
+static void process_one_dso (DSO *dso, int host_paths);
+
+int
+main(int argc, char **argv)
+{
+ int remaining;
+ int multiple = 0;
+ host_paths = 1;
+
+ char * debug = NULL;
+
+ sysroot = getenv ("PRELINK_SYSROOT");
+#ifdef DEFAULT_SYSROOT
+ if (sysroot == NULL)
+ {
+ extern char *make_relative_prefix (const char *, const char *, const char *);
+ sysroot = make_relative_prefix (argv[0], BINDIR, DEFAULT_SYSROOT);
+ }
+#endif
+
+ elf_version (EV_CURRENT);
+
+ argp_parse (&argp, argc, argv, 0, &remaining, 0);
+
+ if (sysroot)
+ sysroot = canonicalize_file_name (sysroot);
+
+ if (remaining == argc)
+ error (1, 0, "missing file arguments\nTry `%s: --help' for more information.", argv[0]);
+
+ if ((argc-remaining) >= 2)
+ multiple = 1;
+
+ /* More simplistic then glibc, one option only... */
+ debug = getenv ("RTLD_DEBUG");
+ if (debug && (!strcmp(debug, "files") || !strcmp(debug, "all")))
+ _dl_debug_mask |= DL_DEBUG_FILES;
+
+ if (debug && (!strcmp(debug, "symbols") || !strcmp(debug, "all")))
+ _dl_debug_mask |= DL_DEBUG_SYMBOLS;
+
+ if (debug && (!strcmp(debug, "versions") || !strcmp(debug, "all")))
+ _dl_debug_mask |= DL_DEBUG_VERSIONS;
+
+ if (debug && (!strcmp(debug, "bindings") || !strcmp(debug, "all")))
+ _dl_debug_mask |= DL_DEBUG_BINDINGS;
+
+ while (remaining < argc)
+ {
+ DSO *dso = NULL;
+ int i, fd;
+
+ struct stat64 st;
+
+ if (host_paths)
+ fd = open (argv[remaining], O_RDONLY);
+ else
+ fd = wrap_open (argv[remaining], O_RDONLY);
+
+ if (fd >= 0 && fstat64(fd, &st) == 0)
+ if (!S_ISREG(st.st_mode))
+ {
+ error (0, 0, "%s: %s",
+ argv[remaining],
+ "not regular file");
+ goto exit;
+ }
+
+ if (fd >= 0) {
+ dso = fdopen_dso (fd, argv[remaining]);
+ dst_ORIGIN = dirname(strdup(dso->filename));
+ }
+
+ if (dso == NULL)
+ {
+ error (0, 0, "%s: %s",
+ argv[remaining],
+ strerror(errno));
+ goto exit;
+ }
+
+ load_ld_so_conf (gelf_getclass (dso->elf) == ELFCLASS64,
+ ( dso->ehdr.e_machine == EM_MIPS) && ( dso->ehdr.e_flags & EF_MIPS_ABI2 ) );
+
+ if (multiple)
+ printf ("%s:\n", argv[remaining]);
+
+ for (i = 0; i < dso->ehdr.e_phnum; ++i)
+ if (dso->phdr[i].p_type == PT_INTERP)
+ break;
+
+ /* If there are no PT_INTERP segments, it is statically linked. */
+ if (dso->ehdr.e_type == ET_EXEC && i == dso->ehdr.e_phnum)
+ printf ("\tnot a dynamic executable\n");
+ else
+ {
+ int j;
+ Elf_Data *data;
+ j = addr_to_sec (dso, dso->phdr[i].p_vaddr);
+ if (j != -1)
+ {
+ data = elf_getdata (dso->scn[j], NULL);
+ if (data != NULL)
+ {
+ i = strnlen (data->d_buf, data->d_size);
+ if (i == data->d_size)
+ {
+ rtld_signal_error (0, dso->filename, NULL, ".interp section not zero terminated", 0);
+ }
+ else
+ {
+ rtld_progname = strdup (data->d_buf);
+ }
+ }
+ }
+ process_one_dso (dso, host_paths);
+ }
+
+exit:
+ remaining++;
+ }
+
+ return 0;
+}
+
+/* If you run ldd /lib/ld.so you get:
+ \tstatically linked
+
+ The prelink-rtld does not do this, and returns blank...
+ */
+static void
+process_one_dso (DSO *dso, int host_paths)
+{
+ struct dso_list *dso_list, *cur_dso_ent, *old_dso_ent;
+ const char *req;
+ int i;
+ int ld_warn = 1;
+
+ if ((req = getenv ("RTLD_TRACE_PRELINKING")) != NULL)
+ _dl_debug_mask |= DL_DEBUG_PRELINK;
+
+ /* Close enough. Really it's if LD_WARN is "" and RTLD_TRACE_PRELINKING. */
+ if (getenv ("RTLD_WARN") == NULL)
+ ld_warn = 0;
+
+ /* Initialize unique symtable list */
+ _ns_unique_sym_table = calloc(sizeof (struct unique_sym_table), 1);
+
+ dso_list = load_dsos (dso, host_paths);
+
+ cur_dso_ent = dso_list;
+ i = 0;
+ while (cur_dso_ent)
+ {
+ if (cur_dso_ent->dso)
+ {
+ create_map_object_from_dso_ent (cur_dso_ent);
+ if ((GLRO(dl_debug_mask) & DL_DEBUG_PRELINK) && strcmp (req, cur_dso_ent->dso->filename) == 0)
+ requested_map = cur_dso_ent->map;
+ }
+ else
+ {
+ /* This is a dummy entry, we couldn't find the object */
+ cur_dso_ent->map = _dl_new_object(cur_dso_ent->name, cur_dso_ent->canon_filename, lt_library);
+ }
+ i++;
+ cur_dso_ent = cur_dso_ent->next;
+ }
+ dso_list->map->l_local_scope[0] = malloc (sizeof (struct r_scope_elem));
+ dso_list->map->l_local_scope[0]->r_list = malloc (sizeof (struct link_map *) * i);
+ dso_list->map->l_local_scope[0]->r_nlist = i;
+ cur_dso_ent = dso_list;
+ i = 0;
+ while (cur_dso_ent)
+ {
+ if (cur_dso_ent->map)
+ {
+ dso_list->map->l_local_scope[0]->r_list[i] = cur_dso_ent->map;
+ if (cur_dso_ent != dso_list)
+ build_local_scope (cur_dso_ent, dso_list->map->l_local_scope[0]->r_nlist);
+
+ i++;
+ }
+ cur_dso_ent = cur_dso_ent->next;
+ }
+
+ cur_dso_ent = dso_list;
+
+ for (i = 0; i < cur_dso_ent->map->l_local_scope[0]->r_nlist; ++i)
+ if (cur_dso_ent->map->l_local_scope[0]->r_list[i]->l_versions == NULL)
+ _dl_check_map_versions (cur_dso_ent->map->l_local_scope[0]->r_list[i], 0, 0);
+
+ rtld_determine_tlsoffsets (dso->ehdr.e_machine, dso_list->map->l_local_scope[0]);
+
+ cur_dso_ent = dso_list;
+
+ /* In ldd mode, do not show the application. Note that we do show it
+ in list-loaded-objects RTLD_TRACE_PRELINK mode. */
+ if (!(GLRO(dl_debug_mask) & DL_DEBUG_PRELINK) && cur_dso_ent)
+ {
+ /* Based on the presence of DT_NEEDED, see load_dsos */
+ if (static_binary)
+ {
+ printf ("\tstatically linked\n");
+ }
+ cur_dso_ent = cur_dso_ent->next;
+ }
+ while (cur_dso_ent)
+ {
+ char *filename;
+
+ if (host_paths && sysroot && cur_dso_ent->dso)
+ {
+ const char *rooted_filename;
+
+ if (cur_dso_ent->dso->filename[0] == '/')
+ rooted_filename = cur_dso_ent->dso->filename;
+ else
+ rooted_filename = cur_dso_ent->canon_filename;
+
+ filename = malloc (strlen (rooted_filename) + strlen (sysroot) + 1);
+ strcpy (filename, sysroot);
+ strcat (filename, rooted_filename);
+ }
+ else if (cur_dso_ent->dso)
+ filename = strdup (cur_dso_ent->dso->filename);
+ else
+ filename = NULL;
+
+ int size_pointer = 16;
+ if (cur_dso_ent && cur_dso_ent->dso && gelf_getclass (cur_dso_ent->dso->elf) == ELFCLASS32)
+ size_pointer = 8;
+
+ /* The difference between the two numbers must be dso->base,
+ and the first number must be unique. */
+ if (dso_open_error && ld_warn && (GLRO(dl_debug_mask) & DL_DEBUG_PRELINK))
+ {
+ if (cur_dso_ent->dso == NULL)
+ rtld_signal_error(cur_dso_ent->err_no, cur_dso_ent->name, NULL, "cannot open shared object file", 0);
+ }
+ else if (cur_dso_ent->dso == NULL)
+ printf ("\t%s => not found\n", cur_dso_ent->name);
+ else if (GLRO(dl_debug_mask) & DL_DEBUG_PRELINK)
+ {
+ struct link_map * l = cur_dso_ent->map;
+ if (size_pointer == 16)
+ printf ("\t%s => %s (0x%016"PRIx64", 0x%016"PRIx64")",
+ cur_dso_ent->name ? cur_dso_ent->name
+ : rtld_progname ?: "<main program>",
+ filename ? filename
+ : rtld_progname ?: "<main program>",
+ (uint64_t) l->l_map_start,
+ (uint64_t) (l->l_map_start == cur_dso_ent->dso->base ? 0 : l->l_map_start));
+ else
+ printf ("\t%s => %s (0x%08"PRIx32", 0x%08"PRIx32")",
+ cur_dso_ent->name ? cur_dso_ent->name
+ : rtld_progname ?: "<main program>",
+ filename ? filename
+ : rtld_progname ?: "<main program>",
+ (uint32_t) l->l_map_start,
+ (uint32_t) (l->l_map_start == cur_dso_ent->dso->base ? 0 : l->l_map_start));
+
+ if (l->l_tls_modid)
+ if (size_pointer == 16)
+ printf (" TLS(0x%"PRIx64", 0x%016"PRIx64")\n",
+ (uint64_t) l->l_tls_modid,
+ (uint64_t) l->l_tls_offset);
+ else
+ printf (" TLS(0x%"PRIx32", 0x%08"PRIx32")\n",
+ (uint32_t) l->l_tls_modid,
+ (uint32_t) l->l_tls_offset);
+ else
+ printf ("\n");
+ }
+ else
+ {
+ struct link_map * l = cur_dso_ent->map;
+ if (!(GLRO(dl_debug_mask) & DL_DEBUG_PRELINK) && strcmp (cur_dso_ent->name, filename) == 0)
+ if (size_pointer == 16)
+ printf ("\t%s (0x%016"PRIx64")\n", cur_dso_ent->name,
+ (uint64_t) l->l_map_start);
+ else
+ printf ("\t%s (0x%08"PRIx32")\n", cur_dso_ent->name,
+ (uint32_t) l->l_map_start);
+ else
+ if (size_pointer == 16)
+ printf ("\t%s => %s (0x%016"PRIx64")\n", cur_dso_ent->name,
+ filename,
+ (uint64_t) l->l_map_start);
+ else
+ printf ("\t%s => %s (0x%08"PRIx32")\n", cur_dso_ent->name,
+ filename,
+ (uint32_t) l->l_map_start);
+ }
+
+ if (filename)
+ free (filename);
+
+ cur_dso_ent = cur_dso_ent->next;
+ }
+
+ if (dso_open_error)
+ exit (127);
+
+ if (!ld_warn && (GLRO(dl_debug_mask) & DL_DEBUG_PRELINK))
+ handle_relocs (dso_list->dso, dso_list);
+
+ cur_dso_ent = dso_list;
+ while (cur_dso_ent)
+ {
+ if (cur_dso_ent->dso)
+ close_dso (cur_dso_ent->dso);
+ old_dso_ent = cur_dso_ent;
+ cur_dso_ent = cur_dso_ent->next;
+ if (old_dso_ent->needed)
+ free_needed (old_dso_ent->needed);
+ free (old_dso_ent);
+ }
+}
diff --git a/src/rtld/rtld.h b/src/rtld/rtld.h
new file mode 100644
index 0000000..c7b5d91
--- /dev/null
+++ b/src/rtld/rtld.h
@@ -0,0 +1,338 @@
+#ifndef _LD_LIBS_H
+#define _LD_LIBS_H
+
+#include "prelinktab.h"
+
+#include <elf.h>
+
+#if !defined (__linux__)
+#define DT_VERSIONTAGNUM 16
+#endif
+
+#define link_map ldlibs_link_map
+
+struct needed_list
+{
+ struct dso_list *ent;
+ struct needed_list *next;
+};
+
+struct dso_list
+{
+ DSO *dso;
+ struct link_map *map;
+ struct dso_list *next, *prev;
+ struct needed_list *needed, *needed_tail;
+ const char *name;
+ struct dso_list *loader;
+ const char *canon_filename;
+ int err_no;
+};
+
+/* A data structure for a simple single linked list of strings. */
+struct libname_list
+ {
+ const char *name; /* Name requested (before search). */
+ struct libname_list *next; /* Link to next name for this object. */
+ };
+
+struct link_map;
+
+struct r_scope_elem
+{
+ struct link_map **r_list;
+ unsigned int r_nlist;
+};
+
+struct r_found_version
+ {
+ const char *name;
+ Elf64_Word hash;
+
+ int hidden;
+ const char *filename;
+ };
+
+struct unique_sym_table
+ {
+ struct unique_sym
+ {
+ uint32_t hashval;
+ const char *name;
+ const void *sym;
+ const struct link_map *map;
+ } *entries;
+ size_t size;
+ size_t n_elements;
+ void (*free) (void *);
+ };
+
+extern struct unique_sym_table * _ns_unique_sym_table;
+
+/* The size of entries in .hash. Only Alpha and 64-bit S/390 use 64-bit
+ entries; those are not currently supported. */
+typedef uint32_t Elf_Symndx;
+
+/* Mimic libc/include/link.h struct link_map */
+
+struct link_map
+ {
+ int elfclass;
+
+ const char *l_name;
+
+ struct libname_list *l_libname;
+
+#undef DT_THISPROCNUM
+#define DT_THISPROCNUM 0
+
+ void *l_info[DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM
+ + DT_EXTRANUM + DT_VALNUM + DT_ADDRNUM];
+
+ /* Array with vesion names. */
+ struct r_found_version *l_versions;
+ unsigned int l_nversions;
+
+ /* Symbol hash table. */
+ Elf_Symndx l_nbuckets;
+ /* Begin PPC64 workaround */
+ void *l_buckets_start;
+ void *l_buckets_end;
+ /* end workaround */
+ Elf32_Word l_gnu_bitmask_idxbits;
+ Elf32_Word l_gnu_shift;
+ void *l_gnu_bitmask;
+ union
+ {
+ const Elf32_Word *l_gnu_buckets;
+ const Elf_Symndx *l_chain;
+ };
+ union
+ {
+ const Elf32_Word *l_gnu_chain_zero;
+ const Elf_Symndx *l_buckets;
+ };
+
+ enum /* Where this object came from. */
+ {
+ lt_executable, /* The main executable program. */
+ lt_library, /* Library needed by main executable. */
+ lt_loaded /* Extra run-time loaded shared object. */
+ } l_type:2;
+
+ /* Pointer to the version information if available. */
+ Elf64_Versym *l_versyms;
+
+ /* Start and finish of memory map for this object. l_map_start
+ need not be the same as l_addr. */
+ Elf64_Addr l_map_start;
+
+ /* A similar array, this time only with the local scope. This is
+ used occasionally. */
+ struct r_scope_elem *l_local_scope[2];
+
+ /* Thread-local storage related info. */
+
+ /* Size of the TLS block. */
+ uint64_t l_tls_blocksize;
+ /* Alignment requirement of the TLS block. */
+ uint64_t l_tls_align;
+ /* Offset of first byte module alignment. */
+ uint64_t l_tls_firstbyte_offset;
+
+ /* For objects present at startup time: offset in the static TLS block. */
+ uint64_t l_tls_offset;
+ /* Index of the module in the dtv array. */
+ uint64_t l_tls_modid;
+
+ Elf64_Addr sym_base;
+ const char *filename;
+
+ Elf64_Half machine;
+ };
+
+#define ELF_RTYPE_CLASS_COPY 2
+#define ELF_RTYPE_CLASS_PLT 1
+
+int elf_machine_type_class(int type, int machine);
+
+int extern_protected_data(int machine);
+#define ELF_RTYPE_CLASS_EXTERN_PROTECTED_DATA(machine) extern_protected_data(machine)
+
+int machine_no_rela(int machine);
+#define ELF_MACHINE_NO_RELA(machine) machine_no_rela(machine)
+
+int machine_no_rel(int machine);
+#define ELF_MACHINE_NO_REL(machine) machine_no_rel(machine)
+
+#define GL(x) _##x
+#define GLRO(x) _##x
+#define INTUSE(x) x
+
+#define D_PTR(MAP,MEM) MAP->MEM
+#define VERSYMIDX(sym) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGIDX (sym))
+
+extern unsigned int _dl_debug_mask;
+extern unsigned int _dl_dynamic_weak;
+
+extern const char *rtld_progname;
+
+/* This is an optional value before the ':' when debuging is enabled. */
+/* Typically glibc sets this to a number of spaces and the pid of the process*/
+#ifndef RTLD_DEBUG_PID
+# define RTLD_DEBUG_PID " "
+#endif
+#define _dl_debug_printf(...) printf( RTLD_DEBUG_PID ":\t" __VA_ARGS__)
+
+#define __rtld_lock_lock_recursive(NAME)
+#define __rtld_lock_unlock_recursive(NAME)
+
+/* glibc-2.20: sysdeps/generic/ldsodefs.h */
+/* The filename itself, or the main program name, if available. */
+#define DSO_FILENAME(name) ((name)[0] ? (name) \
+ : (rtld_progname ?: "<main program>"))
+
+#define RTLD_PROGNAME (rtld_progname ?: "<program name unknown>")
+
+/* glibc-2.20: sysdeps/generic/ldsodefs.h */
+#define DL_DEBUG_LIBS (1 << 0)
+#define DL_DEBUG_IMPCALLS (1 << 1)
+#define DL_DEBUG_BINDINGS (1 << 2)
+#define DL_DEBUG_SYMBOLS (1 << 3)
+#define DL_DEBUG_VERSIONS (1 << 4)
+#define DL_DEBUG_RELOC (1 << 5)
+#define DL_DEBUG_FILES (1 << 6)
+#define DL_DEBUG_STATISTICS (1 << 7)
+#define DL_DEBUG_UNUSED (1 << 8)
+#define DL_DEBUG_SCOPES (1 << 9)
+/* These two are used only internally. */
+#define DL_DEBUG_HELP (1 << 10)
+#define DL_DEBUG_PRELINK (1 << 11)
+
+#define _dl_trace_prelink_map requested_map
+
+extern struct link_map *requested_map;
+
+#ifndef __glibc_unlikely
+#define __glibc_unlikely(a) (a)
+#endif
+
+#ifndef __glibc_likely
+#define __glibc_likely(a) (a)
+#endif
+
+/* dl-load.c */
+
+#define _dl_new_object rtld_new_object
+
+struct link_map * _dl_new_object (const char *realname, const char *libname, int type);
+
+/* dl-lookup.c */
+
+#define lookup_t struct link_map *
+#define LOOKUP_VALUE(map) map
+
+/* Search loaded objects' symbol tables for a definition of the symbol
+ referred to by UNDEF. *SYM is the symbol table entry containing the
+ reference; it is replaced with the defining symbol, and the base load
+ address of the defining object is returned. SYMBOL_SCOPE is a
+ null-terminated list of object scopes to search; each object's
+ l_searchlist (i.e. the segment of the dependency tree starting at that
+ object) is searched in turn. REFERENCE_NAME should name the object
+ containing the reference; it is used in error messages.
+ TYPE_CLASS describes the type of symbol we are looking for. */
+enum
+ {
+ /* If necessary add dependency between user and provider object. */
+ DL_LOOKUP_ADD_DEPENDENCY = 1,
+ /* Return most recent version instead of default version for
+ unversioned lookup. */
+ DL_LOOKUP_RETURN_NEWEST = 2,
+ /* Set if dl_lookup* called with GSCOPE lock held. */
+ DL_LOOKUP_GSCOPE_LOCK = 4,
+ };
+
+#define _dl_setup_hash rtld_setup_hash
+void _dl_setup_hash (struct link_map *map);
+
+#define _dl_lookup_symbol_x32 rtld_lookup_symbol_x32
+#define _dl_lookup_symbol_x64 rtld_lookup_symbol_x64
+
+/* Lookup versioned symbol. */
+inline lookup_t _dl_lookup_symbol_x (const char *undef,
+ struct link_map *undef_map,
+ const Elf64_Sym **sym,
+ struct r_scope_elem *symbol_scope[],
+ const struct r_found_version *version,
+ int type_class, int flags,
+ struct link_map *skip_map);
+
+/* Lookup versioned symbol. */
+lookup_t _dl_lookup_symbol_x32 (const char *undef,
+ struct link_map *undef_map,
+ const Elf32_Sym **sym,
+ struct r_scope_elem *symbol_scope[],
+ const struct r_found_version *version,
+ int type_class, int flags,
+ struct link_map *skip_map);
+
+/* Lookup versioned symbol. */
+lookup_t _dl_lookup_symbol_x64 (const char *undef,
+ struct link_map *undef_map,
+ const Elf64_Sym **sym,
+ struct r_scope_elem *symbol_scope[],
+ const struct r_found_version *version,
+ int type_class, int flags,
+ struct link_map *skip_map);
+
+/* dl-version.c */
+
+#define _dl_check_map_versions rtld_check_map_versions
+int _dl_check_map_versions (struct link_map *map, int verbose, int trace_mode);
+
+#define _dl_name_match_p rtld_name_match_p
+int _dl_name_match_p (const char *name, const struct link_map *map);
+
+/* Error handling */
+
+#include <error.h>
+#include <errno.h>
+
+/* Mimic the behavior and output of _dl_signal_error */
+#define rtld_signal_error(errcode, objname, occation, errstring, status) \
+ error(status, errcode, "%s: %s%s%s", \
+ occation ?: "error while loading shared libraries", \
+ objname ?: "", (objname && *(char *)objname) ? ": " : "", \
+ errstring ?: "DYNAMIC LINKER BUG!!!")
+
+#define _dl_signal_error(errcode, objname, occation, errstring) rtld_signal_error(errcode, objname, occation, errstring, 1)
+#define _dl_signal_cerror(errcode, objname, occation, errstring) rtld_signal_error(errcode, objname, occation, errstring, 0)
+#define _dl_fatal_printf(errstring) rtld_signal_error(EINVAL, NULL, NULL, errstring, 1)
+
+/* dl-load.c */
+
+extern void create_map_object_from_dso_ent (struct dso_list *);
+
+/* dl-tls.c */
+
+void rtld_determine_tlsoffsets (int e_machine, struct r_scope_elem *search_list);
+
+#define _dl_determine_tlsoffsets rtld_determine_tlsoffsets
+
+/* dl-misc.c */
+
+#define _dl_name_match_p rtld_name_match_p
+#define _dl_higher_prime_number rtld_higher_prime_number
+
+extern int _dl_name_match_p (const char *name, const struct link_map *map);
+extern unsigned long int _dl_higher_prime_number (unsigned long int n);
+
+
+#if defined(__MINGW32__)
+# define HOST_LONG_LONG_FORMAT "I64"
+#else
+# define HOST_LONG_LONG_FORMAT "ll"
+#endif
+
+#endif
+
diff --git a/src/sha.c b/src/sha.c
new file mode 100644
index 0000000..cfbc956
--- /dev/null
+++ b/src/sha.c
@@ -0,0 +1,331 @@
+/* sha.c - Functions to compute the SHA1 hash (message-digest) of files
+ or blocks of memory. Complies to the NIST specification FIPS-180-1.
+
+ Copyright (C) 2000, 2001, 2003 Scott G. Miller
+
+ Credits:
+ Robert Klep <robert@ilse.nl> -- Expansion function fix
+ NOTE: The canonical source of this file is maintained in GNU coreutils.
+*/
+
+#include <sys/types.h>
+#include <stdlib.h>
+#include <string.h>
+#include <byteswap.h>
+#include "md5.h"
+#include "sha.h"
+
+/*
+ Not-swap is a macro that does an endian swap on architectures that are
+ big-endian, as SHA needs some data in a little-endian format
+*/
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+# define SWAP(n) bswap_32 (n)
+# define NOTSWAP(n) (n)
+#else
+# define SWAP(n) (n)
+# define NOTSWAP(n) bswap_32 (n)
+#endif
+
+/* This array contains the bytes used to pad the buffer to the next
+ 64-byte boundary. (RFC 1321, 3.1: Step 1) */
+static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ };
+
+
+/*
+ Takes a pointer to a 160 bit block of data (five 32 bit ints) and
+ intializes it to the start constants of the SHA1 algorithm. This
+ must be called before using hash in the call to sha_hash
+*/
+void
+sha_init_ctx (struct sha_ctx *ctx)
+{
+ ctx->A = 0x67452301;
+ ctx->B = 0xefcdab89;
+ ctx->C = 0x98badcfe;
+ ctx->D = 0x10325476;
+ ctx->E = 0xc3d2e1f0;
+
+ ctx->total[0] = ctx->total[1] = 0;
+ ctx->buflen = 0;
+}
+
+/* Put result from CTX in first 20 bytes following RESBUF. The result
+ must be in little endian byte order.
+
+ IMPORTANT: On some systems it is required that RESBUF is correctly
+ aligned for a 32 bits value. */
+void *
+sha_read_ctx (const struct sha_ctx *ctx, void *resbuf)
+{
+ ((md5_uint32 *) resbuf)[0] = NOTSWAP (ctx->A);
+ ((md5_uint32 *) resbuf)[1] = NOTSWAP (ctx->B);
+ ((md5_uint32 *) resbuf)[2] = NOTSWAP (ctx->C);
+ ((md5_uint32 *) resbuf)[3] = NOTSWAP (ctx->D);
+ ((md5_uint32 *) resbuf)[4] = NOTSWAP (ctx->E);
+
+ return resbuf;
+}
+
+/* Process the remaining bytes in the internal buffer and the usual
+ prolog according to the standard and write the result to RESBUF.
+
+ IMPORTANT: On some systems it is required that RESBUF is correctly
+ aligned for a 32 bits value. */
+void *
+sha_finish_ctx (struct sha_ctx *ctx, void *resbuf)
+{
+ /* Take yet unprocessed bytes into account. */
+ md5_uint32 bytes = ctx->buflen;
+ size_t pad;
+
+ /* Now count remaining bytes. */
+ ctx->total[0] += bytes;
+ if (ctx->total[0] < bytes)
+ ++ctx->total[1];
+
+ pad = bytes >= 56 ? 64 + 56 - bytes : 56 - bytes;
+ memcpy (&ctx->buffer[bytes], fillbuf, pad);
+
+ /* Put the 64-bit file length in *bits* at the end of the buffer. */
+ *(md5_uint32 *) &ctx->buffer[bytes + pad + 4] = NOTSWAP (ctx->total[0] << 3);
+ *(md5_uint32 *) &ctx->buffer[bytes + pad] = NOTSWAP ((ctx->total[1] << 3) |
+ (ctx->total[0] >> 29));
+
+ /* Process last bytes. */
+ sha_process_block (ctx->buffer, bytes + pad + 8, ctx);
+
+ return sha_read_ctx (ctx, resbuf);
+}
+
+/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The
+ result is always in little endian byte order, so that a byte-wise
+ output yields to the wanted ASCII representation of the message
+ digest. */
+void *
+sha_buffer (const char *buffer, size_t len, void *resblock)
+{
+ struct sha_ctx ctx;
+
+ /* Initialize the computation context. */
+ sha_init_ctx (&ctx);
+
+ /* Process whole buffer but last len % 64 bytes. */
+ sha_process_bytes (buffer, len, &ctx);
+
+ /* Put result in desired memory area. */
+ return sha_finish_ctx (&ctx, resblock);
+}
+
+void
+sha_process_bytes (const void *buffer, size_t len, struct sha_ctx *ctx)
+{
+ /* When we already have some bits in our internal buffer concatenate
+ both inputs first. */
+ if (ctx->buflen != 0)
+ {
+ size_t left_over = ctx->buflen;
+ size_t add = 128 - left_over > len ? len : 128 - left_over;
+
+ memcpy (&ctx->buffer[left_over], buffer, add);
+ ctx->buflen += add;
+
+ if (ctx->buflen > 64)
+ {
+ sha_process_block (ctx->buffer, ctx->buflen & ~63, ctx);
+
+ ctx->buflen &= 63;
+ /* The regions in the following copy operation cannot overlap. */
+ memcpy (ctx->buffer, &ctx->buffer[(left_over + add) & ~63],
+ ctx->buflen);
+ }
+
+ buffer = (const char *) buffer + add;
+ len -= add;
+ }
+
+ /* Process available complete blocks. */
+ if (len >= 64)
+ {
+#define UNALIGNED_P(p) (((md5_uintptr) p) % __alignof__ (md5_uint32) != 0)
+ if (UNALIGNED_P (buffer))
+ while (len > 64)
+ {
+ sha_process_block (memcpy (ctx->buffer, buffer, 64), 64, ctx);
+ buffer = (const char *) buffer + 64;
+ len -= 64;
+ }
+ else
+ {
+ sha_process_block (buffer, len & ~63, ctx);
+ buffer = (const char *) buffer + (len & ~63);
+ len &= 63;
+ }
+ }
+
+ /* Move remaining bytes in internal buffer. */
+ if (len > 0)
+ {
+ size_t left_over = ctx->buflen;
+
+ memcpy (&ctx->buffer[left_over], buffer, len);
+ left_over += len;
+ if (left_over >= 64)
+ {
+ sha_process_block (ctx->buffer, 64, ctx);
+ left_over -= 64;
+ memcpy (ctx->buffer, &ctx->buffer[64], left_over);
+ }
+ ctx->buflen = left_over;
+ }
+}
+
+/* --- Code below is the primary difference between md5.c and sha.c --- */
+
+/* SHA1 round constants */
+#define K1 0x5a827999L
+#define K2 0x6ed9eba1L
+#define K3 0x8f1bbcdcL
+#define K4 0xca62c1d6L
+
+/* Round functions. Note that F2 is the same as F4. */
+#define F1(B,C,D) ( D ^ ( B & ( C ^ D ) ) )
+#define F2(B,C,D) (B ^ C ^ D)
+#define F3(B,C,D) ( ( B & C ) | ( D & ( B | C ) ) )
+#define F4(B,C,D) (B ^ C ^ D)
+
+/* Process LEN bytes of BUFFER, accumulating context into CTX.
+ It is assumed that LEN % 64 == 0.
+ Most of this code comes from GnuPG's cipher/sha1.c. */
+
+void
+sha_process_block (const void *buffer, size_t len, struct sha_ctx *ctx)
+{
+ const md5_uint32 *words = buffer;
+ size_t nwords = len / sizeof (md5_uint32);
+ const md5_uint32 *endp = words + nwords;
+ md5_uint32 x[16];
+ md5_uint32 a = ctx->A;
+ md5_uint32 b = ctx->B;
+ md5_uint32 c = ctx->C;
+ md5_uint32 d = ctx->D;
+ md5_uint32 e = ctx->E;
+
+ /* First increment the byte count. RFC 1321 specifies the possible
+ length of the file up to 2^64 bits. Here we only compute the
+ number of bytes. Do a double word increment. */
+ ctx->total[0] += len;
+ if (ctx->total[0] < len)
+ ++ctx->total[1];
+
+#define M(I) ( tm = x[I&0x0f] ^ x[(I-14)&0x0f] \
+ ^ x[(I-8)&0x0f] ^ x[(I-3)&0x0f] \
+ , (x[I&0x0f] = rol(tm, 1)) )
+
+#define R(A,B,C,D,E,F,K,M) do { E += rol( A, 5 ) \
+ + F( B, C, D ) \
+ + K \
+ + M; \
+ B = rol( B, 30 ); \
+ } while(0)
+
+ while (words < endp)
+ {
+ md5_uint32 tm;
+ int t;
+ /* FIXME: see sha1.c for a better implementation. */
+ for (t = 0; t < 16; t++)
+ {
+ x[t] = NOTSWAP (*words);
+ words++;
+ }
+
+ R( a, b, c, d, e, F1, K1, x[ 0] );
+ R( e, a, b, c, d, F1, K1, x[ 1] );
+ R( d, e, a, b, c, F1, K1, x[ 2] );
+ R( c, d, e, a, b, F1, K1, x[ 3] );
+ R( b, c, d, e, a, F1, K1, x[ 4] );
+ R( a, b, c, d, e, F1, K1, x[ 5] );
+ R( e, a, b, c, d, F1, K1, x[ 6] );
+ R( d, e, a, b, c, F1, K1, x[ 7] );
+ R( c, d, e, a, b, F1, K1, x[ 8] );
+ R( b, c, d, e, a, F1, K1, x[ 9] );
+ R( a, b, c, d, e, F1, K1, x[10] );
+ R( e, a, b, c, d, F1, K1, x[11] );
+ R( d, e, a, b, c, F1, K1, x[12] );
+ R( c, d, e, a, b, F1, K1, x[13] );
+ R( b, c, d, e, a, F1, K1, x[14] );
+ R( a, b, c, d, e, F1, K1, x[15] );
+ R( e, a, b, c, d, F1, K1, M(16) );
+ R( d, e, a, b, c, F1, K1, M(17) );
+ R( c, d, e, a, b, F1, K1, M(18) );
+ R( b, c, d, e, a, F1, K1, M(19) );
+ R( a, b, c, d, e, F2, K2, M(20) );
+ R( e, a, b, c, d, F2, K2, M(21) );
+ R( d, e, a, b, c, F2, K2, M(22) );
+ R( c, d, e, a, b, F2, K2, M(23) );
+ R( b, c, d, e, a, F2, K2, M(24) );
+ R( a, b, c, d, e, F2, K2, M(25) );
+ R( e, a, b, c, d, F2, K2, M(26) );
+ R( d, e, a, b, c, F2, K2, M(27) );
+ R( c, d, e, a, b, F2, K2, M(28) );
+ R( b, c, d, e, a, F2, K2, M(29) );
+ R( a, b, c, d, e, F2, K2, M(30) );
+ R( e, a, b, c, d, F2, K2, M(31) );
+ R( d, e, a, b, c, F2, K2, M(32) );
+ R( c, d, e, a, b, F2, K2, M(33) );
+ R( b, c, d, e, a, F2, K2, M(34) );
+ R( a, b, c, d, e, F2, K2, M(35) );
+ R( e, a, b, c, d, F2, K2, M(36) );
+ R( d, e, a, b, c, F2, K2, M(37) );
+ R( c, d, e, a, b, F2, K2, M(38) );
+ R( b, c, d, e, a, F2, K2, M(39) );
+ R( a, b, c, d, e, F3, K3, M(40) );
+ R( e, a, b, c, d, F3, K3, M(41) );
+ R( d, e, a, b, c, F3, K3, M(42) );
+ R( c, d, e, a, b, F3, K3, M(43) );
+ R( b, c, d, e, a, F3, K3, M(44) );
+ R( a, b, c, d, e, F3, K3, M(45) );
+ R( e, a, b, c, d, F3, K3, M(46) );
+ R( d, e, a, b, c, F3, K3, M(47) );
+ R( c, d, e, a, b, F3, K3, M(48) );
+ R( b, c, d, e, a, F3, K3, M(49) );
+ R( a, b, c, d, e, F3, K3, M(50) );
+ R( e, a, b, c, d, F3, K3, M(51) );
+ R( d, e, a, b, c, F3, K3, M(52) );
+ R( c, d, e, a, b, F3, K3, M(53) );
+ R( b, c, d, e, a, F3, K3, M(54) );
+ R( a, b, c, d, e, F3, K3, M(55) );
+ R( e, a, b, c, d, F3, K3, M(56) );
+ R( d, e, a, b, c, F3, K3, M(57) );
+ R( c, d, e, a, b, F3, K3, M(58) );
+ R( b, c, d, e, a, F3, K3, M(59) );
+ R( a, b, c, d, e, F4, K4, M(60) );
+ R( e, a, b, c, d, F4, K4, M(61) );
+ R( d, e, a, b, c, F4, K4, M(62) );
+ R( c, d, e, a, b, F4, K4, M(63) );
+ R( b, c, d, e, a, F4, K4, M(64) );
+ R( a, b, c, d, e, F4, K4, M(65) );
+ R( e, a, b, c, d, F4, K4, M(66) );
+ R( d, e, a, b, c, F4, K4, M(67) );
+ R( c, d, e, a, b, F4, K4, M(68) );
+ R( b, c, d, e, a, F4, K4, M(69) );
+ R( a, b, c, d, e, F4, K4, M(70) );
+ R( e, a, b, c, d, F4, K4, M(71) );
+ R( d, e, a, b, c, F4, K4, M(72) );
+ R( c, d, e, a, b, F4, K4, M(73) );
+ R( b, c, d, e, a, F4, K4, M(74) );
+ R( a, b, c, d, e, F4, K4, M(75) );
+ R( e, a, b, c, d, F4, K4, M(76) );
+ R( d, e, a, b, c, F4, K4, M(77) );
+ R( c, d, e, a, b, F4, K4, M(78) );
+ R( b, c, d, e, a, F4, K4, M(79) );
+
+ a = ctx->A += a;
+ b = ctx->B += b;
+ c = ctx->C += c;
+ d = ctx->D += d;
+ e = ctx->E += e;
+ }
+}
diff --git a/src/sha.h b/src/sha.h
new file mode 100644
index 0000000..13583e3
--- /dev/null
+++ b/src/sha.h
@@ -0,0 +1,69 @@
+/* sha.h - Declaration of functions and datatypes for SHA1 sum computing
+ library functions.
+
+ Copyright (C) 1999, Scott G. Miller
+*/
+
+#ifndef _SHA_H
+# define _SHA_H 1
+
+# include "md5.h"
+
+/* Structure to save state of computation between the single steps. */
+struct sha_ctx
+{
+ md5_uint32 A;
+ md5_uint32 B;
+ md5_uint32 C;
+ md5_uint32 D;
+ md5_uint32 E;
+
+ md5_uint32 total[2];
+ md5_uint32 buflen;
+ char buffer[128];
+};
+
+
+/* Starting with the result of former calls of this function (or the
+ initialization function update the context for the next LEN bytes
+ starting at BUFFER.
+ It is necessary that LEN is a multiple of 64!!! */
+extern void sha_process_block (const void *buffer, size_t len,
+ struct sha_ctx *ctx);
+
+/* Starting with the result of former calls of this function (or the
+ initialization function update the context for the next LEN bytes
+ starting at BUFFER.
+ It is NOT required that LEN is a multiple of 64. */
+extern void sha_process_bytes (const void *buffer, size_t len,
+ struct sha_ctx *ctx);
+
+/* Initialize structure containing state of computation. */
+extern void sha_init_ctx (struct sha_ctx *ctx);
+
+/* Process the remaining bytes in the buffer and put result from CTX
+ in first 16 bytes following RESBUF. The result is always in little
+ endian byte order, so that a byte-wise output yields to the wanted
+ ASCII representation of the message digest.
+
+ IMPORTANT: On some systems it is required that RESBUF is correctly
+ aligned for a 32 bits value. */
+extern void *sha_finish_ctx (struct sha_ctx *ctx, void *resbuf);
+
+
+/* Put result from CTX in first 16 bytes following RESBUF. The result is
+ always in little endian byte order, so that a byte-wise output yields
+ to the wanted ASCII representation of the message digest.
+
+ IMPORTANT: On some systems it is required that RESBUF is correctly
+ aligned for a 32 bits value. */
+extern void *sha_read_ctx (const struct sha_ctx *ctx, void *resbuf);
+
+
+/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The
+ result is always in little endian byte order, so that a byte-wise
+ output yields to the wanted ASCII representation of the message
+ digest. */
+extern void *sha_buffer (const char *buffer, size_t len, void *resblock);
+
+#endif
diff --git a/src/space.c b/src/space.c
new file mode 100644
index 0000000..4bd4760
--- /dev/null
+++ b/src/space.c
@@ -0,0 +1,767 @@
+/* Copyright (C) 2001, 2002, 2003, 2004, 2006, 2007 Red Hat, Inc.
+ Written by Jakub Jelinek <jakub@redhat.com>, 2001.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include <config.h>
+#include <assert.h>
+#include <errno.h>
+#include <error.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include "prelink.h"
+#include "reloc.h"
+#include "space.h"
+
+#define DEBUG_SECTIONS
+
+#ifdef DEBUG_SECTIONS
+void
+print_sections (DSO *dso, GElf_Ehdr *ehdr, GElf_Shdr *shdr)
+{
+ int elf64 = ehdr->e_ident[EI_CLASS] == ELFCLASS64;
+ int i, j, shf, flag;
+ char buf[32], *q;
+ const char *p;
+ static struct { int sh_type; const char *type_name; } types[] =
+ {
+ { SHT_NULL, "NULL" },
+ { SHT_PROGBITS, "PROGBITS" },
+ { SHT_SYMTAB, "SYMTAB" },
+ { SHT_STRTAB, "STRTAB" },
+ { SHT_RELA, "RELA" },
+ { SHT_HASH, "HASH" },
+ { SHT_DYNAMIC, "DYNAMIC" },
+ { SHT_NOTE, "NOTE" },
+ { SHT_NOBITS, "NOBITS" },
+ { SHT_REL, "REL" },
+ { SHT_SHLIB, "SHLIB" },
+ { SHT_DYNSYM, "DYNSYM" },
+ { SHT_INIT_ARRAY, "INIT_ARRAY" },
+ { SHT_FINI_ARRAY, "FINI_ARRAY" },
+ { SHT_PREINIT_ARRAY, "PREINIT_ARRAY" },
+ { SHT_GROUP, "GROUP" },
+ { SHT_SYMTAB_SHNDX, "SYMTAB SECTION INDICIES" },
+ { SHT_GNU_verdef, "VERDEF" },
+ { SHT_GNU_verneed, "VERNEED" },
+ { SHT_GNU_versym, "VERSYM" },
+ { SHT_GNU_LIBLIST, "LIBLIST" },
+ { SHT_GNU_HASH, "GNU_HASH" },
+ { 0, NULL }
+ };
+
+ if (elf64)
+ printf (" [Nr] Name Type Address Off Size ES Flg Lk Inf Al\n");
+ else
+ printf (" [Nr] Name Type Addr Off Size ES Flg Lk Inf Al\n");
+ for (i = 0; i < ehdr->e_shnum; ++i)
+ {
+ p = NULL;
+ for (j = 0; types[j].type_name; ++j)
+ if (types[j].sh_type == shdr[i].sh_type)
+ {
+ p = types[j].type_name;
+ break;
+ }
+
+ if (p == NULL)
+ {
+ if (shdr[i].sh_type >= SHT_LOPROC && shdr[i].sh_type <= SHT_HIPROC)
+ sprintf (buf, "LOPROC+%x", shdr[i].sh_type - SHT_LOPROC);
+ else if (shdr[i].sh_type >= SHT_LOOS && shdr[i].sh_type <= SHT_HIOS)
+ sprintf (buf, "LOOS+%x", shdr[i].sh_type - SHT_LOOS);
+ else if (shdr[i].sh_type >= SHT_LOUSER && shdr[i].sh_type <= SHT_HIUSER)
+ sprintf (buf, "LOUSER+%x", shdr[i].sh_type - SHT_LOUSER);
+ else
+ sprintf (buf, "Unknown: %x", shdr[i].sh_type);
+ p = buf;
+ }
+
+ printf (" [%2d] %-17.17s %-15.15s ", i,
+ strptr (dso, ehdr->e_shstrndx, shdr[i].sh_name), p);
+
+ q = buf;
+ shf = shdr[i].sh_flags;
+ while (shf)
+ {
+ flag = shf & -shf;
+ shf &= ~flag;
+ switch (flag)
+ {
+ case SHF_WRITE: *q++ = 'W'; break;
+ case SHF_ALLOC: *q++ = 'A'; break;
+ case SHF_EXECINSTR: *q++ = 'X'; break;
+ case SHF_MERGE: *q++ = 'M'; break;
+ case SHF_STRINGS: *q++ = 'S'; break;
+ case SHF_INFO_LINK: *q++ = 'I'; break;
+ case SHF_LINK_ORDER: *q++ = 'L'; break;
+ case SHF_OS_NONCONFORMING: *q++ = 'O'; break;
+ case SHF_TLS: *q++ = 'T'; break;
+ default:
+ if (flag & SHF_MASKOS)
+ *q++ = 'o', shf &= ~SHF_MASKOS;
+ else if (flag & SHF_MASKPROC)
+ *q++ = 'p', shf &= ~SHF_MASKPROC;
+ else
+ *q++ = 'x';
+ break;
+ }
+ }
+ *q = '\0';
+ if (elf64)
+ printf (" %16.16llx %6.6llx %6.6llx %2.2lx %3s %2ld %3lx %2ld\n",
+ (long long) shdr[i].sh_addr, (long long) shdr[i].sh_offset,
+ (long long) shdr[i].sh_size, (long) shdr[i].sh_entsize,
+ buf, (long) shdr[i].sh_link, (long) shdr[i].sh_info,
+ (long) shdr[i].sh_addralign);
+ else
+ printf (" %8.8lx %6.6lx %6.6lx %2.2lx %3s %2ld %3lx %2ld\n",
+ (long) shdr[i].sh_addr, (long) shdr[i].sh_offset,
+ (long) shdr[i].sh_size, (long) shdr[i].sh_entsize,
+ buf, (long) shdr[i].sh_link, (long) shdr[i].sh_info,
+ (long) shdr[i].sh_addralign);
+ }
+}
+#endif
+
+void
+insert_readonly_section (GElf_Ehdr *ehdr, GElf_Shdr *shdr, int n,
+ struct readonly_adjust *adjust)
+{
+ int i;
+
+ memmove (&shdr[n + 1], &shdr[n],
+ (ehdr->e_shnum - n) * sizeof (GElf_Shdr));
+ ++ehdr->e_shnum;
+ for (i = 0; i < adjust->newcount; ++i)
+ if (adjust->new[i] >= n)
+ ++adjust->new[i];
+}
+
+int
+remove_readonly_section (GElf_Ehdr *ehdr, GElf_Shdr *shdr, int n,
+ struct readonly_adjust *adjust)
+{
+ int i, ret = -1;
+
+ memmove (&shdr[n], &shdr[n + 1],
+ (ehdr->e_shnum - n) * sizeof (GElf_Shdr));
+ --ehdr->e_shnum;
+ for (i = 0; i < adjust->newcount; ++i)
+ if (adjust->new[i] > n)
+ --adjust->new[i];
+ else if (adjust->new[i] == n)
+ {
+ adjust->new[i] = -1;
+ ret = i;
+ }
+
+ return ret;
+}
+
+static inline int
+readonly_is_movable (DSO *dso, GElf_Ehdr *ehdr, GElf_Shdr *shdr, int k)
+{
+ if (! (shdr[k].sh_flags & (SHF_ALLOC | SHF_WRITE)))
+ return 0;
+
+ switch (shdr[k].sh_type)
+ {
+ case SHT_HASH:
+ case SHT_GNU_HASH:
+ case SHT_DYNSYM:
+ case SHT_REL:
+ case SHT_RELA:
+ case SHT_STRTAB:
+ case SHT_NOTE:
+ case SHT_GNU_verdef:
+ case SHT_GNU_verneed:
+ case SHT_GNU_versym:
+ case SHT_GNU_LIBLIST:
+ return 1;
+ default:
+ if (strcmp (strptr (dso, ehdr->e_shstrndx,
+ shdr[k].sh_name), ".interp") == 0)
+ return 1;
+ return 0;
+ }
+}
+
+int
+find_readonly_space (DSO *dso, GElf_Shdr *add, GElf_Ehdr *ehdr,
+ GElf_Phdr *phdr, GElf_Shdr *shdr,
+ struct readonly_adjust *adjust)
+{
+ int i, j;
+ GElf_Addr addr;
+ GElf_Off p_filesz;
+
+ if (add->sh_addr)
+ {
+ /* Prefer the current address if possible. */
+ for (i = 0; i < ehdr->e_phnum; ++i)
+ if (phdr[i].p_type == PT_LOAD
+ && (phdr[i].p_flags & (PF_R | PF_W)) == PF_R
+ && phdr[i].p_vaddr <= add->sh_addr
+ && phdr[i].p_vaddr + phdr[i].p_filesz
+ >= add->sh_addr + add->sh_size)
+ break;
+
+ if (i < ehdr->e_phnum)
+ for (j = 1; j < ehdr->e_shnum; ++j)
+ if ((shdr[j].sh_flags & SHF_ALLOC)
+ && shdr[j].sh_addr >= add->sh_addr)
+ {
+ if (shdr[j].sh_addr >= add->sh_addr + add->sh_size
+ && shdr[j - 1].sh_addr + shdr[j - 1].sh_size <= add->sh_addr)
+ {
+ insert_readonly_section (ehdr, shdr, j, adjust);
+ shdr[j] = *add;
+ shdr[j].sh_offset = (shdr[j].sh_addr - phdr[i].p_vaddr)
+ + phdr[i].p_offset;
+ return j;
+ }
+ break;
+ }
+ }
+
+ for (i = 0; i < ehdr->e_phnum; ++i)
+ if (phdr[i].p_type == PT_LOAD
+ && (phdr[i].p_flags & (PF_R | PF_W)) == PF_R)
+ {
+ GElf_Addr start = phdr[i].p_vaddr;
+ int after = -1, min;
+
+ if (phdr[i].p_offset < ehdr->e_phoff)
+ {
+ for (j = 0; j < ehdr->e_phnum; j++)
+ if (phdr[j].p_type == PT_PHDR
+ && phdr[j].p_offset == ehdr->e_phoff
+ && phdr[j].p_filesz >= ehdr->e_phnum * ehdr->e_phentsize)
+ break;
+ start += ehdr->e_phoff;
+ if (j < ehdr->e_phnum)
+ start += phdr[j].p_filesz;
+ else
+ start += ehdr->e_phnum * ehdr->e_phentsize;
+ start -= phdr[i].p_offset;
+ }
+ start = (start + add->sh_addralign - 1) & ~(add->sh_addralign - 1);
+ for (j = 1; j < ehdr->e_shnum; ++j)
+ if ((shdr[j].sh_flags & SHF_ALLOC)
+ && shdr[j].sh_addr >= phdr[i].p_vaddr
+ && shdr[j].sh_addr + shdr[j].sh_size
+ <= phdr[i].p_vaddr + phdr[i].p_filesz)
+ {
+ if (after == -1)
+ after = j - 1;
+ if (start + add->sh_size > shdr[j].sh_addr)
+ {
+ start = shdr[j].sh_addr + shdr[j].sh_size;
+ start = (start + add->sh_addralign - 1)
+ & ~(add->sh_addralign - 1);
+ after = j;
+ }
+ }
+
+ min = -1;
+ for (j = i + 1; j < ehdr->e_phnum; ++j)
+ if (phdr[j].p_offset >= phdr[i].p_offset + phdr[i].p_filesz
+ && (min == -1 || phdr[min].p_offset > phdr[j].p_offset))
+ min = j;
+
+ if (after != -1
+ && (start + add->sh_size <= phdr[i].p_vaddr + phdr[i].p_filesz
+ || (phdr[i].p_filesz == phdr[i].p_memsz
+ && (min == -1
+ || start + add->sh_size - phdr[i].p_vaddr
+ <= phdr[min].p_offset))))
+ {
+ insert_readonly_section (ehdr, shdr, after + 1, adjust);
+ shdr[after + 1] = *add;
+ shdr[after + 1].sh_addr = start;
+ shdr[after + 1].sh_offset = (start - phdr[i].p_vaddr)
+ + phdr[i].p_offset;
+ if (start + add->sh_size > phdr[i].p_vaddr + phdr[i].p_filesz)
+ {
+ adjust_nonalloc (dso, ehdr, shdr, 0, 0,
+ start + add->sh_size - phdr[i].p_vaddr
+ - phdr[i].p_filesz);
+ phdr[i].p_filesz = start + add->sh_size - phdr[i].p_vaddr;
+ phdr[i].p_memsz = phdr[i].p_filesz;
+ }
+ return after + 1;
+ }
+ }
+
+ /* If SHT_NOBITS sections are small, just extend the last PT_LOAD
+ segment. Small enough here means that the whole .bss fits into
+ the same CPU page as the alloced part of it. */
+ for (i = -1, j = 0; j < ehdr->e_phnum; ++j)
+ if (phdr[j].p_type == PT_LOAD)
+ i = j;
+ p_filesz = phdr[i].p_filesz;
+
+ /* If we'll be converting NOBITS .plt to PROGBITS, account for that in the
+ calculation. */
+ for (j = 1; j < ehdr->e_shnum; ++j)
+ {
+ if (shdr[j].sh_type == SHT_NOBITS
+ && shdr[j].sh_addr >= phdr[i].p_vaddr
+ && shdr[j].sh_addr + shdr[j].sh_size
+ <= phdr[i].p_vaddr + phdr[i].p_memsz
+ && !strcmp (strptr (dso, ehdr->e_shstrndx, shdr[j].sh_name), ".plt"))
+ {
+ if (shdr[j].sh_addr + shdr[j].sh_size - phdr[i].p_vaddr > p_filesz)
+ p_filesz = shdr[j].sh_addr + shdr[j].sh_size - phdr[i].p_vaddr;
+ break;
+ }
+ }
+
+ if (phdr[i].p_filesz
+ && p_filesz <= phdr[i].p_memsz
+ && !(((phdr[i].p_vaddr + phdr[i].p_memsz - 1)
+ ^ (phdr[i].p_vaddr + p_filesz - 1)) & ~(dso->arch->page_size - 1)))
+ {
+ for (j = 1; j < ehdr->e_shnum; ++j)
+ {
+ if (!(shdr[j].sh_flags & (SHF_ALLOC | SHF_WRITE | SHF_ALLOC)))
+ break;
+ if (shdr[j].sh_type == SHT_NOBITS
+ && (shdr[j].sh_flags & SHF_TLS) == 0
+ && shdr[j].sh_addr >= phdr[i].p_vaddr)
+ shdr[j].sh_type = SHT_PROGBITS;
+ }
+
+ insert_readonly_section (ehdr, shdr, j, adjust);
+ shdr[j] = *add;
+ shdr[j].sh_addr = (shdr[j - 1].sh_addr + shdr[j - 1].sh_size
+ + add->sh_addralign - 1) & ~(add->sh_addralign - 1);
+ shdr[j].sh_offset = (shdr[j].sh_addr - phdr[i].p_vaddr)
+ + phdr[i].p_offset;
+ phdr[i].p_filesz = shdr[j].sh_addr + add->sh_size - phdr[i].p_vaddr;
+ phdr[i].p_memsz = phdr[i].p_filesz;
+ adjust_nonalloc (dso, ehdr, shdr, 0, 0, phdr[i].p_offset
+ + phdr[i].p_filesz - shdr[j + 1].sh_offset);
+ return j;
+ }
+
+ /* See if we can decrease binary's base VMA and thus gain space.
+ This trick is mainly useful for IA-32. */
+ for (i = 0; i < ehdr->e_phnum; ++i)
+ if (phdr[i].p_type == PT_LOAD)
+ break;
+
+ addr = (add->sh_size + add->sh_addralign - 1 + phdr[i].p_align - 1)
+ & ~(phdr[i].p_align - 1);
+ if (phdr[i].p_align <= dso->arch->page_size
+ && phdr[i].p_flags == (PF_R | PF_X)
+ && phdr[i].p_filesz == phdr[i].p_memsz
+ && phdr[i].p_vaddr - addr
+ && ! (((phdr[i].p_vaddr - addr) ^ phdr[i].p_vaddr)
+ & ~(phdr[i].p_align * 256 - 1)))
+ {
+ int moveend;
+ if (! adjust->basemove_end)
+ {
+ for (moveend = 1; moveend < ehdr->e_shnum; ++moveend)
+ if (strcmp (strptr (dso, ehdr->e_shstrndx,
+ shdr[moveend].sh_name), ".interp")
+ && shdr[moveend].sh_type != SHT_NOTE)
+ break;
+ if (moveend < ehdr->e_shnum && moveend > 1)
+ {
+ adjust->basemove_end = shdr[moveend].sh_addr;
+ adjust->moveend = moveend;
+ }
+ }
+ else
+ moveend = adjust->moveend;
+ if (moveend < ehdr->e_shnum && moveend > 1
+ && (shdr[moveend].sh_flags & (SHF_ALLOC | SHF_WRITE)))
+ {
+ int k = moveend;
+ GElf_Addr adj = addr;
+
+ if (add->sh_addr && ! adjust->move2
+ && phdr[i].p_vaddr <= add->sh_addr
+ && phdr[i].p_vaddr + phdr[i].p_filesz > add->sh_addr)
+ {
+ for (k = moveend; k < ehdr->e_shnum; ++k)
+ {
+ if (! (shdr[k].sh_flags & (SHF_ALLOC | SHF_WRITE)))
+ {
+ k = ehdr->e_shnum;
+ break;
+ }
+
+ if (shdr[k].sh_addr > add->sh_addr)
+ {
+ /* Don't allow inserting in between reloc sections
+ if they are adjacent. Similarly for adjacent
+ note sections. */
+ int sh_type1 = (shdr[k - 1].sh_type == SHT_RELA)
+ ? SHT_REL : shdr[k - 1].sh_type;
+ int sh_type2 = (shdr[k].sh_type == SHT_RELA)
+ ? SHT_REL : shdr[k].sh_type;
+
+ if (sh_type1 != sh_type2)
+ break;
+
+ if (sh_type1 != SHT_REL && sh_type1 != SHT_NOTE)
+ break;
+ if ((shdr[k - 1].sh_addr
+ + ((shdr[k - 1].sh_size + 3) & -4))
+ != shdr[k].sh_addr)
+ break;
+ }
+
+ if (! readonly_is_movable (dso, ehdr, shdr, k))
+ {
+ k = ehdr->e_shnum;
+ break;
+ }
+ }
+
+ if (k < ehdr->e_shnum)
+ {
+ GElf_Addr a;
+
+ a = shdr[k].sh_addr;
+ a -= shdr[k - 1].sh_addr + shdr[k - 1].sh_size;
+ assert (add->sh_addralign <= phdr[i].p_align);
+ assert (add->sh_size > a);
+ a = (add->sh_size - a + phdr[i].p_align - 1)
+ & ~(phdr[i].p_align - 1);
+ if (a < adj)
+ {
+ adjust->move2 = 1;
+ adj = a;
+ }
+ else
+ k = moveend;
+ }
+ else
+ k = moveend;
+ }
+
+ for (j = 1; j < k; ++j)
+ shdr[j].sh_addr -= adj;
+ phdr[i].p_vaddr -= adj;
+ phdr[i].p_paddr -= adj;
+ phdr[i].p_filesz += adj;
+ phdr[i].p_memsz += adj;
+ for (j = 0; j < ehdr->e_phnum; ++j)
+ {
+ if (j == i)
+ continue;
+ /* Leave STACK segment alone, it has p_vaddr == p_paddr == 0
+ and p_offset == p_filesz == p_memsz == 0. */
+ if (phdr[j].p_type == PT_GNU_STACK)
+ continue;
+ if (phdr[j].p_vaddr
+ < adjust->basemove_end - adjust->basemove_adjust)
+ {
+ phdr[j].p_vaddr -= adj;
+ phdr[j].p_paddr -= adj;
+ }
+ else
+ phdr[j].p_offset += adj;
+ }
+ adjust->basemove_adjust += adj;
+ insert_readonly_section (ehdr, shdr, k, adjust);
+ shdr[k] = *add;
+ if (k == moveend)
+ {
+ addr = shdr[k - 1].sh_addr + shdr[k - 1].sh_size;
+ addr = (addr + add->sh_addralign - 1) & ~(add->sh_addralign - 1);
+ }
+ else
+ {
+ addr = (shdr[k + 1].sh_addr - add->sh_size)
+ & ~(add->sh_addralign - 1);
+ }
+
+ shdr[k].sh_addr = addr;
+ shdr[k].sh_offset = (addr - phdr[i].p_vaddr) + phdr[i].p_offset;
+ adjust_nonalloc (dso, ehdr, shdr, 0, 0, adj);
+ return k;
+ }
+ }
+
+ /* We have to create new PT_LOAD if at all possible. */
+ for (j = 0; j < ehdr->e_phnum; ++j)
+ if (phdr[j].p_type == PT_NULL)
+ break;
+
+ if (j < ehdr->e_phnum)
+ {
+ memmove (phdr, &phdr[j + 1],
+ (ehdr->e_phnum - j - 1) * sizeof (GElf_Phdr));
+ ehdr->e_phnum--;
+ }
+ else
+ {
+ addr = ehdr->e_phoff + (ehdr->e_phnum + 1) * ehdr->e_phentsize;
+ for (j = 1; j < ehdr->e_shnum; ++j)
+ {
+ if (addr > shdr[j].sh_offset)
+ {
+ GElf_Addr start, addstart, endaddr, *old_addr;
+ GElf_Addr minsize = ~(GElf_Addr) 0;
+ int movesec = -1, last, k, e;
+
+ if (ehdr->e_phoff < phdr[i].p_offset
+ || ehdr->e_phoff + (ehdr->e_phnum + 1) * ehdr->e_phentsize
+ > phdr[i].p_offset + phdr[i].p_filesz
+ || ! readonly_is_movable (dso, ehdr, shdr, j)
+ || shdr[j].sh_addr >= phdr[i].p_vaddr + phdr[i].p_filesz)
+ {
+ error (0, 0, "%s: No space in ELF segment table to add new ELF segment",
+ dso->filename);
+ return 0;
+ }
+
+ start = phdr[i].p_vaddr - phdr[i].p_offset + ehdr->e_phoff
+ + (ehdr->e_phnum + 1) * ehdr->e_phentsize;
+ for (last = 1; last < ehdr->e_shnum; ++last)
+ if (! readonly_is_movable (dso, ehdr, shdr, last)
+ || shdr[last].sh_addr >= phdr[i].p_vaddr + phdr[i].p_filesz)
+ break;
+ for (j = 1; j < last; ++j)
+ {
+ addstart = (start + add->sh_addralign - 1)
+ & ~(add->sh_addralign - 1);
+ start = (start + shdr[j].sh_addralign - 1)
+ & ~(shdr[j].sh_addralign - 1);
+ endaddr = -1;
+ if (j + 1 < ehdr->e_shnum)
+ endaddr = shdr[j + 1].sh_addr;
+ if (phdr[i].p_vaddr + phdr[i].p_filesz < endaddr)
+ endaddr = phdr[i].p_vaddr + phdr[i].p_filesz;
+
+ switch (shdr[j].sh_type)
+ {
+ case SHT_HASH:
+ case SHT_GNU_HASH:
+ case SHT_DYNSYM:
+ case SHT_STRTAB:
+ case SHT_GNU_verdef:
+ case SHT_GNU_verneed:
+ case SHT_GNU_versym:
+ case SHT_GNU_LIBLIST:
+ if (endaddr >= start
+ && endaddr - start < minsize)
+ {
+ minsize = endaddr - start;
+ movesec = j;
+ }
+ if (endaddr > addstart
+ && endaddr - addstart > add->sh_size
+ && endaddr - addstart - add->sh_size
+ < minsize)
+ {
+ minsize = endaddr - addstart - add->sh_size;
+ movesec = j;
+ }
+ break;
+ case SHT_REL:
+ case SHT_RELA:
+ case SHT_NOTE:
+ /* Don't allow inserting in between reloc sections
+ if they are adjacent. Similarly for adjacent
+ note sections. */
+ if (j + 1 < ehdr->e_shnum)
+ {
+ if (shdr[j].sh_type == SHT_NOTE)
+ {
+ if (shdr[j + 1].sh_type != SHT_NOTE)
+ break;
+ }
+ else if (shdr[j + 1].sh_type != SHT_REL
+ && shdr[j + 1].sh_type != SHT_RELA)
+ {
+ break;
+ }
+
+ if ((shdr[j].sh_addr
+ + ((shdr[j].sh_size + 3) & -4))
+ != shdr[j + 1].sh_addr)
+ break;
+
+ start += shdr[j].sh_size;
+ continue;
+ }
+ break;
+ }
+
+ if (start + shdr[j].sh_size <= endaddr)
+ {
+ movesec = j + 1;
+ break;
+ }
+ start += shdr[j].sh_size;
+ }
+
+ if (movesec == -1)
+ {
+ error (0, 0, "%s: No space in ELF segment table to add new ELF segment",
+ dso->filename);
+ return 0;
+ }
+
+ start = phdr[i].p_vaddr - phdr[i].p_offset + ehdr->e_phoff
+ + (ehdr->e_phnum + 1) * ehdr->e_phentsize;
+ old_addr = (GElf_Addr *) alloca (movesec * sizeof (GElf_Addr));
+ for (k = 1; k < movesec; ++k)
+ {
+ start = (start + shdr[k].sh_addralign - 1)
+ & ~(shdr[k].sh_addralign - 1);
+ old_addr[k] = shdr[k].sh_addr;
+ shdr[k].sh_addr = start;
+ shdr[k].sh_offset = start + phdr[i].p_offset
+ - phdr[i].p_vaddr;
+ start += shdr[k].sh_size;
+ }
+
+ for (e = 0; e < ehdr->e_phnum; ++e)
+ if (phdr[e].p_type != PT_LOAD
+ && phdr[e].p_type != PT_GNU_STACK)
+ for (k = 1; k < movesec; ++k)
+ if (old_addr[k] == phdr[e].p_vaddr)
+ {
+ if (phdr[e].p_filesz != shdr[k].sh_size
+ || phdr[e].p_memsz != shdr[k].sh_size)
+ {
+ int k1 = -1;
+ if (phdr[e].p_type == PT_NOTE
+ && shdr[k].sh_type == SHT_NOTE
+ && phdr[e].p_filesz == phdr[e].p_memsz)
+ {
+ k1 = k;
+ while (k1 < movesec)
+ {
+ if (shdr[k1].sh_type != SHT_NOTE
+ || shdr[k1].sh_addr - old_addr[k1]
+ != shdr[k].sh_addr - old_addr[k]
+ || old_addr[k1] + shdr[k1].sh_size
+ > phdr[e].p_vaddr + phdr[e].p_filesz)
+ {
+ k1 = -1;
+ break;
+ }
+ if (old_addr[k1] + shdr[k1].sh_size
+ == phdr[e].p_vaddr + phdr[e].p_filesz)
+ break;
+ ++k1;
+ }
+ if (k1 == movesec)
+ k1 = -1;
+ }
+ if (k1 == -1)
+ {
+ error (0, 0, "%s: Non-PT_LOAD segment spanning more than one section",
+ dso->filename);
+ return 0;
+ }
+ }
+ phdr[e].p_vaddr += shdr[k].sh_addr - old_addr[k];
+ phdr[e].p_paddr += shdr[k].sh_addr - old_addr[k];
+ phdr[e].p_offset += shdr[k].sh_addr - old_addr[k];
+ break;
+ }
+
+ if (j < last)
+ /* Now continue as if there was place for a new PT_LOAD
+ in ElfW(Phdr) table initially. */
+ break;
+ else
+ {
+ GElf_Shdr moveshdr;
+ int newidx, ret, movedidx, oldidx;
+
+ moveshdr = shdr[movesec];
+ newidx = remove_readonly_section (ehdr, shdr, movesec, adjust);
+ oldidx = adjust->move->new_to_old[movesec];
+ remove_section (adjust->move, movesec);
+ ret = find_readonly_space (dso, add, ehdr, phdr, shdr, adjust);
+ if (ret == 0)
+ return 0;
+ movedidx = find_readonly_space (dso, &moveshdr, ehdr, phdr,
+ shdr, adjust);
+ if (movedidx == 0)
+ return 0;
+ if (newidx != -1)
+ adjust->new[newidx] = movedidx;
+ add_section (adjust->move, movedidx);
+ if (oldidx != -1)
+ {
+ adjust->move->old_to_new[oldidx] = movedidx;
+ adjust->move->new_to_old[movedidx] = oldidx;
+ }
+ if (movedidx <= ret)
+ ++ret;
+ return ret;
+ }
+ }
+ }
+ }
+
+ for (i = 0, j = 0; i < ehdr->e_phnum; ++i)
+ if (phdr[i].p_type == PT_LOAD)
+ j = i;
+ else if (phdr[i].p_type == PT_PHDR)
+ {
+ if (phdr[i].p_filesz == ehdr->e_phnum * ehdr->e_phentsize)
+ phdr[i].p_filesz += ehdr->e_phentsize;
+ if (phdr[i].p_memsz == ehdr->e_phnum * ehdr->e_phentsize)
+ phdr[i].p_memsz += ehdr->e_phentsize;
+ }
+
+ memmove (&phdr[j + 2], &phdr[j + 1],
+ (ehdr->e_phnum - j - 1) * sizeof (GElf_Phdr));
+ ++ehdr->e_phnum;
+ phdr[++j].p_type = PT_LOAD;
+ phdr[j].p_offset = phdr[j - 1].p_offset + phdr[j - 1].p_filesz;
+ phdr[j].p_offset = (phdr[j].p_offset + add->sh_addralign - 1)
+ & ~(add->sh_addralign - 1);
+ phdr[j].p_align = phdr[j - 1].p_align;
+ phdr[j].p_vaddr = phdr[j - 1].p_vaddr + phdr[j - 1].p_memsz;
+ phdr[j].p_vaddr += (phdr[j].p_align - 1);
+ phdr[j].p_vaddr &= ~(phdr[j].p_align - 1);
+ phdr[j].p_vaddr += (phdr[j].p_offset & (phdr[j].p_align - 1));
+ phdr[j].p_paddr = phdr[j].p_vaddr;
+ /* Although the content of the segment is read-only, unless it ends on
+ a page boundary, we must make it writeable. This is because the rest of
+ the last page in the segment will be used as sbrk area which is assumed
+ to be writeable. */
+ phdr[j].p_flags = (PF_R | PF_W);
+ phdr[j].p_filesz = add->sh_size;
+ phdr[j].p_memsz = add->sh_size;
+ for (i = 1; i < ehdr->e_shnum; ++i)
+ if (! (shdr[i].sh_flags & (SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR)))
+ break;
+ assert (i < ehdr->e_shnum);
+ insert_readonly_section (ehdr, shdr, i, adjust);
+ shdr[i] = *add;
+ shdr[i].sh_addr = phdr[j].p_vaddr;
+ shdr[i].sh_offset = phdr[j].p_offset;
+ adjust_nonalloc (dso, ehdr, shdr, 0, 0,
+ phdr[j].p_offset + phdr[j].p_filesz - phdr[j - 1].p_offset
+ - phdr[j - 1].p_filesz);
+ return i;
+}
diff --git a/src/space.h b/src/space.h
new file mode 100644
index 0000000..5c9f725
--- /dev/null
+++ b/src/space.h
@@ -0,0 +1,39 @@
+/* Copyright (C) 2001, 2004 Red Hat, Inc.
+ Written by Jakub Jelinek <jakub@redhat.com>, 2001.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ifndef SPACE_H
+#define SPACE_H
+
+struct readonly_adjust
+{
+ off_t basemove_adjust;
+ GElf_Addr basemove_end;
+ int moveend;
+ int move2;
+ int newcount, *new;
+ struct section_move *move;
+};
+
+void insert_readonly_section (GElf_Ehdr *ehdr, GElf_Shdr *shdr, int n,
+ struct readonly_adjust *adjust);
+int remove_readonly_section (GElf_Ehdr *ehdr, GElf_Shdr *shdr, int n,
+ struct readonly_adjust *adjust);
+int find_readonly_space (DSO *dso, GElf_Shdr *add, GElf_Ehdr *ehdr,
+ GElf_Phdr *phdr, GElf_Shdr *shdr,
+ struct readonly_adjust *adjust);
+
+#endif /* SPACE_H */
diff --git a/src/stabs.c b/src/stabs.c
new file mode 100644
index 0000000..c0a5a6a
--- /dev/null
+++ b/src/stabs.c
@@ -0,0 +1,188 @@
+/* Copyright (C) 2001, 2005, 2006 Red Hat, Inc.
+ Written by Jakub Jelinek <jakub@redhat.com>, 2001.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include <config.h>
+#include <assert.h>
+#include <byteswap.h>
+#include <endian.h>
+#include <error.h>
+
+#include "prelink.h"
+
+#define N_ZERO 0x00
+#define N_GSYM 0x20
+#define N_FNAME 0x22
+#define N_FUN 0x24
+#define N_STSYM 0x26
+#define N_LCSYM 0x28
+#define N_MAIN 0x2a
+#define N_BNSYM 0x2e
+#define N_PC 0x30
+#define N_NSYMS 0x32
+#define N_NOMAP 0x34
+#define N_OBJ 0x38
+#define N_OPT 0x3c
+#define N_RSYM 0x40
+#define N_M2C 0x42
+#define N_SLINE 0x44
+#define N_DSLINE 0x46
+#define N_BSLINE 0x48
+#define N_BROWS 0x48
+#define N_DEFD 0x4a
+#define N_ENSYM 0x4e
+#define N_EHDECL 0x50
+#define N_MOD2 0x50
+#define N_CATCH 0x54
+#define N_SSYM 0x60
+#define N_SO 0x64
+#define N_LSYM 0x80
+#define N_BINCL 0x82
+#define N_SOL 0x84
+#define N_PSYM 0xa0
+#define N_EINCL 0xa2
+#define N_ENTRY 0xa4
+#define N_LBRAC 0xc0
+#define N_EXCL 0xc2
+#define N_SCOPE 0xc4
+#define N_RBRAC 0xe0
+#define N_BCOMM 0xe2
+#define N_ECOMM 0xe4
+#define N_ECOML 0xe8
+#define N_LENG 0xfe
+
+static uint32_t
+read_native (char *p)
+{
+ return *(uint32_t *)p;
+}
+
+static uint32_t
+read_swap (char *p)
+{
+ return bswap_32 (*(uint32_t *)p);
+}
+
+static void
+write_native (char *p, uint32_t v)
+{
+ *(uint32_t *)p = v;
+}
+
+static void
+write_swap (char *p, uint32_t v)
+{
+ *(uint32_t *)p = bswap_32 (v);
+}
+
+int
+adjust_stabs (DSO *dso, int n, GElf_Addr start, GElf_Addr adjust)
+{
+ Elf_Data *data = NULL;
+ Elf_Scn *scn = dso->scn[n];
+ off_t off;
+ uint32_t (*read_32) (char *p);
+ void (*write_32) (char *p, uint32_t v);
+ uint32_t value;
+ int sec, type;
+
+ assert (dso->shdr[n].sh_entsize == 12);
+ data = elf_getdata (scn, NULL);
+ assert (data != NULL && data->d_buf != NULL);
+ assert (elf_getdata (scn, data) == NULL);
+ assert (data->d_off == 0 && data->d_size == dso->shdr[n].sh_size);
+#if __BYTE_ORDER == __BIG_ENDIAN
+ if (dso->ehdr.e_ident[EI_DATA] == ELFDATA2MSB)
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
+ if (dso->ehdr.e_ident[EI_DATA] == ELFDATA2LSB)
+#else
+# error Not supported host endianess
+#endif
+ {
+ read_32 = read_native;
+ write_32 = write_native;
+ }
+#if __BYTE_ORDER == __BIG_ENDIAN
+ else if (dso->ehdr.e_ident[EI_DATA] == ELFDATA2LSB)
+#elif __BYTE_ORDER == __LITTLE_ENDIAN
+ else if (dso->ehdr.e_ident[EI_DATA] == ELFDATA2MSB)
+#endif
+ {
+ read_32 = read_swap;
+ write_32 = write_swap;
+ }
+ else
+ {
+ error (0, 0, "%s: Wrong ELF data enconding", dso->filename);
+ return 1;
+ }
+
+ for (off = 0; off < data->d_size; off += 12)
+ {
+ switch ((type = *(uint8_t *)(data->d_buf + off + 4)))
+ {
+ case N_FUN:
+ /* If string is "", N_FUN is function length, otherwise
+ it is function start address. */
+ if (read_32 (data->d_buf + off) == 0)
+ break;
+ /* FALLTHROUGH */
+ case N_STSYM:
+ case N_LCSYM:
+ case N_CATCH:
+ case N_SO:
+ case N_SOL:
+ case N_BNSYM:
+ case N_ENSYM:
+ value = read_32 (data->d_buf + off + 8);
+ sec = addr_to_sec (dso, value);
+ if (sec != -1)
+ {
+ addr_adjust (value, start, adjust);
+ write_32 (data->d_buf + off + 8, value);
+ }
+ break;
+ /* These should be always 0. */
+ case N_GSYM:
+ case N_BINCL:
+ case N_EINCL:
+ case N_EXCL:
+ case N_BCOMM:
+ case N_ECOMM:
+ /* These contain other values. */
+ case N_ZERO:
+ case N_NSYMS:
+ case N_NOMAP:
+ case N_RSYM:
+ case N_LSYM:
+ case N_PSYM:
+ case N_OPT:
+ /* These are relative. */
+ case N_LBRAC:
+ case N_RBRAC:
+ case N_SLINE:
+ case N_BSLINE:
+ case N_DSLINE:
+ break;
+ default:
+ error (0, 0, "%s: Unknown stabs code 0x%02x\n", dso->filename, type);
+ return 1;
+ }
+ }
+
+ elf_flagscn (scn, ELF_C_SET, ELF_F_DIRTY);
+ return 0;
+}
diff --git a/src/undo.c b/src/undo.c
new file mode 100644
index 0000000..8a55bf2
--- /dev/null
+++ b/src/undo.c
@@ -0,0 +1,713 @@
+/* Copyright (C) 2001, 2002, 2003, 2005, 2010 Red Hat, Inc.
+ Written by Jakub Jelinek <jakub@redhat.com>, 2001.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include <config.h>
+#include <assert.h>
+#include <endian.h>
+#include <errno.h>
+#include <error.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include "prelink.h"
+#include "reloc.h"
+
+static int
+undo_prelink_rel (DSO *dso, int n)
+{
+ Elf_Data *data = NULL;
+ Elf_Scn *scn = dso->scn[n];
+ GElf_Rel rel;
+ int sec;
+
+ if (dso->arch->undo_prelink_rel == NULL)
+ return 0;
+ while ((data = elf_getdata (scn, data)) != NULL)
+ {
+ int ndx, maxndx;
+ GElf_Addr addr = dso->shdr[n].sh_addr + data->d_off;
+
+ maxndx = data->d_size / dso->shdr[n].sh_entsize;
+ for (ndx = 0; ndx < maxndx;
+ ++ndx, addr += dso->shdr[n].sh_entsize)
+ {
+ gelfx_getrel (dso->elf, data, ndx, &rel);
+ sec = addr_to_sec (dso, rel.r_offset);
+ if (sec == -1)
+ continue;
+
+ switch (dso->arch->undo_prelink_rel (dso, &rel, addr))
+ {
+ case 2:
+ gelfx_update_rel (dso->elf, data, ndx, &rel);
+ break;
+ case 0:
+ break;
+ default:
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+static int
+undo_prelink_rela (DSO *dso, int n)
+{
+ Elf_Data *data = NULL;
+ Elf_Scn *scn = dso->scn[n];
+ GElf_Rela rela;
+ int sec;
+
+ if (dso->arch->undo_prelink_rela == NULL)
+ return 0;
+ while ((data = elf_getdata (scn, data)) != NULL)
+ {
+ int ndx, maxndx;
+ GElf_Addr addr = dso->shdr[n].sh_addr + data->d_off;
+
+ maxndx = data->d_size / dso->shdr[n].sh_entsize;
+ for (ndx = 0; ndx < maxndx;
+ ++ndx, addr += dso->shdr[n].sh_entsize)
+ {
+ gelfx_getrela (dso->elf, data, ndx, &rela);
+ sec = addr_to_sec (dso, rela.r_offset);
+ if (sec == -1)
+ continue;
+
+ switch (dso->arch->undo_prelink_rela (dso, &rela, addr))
+ {
+ case 2:
+ gelfx_update_rela (dso->elf, data, ndx, &rela);
+ break;
+ case 0:
+ break;
+ default:
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+static int
+remove_dynamic_prelink_tags (DSO *dso)
+{
+ Elf_Data *data;
+ Elf_Scn *scn;
+ GElf_Dyn dyn;
+ int ndx;
+
+ assert (dso->shdr[dso->dynamic].sh_type == SHT_DYNAMIC);
+ scn = dso->scn[dso->dynamic];
+ data = elf_getdata (scn, NULL);
+ assert (elf_getdata (scn, data) == NULL);
+ ndx = data->d_size / dso->shdr[dso->dynamic].sh_entsize;
+ while (--ndx >= 0)
+ {
+ gelfx_getdyn (dso->elf, data, ndx, &dyn);
+ switch (dyn.d_tag)
+ {
+ case DT_NULL:
+ continue;
+ case DT_CHECKSUM:
+ case DT_GNU_PRELINKED:
+ case DT_GNU_LIBLIST:
+ case DT_GNU_LIBLISTSZ:
+ case DT_GNU_CONFLICT:
+ case DT_GNU_CONFLICTSZ:
+ dyn.d_tag = DT_NULL;
+ dyn.d_un.d_val = 0;
+ gelfx_update_dyn (dso->elf, data, ndx, &dyn);
+ elf_flagscn (scn, ELF_C_SET, ELF_F_DIRTY);
+ break;
+ default:
+ ndx = 0;
+ break;
+ }
+ }
+ return 0;
+}
+
+int
+undo_sections (DSO *dso, int undo, struct section_move *move,
+ struct reloc_info *rinfo, GElf_Ehdr *ehdr,
+ GElf_Phdr *phdr, GElf_Shdr *shdr)
+{
+ Elf_Data src, dst, *d;
+ Elf_Scn *scn;
+ int i, j;
+
+ scn = dso->scn[undo];
+ d = elf_getdata (scn, NULL);
+ assert (d != NULL && elf_getdata (scn, d) == NULL);
+
+ src = *d;
+ src.d_type = ELF_T_EHDR;
+ src.d_align = dso->shdr[undo].sh_addralign;
+ src.d_size = gelf_fsize (dso->elf, ELF_T_EHDR, 1, EV_CURRENT);
+ dst = src;
+ if (src.d_size > d->d_size)
+ {
+ error (0, 0, "%s: .gnu.prelink_undo section too small",
+ dso->filename);
+ return 1;
+ }
+ switch (gelf_getclass (dso->elf))
+ {
+ case ELFCLASS32:
+ dst.d_buf = alloca (dst.d_size);
+ break;
+ case ELFCLASS64:
+ dst.d_buf = ehdr;
+ break;
+ default:
+ return 1;
+ }
+ if (gelf_xlatetom (dso->elf, &dst, &src, dso->ehdr.e_ident[EI_DATA]) == NULL)
+ {
+ error (0, 0, "%s: Could not read .gnu.prelink_undo section",
+ dso->filename);
+ return 1;
+ }
+ if (gelf_getclass (dso->elf) == ELFCLASS32)
+ {
+ Elf32_Ehdr *ehdr32 = (Elf32_Ehdr *) dst.d_buf;
+
+ memcpy (ehdr->e_ident, ehdr32->e_ident, sizeof (ehdr->e_ident));
+#define COPY(name) ehdr->name = ehdr32->name
+ COPY (e_type);
+ COPY (e_machine);
+ COPY (e_version);
+ COPY (e_entry);
+ COPY (e_phoff);
+ COPY (e_shoff);
+ COPY (e_flags);
+ COPY (e_ehsize);
+ COPY (e_phentsize);
+ COPY (e_phnum);
+ COPY (e_shentsize);
+ COPY (e_shnum);
+ COPY (e_shstrndx);
+#undef COPY
+ }
+
+ if (memcmp (ehdr->e_ident, dso->ehdr.e_ident, sizeof (ehdr->e_ident))
+ || ehdr->e_type != dso->ehdr.e_type
+ || ehdr->e_machine != dso->ehdr.e_machine
+ || ehdr->e_version != dso->ehdr.e_version
+ || ehdr->e_flags != dso->ehdr.e_flags
+ || ehdr->e_ehsize != dso->ehdr.e_ehsize
+ || ehdr->e_phentsize != dso->ehdr.e_phentsize
+ || ehdr->e_shentsize != dso->ehdr.e_shentsize)
+ {
+ error (0, 0, "%s: ELF headers changed since prelinking",
+ dso->filename);
+ return 1;
+ }
+
+ if (ehdr->e_phnum > dso->ehdr.e_phnum)
+ {
+ error (0, 0, "%s: Number of program headers is less than before prelinking",
+ dso->filename);
+ return 1;
+ }
+
+ if (d->d_size != (src.d_size
+ + gelf_fsize (dso->elf, ELF_T_PHDR, ehdr->e_phnum,
+ EV_CURRENT)
+ + gelf_fsize (dso->elf, ELF_T_SHDR, ehdr->e_shnum - 1,
+ EV_CURRENT)))
+ {
+ error (0, 0, "%s: Incorrect size of .gnu.prelink_undo section",
+ dso->filename);
+ return 1;
+ }
+
+ src.d_type = ELF_T_PHDR;
+ src.d_buf += src.d_size;
+ src.d_size = gelf_fsize (dso->elf, ELF_T_PHDR, ehdr->e_phnum, EV_CURRENT);
+ dst = src;
+ switch (gelf_getclass (dso->elf))
+ {
+ case ELFCLASS32:
+ dst.d_buf = alloca (dst.d_size);
+ break;
+ case ELFCLASS64:
+ dst.d_buf = phdr;
+ break;
+ }
+ if (gelf_xlatetom (dso->elf, &dst, &src, dso->ehdr.e_ident[EI_DATA]) == NULL)
+ {
+ error (0, 0, "%s: Could not read .gnu.prelink_undo section",
+ dso->filename);
+ return 1;
+ }
+
+ if (gelf_getclass (dso->elf) == ELFCLASS32)
+ {
+ Elf32_Phdr *phdr32 = (Elf32_Phdr *) dst.d_buf;
+
+ for (i = 0; i < ehdr->e_phnum; ++i)
+ {
+#define COPY(name) phdr[i].name = phdr32[i].name
+ COPY(p_type);
+ COPY(p_flags);
+ COPY(p_offset);
+ COPY(p_vaddr);
+ COPY(p_paddr);
+ COPY(p_filesz);
+ COPY(p_memsz);
+ COPY(p_align);
+#undef COPY
+ }
+ }
+
+ memset (shdr, 0, sizeof (GElf_Shdr));
+ src.d_type = ELF_T_SHDR;
+ src.d_buf += src.d_size;
+ src.d_size = gelf_fsize (dso->elf, ELF_T_SHDR, ehdr->e_shnum - 1, EV_CURRENT);
+ dst = src;
+ switch (gelf_getclass (dso->elf))
+ {
+ case ELFCLASS32:
+ dst.d_buf = alloca (dst.d_size);
+ break;
+ case ELFCLASS64:
+ dst.d_buf = shdr + 1;
+ break;
+ default:
+ return 1;
+ }
+ if (gelf_xlatetom (dso->elf, &dst, &src, dso->ehdr.e_ident[EI_DATA]) == NULL)
+ {
+ error (0, 0, "%s: Could not read .gnu.prelink_undo section",
+ dso->filename);
+ return 1;
+ }
+
+ if (gelf_getclass (dso->elf) == ELFCLASS32)
+ {
+ Elf32_Shdr *shdr32 = (Elf32_Shdr *) dst.d_buf;
+
+ for (i = 1; i < ehdr->e_shnum; ++i)
+ {
+#define COPY(name) shdr[i].name = shdr32[i - 1].name
+ COPY (sh_name);
+ COPY (sh_type);
+ COPY (sh_flags);
+ COPY (sh_addr);
+ COPY (sh_offset);
+ COPY (sh_size);
+ COPY (sh_link);
+ COPY (sh_info);
+ COPY (sh_addralign);
+ COPY (sh_entsize);
+#undef COPY
+ }
+ }
+
+ move->new_shnum = ehdr->e_shnum;
+ for (i = 1; i < move->old_shnum; ++i)
+ move->old_to_new[i] = -1;
+ for (i = 1; i < move->new_shnum; ++i)
+ move->new_to_old[i] = -1;
+
+ for (i = 1; i < move->old_shnum; ++i)
+ {
+ for (j = 1; j < move->new_shnum; ++j)
+ if (dso->shdr[i].sh_name == shdr[j].sh_name
+ && dso->shdr[i].sh_type == shdr[j].sh_type
+ && dso->shdr[i].sh_flags == shdr[j].sh_flags
+ && dso->shdr[i].sh_addralign == shdr[j].sh_addralign
+ && dso->shdr[i].sh_entsize == shdr[j].sh_entsize
+ && dso->shdr[i].sh_size == shdr[j].sh_size
+ && move->new_to_old[j] == -1)
+ break;
+
+ if (j == move->new_shnum)
+ continue;
+
+ move->old_to_new[i] = j;
+ move->new_to_old[j] = i;
+ }
+
+ for (i = 1; i < move->old_shnum; ++i)
+ if (move->old_to_new[i] == -1)
+ {
+ const char *name = strptr (dso, dso->ehdr.e_shstrndx,
+ dso->shdr[i].sh_name);
+
+ if (! strcmp (name, ".gnu.prelink_undo")
+ || ! strcmp (name, ".gnu.conflict")
+ || ! strcmp (name, ".gnu.liblist")
+ || ! strcmp (name, ".gnu.libstr")
+ || ((! strcmp (name, ".dynbss") || ! strcmp (name, ".sdynbss"))
+ && dso->ehdr.e_type == ET_EXEC))
+ continue;
+
+ if ((! strcmp (name, ".dynstr") && dso->ehdr.e_type == ET_EXEC)
+ || i == dso->ehdr.e_shstrndx)
+ {
+ for (j = 1; j < move->new_shnum; ++j)
+ if (dso->shdr[i].sh_name == shdr[j].sh_name
+ && dso->shdr[i].sh_type == shdr[j].sh_type
+ && dso->shdr[i].sh_flags == shdr[j].sh_flags
+ && dso->shdr[i].sh_addralign == shdr[j].sh_addralign
+ && dso->shdr[i].sh_entsize == shdr[j].sh_entsize
+ && dso->shdr[i].sh_size > shdr[j].sh_size
+ && move->new_to_old[j] == -1)
+ break;
+
+ if (j < move->new_shnum)
+ {
+ move->old_to_new[i] = j;
+ move->new_to_old[j] = i;
+ continue;
+ }
+ }
+
+ if (((i >= rinfo->first && i <= rinfo->last) || i == rinfo->plt)
+ && dso->shdr[i].sh_type == SHT_RELA)
+ {
+ for (j = 1; j < move->new_shnum; ++j)
+ if (dso->shdr[i].sh_name == shdr[j].sh_name
+ && shdr[j].sh_type == SHT_REL
+ && dso->shdr[i].sh_flags == shdr[j].sh_flags
+ && dso->shdr[i].sh_addralign == shdr[j].sh_addralign
+ && 2 * dso->shdr[i].sh_entsize == 3 * shdr[j].sh_entsize
+ && 2 * dso->shdr[i].sh_size == 3 * shdr[j].sh_size
+ && move->new_to_old[j] == -1)
+ break;
+
+ if (j < move->new_shnum)
+ {
+ move->old_to_new[i] = j;
+ move->new_to_old[j] = i;
+ continue;
+ }
+ }
+
+ if (! strcmp (name, ".bss")
+ || ! strcmp (name, ".sbss")
+ || ((! strcmp (name, ".plt") || ! strcmp (name, ".iplt"))
+ && dso->shdr[i].sh_type == SHT_PROGBITS))
+ {
+ int is_plt = ! strcmp (name, ".plt");
+
+ for (j = 1; j < move->new_shnum; ++j)
+ if (dso->shdr[i].sh_name == shdr[j].sh_name
+ && dso->shdr[i].sh_flags == shdr[j].sh_flags
+ && dso->shdr[i].sh_addralign == shdr[j].sh_addralign
+ && (is_plt || dso->shdr[i].sh_entsize == shdr[j].sh_entsize)
+ && move->new_to_old[j] == -1)
+ {
+ if (is_plt)
+ {
+ if (dso->shdr[i].sh_size != shdr[j].sh_size)
+ continue;
+ if (shdr[j].sh_type == SHT_NOBITS
+ && dso->shdr[i].sh_entsize == shdr[j].sh_entsize)
+ break;
+ /* On Alpha prelink fixes bogus sh_entsize of .plt
+ sections. */
+ if (shdr[j].sh_type == SHT_PROGBITS)
+ break;
+ }
+ else
+ {
+ const char *pname;
+
+ if (dso->shdr[i].sh_type != shdr[j].sh_type
+ && (dso->shdr[i].sh_type != SHT_PROGBITS
+ || shdr[j].sh_type != SHT_NOBITS))
+ continue;
+
+ if (dso->shdr[i].sh_size == shdr[j].sh_size)
+ break;
+
+ pname = strptr (dso, dso->ehdr.e_shstrndx,
+ dso->shdr[i - 1].sh_name);
+ if (strcmp (pname, ".dynbss")
+ && strcmp (pname, ".sdynbss"))
+ continue;
+
+ if (dso->shdr[i].sh_size + dso->shdr[i - 1].sh_size
+ == shdr[j].sh_size)
+ break;
+ }
+ }
+
+ if (j < move->new_shnum)
+ {
+ move->old_to_new[i] = j;
+ move->new_to_old[j] = i;
+ continue;
+ }
+ }
+
+ error (0, 0, "%s: Section %s created after prelinking",
+ dso->filename, name);
+ return 1;
+ }
+
+ for (i = 1; i < move->new_shnum; ++i)
+ if (move->new_to_old[i] == -1)
+ {
+ const char *name = strptr (dso, dso->ehdr.e_shstrndx, shdr[i].sh_name);
+
+ error (0, 0, "%s: Section %s removed after prelinking", dso->filename,
+ name);
+ return 1;
+ }
+
+ return 0;
+}
+
+int
+prelink_undo (DSO *dso)
+{
+ GElf_Ehdr ehdr;
+ GElf_Shdr shdr[dso->ehdr.e_shnum + 20], old_shdr[dso->ehdr.e_shnum];
+ GElf_Phdr phdr[dso->ehdr.e_phnum];
+ Elf_Scn *scn;
+ Elf_Data *d;
+ int undo, i;
+ struct section_move *move;
+ struct reloc_info rinfo;
+
+ for (undo = 1; undo < dso->ehdr.e_shnum; ++undo)
+ if (! strcmp (strptr (dso, dso->ehdr.e_shstrndx, dso->shdr[undo].sh_name),
+ ".gnu.prelink_undo"))
+ break;
+
+ if (undo == dso->ehdr.e_shnum)
+ {
+ if (undo_output)
+ return 0;
+ error (0, 0, "%s does not have .gnu.prelink_undo section", dso->filename);
+ return 1;
+ }
+
+ memcpy (old_shdr, dso->shdr, sizeof (GElf_Shdr) * dso->ehdr.e_shnum);
+ move = init_section_move (dso);
+ if (move == NULL)
+ return 1;
+
+ if (find_reloc_sections (dso, &rinfo))
+ goto error_out;
+
+ if (undo_sections (dso, undo, move, &rinfo, &ehdr, phdr, shdr))
+ goto error_out;
+
+ if (reopen_dso (dso, move, (undo_output && strcmp (undo_output, "-") == 0)
+ ? "/tmp/undo" : undo_output))
+ goto error_out;
+
+ if (find_reloc_sections (dso, &rinfo))
+ goto error_out;
+
+ for (i = 1; i < dso->ehdr.e_shnum; i++)
+ {
+ if (! (dso->shdr[i].sh_flags & SHF_ALLOC))
+ continue;
+ if (! strcmp (strptr (dso, dso->ehdr.e_shstrndx,
+ dso->shdr[i].sh_name),
+ ".gnu.conflict"))
+ continue;
+ switch (dso->shdr[i].sh_type)
+ {
+ case SHT_REL:
+ if (undo_prelink_rel (dso, i))
+ goto error_out;
+ break;
+ case SHT_RELA:
+ if (undo_prelink_rela (dso, i))
+ goto error_out;
+ break;
+ }
+ }
+
+ if (dso->arch->arch_undo_prelink && dso->arch->arch_undo_prelink (dso))
+ goto error_out;
+
+ if (dso->ehdr.e_type == ET_DYN)
+ {
+ GElf_Addr adjust = 0, diff;
+
+ for (i = dso->ehdr.e_shnum - 1; i > 0; --i)
+ if (shdr[i].sh_flags & (SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR))
+ {
+ adjust = shdr[i].sh_addr - dso->shdr[i].sh_addr;
+ break;
+ }
+ while (i > 0)
+ {
+ int nsec = 1, j;
+ /* Change here PROGBITS .plt into NOBITS if needed. */
+
+ /* Convert RELA to REL if needed. */
+ if (dso->shdr[i].sh_type == SHT_RELA && shdr[i].sh_type == SHT_REL)
+ {
+ assert (dso->arch->rela_to_rel != NULL);
+ if (i == rinfo.plt)
+ {
+ if (convert_rela_to_rel (dso, i))
+ goto error_out;
+ dso->shdr[i].sh_size = shdr[i].sh_size;
+ }
+ else if (i == rinfo.last)
+ {
+ GElf_Addr start = dso->shdr[rinfo.first].sh_addr;
+
+ for (j = rinfo.first; j <= rinfo.last; ++j)
+ {
+ if (convert_rela_to_rel (dso, j))
+ goto error_out;
+ dso->shdr[j].sh_addr = start;
+ dso->shdr[j].sh_size = shdr[j].sh_size;
+ start += dso->shdr[j].sh_size;
+ }
+ nsec = rinfo.last - rinfo.first + 1;
+ i = rinfo.first;
+ }
+ else
+ {
+ error (0, 0, "%s: Cannot convert RELA to REL", dso->filename);
+ goto error_out;
+ }
+ }
+ diff = shdr[i].sh_addr - dso->shdr[i].sh_addr;
+ if (diff != adjust)
+ {
+ assert (diff >= adjust);
+ if (adjust_dso (dso, dso->shdr[i + nsec].sh_addr, adjust - diff))
+ goto error_out;
+ adjust = diff;
+ }
+ --i;
+ }
+ if (adjust && adjust_dso (dso, 0, adjust))
+ goto error_out;
+ for (i = 1; i < dso->ehdr.e_shnum; ++i)
+ if (shdr[i].sh_flags & (SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR))
+ assert (shdr[i].sh_addr == dso->shdr[i].sh_addr);
+ }
+ else
+ {
+ /* Executable. */
+ for (i = 1; i < dso->ehdr.e_shnum; ++i)
+ {
+ const char *name = strptr (dso, dso->ehdr.e_shstrndx,
+ dso->shdr[i].sh_name);
+
+ if (dso->shdr[i].sh_type == SHT_PROGBITS
+ && shdr[i].sh_type == SHT_NOBITS)
+ {
+ assert (strcmp (name, ".bss") == 0
+ || strcmp (name, ".sbss") == 0
+ || strcmp (name, ".plt") == 0
+ || strcmp (name, ".iplt") == 0);
+ scn = dso->scn[i];
+ d = elf_getdata (scn, NULL);
+ assert (d != NULL && elf_getdata (scn, d) == NULL);
+ assert (d->d_size == 0 || d->d_buf != NULL);
+ assert (d->d_size == dso->shdr[i].sh_size);
+ free (d->d_buf);
+ d->d_buf = NULL;
+ dso->shdr[i].sh_type = SHT_NOBITS;
+ }
+ else if (dso->shdr[i].sh_type == SHT_RELA
+ && shdr[i].sh_type == SHT_REL)
+ {
+ if (convert_rela_to_rel (dso, i))
+ goto error_out;
+ dso->shdr[i].sh_size = shdr[i].sh_size;
+ }
+ else
+ assert (dso->shdr[i].sh_type == shdr[i].sh_type);
+ if (dso->shdr[i].sh_size != shdr[i].sh_size)
+ {
+ /* This is handled in code below for both ET_DYN and ET_EXEC. */
+ if (i == dso->ehdr.e_shstrndx)
+ continue;
+ assert (shdr[i].sh_type == SHT_NOBITS
+ || shdr[i].sh_size < dso->shdr[i].sh_size);
+ assert (strcmp (name, ".dynstr") == 0
+ || strcmp (name, ".bss") == 0
+ || strcmp (name, ".sbss") == 0);
+ scn = dso->scn[i];
+ d = elf_getdata (scn, NULL);
+ assert (d != NULL && elf_getdata (scn, d) == NULL);
+ d->d_size = shdr[i].sh_size;
+ }
+ }
+
+ if (update_dynamic_tags (dso, shdr, old_shdr, move))
+ goto error_out;
+
+ for (i = 1; i < dso->ehdr.e_shnum; ++i)
+ if (shdr[i].sh_flags & (SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR))
+ dso->shdr[i].sh_addr = shdr[i].sh_addr;
+ }
+
+ /* Clear .dynamic entries added by prelink, update others. */
+ if (remove_dynamic_prelink_tags (dso)
+ || update_dynamic_rel (dso, &rinfo))
+ goto error_out;
+
+ /* Shrink .shstrtab. */
+ i = dso->ehdr.e_shstrndx;
+ if (shdr[i].sh_size < dso->shdr[i].sh_size)
+ {
+ scn = dso->scn[i];
+ d = elf_getdata (scn, NULL);
+ assert (d != NULL && elf_getdata (scn, d) == NULL);
+ assert (d->d_size == dso->shdr[i].sh_size);
+ d->d_size = shdr[i].sh_size;
+ }
+
+ /* Now restore the rest. */
+ for (i = 1; i < dso->ehdr.e_shnum; ++i)
+ dso->shdr[i] = shdr[i];
+ if (dso->ehdr.e_phnum != ehdr.e_phnum)
+ {
+ assert (ehdr.e_phnum < dso->ehdr.e_phnum);
+ if (gelf_newphdr (dso->elf, ehdr.e_phnum) == 0)
+ {
+ error (0, 0, "Could not create new ELF headers");
+ goto error_out;
+ }
+ }
+ for (i = 0; i < ehdr.e_phnum; ++i)
+ dso->phdr[i] = phdr[i];
+ dso->permissive = 1;
+ assert (dso->ehdr.e_entry == ehdr.e_entry);
+ assert (dso->ehdr.e_shnum == ehdr.e_shnum);
+ assert (dso->ehdr.e_shstrndx == ehdr.e_shstrndx);
+ dso->ehdr.e_phoff = ehdr.e_phoff;
+ dso->ehdr.e_shoff = ehdr.e_shoff;
+ dso->ehdr.e_phnum = ehdr.e_phnum;
+ free (move);
+ return 0;
+
+error_out:
+ free (move);
+ return 1;
+}
diff --git a/src/undoall.c b/src/undoall.c
new file mode 100644
index 0000000..99d2397
--- /dev/null
+++ b/src/undoall.c
@@ -0,0 +1,175 @@
+/* Copyright (C) 2002, 2005 Red Hat, Inc.
+ Written by Jakub Jelinek <jakub@redhat.com>, 2002.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include <config.h>
+#include <alloca.h>
+#include <errno.h>
+#include <error.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <unistd.h>
+#include "prelinktab.h"
+
+static int
+undo_one (void **p, void *info)
+{
+ struct prelink_entry *ent = * (struct prelink_entry **) p;
+ DSO *dso;
+ struct stat64 st;
+ struct prelink_link *hardlink;
+ char *move = NULL, *move_temp;
+ size_t movelen = 0;
+
+ if (ent->done != 2)
+ return 1;
+
+ if (ent->type != ET_DYN
+ && (ent->type != ET_EXEC || libs_only))
+ return 1;
+
+ dso = open_dso (ent->canon_filename);
+ if (dso == NULL)
+ goto error_out;
+
+ if (fstat64 (dso->fd, &st) < 0)
+ {
+ error (0, errno, "%s changed during prelinking", ent->filename);
+ goto error_out;
+ }
+
+ if (st.st_dev != ent->dev || st.st_ino != ent->ino)
+ {
+ error (0, 0, "%s changed during prelinking", ent->filename);
+ goto error_out;
+ }
+
+ if (verbose)
+ {
+ if (dry_run)
+ printf ("Would undo %s\n", ent->canon_filename);
+ else
+ printf ("Undoing %s\n", ent->canon_filename);
+ }
+
+ if (prelink_undo (dso))
+ goto error_out;
+
+ if (dry_run)
+ close_dso (dso);
+ else
+ {
+ if (update_dso (dso, NULL))
+ {
+ dso = NULL;
+ goto error_out;
+ }
+ }
+
+ dso = NULL;
+
+ /* Redo hardlinks. */
+ for (hardlink = ent->hardlink; hardlink; hardlink = hardlink->next)
+ {
+ size_t len;
+
+ if (wrap_lstat64 (hardlink->canon_filename, &st) < 0)
+ {
+ error (0, 0, "Could not stat %s (former hardlink to %s)",
+ hardlink->canon_filename, ent->canon_filename);
+ continue;
+ }
+
+ if (st.st_dev != ent->dev || st.st_ino != ent->ino)
+ {
+ error (0, 0, "%s is no longer hardlink to %s",
+ hardlink->canon_filename, ent->canon_filename);
+ continue;
+ }
+
+ if (verbose)
+ {
+ if (dry_run)
+ printf ("Would link %s to %s\n", hardlink->canon_filename,
+ ent->canon_filename);
+ else
+ printf ("Linking %s to %s\n", hardlink->canon_filename,
+ ent->canon_filename);
+ }
+
+ len = strlen (hardlink->canon_filename);
+ if (len + sizeof (".#prelink#") > movelen)
+ {
+ movelen = len + sizeof (".#prelink#");
+ move_temp = move;
+ move = realloc (move, movelen);
+ if (move == NULL)
+ {
+ free(move_temp);
+ error (0, ENOMEM, "Could not hardlink %s to %s",
+ hardlink->canon_filename, ent->canon_filename);
+ movelen = 0;
+ continue;
+ }
+ }
+
+ memcpy (mempcpy (move, hardlink->canon_filename, len), ".#prelink#",
+ sizeof (".#prelink#"));
+ if (wrap_rename (hardlink->canon_filename, move) < 0)
+ {
+ error (0, errno, "Could not hardlink %s to %s",
+ hardlink->canon_filename, ent->canon_filename);
+ continue;
+ }
+
+ if (wrap_link (ent->canon_filename, hardlink->canon_filename) < 0)
+ {
+ error (0, errno, "Could not hardlink %s to %s",
+ hardlink->canon_filename, ent->canon_filename);
+
+ if (wrap_rename (move, hardlink->canon_filename) < 0)
+ {
+ error (0, errno, "Could not rename %s back to %s",
+ move, hardlink->canon_filename);
+ }
+ continue;
+ }
+
+ if (wrap_unlink (move) < 0)
+ {
+ error (0, errno, "Could not unlink %s", move);
+ continue;
+ }
+ }
+ free (move);
+ return 1;
+
+error_out:
+ if (dso)
+ close_dso (dso);
+ (*(int *)info)++;
+ return 1;
+}
+
+int
+undo_all (void)
+{
+ int failures = 0;
+ htab_traverse (prelink_filename_htab, undo_one, &failures);
+ return failures != 0;
+}
diff --git a/src/verify.c b/src/verify.c
new file mode 100644
index 0000000..d9f4d7d
--- /dev/null
+++ b/src/verify.c
@@ -0,0 +1,458 @@
+/* Copyright (C) 2002, 2003, 2006, 2007, 2010 Red Hat, Inc.
+ Written by Jakub Jelinek <jakub@redhat.com>, 2002.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include <config.h>
+#include <assert.h>
+#include <endian.h>
+#include <errno.h>
+#include <error.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include "prelink.h"
+#include "md5.h"
+#include "sha.h"
+
+ssize_t
+send_file (int outfd, int infd, off_t *poff, size_t count)
+{
+ char buf[65536], *b, *p, *q;
+ size_t todo = count, len;
+ ssize_t n;
+
+ b = mmap (NULL, count, PROT_READ, MAP_PRIVATE, infd, *poff);
+ if (b != MAP_FAILED)
+ {
+ p = b;
+ q = p + count;
+ while (p != q)
+ {
+ n = TEMP_FAILURE_RETRY (write (outfd, p, q - p));
+ if (n <= 0)
+ {
+ munmap (b, count);
+ return -1;
+ }
+ p += n;
+ }
+ munmap (b, count);
+ return count;
+ }
+
+ if (lseek (infd, *poff, SEEK_SET) != *poff)
+ return -1;
+ while (todo > 0)
+ {
+ len = todo > sizeof (buf) ? sizeof (buf) : todo;
+ p = buf;
+ q = buf + len;
+ while (p != q)
+ {
+ n = TEMP_FAILURE_RETRY (read (infd, p, q - p));
+ if (n <= 0)
+ return -1;
+ p += n;
+ }
+ p = buf;
+ while (p != q)
+ {
+ n = TEMP_FAILURE_RETRY (write (outfd, p, q - p));
+ if (n <= 0)
+ return -1;
+ p += n;
+ }
+ todo -= len;
+ }
+ return count;
+}
+
+static int
+checksum_file (int fd, size_t count,
+ void (*sum) (const void *, size_t, void *), void *arg)
+{
+ char buf[65536+64], *b, *p, *q;
+ size_t todo = count, len;
+ ssize_t n;
+
+ b = mmap (NULL, count, PROT_READ, MAP_PRIVATE, fd, 0);
+ if (b != MAP_FAILED)
+ {
+ sum (b, count, arg);
+ munmap (b, count);
+ return 0;
+ }
+
+ b = (char *) (((uintptr_t) buf + 63) & ~(uintptr_t) 63);
+ while (todo > 0)
+ {
+ len = todo > 65536 ? 65536 : todo;
+ p = b;
+ q = b + len;
+ while (p != q)
+ {
+ n = TEMP_FAILURE_RETRY (read (fd, p, q - p));
+ if (n < 0)
+ return 1;
+ p += n;
+ }
+ sum (b, len, arg);
+ todo -= len;
+ }
+ return 0;
+}
+
+static int
+handle_verify (int fd, const char *filename)
+{
+ off_t off;
+ size_t cnt;
+ struct stat64 st;
+
+ if (fstat64 (fd, &st) < 0)
+ {
+ error (0, errno, "%s: couldn't fstat temporary file", filename);
+ return 1;
+ }
+
+ if (verify_method == VERIFY_CONTENT)
+ {
+ off = 0;
+ if (send_file (1, fd, &off, st.st_size) != st.st_size)
+ {
+ error (0, errno, "Couldn't write file to standard output");
+ return 1;
+ }
+ }
+ else if (verify_method == VERIFY_MD5)
+ {
+ struct md5_ctx ctx;
+ unsigned char bin_buffer[16];
+
+ md5_init_ctx (&ctx);
+ if (checksum_file (fd, st.st_size,
+ (void (*) (const void *, size_t, void *))
+ md5_process_bytes, &ctx))
+ {
+ error (0, errno, "%s: Couldn't read temporary file", filename);
+ return 1;
+ }
+
+ md5_finish_ctx (&ctx, bin_buffer);
+ for (cnt = 0; cnt < 16; ++cnt)
+ printf ("%02x", bin_buffer[cnt]);
+ printf (" %s\n", filename);
+ }
+ else if (verify_method == VERIFY_SHA)
+ {
+ struct sha_ctx ctx;
+ unsigned char bin_buffer[20];
+
+ sha_init_ctx (&ctx);
+ if (checksum_file (fd, st.st_size,
+ (void (*) (const void *, size_t, void *))
+ sha_process_bytes, &ctx))
+ {
+ error (0, errno, "%s: Couldn't read temporary file", filename);
+ return 1;
+ }
+
+ sha_finish_ctx (&ctx, bin_buffer);
+ for (cnt = 0; cnt < 20; ++cnt)
+ printf ("%02x", bin_buffer[cnt]);
+ printf (" %s\n", filename);
+ }
+ return 0;
+}
+
+int
+prelink_verify (const char *filename)
+{
+ DSO *dso = NULL, *dso2 = NULL;
+ int fd = -1, fdorig = -1, fdundone = -1, undo, ret;
+ struct stat64 st, st2;
+ struct prelink_entry *ent;
+ GElf_Addr base;
+ char buffer[32768], buffer2[32768];
+ size_t count;
+ char *p, *q;
+
+ if (wrap_stat64 (filename, &st) < 0)
+ error (EXIT_FAILURE, errno, "Couldn't stat %s", filename);
+
+ dso = open_dso (filename);
+ if (dso == NULL)
+ goto not_prelinked;
+
+ if (dso->ehdr.e_type != ET_DYN && dso->ehdr.e_type != ET_EXEC)
+ {
+ error (0, 0, "%s is not an ELF shared library nor binary", filename);
+ goto not_prelinked;
+ }
+
+ for (undo = 1; undo < dso->ehdr.e_shnum; ++undo)
+ if (! strcmp (strptr (dso, dso->ehdr.e_shstrndx, dso->shdr[undo].sh_name),
+ ".gnu.prelink_undo"))
+ break;
+
+ if (undo == dso->ehdr.e_shnum)
+ goto not_prelinked;
+
+ if (fstat64 (dso->fd, &st2) < 0)
+ {
+ error (0, errno, "Couldn't fstat %s", filename);
+ goto failure;
+ }
+
+ if (st.st_dev != st2.st_dev || st.st_ino != st2.st_ino
+ || st.st_size != st2.st_size)
+ {
+ error (0, 0, "%s: changed during --verify", filename);
+ goto failure;
+ }
+
+ if (read_config (prelink_conf))
+ goto failure;
+
+ if (gather_config ())
+ goto failure;
+
+ if (gather_object (filename, 0, 0))
+ goto failure;
+
+ ent = prelink_find_entry (filename, &st, 0);
+ if (ent == NULL)
+ {
+ error (0, 0, "%s disappeared while running --verify", filename);
+ goto failure;
+ }
+
+ if (ent->done != 2)
+ {
+ error (0, 0, "%s: at least one of file's dependencies has changed since prelinking",
+ filename);
+ goto failure;
+ }
+
+ base = dso->base;
+ ent->base = base;
+
+ ret = prelink_undo (dso);
+ if (ret)
+ goto failure;
+
+ switch (write_dso (dso))
+ {
+ case 2:
+ error (0, 0, "Could not write temporary for %s: %s", filename,
+ elf_errmsg (-1));
+ goto failure;
+ case 1:
+ goto failure;
+ case 0:
+ break;
+ }
+
+ fd = wrap_open (dso->temp_filename, O_RDONLY);
+ if (fd < 0)
+ {
+ error (0, errno, "Could not verify %s", filename);
+ goto failure;
+ }
+
+ fdorig = dup (dso->fdro);
+ if (fdorig < 0)
+ {
+ error (0, errno, "Could not verify %s", filename);
+ goto failure;
+ }
+
+ ent->filename = dso->temp_filename;
+ dso->temp_filename = NULL;
+ close_dso (dso);
+ dso = NULL;
+
+ fchmod (fd, 0700);
+
+ dso2 = fdopen_dso (fd, filename);
+ if (dso2 == NULL)
+ goto failure_unlink;
+ fd = -1;
+
+ if (prelink_prepare (dso2))
+ goto failure_unlink;
+
+ if (ent->type == ET_DYN && relocate_dso (dso2, base))
+ goto failure_unlink;
+
+ if (prelink (dso2, ent))
+ goto failure_unlink;
+
+ wrap_unlink (ent->filename);
+
+ if (write_dso (dso2))
+ goto failure;
+
+ fd = dup (dso2->fd);
+ if (fd < 0)
+ {
+ error (0, errno, "Could not verify %s", filename);
+ goto failure;
+ }
+
+ fdundone = dup (dso2->fdro);
+ if (fdundone < 0)
+ {
+ error (0, errno, "Could not verify %s", filename);
+ goto failure;
+ }
+
+ close_dso (dso2);
+ dso2 = NULL;
+
+ if (fstat64 (fdorig, &st2) < 0)
+ {
+ error (0, errno, "Couldn't fstat %s", filename);
+ goto failure;
+ }
+
+ if (st.st_dev != st2.st_dev || st.st_ino != st2.st_ino
+ || st.st_size != st2.st_size)
+ {
+ error (0, 0, "%s: changed during --verify", filename);
+ goto failure;
+ }
+
+ if (fstat64 (fd, &st2) < 0)
+ {
+ error (0, errno, "Couldn't fstat temporary file");
+ goto failure;
+ }
+
+ if (st.st_size != st2.st_size)
+ {
+ error (0, 0, "%s: prelinked file size differs", filename);
+ goto failure;
+ }
+
+ q = MAP_FAILED;
+ p = mmap (NULL, st.st_size, PROT_READ, MAP_PRIVATE, fdorig, 0);
+ if (p != MAP_FAILED)
+ {
+ q = mmap (NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+ if (q == MAP_FAILED)
+ {
+ munmap (p, st.st_size);
+ p = MAP_FAILED;
+ }
+ }
+ if (p != MAP_FAILED)
+ {
+ int ret = memcmp (p, q, st.st_size);
+
+ munmap (p, st.st_size);
+ munmap (q, st.st_size);
+ if (ret != 0)
+ {
+ error (0, 0, "%s: prelinked file was modified", filename);
+ goto failure;
+ }
+ }
+ else
+ {
+ if (lseek (fdorig, 0, SEEK_SET) != 0
+ || lseek (fd, 0, SEEK_SET) != 0)
+ {
+ error (0, errno, "%s: couldn't seek to start of files", filename);
+ goto failure;
+ }
+
+ count = st.st_size;
+ while (count > 0)
+ {
+ size_t len = sizeof (buffer);
+
+ if (len > count)
+ len = count;
+ if (read (fdorig, buffer, len) != len)
+ {
+ error (0, errno, "%s: couldn't read file", filename);
+ goto failure;
+ }
+ if (read (fd, buffer2, len) != len)
+ {
+ error (0, errno, "%s: couldn't read temporary file", filename);
+ goto failure;
+ }
+ if (memcmp (buffer, buffer2, len) != 0)
+ {
+ error (0, 0, "%s: prelinked file was modified", filename);
+ goto failure;
+ }
+ count -= len;
+ }
+ }
+
+ if (handle_verify (fdundone, filename))
+ goto failure;
+
+ fsync (fd);
+ fsync (fdorig);
+ fsync (fdundone);
+ close (fd);
+ close (fdorig);
+ close (fdundone);
+ return 0;
+
+failure_unlink:
+ unlink (ent->filename);
+failure:
+ if (fd != -1)
+ {
+ fsync (fd);
+ close (fd);
+ }
+ if (fdorig != -1)
+ {
+ fsync (fdorig);
+ close (fdorig);
+ }
+ if (fdundone != -1)
+ {
+ fsync (fdundone);
+ close (fdundone);
+ }
+ if (dso)
+ close_dso (dso);
+ if (dso2)
+ close_dso (dso2);
+ return EXIT_FAILURE;
+
+not_prelinked:
+ if (dso)
+ close_dso (dso);
+ fd = wrap_open (filename, O_RDONLY);
+ if (fd < 0)
+ error (EXIT_FAILURE, errno, "Couldn't open %s", filename);
+ if (handle_verify (fd, filename))
+ return EXIT_FAILURE;
+ fsync (fd);
+ close (fd);
+ return 0;
+}
diff --git a/src/wrap-file.c b/src/wrap-file.c
new file mode 100644
index 0000000..f2cf305
--- /dev/null
+++ b/src/wrap-file.c
@@ -0,0 +1,399 @@
+/* Copyright (C) 2003 MontaVista Software, Inc.
+ Written by Daniel Jacobowitz <drow@mvista.com>, 2003.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include <config.h>
+#include <assert.h>
+#include <errno.h>
+#include <error.h>
+#include <fcntl.h>
+#include <ftw.h>
+#include <glob.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/xattr.h>
+#include <time.h>
+#include <unistd.h>
+#include <utime.h>
+#include "prelink.h"
+
+#ifndef PATH_MAX
+#define PATH_MAX 1024
+#endif
+
+#ifndef MAXSYMLINKS
+#define MAXSYMLINKS 20
+#endif
+
+extern char *canon_filename (const char *name, int nested, struct stat64 *stp,
+ const char *chroot, int allow_last_link,
+ int allow_missing);
+
+const char *sysroot;
+
+char *
+sysroot_file_name (const char *name, int allow_last_link)
+{
+ struct stat64 st;
+ char *ret;
+
+ if (sysroot == NULL)
+ return (char *) name;
+
+ ret = canon_filename (name, 0, &st, sysroot, allow_last_link, 1);
+
+ if (ret == NULL)
+ /* That will have set errno. */
+ return NULL;
+
+ return ret;
+}
+
+char *
+unsysroot_file_name (const char *name)
+{
+ if (sysroot)
+ {
+ int sysroot_len = strlen (sysroot);
+ if (strncmp (name, sysroot, sysroot_len) == 0)
+ {
+ if (name[sysroot_len] == '/')
+ return strdup (name + sysroot_len);
+ else if (name[sysroot_len] == 0)
+ return strdup ("/");
+ }
+ }
+ return (char *)name;
+}
+
+static int
+wrap_stat_body (const char *file, struct stat64 *buf, int lstat)
+{
+ char* file_copy;
+ char *tmpname;
+ int ret;
+ int len;
+
+ tmpname = sysroot_file_name (file, lstat);
+
+ if (tmpname == NULL)
+ return -1;
+
+ file_copy = strdup (tmpname);
+
+ if (tmpname != file)
+ free (tmpname);
+
+ if (file_copy == NULL)
+ return -1;
+
+ len = strlen (file_copy);
+ if (len && (file_copy[len - 1] == '/' || file_copy[len - 1] == '\\'))
+ file_copy[len - 1] = '\0';
+
+ ret = lstat ? lstat64 (file_copy, buf) : stat64 (file_copy, buf);
+
+ free (file_copy);
+
+ return ret;
+}
+
+int
+wrap_lstat64 (const char *file, struct stat64 *buf)
+{
+ return wrap_stat_body (file, buf, 1);
+}
+
+int
+wrap_stat64 (const char *file, struct stat64 *buf)
+{
+ return wrap_stat_body (file, buf, 0);
+}
+
+int
+wrap_rename (const char *old, const char *new)
+{
+ char *tmpold = sysroot_file_name (old, 1);
+ char *tmpnew;
+ int ret;
+
+ if (tmpold == NULL)
+ return -1;
+
+ tmpnew = sysroot_file_name (new, 1);
+ if (tmpnew == NULL)
+ return -1;
+
+ ret = rename (tmpold, tmpnew);
+
+ if (tmpold != old)
+ free (tmpold);
+ if (tmpnew != new)
+ free (tmpnew);
+ return ret;
+}
+
+int
+wrap_open (const char *name, int mode, ...)
+{
+ char *tmpname = sysroot_file_name (name, 0);
+ int ret;
+
+ if (tmpname == NULL)
+ return -1;
+
+ if (mode & O_CREAT)
+ {
+ va_list va;
+ int flags;
+ va_start (va, mode);
+ flags = va_arg (va, int);
+ va_end (va);
+ ret = open (tmpname, mode, flags);
+ }
+ else
+ ret = open (tmpname, mode);
+
+ if (tmpname != name)
+ free (tmpname);
+ return ret;
+}
+
+int
+wrap_access (const char *name, int mode)
+{
+ char *tmpname = sysroot_file_name (name, 0);
+ int ret;
+
+ if (tmpname == NULL)
+ return -1;
+
+ ret = access (tmpname, mode);
+
+ if (tmpname != name)
+ free (tmpname);
+ return ret;
+}
+
+int
+wrap_link (const char *old, const char *new)
+{
+ char *tmpold = sysroot_file_name (old, 1);
+ char *tmpnew;
+ int ret;
+
+ if (tmpold == NULL)
+ return -1;
+
+ tmpnew = sysroot_file_name (new, 1);
+ if (tmpnew == NULL)
+ return -1;
+
+ ret = link (tmpold, tmpnew);
+
+ if (tmpold != old)
+ free (tmpold);
+ if (tmpnew != new)
+ free (tmpnew);
+ return ret;
+}
+
+/* Note that this isn't recursive safe, since nftw64 doesn't
+ pass an opaque object around to use. But that fits our needs
+ for now. */
+
+static __nftw64_func_t nftw64_cur_func;
+
+static int
+wrap_nftw64_func (const char *filename, const struct stat64 *status,
+ int flag, struct FTW *info)
+{
+ char *tmpname = unsysroot_file_name (filename);
+ int ret = nftw64_cur_func (tmpname, status, flag, info);
+
+ if (tmpname != filename)
+ free (tmpname);
+ return ret;
+}
+
+int
+wrap_nftw64 (const char *dir, __nftw64_func_t func,
+ int descriptors, int flag)
+{
+ char *tmpdir = sysroot_file_name (dir, 1);
+ int ret;
+
+ if (tmpdir == NULL)
+ return -1;
+
+ nftw64_cur_func = func;
+ ret = nftw64 (tmpdir, wrap_nftw64_func, descriptors, flag);
+
+ if (tmpdir != dir)
+ free (tmpdir);
+ return ret;
+}
+
+int
+wrap_utime (const char *file, struct utimbuf *file_times)
+{
+ char *tmpname = sysroot_file_name (file, 0);
+ int ret;
+
+ if (tmpname == NULL)
+ return -1;
+
+ ret = utime (tmpname, file_times);
+
+ if (tmpname != file)
+ free (tmpname);
+ return ret;
+}
+
+int
+wrap_mkstemp (char *filename)
+{
+ char *tmpname = sysroot_file_name (filename, 1);
+ int ret;
+
+ if (tmpname == NULL)
+ return -1;
+
+ ret = mkstemp (tmpname);
+
+ if (tmpname != filename)
+ {
+ strcpy (filename, tmpname + strlen (sysroot));
+ free (tmpname);
+ }
+ return ret;
+}
+
+int
+wrap_unlink (const char *filename)
+{
+ char *tmpname = sysroot_file_name (filename, 1);
+ int ret;
+
+ if (tmpname == NULL)
+ return -1;
+
+ ret = unlink (tmpname);
+
+ if (tmpname != filename)
+ free (tmpname);
+ return ret;
+}
+
+int
+wrap_readlink (const char *path, char *buf, int len)
+{
+ char *tmpname = sysroot_file_name (path, 1);
+ int ret;
+
+ if (tmpname == NULL)
+ return -1;
+
+ ret = readlink (tmpname, buf, len);
+
+ if (tmpname != path)
+ free (tmpname);
+ return ret;
+}
+
+int
+wrap_setxattr (const char *path, const char *name, const void *value,
+ size_t size, int flags)
+{
+ char *tmpname = sysroot_file_name (path, 0);
+ int ret;
+
+ if (tmpname == NULL)
+ return -1;
+
+ ret = setxattr (tmpname, name, value, size, flags);
+
+ if (tmpname != path)
+ free (tmpname);
+ return ret;
+}
+
+ssize_t
+wrap_getxattr (const char *path, const char *name, void *value,
+ size_t size)
+{
+ char *tmpname = sysroot_file_name (path, 0);
+ ssize_t ret;
+
+ if (tmpname == NULL)
+ return -1;
+
+ ret = getxattr (tmpname, name, value, size);
+
+ if (tmpname != path)
+ free (tmpname);
+ return ret;
+}
+
+ssize_t
+wrap_listxattr (const char *path, char *list, size_t size)
+{
+ char *tmpname = sysroot_file_name (path, 0);
+ ssize_t ret;
+
+ if (tmpname == NULL)
+ return -1;
+
+ ret = listxattr (tmpname, list, size);
+
+ if (tmpname != path)
+ free (tmpname);
+ return ret;
+}
+
+int
+wrap_glob (const char *pattern, int flags,
+ int (*errfunc) (const char *epath, int eerrno),
+ glob_t *pglob)
+{
+ char *tmp;
+ int ret;
+
+ if (!sysroot)
+ return glob (pattern, flags, errfunc, pglob);
+
+ asprintf (&tmp, "%s%s", sysroot, pattern);
+
+ ret = glob(tmp, flags, errfunc, pglob);
+ if (!ret)
+ {
+ size_t n;
+
+ for (n = 0; n < pglob->gl_pathc; ++n)
+ {
+ char *usname = unsysroot_file_name(pglob->gl_pathv[n]);
+ if (usname != pglob->gl_pathv[n])
+ free(pglob->gl_pathv[n]);
+ pglob->gl_pathv[n] = usname;
+ }
+ }
+
+ free(tmp);
+ return ret;
+}