summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--trunk/ChangeLog280
-rw-r--r--trunk/src/Makefile.am4
-rw-r--r--trunk/src/Makefile.in4
-rw-r--r--trunk/src/arch-alpha.c20
-rw-r--r--trunk/src/arch-arm.c35
-rw-r--r--trunk/src/arch-cris.c14
-rw-r--r--trunk/src/arch-i386.c52
-rw-r--r--trunk/src/arch-ia64.c14
-rw-r--r--trunk/src/arch-mips.c16
-rw-r--r--trunk/src/arch-ppc.c28
-rw-r--r--trunk/src/arch-ppc64.c25
-rw-r--r--trunk/src/arch-s390.c16
-rw-r--r--trunk/src/arch-s390x.c24
-rw-r--r--trunk/src/arch-sh.c26
-rw-r--r--trunk/src/arch-sparc.c20
-rw-r--r--trunk/src/arch-sparc64.c28
-rw-r--r--trunk/src/arch-x86_64.c40
-rw-r--r--trunk/src/conflict.c177
-rw-r--r--trunk/src/cxx.c490
-rw-r--r--trunk/src/doit.c60
-rw-r--r--trunk/src/dso.c1
-rw-r--r--trunk/src/dwarf2.c74
-rw-r--r--trunk/src/dwarf2.h25
-rw-r--r--trunk/src/fptr.c15
-rw-r--r--trunk/src/gather.c113
-rw-r--r--trunk/src/get.c119
-rw-r--r--trunk/src/main.c9
-rw-r--r--trunk/src/prelink.c36
-rw-r--r--trunk/src/prelink.h43
-rw-r--r--trunk/src/space.c350
-rw-r--r--trunk/src/verify.c7
-rw-r--r--trunk/testsuite/Makefile.am5
-rw-r--r--trunk/testsuite/Makefile.in5
-rwxr-xr-xtrunk/testsuite/cxx1.sh7
-rw-r--r--trunk/testsuite/cxx2.C51
-rwxr-xr-xtrunk/testsuite/cxx2.sh19
-rw-r--r--trunk/testsuite/ifunc.h33
-rw-r--r--trunk/testsuite/ifunc1.c29
-rwxr-xr-xtrunk/testsuite/ifunc1.sh21
-rw-r--r--trunk/testsuite/ifunc1lib1.c32
-rw-r--r--trunk/testsuite/ifunc1lib2.c39
-rwxr-xr-xtrunk/testsuite/ifunc2.sh21
-rw-r--r--trunk/testsuite/ifunc3.c32
-rwxr-xr-xtrunk/testsuite/ifunc3.sh21
-rw-r--r--trunk/testsuite/ifunc3lib1.c37
-rw-r--r--trunk/testsuite/ifunctest.c16
-rwxr-xr-xtrunk/testsuite/quick2.sh8
-rwxr-xr-xtrunk/testsuite/reloc2.sh4
-rw-r--r--trunk/testsuite/reloc5.c3
-rw-r--r--trunk/testsuite/shuffle2.c6
-rw-r--r--trunk/testsuite/shuffle9.c58
-rwxr-xr-xtrunk/testsuite/shuffle9.sh18
-rwxr-xr-xtrunk/testsuite/tls3.sh4
53 files changed, 2043 insertions, 591 deletions
diff --git a/trunk/ChangeLog b/trunk/ChangeLog
index 9e2961f..a5c0c5e 100644
--- a/trunk/ChangeLog
+++ b/trunk/ChangeLog
@@ -1,3 +1,283 @@
+2009-08-06 Joseph Myers <joseph@codesourcery.com>
+
+ * src/dwarf2.c (dwarf2_write_le64, dwarf2_write_be64): Shift by 56
+ not 58 for MSB.
+
+2009-07-09 Jakub Jelinek <jakub@redhat.com>
+
+ * src/conflict.c (prelink_build_conflicts): Don't call
+ prelink_conflict_rel{,a} on .gnu.conflict section in executables.
+
+2009-06-15 Jakub Jelinek <jakub@redhat.com>
+
+ * src/prelink.h (R_386_IRELATIVE, R_X86_64_IRELATIVE): Define
+ if not defined.
+ (struct PLArch): Add dest_addr argument to apply_conflict_rela
+ hook.
+ (struct prelink_conflict): Change used type from int to unsigned
+ char, add ifunc field.
+ (get_relocated_mem): Add dest_addr argument.
+ * src/get.c (prelink_record_relocations): Handle lookups resolving
+ to STT_GNU_IFUNC symbols.
+ * src/conflict.c (get_relocated_mem): Add dest_addr argument, pass
+ it through to the apply_conflict_rela hook. Fail if
+ apply_conflict_rela hook failed.
+ (prelink_build_conflicts): Build conflicts even in the executable,
+ and for libraries even if no conflicts were reported by the dynamic
+ linker. In the executable ignore any unused conflicts except for
+ ifunc conflicts. Adjust get_relocated_mem callers.
+ * src/cxx.c (remove_redundant_cxx_conflicts): Adjust
+ get_relocated_mem callers.
+ * arch-alpha.c (alpha_apply_conflict_rela): Add dest_addr argument.
+ (alpha_prelink_conflict_rela): Return early if info->dso == dso.
+ * arch-arm.c (arm_apply_conflict_rela): Add dest_addr argument.
+ (arm_prelink_conflict_rel, arm_prelink_conflict_rela): Return early
+ if info->dso == dso.
+ * arch-cris.c (cris_apply_conflict_rela): Add dest_addr argument.
+ (cris_prelink_conflict_rela): Return early if info->dso == dso.
+ * arch-ia64.c (ia64_apply_conflict_rela): Add dest_addr argument.
+ (ia64_prelink_conflict_rela): Return early if info->dso == dso.
+ * arch-ppc.c (ppc_apply_conflict_rela): Add dest_addr argument.
+ (ppc_prelink_conflict_rela): Return early if info->dso == dso.
+ * arch-ppc64.c (ppc64_apply_conflict_rela): Add dest_addr argument.
+ (ppc64_prelink_conflict_rela): Return early if info->dso == dso.
+ * arch-s390.c (s390_apply_conflict_rela): Add dest_addr argument.
+ (s390_prelink_conflict_rela): Return early if info->dso == dso.
+ * arch-s390x.c (s390x_apply_conflict_rela): Add dest_addr argument.
+ (s390x_prelink_conflict_rela): Return early if info->dso == dso.
+ * arch-sh.c (sh_apply_conflict_rela): Add dest_addr argument.
+ (sh_prelink_conflict_rela): Return early if info->dso == dso.
+ * arch-sparc.c (sparc_apply_conflict_rela): Add dest_addr argument.
+ (sparc_prelink_conflict_rela): Return early if info->dso == dso.
+ * arch-sparc64.c (sparc64_apply_conflict_rela): Add dest_addr argument.
+ (sparc64_prelink_conflict_rela): Return early if info->dso == dso.
+ * arch-mips.c (mipz_apply_conflict_rela): Add dest_addr argument.
+ (mips_prelink_conflict_reloc, mips_arch_prelink_conflict): Return
+ early if info->dso == dso.
+ * arch-i386.c (i386_adjust_rel, i386_adjust_rela, i386_prelink_rel,
+ i386_prelink_rela, i386_rel_to_rela, i386_undo_prelink_rel,
+ i386_rela_to_rel): Handle R_386_IRELATIVE.
+ (i386_apply_conflict_rela): Add dest_addr argument, handle
+ R_386_IRELATIVE.
+ (i386_prelink_conflict_rel, i386_prelink_conflict_rela): Handle
+ R_386_IRELATIVE and conflict->ifunc conflicts.
+ * arch-x86_64.c (x86_64_adjust_rela, x86_64_prelink_rela,
+ x86_64_undo_prelink_rela): Handle R_X86_64_IRELATIVE.
+ (x86_64_apply_conflict_rela): Handle R_X86_64_IRELATIVE and
+ conflict->ifunc conflicts.
+ * testsuite/Makefile.am (TESTS): Add ifunc1.sh, ifunc2.sh and
+ ifunc3.sh.
+ * testsuite/Makefile.in: Regenerated.
+ * testsuite/ifunc1.sh: New test.
+ * testsuite/ifunc2.sh: New test.
+ * testsuite/ifunc3.sh: New test.
+ * testsuite/ifunc1.c: New file.
+ * testsuite/ifunc1lib1.c: New file.
+ * testsuite/ifunc1lib2.c: New file.
+ * testsuite/ifunc3.c: New file.
+ * testsuite/ifunc3lib1.c: New file.
+ * testsuite/ifunc.h: New file.
+ * testsuite/ifunctest.c: New file.
+
+ * src/Makefile.am (DEFS, AM_CFLAGS): Add -Wno-pointer-sign.
+ * src/Makefile.in: Regenerated.
+ * src/data.c (reopen_dso): Initialize data variable to avoid
+ warnings.
+
+ * src/dwarf2.h (DW_TAG_condition, DW_TAG_shared_type): Define.
+ (DW_OP_form_tls_address, DW_OP_call_frame_cfa, DW_OP_bit_piece,
+ DW_OP_implicit_value, DW_OP_stack_value, DW_OP_GNU_uninit,
+ DW_OP_GNU_encoded_addr): Define.
+ (DW_ATE_packed_decimal, DW_ATE_numeric_string, DW_ATE_edited,
+ DW_ATE_signed_fixed, DW_ATE_unsigned_fixed, DW_ATE_decimal_float):
+ Define.
+ (DW_CFA_val_offset, DW_CFA_val_offset_sf, DW_CFA_val_expression):
+ Define.
+ (DW_LANG_PLI, DW_LANG_ObjC, DW_LANG_ObjC_plus_plus, DW_LANG_UPC,
+ DW_LANG_D): Define.
+ * src/dwarf2.c (debug_sections): Add .debug_pubtypes.
+ (DEBUG_PUBTYPES): Define.
+ (DEBUG_MACINFO, DEBUG_LOC, DEBUG_STR, DEBUG_FRAME, DEBUG_RANGES):
+ Adjust.
+ (struct cu_data): Add cu_version field.
+ (read_abbrev): Adjust error messages not to be DWARF-2 specific.
+ (adjust_location_list): Likewise. Fix up DW_OP_call_ref handling,
+ handle DW_OP_form_tls_address, DW_OP_call_frame_cfa,
+ DW_OP_GNU_uninit, DW_OP_bit_piece, DW_OP_stack_value and
+ DW_OP_implicit_value.
+ (adjust_attributes): For cu->cu_version == 2 skip ptr_size bytes
+ instead of just 4. Adjust error messages not to be DWARF-2
+ specific.
+ (adjust_dwarf2_line): Handle version 3 of .debug_line.
+ (adjust_dwarf2_frame): Just that CIE version is 1 or 3, for
+ version 1 skip just one byte instead of uleb128 for return address
+ column. Handle DW_CFA_val_offset, DW_CFA_val_offset_sf and
+ DW_CFA_val_expression.
+ (adjust_dwarf2): Handle version 3 of .debug_info, initialize
+ cu.cu_version. Adjust error messages not to be DWARF-2 specific.
+ Note that .debug_pubtypes doesn't need adjustments.
+
+2009-03-11 Jakub Jelinek <jakub@redhat.com>
+
+ * src/prelink.h (PLArch): Add rtype_class_valid field.
+ * src/get.c (prelink_record_relocations): If not /4, or
+ dso->arch->rtype_class_valid instead of RTYPE_CLASS_VALID
+ into reloc_class.
+ * src/cxx.c (remove_redundant_cxx_conflicts): Use
+ info->dso->arch->rtype_class_valid instead of RTYPE_CLASS_VALID.
+ * src/arch-ppc64.c (ppc64_reloc_class): For R_PPC64_COPY return
+ RTYPE_CLASS_COPY | RTYPE_CLASS_PLT, for non-TLS relocs return
+ RTYPE_CLASS_PLT.
+ (PL_ARCH): Set rtype_class_valid to RTYPE_CLASS_PLT.
+ * src/arch-alpha.c (PL_ARCH): Set rtype_class_valid to
+ RTYPE_CLASS_VALID.
+ * src/arch-arm.c (PL_ARCH): Likewise.
+ * src/arch-cris.c (PL_ARCH): Likewise.
+ * src/arch-i386.c (PL_ARCH): Likewise.
+ * src/arch-ia64.c (PL_ARCH): Likewise.
+ * src/arch-mips.c (PL_ARCH): Likewise.
+ * src/arch-ppc.c (PL_ARCH): Likewise.
+ * src/arch-s390.c (PL_ARCH): Likewise.
+ * src/arch-s390x.c (PL_ARCH): Likewise.
+ * src/arch-sh.c (PL_ARCH): Likewise.
+ * src/arch-sparc.c (PL_ARCH): Likewise.
+ * src/arch-sparc64.c (PL_ARCH): Likewise.
+ * src/arch-x86_64.c (PL_ARCH): Likewise.
+
+2009-03-04 Joseph Myers <joseph@codesourcery.com>
+
+ * testsuite/reloc2.sh, testsuite/tls3.sh: Add ARM to architectures
+ requiring PIC shared libraries.
+
+2009-03-04 Daniel Jacobowitz <dan@codesourcery.com>
+ Joseph Myers <joseph@codesourcery.com>
+
+ * src/arch-arm.c (arm_prelink_rel, arm_prelink_rela,
+ arm_prelink_conflict_rel, arm_prelink_conflict_rela, arm_rel_to_rela,
+ arm_rela_to_rel, arm_need_rel_to_rela, arm_undo_prelink_rel,
+ arm_reloc_class): Handle TLS relocations.
+ * src/prelink.h (R_ARM_TLS_DTPMOD32, R_ARM_TLS_DTPOFF32,
+ R_ARM_TLS_TPOFF32): Define if R_ARM_TLS_DTPMOD32 not already
+ defined.
+
+2009-03-04 Daniel Jacobowitz <dan@codesourcery.com>
+
+ * src/arch-arm.c (arm_adjust_dyn, arm_adjust_rel, arm_adjust_rela,
+ arm_prelink_rel, arm_prelink_rela, arm_apply_conflict_rela,
+ arm_apply_rel, arm_apply_rela, arm_prelink_conflict_rela,
+ arm_rel_to_rela, arm_rela_to_rel, arm_need_rel_to_rela,
+ arm_arch_prelink, arm_arch_undo_prelink, arm_undo_prelink_rel):
+ Use endian-neutral functions.
+
+2008-09-29 Joseph Myers <joseph@codesourcery.com>
+
+ * src/arch-sparc64.c (sparc64_prelink_rela,
+ sparc64_prelink_conflict_rela, sparc64_undo_prelink_rela,
+ sparc64_reloc_class): Handle TLS relocations.
+ (PL_ARCH): Update mmap_base and mmap_end for TASK_UNMAPPED_BASE
+ change to 0xfffff80100000000.
+
+2007-12-04 Daniel Jacobowitz <dan@codesourcery.com>
+
+ * src/gather.c (gather_object): Print an error if nftw64 fails.
+
+2007-10-09 Jakub Jelinek <jakub@redhat.com>
+
+ * src/cxx.c (remove_redundant_cxx_conflicts): Allow .sdata
+ section as well.
+
+ * src/prelink.h (struct prelink_conflict): Add next2 field.
+ (struct prelink_conflicts): Add hash2 field.
+ * src/get.c (prelink_record_relocations): Clear next2 fields.
+ * src/prelink.c (free_info): Also free hash2 table.
+ * src/cxx.c (remove_redundant_cxx_conflicts): Populate hash2
+ if not populated yet, use it to speed up pltref checking.
+
+ * src/prelink.h (struct prelink_conflicts): New type.
+ (struct prelink_info): Change type of conflicts and curconflicts
+ fields to struct prelink_conflicts *.
+ * src/get.c (conflict_hash_init): New function.
+ (prelink_record_relocations): Adjust initialization of conflicts
+ array. If conflict linked lists has more than 15 entries, use
+ hash table with chains.
+ * src/prelink.c (free_info): Handle freeing conflict list using a hash
+ table.
+ * src/fptr.c (opd_init): Only walk corresponding hash chain if
+ conflict list is using a hash table.
+ * src/conflict.c (prelink_conflict): Likewise.
+ (prelink_build_conflicts): Handle conflict list using a hash table.
+ * src/cxx.c (remove_redundant_cxx_conflicts): Likewise. Only walk
+ corresponding hash chain if conflict list is using a hash table.
+
+ * src/doit.c (find_ents): Clear e->u.tmp.
+ (clear_ent_marks, find_unlisted_dependency): Remove.
+ (prelink_ent): More efficient non-recursive check for
+ unlisted dependencies.
+
+ * src/cxx.c (find_cxx_sym): If fcs->lastndx != -1, search first
+ among symbols around it.
+
+2007-10-08 Jakub Jelinek <jakub@redhat.com>
+
+ * src/space.c (find_readonly_space): Disallow section insertion in
+ between adjacent SHT_NOTE sections. When creating new PT_LOAD,
+ handle multiple consecutive SHT_NOTE sections with just one PT_NOTE
+ segment for them.
+ * testsuite/Makefile.am (TESTS): Add shuffle9.sh.
+ * testsuite/Makefile.in: Regenerated.
+ * testsuite/shuffle9.sh: New test.
+ * testsuite/shuffle9.c: New.
+
+ * testsuite/shuffle2.c: Add .previous at the end of __asm.
+ * testsuite/reloc5.c (main): Likewise.
+
+ * testsuite/tls3.sh: If libs aren't built with -fpic,
+ disable the test under SELinux in enforcing mode.
+
+ * src/cxx.c: Include alloca.h.
+ (specials): Moved out of remove_redundant_cxx_conflicts to toplevel.
+ Remove section fields.
+ (find_cxx_sym_valsize, find_cxx_sym_cache): New structs.
+ (struct find_cxx_sym): Add cache and lastndx fields.
+ (cachecmp, create_cache): New functions.
+ (find_cxx_sym): Add cache argument. If cache[n] is NULL, call
+ create_cache. Do a binary search in cache[n]->vals array instead
+ of always reading the whole symbol table.
+ (remove_redundant_cxx_conflicts): Adjust find_cxx_sym caller.
+ Check if secname is ".data" or ".data.rel.ro" instead of comparing
+ it against specials[k].secname. Use binary search in binsymcache
+ when doing check_pltref checks.
+ * testsuite/Makefile.am (TESTS): Add cxx2.sh.
+ * testsuite/Makefile.in: Regenerated.
+ * testsuite/cxx1.sh: Check that some conflicts are optimized out
+ by C++ optimizations.
+ * testsuite/cxx2.sh: New test.
+ * testsuite/cxx2.C: New.
+
+2007-10-04 Jakub Jelinek <jakub@redhat.com>
+
+ * src/prelink.h (read_config): New prototype.
+ (gather_config, blacklist_from_config): Remove argument.
+ * src/gather.c (struct config_line): New type.
+ (config_lines, config_end): New variables.
+ (read_config): New function.
+ (gather_config, blacklist_from_config): Walk config_lines
+ chain instead of reading the config file.
+ * src/verify.c (prelink_verify): Call read_config. Don't
+ pass any argument to gather_config.
+ * src/main.c (main): Likewise. Also for blacklist_from_config.
+ * testsuite/quick2.sh: Use new -c etc/prelink.conf.d/*.conf
+ feature in prelink.conf and multiple config snippets.
+
+2007-06-27 Jakub Jelinek <jakub@redhat.com>
+
+ * testsuite/reloc2.sh: If libs aren't built with -fpic,
+ disable the test under SELinux in enforcing mode.
+
+2007-03-02 Sandra Loosemore <sandra@codesourcery.com>
+
+ * doc/prelink.8: Spelling and grammar fixes.
+
2006-12-01 Jakub Jelinek <jakub@redhat.com>
* src/verify.c (prelink_verify): Unlink ent->filename in case of
diff --git a/trunk/src/Makefile.am b/trunk/src/Makefile.am
index 64dad8f..387b6ef 100644
--- a/trunk/src/Makefile.am
+++ b/trunk/src/Makefile.am
@@ -5,8 +5,8 @@ AUTOMAKE_OPTIONS = 1.4 gnu
PKGVERSION = "\"@PKGVERSION@\""
REPORT_BUGS_TO = "\"@REPORT_BUGS_TO@\""
-DEFS = -D_GNU_SOURCE -DHAVE_CONFIG_H -Wall
-AM_CFLAGS = -Wall
+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)'`\"" \
diff --git a/trunk/src/Makefile.in b/trunk/src/Makefile.in
index 7dbe941..85cf845 100644
--- a/trunk/src/Makefile.in
+++ b/trunk/src/Makefile.in
@@ -97,8 +97,8 @@ install_sh = @install_sh@
AUTOMAKE_OPTIONS = 1.4 gnu
-DEFS = -D_GNU_SOURCE -DHAVE_CONFIG_H -Wall
-AM_CFLAGS = -Wall
+DEFS = -D_GNU_SOURCE -DHAVE_CONFIG_H -Wall -Wno-pointer-sign
+AM_CFLAGS = -Wall -Wno-pointer-sign
AM_CPPFLAGS = -DSBINDIR='"@sbindir@"'
INCLUDES = @GELFINCLUDE@
diff --git a/trunk/src/arch-alpha.c b/trunk/src/arch-alpha.c
index f35ee18..7802a3e 100644
--- a/trunk/src/arch-alpha.c
+++ b/trunk/src/arch-alpha.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001, 2002, 2003, 2004 Red Hat, Inc.
+/* 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
@@ -30,14 +30,14 @@
static int
alpha_adjust_dyn (DSO *dso, int n, GElf_Dyn *dyn, GElf_Addr start,
- GElf_Addr adjust)
+ GElf_Addr adjust)
{
return 0;
}
static int
alpha_adjust_rel (DSO *dso, GElf_Rel *rel, GElf_Addr start,
- GElf_Addr adjust)
+ GElf_Addr adjust)
{
error (0, 0, "%s: Alpha doesn't support REL relocs", dso->filename);
return 1;
@@ -45,7 +45,7 @@ alpha_adjust_rel (DSO *dso, GElf_Rel *rel, GElf_Addr start,
static int
alpha_adjust_rela (DSO *dso, GElf_Rela *rela, GElf_Addr start,
- GElf_Addr adjust)
+ GElf_Addr adjust)
{
if (GELF_R_TYPE (rela->r_info) == R_ALPHA_RELATIVE
|| GELF_R_TYPE (rela->r_info) == R_ALPHA_JMP_SLOT)
@@ -195,7 +195,7 @@ alpha_prelink_rela (struct prelink_info *info, GElf_Rela *rela,
static int
alpha_apply_conflict_rela (struct prelink_info *info, GElf_Rela *rela,
- char *buf)
+ char *buf, GElf_Addr dest_addr)
{
switch (GELF_R_TYPE (rela->r_info) & 0xff)
{
@@ -260,7 +260,8 @@ alpha_prelink_conflict_rela (DSO *dso, struct prelink_info *info,
GElf_Rela *ret;
if (GELF_R_TYPE (rela->r_info) == R_ALPHA_RELATIVE
- || GELF_R_TYPE (rela->r_info) == R_ALPHA_NONE)
+ || 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),
@@ -280,6 +281,12 @@ alpha_prelink_conflict_rela (DSO *dso, struct prelink_info *info,
}
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
@@ -467,6 +474,7 @@ PL_ARCH(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,
diff --git a/trunk/src/arch-arm.c b/trunk/src/arch-arm.c
index 0dddaac..ba53929 100644
--- a/trunk/src/arch-arm.c
+++ b/trunk/src/arch-arm.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001, 2002, 2004 Red Hat, Inc.
+/* 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
@@ -36,7 +36,7 @@
static int
arm_adjust_dyn (DSO *dso, int n, GElf_Dyn *dyn, GElf_Addr start,
- GElf_Addr adjust)
+ GElf_Addr adjust)
{
if (dyn->d_tag == DT_PLTGOT)
{
@@ -73,7 +73,7 @@ arm_adjust_dyn (DSO *dso, int n, GElf_Dyn *dyn, GElf_Addr start,
static int
arm_adjust_rel (DSO *dso, GElf_Rel *rel, GElf_Addr start,
- GElf_Addr adjust)
+ GElf_Addr adjust)
{
Elf32_Addr data;
switch (GELF_R_TYPE (rel->r_info))
@@ -90,7 +90,7 @@ arm_adjust_rel (DSO *dso, GElf_Rel *rel, GElf_Addr start,
static int
arm_adjust_rela (DSO *dso, GElf_Rela *rela, GElf_Addr start,
- GElf_Addr adjust)
+ GElf_Addr adjust)
{
Elf32_Addr data;
@@ -186,7 +186,7 @@ arm_prelink_rel (struct prelink_info *info, GElf_Rel *rel, GElf_Addr reladdr)
static int
arm_prelink_rela (struct prelink_info *info, GElf_Rela *rela,
- GElf_Addr relaaddr)
+ GElf_Addr relaaddr)
{
DSO *dso;
GElf_Addr value;
@@ -254,7 +254,7 @@ arm_prelink_rela (struct prelink_info *info, GElf_Rela *rela,
static int
arm_apply_conflict_rela (struct prelink_info *info, GElf_Rela *rela,
- char *buf)
+ char *buf, GElf_Addr dest_addr)
{
switch (GELF_R_TYPE (rela->r_info))
{
@@ -354,7 +354,7 @@ arm_apply_rela (struct prelink_info *info, GElf_Rela *rela, char *buf)
static int
arm_prelink_conflict_rel (DSO *dso, struct prelink_info *info, GElf_Rel *rel,
- GElf_Addr reladdr)
+ GElf_Addr reladdr)
{
GElf_Addr value;
struct prelink_conflict *conflict;
@@ -362,7 +362,8 @@ arm_prelink_conflict_rel (DSO *dso, struct prelink_info *info, GElf_Rel *rel,
GElf_Rela *ret;
if (GELF_R_TYPE (rel->r_info) == R_ARM_RELATIVE
- || GELF_R_TYPE (rel->r_info) == R_ARM_NONE)
+ || GELF_R_TYPE (rel->r_info) == R_ARM_NONE
+ || info->dso == dso)
/* Fast path: nothing to do. */
return 0;
conflict = prelink_conflict (info, GELF_R_SYM (rel->r_info),
@@ -384,6 +385,12 @@ arm_prelink_conflict_rel (DSO *dso, struct prelink_info *info, GElf_Rel *rel,
}
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
@@ -452,7 +459,7 @@ arm_prelink_conflict_rel (DSO *dso, struct prelink_info *info, GElf_Rel *rel,
static int
arm_prelink_conflict_rela (DSO *dso, struct prelink_info *info,
- GElf_Rela *rela, GElf_Addr relaaddr)
+ GElf_Rela *rela, GElf_Addr relaaddr)
{
GElf_Addr value;
struct prelink_conflict *conflict;
@@ -461,7 +468,8 @@ arm_prelink_conflict_rela (DSO *dso, struct prelink_info *info,
Elf32_Sword val;
if (GELF_R_TYPE (rela->r_info) == R_ARM_RELATIVE
- || GELF_R_TYPE (rela->r_info) == R_ARM_NONE)
+ || GELF_R_TYPE (rela->r_info) == R_ARM_NONE
+ || info->dso == dso)
/* Fast path: nothing to do. */
return 0;
conflict = prelink_conflict (info, GELF_R_SYM (rela->r_info),
@@ -484,6 +492,12 @@ arm_prelink_conflict_rela (DSO *dso, struct prelink_info *info,
}
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
@@ -823,6 +837,7 @@ PL_ARCH(arm) = {
.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.2",
.dynamic_linker_alt = "/lib/ld-linux.so.3",
.adjust_dyn = arm_adjust_dyn,
diff --git a/trunk/src/arch-cris.c b/trunk/src/arch-cris.c
index b110539..3272779 100644
--- a/trunk/src/arch-cris.c
+++ b/trunk/src/arch-cris.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001, 2002, 2004 Red Hat, Inc.
+/* 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
@@ -159,7 +159,7 @@ cris_prelink_rela (struct prelink_info *info, GElf_Rela *rela,
static int
cris_apply_conflict_rela (struct prelink_info *info, GElf_Rela *rela,
- char *buf)
+ char *buf, GElf_Addr dest_addr)
{
switch (GELF_R_TYPE (rela->r_info))
{
@@ -247,13 +247,20 @@ cris_prelink_conflict_rela (DSO *dso, struct prelink_info *info,
GElf_Rela *ret;
if (GELF_R_TYPE (rela->r_info) == R_CRIS_RELATIVE
- || GELF_R_TYPE (rela->r_info) == R_CRIS_NONE)
+ || 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)
@@ -375,6 +382,7 @@ PL_ARCH(cris) = {
.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,
diff --git a/trunk/src/arch-i386.c b/trunk/src/arch-i386.c
index 37b5c67..5661dcb 100644
--- a/trunk/src/arch-i386.c
+++ b/trunk/src/arch-i386.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001, 2002, 2003, 2004 Red Hat, Inc.
+/* 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
@@ -75,6 +75,7 @@ i386_adjust_rel (DSO *dso, GElf_Rel *rel, GElf_Addr start,
{
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);
@@ -92,6 +93,7 @@ i386_adjust_rela (DSO *dso, GElf_Rela *rela, GElf_Addr start,
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;
@@ -117,6 +119,7 @@ i386_prelink_rel (struct prelink_info *info, GElf_Rel *rel, GElf_Addr reladdr)
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;
@@ -187,6 +190,7 @@ i386_prelink_rela (struct prelink_info *info, GElf_Rela *rela,
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;
@@ -244,8 +248,10 @@ i386_prelink_rela (struct prelink_info *info, GElf_Rela *rela,
static int
i386_apply_conflict_rela (struct prelink_info *info, GElf_Rela *rela,
- char *buf)
+ char *buf, GElf_Addr dest_addr)
{
+ GElf_Rela *ret;
+
switch (GELF_R_TYPE (rela->r_info))
{
case R_386_GLOB_DAT:
@@ -253,6 +259,16 @@ i386_apply_conflict_rela (struct prelink_info *info, GElf_Rela *rela,
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 ();
}
@@ -339,20 +355,25 @@ i386_prelink_conflict_rel (DSO *dso, struct prelink_info *info, GElf_Rel *rel,
GELF_R_TYPE (rel->r_info));
if (conflict == NULL)
{
- if (info->curtls == NULL)
- return 0;
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
@@ -376,6 +397,11 @@ i386_prelink_conflict_rel (DSO *dso, struct prelink_info *info, GElf_Rel *rel,
/* 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:
@@ -441,20 +467,25 @@ i386_prelink_conflict_rela (DSO *dso, struct prelink_info *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_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
@@ -477,11 +508,16 @@ i386_prelink_conflict_rela (DSO *dso, struct prelink_info *info,
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);
@@ -539,6 +575,7 @@ i386_rel_to_rela (DSO *dso, GElf_Rel *rel, GElf_Rela *rela)
/* 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:
@@ -672,6 +709,7 @@ i386_undo_prelink_rel (DSO *dso, GElf_Rel *rel, GElf_Addr reladdr)
{
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);
@@ -746,6 +784,7 @@ i386_rela_to_rel (DSO *dso, GElf_Rela *rela, GElf_Rel *rel)
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:
@@ -1052,6 +1091,7 @@ PL_ARCH(i386) = {
.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,
diff --git a/trunk/src/arch-ia64.c b/trunk/src/arch-ia64.c
index 89df85e..6039115 100644
--- a/trunk/src/arch-ia64.c
+++ b/trunk/src/arch-ia64.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001, 2002, 2003, 2004 Red Hat, Inc.
+/* 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
@@ -196,7 +196,7 @@ ia64_prelink_rela (struct prelink_info *info, GElf_Rela *rela,
static int
ia64_apply_conflict_rela (struct prelink_info *info, GElf_Rela *rela,
- char *buf)
+ char *buf, GElf_Addr dest_addr)
{
if ((GELF_R_TYPE (rela->r_info) & ~1) == R_IA64_IPLTMSB)
{
@@ -312,13 +312,20 @@ ia64_prelink_conflict_rela (DSO *dso, struct prelink_info *info,
GElf_Rela *ret;
if ((GELF_R_TYPE (rela->r_info) & ~3) == R_IA64_REL32MSB
- || GELF_R_TYPE (rela->r_info) == R_IA64_NONE)
+ || 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)
@@ -493,6 +500,7 @@ PL_ARCH(ia64) = {
.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,
diff --git a/trunk/src/arch-mips.c b/trunk/src/arch-mips.c
index b85616e..2e0ea4c 100644
--- a/trunk/src/arch-mips.c
+++ b/trunk/src/arch-mips.c
@@ -660,11 +660,14 @@ mips_prelink_conflict_reloc (DSO *dso, struct prelink_info *info,
{
GElf_Addr value;
struct prelink_conflict *conflict;
- struct prelink_tls *tls;
+ 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);
@@ -688,6 +691,12 @@ mips_prelink_conflict_reloc (DSO *dso, struct prelink_info *info,
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;
@@ -791,7 +800,7 @@ mips_arch_prelink_conflict (DSO *dso, struct prelink_info *info)
struct prelink_conflict *conflict;
GElf_Rela *entry;
- if (dso->info[DT_PLTGOT] == 0)
+ if (info->dso == dso || dso->info[DT_PLTGOT] == 0)
return 0;
/* Add a conflict for every global GOT entry that does not hold the
@@ -829,7 +838,7 @@ mips_arch_prelink_conflict (DSO *dso, struct prelink_info *info)
static int
mips_apply_conflict_rela (struct prelink_info *info, GElf_Rela *rela,
- char *buf)
+ char *buf, GElf_Addr dest_addr)
{
DSO *dso;
@@ -1348,6 +1357,7 @@ PL_ARCH(mips) = {
/* 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,
diff --git a/trunk/src/arch-ppc.c b/trunk/src/arch-ppc.c
index 4bf5aca..99dbea5 100644
--- a/trunk/src/arch-ppc.c
+++ b/trunk/src/arch-ppc.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001, 2002, 2003, 2004, 2005 Red Hat, Inc.
+/* Copyright (C) 2001, 2002, 2003, 2004, 2005, 2009 Red Hat, Inc.
Written by Jakub Jelinek <jakub@redhat.com>, 2001.
This program is free software; you can redistribute it and/or modify
@@ -37,7 +37,7 @@
static int
ppc_adjust_dyn (DSO *dso, int n, GElf_Dyn *dyn, GElf_Addr start,
- GElf_Addr adjust)
+ GElf_Addr adjust)
{
if (dyn->d_tag == DT_PPC_GOT)
{
@@ -116,7 +116,7 @@ ppc_adjust_dyn (DSO *dso, int n, GElf_Dyn *dyn, GElf_Addr start,
static int
ppc_adjust_rel (DSO *dso, GElf_Rel *rel, GElf_Addr start,
- GElf_Addr adjust)
+ GElf_Addr adjust)
{
error (0, 0, "%s: PowerPC doesn't support REL relocs", dso->filename);
return 1;
@@ -124,7 +124,7 @@ ppc_adjust_rel (DSO *dso, GElf_Rel *rel, GElf_Addr start,
static int
ppc_adjust_rela (DSO *dso, GElf_Rela *rela, GElf_Addr start,
- GElf_Addr adjust)
+ GElf_Addr adjust)
{
if (GELF_R_TYPE (rela->r_info) == R_PPC_RELATIVE)
{
@@ -143,7 +143,7 @@ ppc_adjust_rela (DSO *dso, GElf_Rela *rela, GElf_Addr start,
static int
ppc_prelink_rel (struct prelink_info *info, GElf_Rel *rel,
- GElf_Addr reladdr)
+ GElf_Addr reladdr)
{
error (0, 0, "%s: PowerPC doesn't support REL relocs", info->dso->filename);
return 1;
@@ -201,7 +201,7 @@ ppc_fixup_plt (DSO *dso, GElf_Rela *rela, GElf_Addr value)
static int
ppc_prelink_rela (struct prelink_info *info, GElf_Rela *rela,
- GElf_Addr relaaddr)
+ GElf_Addr relaaddr)
{
DSO *dso = info->dso;
GElf_Addr value;
@@ -330,7 +330,7 @@ ppc_prelink_rela (struct prelink_info *info, GElf_Rela *rela,
static int
ppc_apply_conflict_rela (struct prelink_info *info, GElf_Rela *rela,
- char *buf)
+ char *buf, GElf_Addr dest_addr)
{
switch (GELF_R_TYPE (rela->r_info))
{
@@ -418,7 +418,7 @@ ppc_apply_rela (struct prelink_info *info, GElf_Rela *rela, char *buf)
static int
ppc_prelink_conflict_rel (DSO *dso, struct prelink_info *info,
- GElf_Rel *rel, GElf_Addr reladdr)
+ GElf_Rel *rel, GElf_Addr reladdr)
{
error (0, 0, "%s: PowerPC doesn't support REL relocs", dso->filename);
return 1;
@@ -426,7 +426,7 @@ ppc_prelink_conflict_rel (DSO *dso, struct prelink_info *info,
static int
ppc_prelink_conflict_rela (DSO *dso, struct prelink_info *info,
- GElf_Rela *rela, GElf_Addr relaaddr)
+ GElf_Rela *rela, GElf_Addr relaaddr)
{
GElf_Addr value;
struct prelink_conflict *conflict;
@@ -435,7 +435,8 @@ ppc_prelink_conflict_rela (DSO *dso, struct prelink_info *info,
int r_type;
if (GELF_R_TYPE (rela->r_info) == R_PPC_RELATIVE
- || GELF_R_TYPE (rela->r_info) == R_PPC_NONE)
+ || GELF_R_TYPE (rela->r_info) == R_PPC_NONE
+ || info->dso == dso)
/* Fast path: nothing to do. */
return 0;
conflict = prelink_conflict (info, GELF_R_SYM (rela->r_info),
@@ -459,6 +460,12 @@ ppc_prelink_conflict_rela (DSO *dso, struct prelink_info *info,
}
value = 0;
}
+ else if (conflict->ifunc)
+ {
+ error (0, 0, "%s: STT_GNU_IFUNC not handled on PowerPC yet",
+ dso->filename);
+ return 1;
+ }
else
{
/* DTPREL wants to see only real conflicts, not lookups
@@ -1122,6 +1129,7 @@ PL_ARCH(ppc) = {
.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,
diff --git a/trunk/src/arch-ppc64.c b/trunk/src/arch-ppc64.c
index ec28ee8..6f9f644 100644
--- a/trunk/src/arch-ppc64.c
+++ b/trunk/src/arch-ppc64.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2002, 2003, 2004 Red Hat, Inc.
+/* 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
@@ -60,7 +60,7 @@ ppc64_adjust_section (DSO *dso, int n, GElf_Addr start, GElf_Addr adjust)
static int
ppc64_adjust_dyn (DSO *dso, int n, GElf_Dyn *dyn, GElf_Addr start,
- GElf_Addr adjust)
+ GElf_Addr adjust)
{
if (dyn->d_tag == DT_PPC64_GLINK && dyn->d_un.d_ptr >= start)
{
@@ -73,7 +73,7 @@ ppc64_adjust_dyn (DSO *dso, int n, GElf_Dyn *dyn, GElf_Addr start,
static int
ppc64_adjust_rel (DSO *dso, GElf_Rel *rel, GElf_Addr start,
- GElf_Addr adjust)
+ GElf_Addr adjust)
{
error (0, 0, "%s: PowerPC64 doesn't support REL relocs", dso->filename);
return 1;
@@ -81,7 +81,7 @@ ppc64_adjust_rel (DSO *dso, GElf_Rel *rel, GElf_Addr start,
static int
ppc64_adjust_rela (DSO *dso, GElf_Rela *rela, GElf_Addr start,
- GElf_Addr adjust)
+ GElf_Addr adjust)
{
if (GELF_R_TYPE (rela->r_info) == R_PPC64_RELATIVE)
{
@@ -306,7 +306,7 @@ ppc64_prelink_rela (struct prelink_info *info, GElf_Rela *rela,
static int
ppc64_apply_conflict_rela (struct prelink_info *info, GElf_Rela *rela,
- char *buf)
+ char *buf, GElf_Addr dest_addr)
{
switch (GELF_R_TYPE (rela->r_info))
{
@@ -439,7 +439,8 @@ ppc64_prelink_conflict_rela (DSO *dso, struct prelink_info *info,
int r_type;
if (GELF_R_TYPE (rela->r_info) == R_PPC64_RELATIVE
- || GELF_R_TYPE (rela->r_info) == R_PPC64_NONE)
+ || GELF_R_TYPE (rela->r_info) == R_PPC64_NONE
+ || info->dso == dso)
/* Fast path: nothing to do. */
return 0;
conflict = prelink_conflict (info, GELF_R_SYM (rela->r_info),
@@ -463,6 +464,12 @@ ppc64_prelink_conflict_rela (DSO *dso, struct prelink_info *info,
}
value = 0;
}
+ else if (conflict->ifunc)
+ {
+ error (0, 0, "%s: STT_GNU_IFUNC not handled on PowerPC64 yet",
+ dso->filename);
+ return 1;
+ }
else
{
/* DTPREL wants to see only real conflicts, not lookups
@@ -771,13 +778,12 @@ ppc64_reloc_class (int reloc_type)
{
switch (reloc_type)
{
- case R_PPC64_COPY: return RTYPE_CLASS_COPY;
- case R_PPC64_ADDR24: return RTYPE_CLASS_PLT;
+ 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_VALID;
+ return RTYPE_CLASS_PLT;
}
}
@@ -824,6 +830,7 @@ PL_ARCH(ppc64) = {
.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,
diff --git a/trunk/src/arch-s390.c b/trunk/src/arch-s390.c
index f2ca7e1..7907e83 100644
--- a/trunk/src/arch-s390.c
+++ b/trunk/src/arch-s390.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001, 2002, 2003, 2004 Red Hat, Inc.
+/* 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
@@ -67,7 +67,7 @@ s390_adjust_dyn (DSO *dso, int n, GElf_Dyn *dyn, GElf_Addr start,
static int
s390_adjust_rel (DSO *dso, GElf_Rel *rel, GElf_Addr start,
- GElf_Addr adjust)
+ GElf_Addr adjust)
{
error (0, 0, "%s: S390 doesn't support REL relocs", dso->filename);
return 1;
@@ -168,7 +168,7 @@ s390_prelink_rela (struct prelink_info *info, GElf_Rela *rela,
static int
s390_apply_conflict_rela (struct prelink_info *info, GElf_Rela *rela,
- char *buf)
+ char *buf, GElf_Addr dest_addr)
{
switch (GELF_R_TYPE (rela->r_info))
{
@@ -238,7 +238,8 @@ s390_prelink_conflict_rela (DSO *dso, struct prelink_info *info,
GElf_Rela *ret;
if (GELF_R_TYPE (rela->r_info) == R_390_RELATIVE
- || GELF_R_TYPE (rela->r_info) == R_390_NONE)
+ || GELF_R_TYPE (rela->r_info) == R_390_NONE
+ || info->dso == dso)
/* Fast path: nothing to do. */
return 0;
conflict = prelink_conflict (info, GELF_R_SYM (rela->r_info),
@@ -258,6 +259,12 @@ s390_prelink_conflict_rela (DSO *dso, struct prelink_info *info,
}
value = 0;
}
+ else if (conflict->ifunc)
+ {
+ error (0, 0, "%s: STT_GNU_IFUNC not handled on S390 yet",
+ dso->filename);
+ return 1;
+ }
else
{
/* DTPOFF wants to see only real conflicts, not lookups
@@ -482,6 +489,7 @@ PL_ARCH(s390) = {
.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,
diff --git a/trunk/src/arch-s390x.c b/trunk/src/arch-s390x.c
index e1c213b..8676fff 100644
--- a/trunk/src/arch-s390x.c
+++ b/trunk/src/arch-s390x.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001, 2002, 2003, 2004 Red Hat, Inc.
+/* 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
@@ -67,7 +67,7 @@ s390x_adjust_dyn (DSO *dso, int n, GElf_Dyn *dyn, GElf_Addr start,
static int
s390x_adjust_rel (DSO *dso, GElf_Rel *rel, GElf_Addr start,
- GElf_Addr adjust)
+ GElf_Addr adjust)
{
error (0, 0, "%s: S390 doesn't support REL relocs", dso->filename);
return 1;
@@ -75,7 +75,7 @@ s390x_adjust_rel (DSO *dso, GElf_Rel *rel, GElf_Addr start,
static int
s390x_adjust_rela (DSO *dso, GElf_Rela *rela, GElf_Addr start,
- GElf_Addr adjust)
+ GElf_Addr adjust)
{
Elf64_Addr addr;
@@ -108,7 +108,7 @@ s390x_prelink_rel (struct prelink_info *info, GElf_Rel *rel, GElf_Addr reladdr)
static int
s390x_prelink_rela (struct prelink_info *info, GElf_Rela *rela,
- GElf_Addr relaaddr)
+ GElf_Addr relaaddr)
{
DSO *dso = info->dso;
GElf_Addr value;
@@ -191,7 +191,7 @@ s390x_prelink_rela (struct prelink_info *info, GElf_Rela *rela,
static int
s390x_apply_conflict_rela (struct prelink_info *info, GElf_Rela *rela,
- char *buf)
+ char *buf, GElf_Addr dest_addr)
{
switch (GELF_R_TYPE (rela->r_info))
{
@@ -276,7 +276,7 @@ s390x_apply_rela (struct prelink_info *info, GElf_Rela *rela, char *buf)
static int
s390x_prelink_conflict_rel (DSO *dso, struct prelink_info *info, GElf_Rel *rel,
- GElf_Addr reladdr)
+ GElf_Addr reladdr)
{
error (0, 0, "%s: S390 doesn't support REL relocs", dso->filename);
return 1;
@@ -284,7 +284,7 @@ s390x_prelink_conflict_rel (DSO *dso, struct prelink_info *info, GElf_Rel *rel,
static int
s390x_prelink_conflict_rela (DSO *dso, struct prelink_info *info,
- GElf_Rela *rela, GElf_Addr relaaddr)
+ GElf_Rela *rela, GElf_Addr relaaddr)
{
GElf_Addr value;
struct prelink_conflict *conflict;
@@ -293,7 +293,8 @@ s390x_prelink_conflict_rela (DSO *dso, struct prelink_info *info,
int r_type;
if (GELF_R_TYPE (rela->r_info) == R_390_RELATIVE
- || GELF_R_TYPE (rela->r_info) == R_390_NONE)
+ || GELF_R_TYPE (rela->r_info) == R_390_NONE
+ || info->dso == dso)
/* Fast path: nothing to do. */
return 0;
conflict = prelink_conflict (info, GELF_R_SYM (rela->r_info),
@@ -313,6 +314,12 @@ s390x_prelink_conflict_rela (DSO *dso, struct prelink_info *info,
}
value = 0;
}
+ else if (conflict->ifunc)
+ {
+ error (0, 0, "%s: STT_GNU_IFUNC not handled on S390x yet",
+ dso->filename);
+ return 1;
+ }
else
{
/* DTPOFF wants to see only real conflicts, not lookups
@@ -598,6 +605,7 @@ PL_ARCH(s390x) = {
.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,
diff --git a/trunk/src/arch-sh.c b/trunk/src/arch-sh.c
index d851a4d..1b11312 100644
--- a/trunk/src/arch-sh.c
+++ b/trunk/src/arch-sh.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001, 2002, 2003, 2004 Red Hat, Inc.
+/* 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
@@ -30,7 +30,7 @@
static int
sh_adjust_dyn (DSO *dso, int n, GElf_Dyn *dyn, GElf_Addr start,
- GElf_Addr adjust)
+ GElf_Addr adjust)
{
if (dyn->d_tag == DT_PLTGOT)
{
@@ -67,7 +67,7 @@ sh_adjust_dyn (DSO *dso, int n, GElf_Dyn *dyn, GElf_Addr start,
static int
sh_adjust_rel (DSO *dso, GElf_Rel *rel, GElf_Addr start,
- GElf_Addr adjust)
+ GElf_Addr adjust)
{
error (0, 0, "%s: SH doesn't support REL relocs", dso->filename);
return 1;
@@ -75,7 +75,7 @@ sh_adjust_rel (DSO *dso, GElf_Rel *rel, GElf_Addr start,
static int
sh_adjust_rela (DSO *dso, GElf_Rela *rela, GElf_Addr start,
- GElf_Addr adjust)
+ GElf_Addr adjust)
{
Elf32_Addr data;
@@ -107,7 +107,7 @@ sh_prelink_rel (struct prelink_info *info, GElf_Rel *rel, GElf_Addr reladdr)
static int
sh_prelink_rela (struct prelink_info *info, GElf_Rela *rela,
- GElf_Addr relaaddr)
+ GElf_Addr relaaddr)
{
DSO *dso;
GElf_Addr value;
@@ -151,7 +151,7 @@ sh_prelink_rela (struct prelink_info *info, GElf_Rela *rela,
static int
sh_apply_conflict_rela (struct prelink_info *info, GElf_Rela *rela,
- char *buf)
+ char *buf, GElf_Addr dest_addr)
{
switch (GELF_R_TYPE (rela->r_info))
{
@@ -206,7 +206,7 @@ sh_apply_rela (struct prelink_info *info, GElf_Rela *rela, char *buf)
static int
sh_prelink_conflict_rel (DSO *dso, struct prelink_info *info, GElf_Rel *rel,
- GElf_Addr reladdr)
+ GElf_Addr reladdr)
{
error (0, 0, "%s: SH doesn't support REL relocs", dso->filename);
return 1;
@@ -214,20 +214,27 @@ sh_prelink_conflict_rel (DSO *dso, struct prelink_info *info, GElf_Rel *rel,
static int
sh_prelink_conflict_rela (DSO *dso, struct prelink_info *info,
- GElf_Rela *rela, GElf_Addr relaaddr)
+ 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)
+ || 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)
@@ -414,6 +421,7 @@ PL_ARCH(sh) = {
.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,
diff --git a/trunk/src/arch-sparc.c b/trunk/src/arch-sparc.c
index 6594c8f..e016a79 100644
--- a/trunk/src/arch-sparc.c
+++ b/trunk/src/arch-sparc.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001, 2002, 2004 Red Hat, Inc.
+/* 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
@@ -30,7 +30,7 @@
static int
sparc_adjust_dyn (DSO *dso, int n, GElf_Dyn *dyn, GElf_Addr start,
- GElf_Addr adjust)
+ GElf_Addr adjust)
{
if (dyn->d_tag == DT_PLTGOT)
{
@@ -55,7 +55,7 @@ sparc_adjust_dyn (DSO *dso, int n, GElf_Dyn *dyn, GElf_Addr start,
static int
sparc_adjust_rel (DSO *dso, GElf_Rel *rel, GElf_Addr start,
- GElf_Addr adjust)
+ GElf_Addr adjust)
{
error (0, 0, "%s: Sparc doesn't support REL relocs", dso->filename);
return 1;
@@ -63,7 +63,7 @@ sparc_adjust_rel (DSO *dso, GElf_Rel *rel, GElf_Addr start,
static int
sparc_adjust_rela (DSO *dso, GElf_Rela *rela, GElf_Addr start,
- GElf_Addr adjust)
+ GElf_Addr adjust)
{
if (GELF_R_TYPE (rela->r_info) == R_SPARC_RELATIVE)
{
@@ -235,7 +235,7 @@ sparc_prelink_rela (struct prelink_info *info, GElf_Rela *rela,
static int
sparc_apply_conflict_rela (struct prelink_info *info, GElf_Rela *rela,
- char *buf)
+ char *buf, GElf_Addr dest_addr)
{
switch (GELF_R_TYPE (rela->r_info))
{
@@ -333,7 +333,8 @@ sparc_prelink_conflict_rela (DSO *dso, struct prelink_info *info,
int r_type;
if (GELF_R_TYPE (rela->r_info) == R_SPARC_RELATIVE
- || GELF_R_TYPE (rela->r_info) == R_SPARC_NONE)
+ || 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),
@@ -355,6 +356,12 @@ sparc_prelink_conflict_rela (DSO *dso, struct prelink_info *info,
}
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
@@ -607,6 +614,7 @@ PL_ARCH(sparc) = {
.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,
diff --git a/trunk/src/arch-sparc64.c b/trunk/src/arch-sparc64.c
index 70d3fd7..aee4601 100644
--- a/trunk/src/arch-sparc64.c
+++ b/trunk/src/arch-sparc64.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001, 2002, 2004 Red Hat, Inc.
+/* 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
@@ -32,7 +32,7 @@
static int
sparc64_adjust_dyn (DSO *dso, int n, GElf_Dyn *dyn, GElf_Addr start,
- GElf_Addr adjust)
+ GElf_Addr adjust)
{
if (dyn->d_tag == DT_PLTGOT)
{
@@ -57,7 +57,7 @@ sparc64_adjust_dyn (DSO *dso, int n, GElf_Dyn *dyn, GElf_Addr start,
static int
sparc64_adjust_rel (DSO *dso, GElf_Rel *rel, GElf_Addr start,
- GElf_Addr adjust)
+ GElf_Addr adjust)
{
error (0, 0, "%s: Sparc doesn't support REL relocs", dso->filename);
return 1;
@@ -65,7 +65,7 @@ sparc64_adjust_rel (DSO *dso, GElf_Rel *rel, GElf_Addr start,
static int
sparc64_adjust_rela (DSO *dso, GElf_Rela *rela, GElf_Addr start,
- GElf_Addr adjust)
+ GElf_Addr adjust)
{
if (SPARC64_R_TYPE (rela->r_info) == R_SPARC_RELATIVE)
{
@@ -84,7 +84,7 @@ sparc64_adjust_rela (DSO *dso, GElf_Rela *rela, GElf_Addr start,
static int
sparc64_prelink_rel (struct prelink_info *info, GElf_Rel *rel,
- GElf_Addr reladdr)
+ GElf_Addr reladdr)
{
error (0, 0, "%s: Sparc doesn't support REL relocs", info->dso->filename);
return 1;
@@ -166,7 +166,7 @@ sparc64_fixup_plt (DSO *dso, GElf_Rela *rela, GElf_Addr value)
static int
sparc64_prelink_rela (struct prelink_info *info, GElf_Rela *rela,
- GElf_Addr relaaddr)
+ GElf_Addr relaaddr)
{
DSO *dso = info->dso;
GElf_Addr value;
@@ -309,7 +309,7 @@ sparc64_prelink_rela (struct prelink_info *info, GElf_Rela *rela,
static int
sparc64_apply_conflict_rela (struct prelink_info *info, GElf_Rela *rela,
- char *buf)
+ char *buf, GElf_Addr dest_addr)
{
switch (SPARC64_R_TYPE (rela->r_info))
{
@@ -425,7 +425,7 @@ sparc64_apply_rela (struct prelink_info *info, GElf_Rela *rela, char *buf)
static int
sparc64_prelink_conflict_rel (DSO *dso, struct prelink_info *info,
- GElf_Rel *rel, GElf_Addr reladdr)
+ GElf_Rel *rel, GElf_Addr reladdr)
{
error (0, 0, "%s: Sparc doesn't support REL relocs", dso->filename);
return 1;
@@ -433,7 +433,7 @@ sparc64_prelink_conflict_rel (DSO *dso, struct prelink_info *info,
static int
sparc64_prelink_conflict_rela (DSO *dso, struct prelink_info *info,
- GElf_Rela *rela, GElf_Addr relaaddr)
+ GElf_Rela *rela, GElf_Addr relaaddr)
{
GElf_Addr value;
struct prelink_conflict *conflict;
@@ -442,7 +442,8 @@ sparc64_prelink_conflict_rela (DSO *dso, struct prelink_info *info,
int r_type;
if (SPARC64_R_TYPE (rela->r_info) == R_SPARC_RELATIVE
- || SPARC64_R_TYPE (rela->r_info) == R_SPARC_NONE)
+ || 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),
@@ -464,6 +465,12 @@ sparc64_prelink_conflict_rela (DSO *dso, struct prelink_info *info,
}
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
@@ -807,6 +814,7 @@ PL_ARCH(sparc64) = {
.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,
diff --git a/trunk/src/arch-x86_64.c b/trunk/src/arch-x86_64.c
index 8846672..83286e9 100644
--- a/trunk/src/arch-x86_64.c
+++ b/trunk/src/arch-x86_64.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001, 2002, 2003, 2004, 2006 Red Hat, Inc.
+/* Copyright (C) 2001, 2002, 2003, 2004, 2006, 2009 Red Hat, Inc.
Written by Jakub Jelinek <jakub@redhat.com>, 2001.
This program is free software; you can redistribute it and/or modify
@@ -30,7 +30,7 @@
static int
x86_64_adjust_dyn (DSO *dso, int n, GElf_Dyn *dyn, GElf_Addr start,
- GElf_Addr adjust)
+ GElf_Addr adjust)
{
if (dyn->d_tag == DT_PLTGOT)
{
@@ -75,7 +75,7 @@ x86_64_adjust_rel (DSO *dso, GElf_Rel *rel, GElf_Addr start,
static int
x86_64_adjust_rela (DSO *dso, GElf_Rela *rela, GElf_Addr start,
- GElf_Addr adjust)
+ GElf_Addr adjust)
{
Elf64_Addr addr;
@@ -89,6 +89,10 @@ x86_64_adjust_rela (DSO *dso, GElf_Rela *rela, GElf_Addr start,
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_ule64 (dso, rela->r_offset);
if (addr >= start)
@@ -113,7 +117,8 @@ x86_64_prelink_rela (struct prelink_info *info, GElf_Rela *rela,
GElf_Addr value;
dso = info->dso;
- if (GELF_R_TYPE (rela->r_info) == R_X86_64_NONE)
+ 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)
{
@@ -169,8 +174,9 @@ x86_64_prelink_rela (struct prelink_info *info, GElf_Rela *rela,
static int
x86_64_apply_conflict_rela (struct prelink_info *info, GElf_Rela *rela,
- char *buf)
+ char *buf, GElf_Addr dest_addr)
{
+ GElf_Rela *ret;
switch (GELF_R_TYPE (rela->r_info))
{
case R_X86_64_GLOB_DAT:
@@ -178,6 +184,16 @@ x86_64_apply_conflict_rela (struct prelink_info *info, GElf_Rela *rela,
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;
@@ -252,19 +268,24 @@ x86_64_prelink_conflict_rela (DSO *dso, struct prelink_info *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_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
@@ -288,7 +309,10 @@ x86_64_prelink_conflict_rela (DSO *dso, struct prelink_info *info,
/* 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;
@@ -422,6 +446,7 @@ x86_64_undo_prelink_rela (DSO *dso, GElf_Rela *rela, GElf_Addr relaaddr)
{
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);
@@ -505,6 +530,7 @@ PL_ARCH(x86_64) = {
.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,
diff --git a/trunk/src/conflict.c b/trunk/src/conflict.c
index cb0ba80..3181de1 100644
--- a/trunk/src/conflict.c
+++ b/trunk/src/conflict.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001, 2002, 2003, 2004 Red Hat, Inc.
+/* 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.
@@ -36,8 +36,12 @@ prelink_conflict (struct prelink_info *info, GElf_Word r_sym,
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;
- for (conflict = info->curconflicts; conflict; conflict = conflict->next)
+ 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;
@@ -278,7 +282,7 @@ conflict_rela_cmp (const void *A, const void *B)
int
get_relocated_mem (struct prelink_info *info, DSO *dso, GElf_Addr addr,
- char *buf, GElf_Word size)
+ char *buf, GElf_Word size, GElf_Addr dest_addr)
{
int sec = addr_to_sec (dso, addr), j;
Elf_Scn *scn;
@@ -323,7 +327,7 @@ get_relocated_mem (struct prelink_info *info, DSO *dso, GElf_Addr addr,
reloc offset. */
for (j = 0; j < info->conflict_rela_size; ++j)
{
- int reloc_type, reloc_size;
+ int reloc_type, reloc_size, ret;
off_t off;
if (info->conflict_rela[j].r_offset >= addr + size)
@@ -345,8 +349,12 @@ get_relocated_mem (struct prelink_info *info, DSO *dso, GElf_Addr addr,
return 2;
/* Note that apply_conflict_rela shouldn't rely on R_SYM
field of conflict to be 0. */
- dso->arch->apply_conflict_rela (info, info->conflict_rela + j,
- buf + off);
+ ret
+ = dso->arch->apply_conflict_rela (info, info->conflict_rela + j,
+ buf + off,
+ dest_addr ? dest_addr + off : 0);
+ if (ret)
+ return ret;
}
}
else
@@ -469,15 +477,17 @@ prelink_build_conflicts (struct prelink_info *info)
}
}
- for (i = 1; i < ndeps; ++i)
+ for (i = 0; i < ndeps; ++i)
{
+ int j, sec, first_conflict, maxidx;
+ struct prelink_conflict *conflict;
+
dso = info->dsos[i];
- ent = info->ent->depends[i - 1];
+ ent = i ? info->ent->depends[i - 1] : info->ent;
/* Verify .gnu.liblist sections of all dependent libraries. */
- if (ent->ndepends > 0)
+ if (i && ent->ndepends > 0)
{
- int j;
const char *name;
int nliblist;
Elf32_Lib *liblist;
@@ -541,83 +551,88 @@ prelink_build_conflicts (struct prelink_info *info)
}
}
- if (info->conflicts[i] || info->tls[i].modid)
+ 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)
{
- int j, sec, first_conflict;
- struct prelink_conflict *conflict;
-
- 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)
{
- error (0, 0, "Bad symtab");
- goto error_out;
+ 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;
}
- 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->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))
{
- if (! (dso->shdr[j].sh_flags & SHF_ALLOC))
- continue;
- switch (dso->shdr[j].sh_type)
- {
- case SHT_REL:
- if (prelink_conflict_rel (dso, j, info))
- goto error_out;
- break;
- case SHT_RELA:
- if (prelink_conflict_rela (dso, j, info))
- goto error_out;
- break;
- }
+ error (0, 0, "%s: Conflict %08llx not found in any relocation",
+ dso->filename, (unsigned long long) conflict->symoff);
+ ret = 1;
}
- if (dso->arch->arch_prelink_conflict
- && dso->arch->arch_prelink_conflict (dso, info))
- goto error_out;
+ /* 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
+ = GELF_R_INFO (i, GELF_R_TYPE (info->conflict_rela[j].r_info));
- for (conflict = info->curconflicts; conflict;
- conflict = conflict->next)
- if (! conflict->used)
- {
- error (0, 0, "%s: Conflict %08llx not found in any relocation",
- dso->filename, (unsigned long long) conflict->symoff);
- ret = 1;
- }
+ 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;
- /* 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;
- }
- }
+ 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;
+ }
}
}
@@ -755,11 +770,13 @@ prelink_build_conflicts (struct prelink_info *info)
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);
+ - 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);
+ - info->dynbss_base, cr.rela[i].r_addend,
+ cr.rela[i].r_offset);
switch (j)
{
diff --git a/trunk/src/cxx.c b/trunk/src/cxx.c
index abb97a5..438cdfe 100644
--- a/trunk/src/cxx.c
+++ b/trunk/src/cxx.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001, 2002, 2003 Red Hat, Inc.
+/* 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
@@ -16,6 +16,7 @@
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>
@@ -27,24 +28,168 @@
#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 *fcs, int reloc_size,
+ struct find_cxx_sym_cache **cache)
{
int n, ndeps = info->ent->ndepends + 1;
- int ndx, maxndx;
+ unsigned int hi, lo, mid;
DSO *dso = NULL;
- Elf_Scn *scn;
+ struct find_cxx_sym_cache *c;
if (fcs->dso == NULL
|| addr < fcs->dso->base
@@ -67,44 +212,76 @@ find_cxx_sym (struct prelink_info *info, GElf_Addr addr,
}
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->symsec = addr_to_sec (dso, dso->info[DT_SYMTAB]);
- if (fcs->symsec == -1)
+ 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)
{
- fcs->ent = NULL;
- return -1;
+ 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;
+ }
}
- scn = dso->scn[fcs->symsec];
- fcs->symtab = elf_getdata (scn, NULL);
- assert (elf_getdata (scn, fcs->symtab) == NULL);
- fcs->strsec = addr_to_sec (dso, dso->info[DT_STRTAB]);
- if (fcs->strsec == -1)
+ else
{
- fcs->ent = NULL;
- return -1;
+ 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;
+ }
}
- scn = dso->scn[fcs->strsec];
- fcs->strtab = elf_getdata (scn, NULL);
- assert (elf_getdata (scn, fcs->strtab) == NULL);
}
- else
- dso = fcs->dso;
-
- maxndx = fcs->symtab->d_size / dso->shdr[fcs->symsec].sh_entsize;
- for (ndx = 0; ndx < maxndx; ++ndx)
+ while (lo < hi)
{
- gelfx_getsym (dso->elf, fcs->symtab, ndx, &fcs->sym);
- if (fcs->sym.st_value <= addr
- && fcs->sym.st_value + fcs->sym.st_size >= addr + reloc_size)
- break;
+ 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;
}
- if (ndx == maxndx)
- return -1;
-
- return ndx;
+ return -1;
}
/* The idea here is that C++ virtual tables are always emitted
@@ -117,7 +294,8 @@ int
remove_redundant_cxx_conflicts (struct prelink_info *info)
{
int i, j, k, n, o, state, removed = 0;
- int ndx, maxndx, sec;
+ int ndx, sec;
+ unsigned int hi, lo, mid;
int reloc_type, reloc_size;
struct find_cxx_sym fcs1, fcs2;
char *mem1, *mem2;
@@ -127,24 +305,10 @@ remove_redundant_cxx_conflicts (struct prelink_info *info)
Elf_Data *binsymtab = NULL;
int binsymtabsec;
struct prelink_conflict *conflict;
- static struct
- {
- unsigned char *prefix;
- unsigned char prefix_len, st_info, check_pltref;
- unsigned char *section;
- }
- specials[] =
- {
- /* G++ 3.0 ABI. */
- /* Virtual table. */
- { "_ZTV", 4, GELF_ST_INFO (STB_WEAK, STT_OBJECT), 1, ".data" },
- /* Typeinfo. */
- { "_ZTI", 4, GELF_ST_INFO (STB_WEAK, STT_OBJECT), 0, ".data" },
- /* G++ 2.96-RH ABI. */
- /* Virtual table. */
- { "__vt_", 5, GELF_ST_INFO (STB_WEAK, STT_OBJECT), 0, ".data" },
- { NULL, 0, 0, 0, NULL }
- };
+ 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)
@@ -162,11 +326,19 @@ remove_redundant_cxx_conflicts (struct prelink_info *info)
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);
@@ -186,12 +358,16 @@ remove_redundant_cxx_conflicts (struct prelink_info *info)
}
n = find_cxx_sym (info, info->conflict_rela[i].r_offset,
- &fcs1, reloc_size);
+ &fcs1, reloc_size, cache);
- name = (const char *) fcs1.strtab->d_buf + fcs1.sym.st_name;
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)
@@ -201,31 +377,20 @@ remove_redundant_cxx_conflicts (struct prelink_info *info)
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
- && strcmp (secname, specials[k].section) == 0)
+ && strncmp (name, specials[k].prefix, specials[k].prefix_len) == 0)
break;
if (specials[k].prefix == NULL)
continue;
- /* Now check there are no other symbols pointing to it. */
- maxndx = fcs1.symtab->d_size / fcs1.dso->shdr[fcs1.symsec].sh_entsize;
- for (ndx = 0; ndx < maxndx; ++ndx)
- if (ndx != n)
- {
- GElf_Sym sym;
-
- gelfx_getsym (fcs1.dso->elf, fcs1.symtab, ndx, &sym);
- if ((sym.st_value + sym.st_size > fcs1.sym.st_value
- && sym.st_value < fcs1.sym.st_value + fcs1.sym.st_size)
- || sym.st_value == fcs1.sym.st_value)
- break;
- }
-
- if (ndx < maxndx)
+ if (strcmp (secname, ".data") != 0
+ && strcmp (secname, ".data.rel.ro") != 0
+ && strcmp (secname, ".sdata") != 0)
continue;
if (specials[k].check_pltref)
@@ -234,10 +399,13 @@ remove_redundant_cxx_conflicts (struct prelink_info *info)
symtab_start = fcs1.dso->shdr[fcs1.symsec].sh_addr - fcs1.dso->base;
symoff = symtab_start + n * fcs1.dso->shdr[fcs1.symsec].sh_entsize;
- for (conflict = info->conflicts[fcs1.n]; conflict;
+ 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)
+ && conflict->reloc_class == rtype_class_valid)
break;
if (conflict == NULL)
@@ -257,7 +425,13 @@ remove_redundant_cxx_conflicts (struct prelink_info *info)
goto check_pltref;
o = find_cxx_sym (info, conflict->lookup.ent->base + conflict->lookupval,
- &fcs2, fcs1.sym.st_size);
+ &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
@@ -271,15 +445,16 @@ remove_redundant_cxx_conflicts (struct prelink_info *info)
{
error (0, ENOMEM, "%s: Could not compare %s arrays",
info->dso->filename, name);
- return 1;
+ 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)
+ fcs1.sym.st_size, 0)
|| get_relocated_mem (info, fcs2.dso, fcs2.sym.st_value, mem2,
- fcs1.sym.st_size)
+ fcs1.sym.st_size, 0)
|| memcmp (mem1, mem2, fcs1.sym.st_size) != 0)
{
free (mem1);
@@ -314,50 +489,133 @@ check_pltref:
|| binsymtab == NULL)
continue;
- maxndx = binsymtab->d_size / info->dso->shdr[binsymtabsec].sh_entsize;
- for (ndx = 0; ndx < maxndx; ++ndx)
+ 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);
- if (sym.st_value == info->conflict_rela[i].r_addend)
+ assert (sym.st_value == info->conflict_rela[i].r_addend);
+ if (sym.st_shndx == SHN_UNDEF && sym.st_value)
{
- 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)
{
- struct prelink_symbol *s;
-
- 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)
- {
- for (conflict = info->conflicts[fcs1.n]; 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)
- {
- 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;
- }
- break;
- }
+ 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 =
+ GELF_R_INFO (1, GELF_R_TYPE (info->conflict_rela[i].r_info));
+ ++removed;
+ goto pltref_check_done;
+ }
+
+pltref_check_done:
break;
}
}
@@ -375,5 +633,11 @@ check_pltref:
info->conflict_rela_size = j;
}
- return 0;
+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/trunk/src/doit.c b/trunk/src/doit.c
index 2208ece..c94fc53 100644
--- a/trunk/src/doit.c
+++ b/trunk/src/doit.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001, 2003, 2004, 2005 Red Hat, Inc.
+/* 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
@@ -38,6 +38,7 @@ 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;
@@ -46,39 +47,14 @@ find_ents (void **p, void *info)
}
static void
-clear_ent_marks (struct prelink_entry *ent)
-{
- int i;
-
- ent->u.tmp = 0;
- for (i = 0; i < ent->ndepends; ++i)
- clear_ent_marks (ent->depends[i]);
-}
-
-static struct prelink_entry *
-find_unlisted_dependency (struct prelink_entry *ent)
-{
- int i;
- struct prelink_entry *ret;
-
- if (ent->u.tmp == 0)
- return ent;
- for (i = 0; i < ent->ndepends; ++i)
- if ((ret = find_unlisted_dependency (ent->depends[i])) != NULL)
- return ret;
- return NULL;
-}
-
-static void
prelink_ent (struct prelink_entry *ent)
{
- int i;
+ int i, j;
DSO *dso;
struct stat64 st;
struct prelink_link *hardlink;
char *move = NULL;
size_t movelen = 0;
- struct prelink_entry *dep;
for (i = 0; i < ent->ndepends; ++i)
if (ent->depends[i]->done == 1)
@@ -95,23 +71,31 @@ prelink_ent (struct prelink_entry *ent)
ent->filename, ent->depends[i]->filename);
return;
}
- else
- clear_ent_marks (ent->depends[i]);
ent->u.tmp = 1;
for (i = 0; i < ent->ndepends; ++i)
ent->depends[i]->u.tmp = 1;
-
- if ((dep = find_unlisted_dependency (ent)) != NULL)
+ for (i = 0; i < ent->ndepends; ++i)
{
- 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, dep->filename);
- return;
+ 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)
{
diff --git a/trunk/src/dso.c b/trunk/src/dso.c
index 3c61ff2..b3b6ee3 100644
--- a/trunk/src/dso.c
+++ b/trunk/src/dso.c
@@ -849,6 +849,7 @@ reopen_dso (DSO *dso, struct section_move *move, const char *temp_base)
}
else
{
+ memset (&data, 0, sizeof data);
data.d_type = ELF_T_NUM;
data1 = NULL;
while ((data1 = elf_getdata (dso->scn[j], data1))
diff --git a/trunk/src/dwarf2.c b/trunk/src/dwarf2.c
index a0a89dd..e831a18 100644
--- a/trunk/src/dwarf2.c
+++ b/trunk/src/dwarf2.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001, 2002, 2003, 2005, 2006 Red Hat, Inc.
+/* Copyright (C) 2001, 2002, 2003, 2005, 2006, 2009 Red Hat, Inc.
Written by Jakub Jelinek <jakub@redhat.com>, 2001.
This program is free software; you can redistribute it and/or modify
@@ -155,16 +155,18 @@ static struct
#define DEBUG_LINE 2
#define DEBUG_ARANGES 3
#define DEBUG_PUBNAMES 4
-#define DEBUG_MACINFO 5
-#define DEBUG_LOC 6
-#define DEBUG_STR 7
-#define DEBUG_FRAME 8
-#define DEBUG_RANGES 9
+#define DEBUG_PUBTYPES 5
+#define DEBUG_MACINFO 6
+#define DEBUG_LOC 7
+#define DEBUG_STR 8
+#define DEBUG_FRAME 9
+#define DEBUG_RANGES 10
{ ".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 },
@@ -191,6 +193,7 @@ struct cu_data
{
GElf_Addr cu_entry_pc;
GElf_Addr cu_low_pc;
+ unsigned char cu_version;
};
static hashval_t
@@ -250,7 +253,7 @@ no_memory:
}
if (*slot != NULL)
{
- error (0, 0, "%s: Duplicate DWARF-2 abbreviation %d", dso->filename,
+ error (0, 0, "%s: Duplicate DWARF abbreviation %d", dso->filename,
t->entry);
free (t);
htab_delete (h);
@@ -270,7 +273,7 @@ no_memory:
form = read_uleb128 (ptr);
if (form == 2 || form > DW_FORM_indirect)
{
- error (0, 0, "%s: Unknown DWARF-2 DW_FORM_%d", dso->filename, form);
+ error (0, 0, "%s: Unknown DWARF DW_FORM_%d", dso->filename, form);
htab_delete (h);
return NULL;
}
@@ -280,7 +283,7 @@ no_memory:
}
if (read_uleb128 (ptr) != 0)
{
- error (0, 0, "%s: DWARF-2 abbreviation does not end with 2 zeros",
+ error (0, 0, "%s: DWARF abbreviation does not end with 2 zeros",
dso->filename);
htab_delete (h);
return NULL;
@@ -340,8 +343,11 @@ adjust_location_list (DSO *dso, unsigned char *ptr, size_t len,
case DW_OP_reg0 ... DW_OP_reg31:
case DW_OP_nop:
case DW_OP_push_object_address:
- case DW_OP_call_ref:
+ 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:
@@ -360,6 +366,7 @@ adjust_location_list (DSO *dso, unsigned char *ptr, size_t len,
case DW_OP_const4u:
case DW_OP_const4s:
case DW_OP_call4:
+ case DW_OP_call_ref:
ptr += 4;
break;
case DW_OP_const8u:
@@ -376,11 +383,17 @@ adjust_location_list (DSO *dso, unsigned char *ptr, size_t len,
read_uleb128 (ptr);
break;
case DW_OP_bregx:
+ case DW_OP_bit_piece:
read_uleb128 (ptr);
read_uleb128 (ptr);
break;
+ case DW_OP_implicit_value:
+ {
+ uint32_t len = read_uleb128 (ptr);
+ ptr += len;
+ }
default:
- error (0, 0, "%s: Unknown DWARF-2 DW_OP_%d", dso->filename, op);
+ error (0, 0, "%s: Unknown DWARF DW_OP_%d", dso->filename, op);
return 1;
}
}
@@ -596,6 +609,11 @@ adjust_attributes (DSO *dso, unsigned char *ptr, struct abbrev_tag *t,
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:
ptr += 4;
break;
@@ -622,7 +640,7 @@ adjust_attributes (DSO *dso, unsigned char *ptr, struct abbrev_tag *t,
assert (len < UINT_MAX);
break;
default:
- error (0, 0, "%s: Unknown DWARF-2 DW_FORM_%d", dso->filename,
+ error (0, 0, "%s: Unknown DWARF DW_FORM_%d", dso->filename,
form);
return NULL;
}
@@ -645,7 +663,7 @@ adjust_attributes (DSO *dso, unsigned char *ptr, struct abbrev_tag *t,
|| (t->attr[i].attr >= DW_AT_sf_names
&& t->attr[i].attr <= DW_AT_body_end))
break;
- error (0, 0, "%s: Unknown DWARF-2 DW_AT_%d with block DW_FORM",
+ error (0, 0, "%s: Unknown DWARF DW_AT_%d with block DW_FORM",
dso->filename, t->attr[i].attr);
return NULL;
}
@@ -688,7 +706,7 @@ adjust_dwarf2_line (DSO *dso, GElf_Addr start, GElf_Addr adjust)
}
value = read_16 (ptr);
- if (value != 2)
+ if (value != 2 && value != 3)
{
error (0, 0, "%s: DWARF version %d unhandled", dso->filename,
value);
@@ -836,7 +854,13 @@ adjust_dwarf2_frame (DSO *dso, GElf_Addr start, GElf_Addr adjust)
if (value == 0xffffffff)
{
/* CIE. */
- ptr++; /* Skip version. */
+ uint32_t version = *ptr++;
+ if (version != 1 && version != 3)
+ {
+ error (0, 0, "%s: unhandled .debug_frame version %d",
+ dso->filename, version);
+ return 1;
+ }
if (*ptr != '\0')
{
error (0, 0, "%s: .debug_frame unhandled augmentation \"%s\"",
@@ -846,7 +870,10 @@ adjust_dwarf2_frame (DSO *dso, GElf_Addr start, GElf_Addr adjust)
ptr++; /* Skip augmentation. */
read_uleb128 (ptr); /* Skip code_alignment factor. */
read_uleb128 (ptr); /* Skip data_alignment factor. */
- read_uleb128 (ptr); /* Skip return_address_register. */
+ if (version >= 3)
+ read_uleb128 (ptr); /* Skip return_address_register. */
+ else
+ ptr++;
}
else
{
@@ -881,6 +908,8 @@ adjust_dwarf2_frame (DSO *dso, GElf_Addr start, GElf_Addr adjust)
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:
@@ -907,6 +936,7 @@ adjust_dwarf2_frame (DSO *dso, GElf_Addr start, GElf_Addr adjust)
ptr += 4;
break;
case DW_CFA_expression:
+ case DW_CFA_val_expression:
read_uleb128 (ptr);
/* FALLTHROUGH */
case DW_CFA_def_cfa_expression:
@@ -1041,12 +1071,13 @@ adjust_dwarf2 (DSO *dso, int n, GElf_Addr start, GElf_Addr adjust)
}
value = read_16 (ptr);
- if (value != 2)
+ if (value != 2 && value != 3)
{
error (0, 0, "%s: DWARF version %d unhandled", dso->filename,
value);
return 1;
}
+ cu.cu_version = value;
value = read_32 (ptr);
if (value >= debug_sections[DEBUG_ABBREV].size)
@@ -1054,7 +1085,7 @@ adjust_dwarf2 (DSO *dso, int n, GElf_Addr start, GElf_Addr adjust)
if (debug_sections[DEBUG_ABBREV].data == NULL)
error (0, 0, "%s: .debug_abbrev not present", dso->filename);
else
- error (0, 0, "%s: DWARF-2 CU abbrev offset too large",
+ error (0, 0, "%s: DWARF CU abbrev offset too large",
dso->filename);
return 1;
}
@@ -1074,14 +1105,14 @@ adjust_dwarf2 (DSO *dso, int n, GElf_Addr start, GElf_Addr adjust)
}
else
{
- error (0, 0, "%s: Invalid DWARF-2 pointer size %d",
+ error (0, 0, "%s: Invalid DWARF pointer size %d",
dso->filename, ptr_size);
return 1;
}
}
else if (read_1 (ptr) != ptr_size)
{
- error (0, 0, "%s: DWARF-2 pointer size differs between CUs",
+ error (0, 0, "%s: DWARF pointer size differs between CUs",
dso->filename);
return 1;
}
@@ -1102,7 +1133,7 @@ adjust_dwarf2 (DSO *dso, int n, GElf_Addr start, GElf_Addr adjust)
t = htab_find_with_hash (abbrev, &tag, tag.entry);
if (t == NULL)
{
- error (0, 0, "%s: Could not find DWARF-2 abbreviation %d",
+ error (0, 0, "%s: Could not find DWARF abbreviation %d",
dso->filename, tag.entry);
htab_delete (abbrev);
return 1;
@@ -1138,6 +1169,7 @@ adjust_dwarf2 (DSO *dso, int n, GElf_Addr start, GElf_Addr adjust)
/* .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. */
diff --git a/trunk/src/dwarf2.h b/trunk/src/dwarf2.h
index 1f938f5..143a00b 100644
--- a/trunk/src/dwarf2.h
+++ b/trunk/src/dwarf2.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001, 2002 Red Hat, Inc.
+/* Copyright (C) 2001, 2002, 2009 Red Hat, Inc.
Written by Jakub Jelinek <jakub@redhat.com>, 2001.
This program is free software; you can redistribute it and/or modify
@@ -71,6 +71,8 @@
#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_MIPS_loop 0x4081
#define DW_TAG_format_label 0x4101
#define DW_TAG_function_template 0x4102
@@ -348,7 +350,14 @@
#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_lo_user 0xe0
#define DW_OP_hi_user 0xff
@@ -362,6 +371,12 @@
#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
@@ -437,6 +452,9 @@
#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
@@ -468,6 +486,11 @@
#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_Mips_Assembler 0x8001
#define DW_LANG_lo_user 0x8000
#define DW_LANG_hi_user 0xffff
diff --git a/trunk/src/fptr.c b/trunk/src/fptr.c
index 7602d5e..cfe3aed 100644
--- a/trunk/src/fptr.c
+++ b/trunk/src/fptr.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001, 2002, 2003 Red Hat, Inc.
+/* 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
@@ -147,17 +147,21 @@ opd_init (struct prelink_info *info)
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]; conflict;
+ for (conflict = info->conflicts[i + 1].hash[symoff % maxidx]; conflict;
conflict = conflict->next)
{
- if (conflict->symoff == ol->u.refs[j].symoff
+ if (conflict->symoff == symoff
&& conflict->reloc_class != RTYPE_CLASS_COPY
&& conflict->reloc_class != RTYPE_CLASS_TLS)
break;
@@ -183,6 +187,7 @@ opd_init (struct prelink_info *info)
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)
@@ -190,7 +195,9 @@ opd_init (struct prelink_info *info)
assert (k < info->ent->ndepends);
- for (conflict = info->conflicts[k + 1]; conflict;
+ 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
diff --git a/trunk/src/gather.c b/trunk/src/gather.c
index 958a8ad..16ed21b 100644
--- a/trunk/src/gather.c
+++ b/trunk/src/gather.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006 Red Hat, Inc.
+/* 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
@@ -1077,6 +1077,8 @@ gather_object (const char *name, int deref, int onefs)
++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;
@@ -1087,13 +1089,20 @@ gather_object (const char *name, int deref, int onefs)
return gather_binlib (name, &st);
}
+static struct config_line
+{
+ struct config_line *next;
+ char line[1];
+} *config_lines, **config_end = &config_lines;
+
int
-gather_config (const char *config)
+read_config (const char *config)
{
FILE *file = fopen (config, "r");
char *line = NULL;
- size_t len;
+ size_t len, llen;
int ret = 0;
+ struct config_line *c;
if (file == NULL)
{
@@ -1101,12 +1110,9 @@ gather_config (const char *config)
return 1;
}
- implicit = 1;
do
{
ssize_t i = getline (&line, &len, file);
- int deref = 0;
- int onefs = 0;
char *p;
if (i < 0)
@@ -1120,6 +1126,62 @@ gather_config (const char *config)
*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 (!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 == '-')
{
@@ -1127,7 +1189,7 @@ gather_config (const char *config)
{
case 'h': deref = 1; break;
case 'l': onefs = 1; break;
- case 'b': *p = '\0'; continue;
+ case 'b': p = ""; continue;
default:
error (0, 0, "Unknown directory option `%s'\n", p);
break;
@@ -1170,10 +1232,8 @@ gather_config (const char *config)
break;
}
}
- } while (!feof (file));
+ }
- free (line);
- fclose (file);
implicit = 0;
return ret;
}
@@ -1351,39 +1411,18 @@ add_blacklist_ext (const char *ext)
}
int
-blacklist_from_config (const char *config)
+blacklist_from_config (void)
{
- FILE *file = fopen (config, "r");
- char *line = NULL;
- size_t len;
+ struct config_line *c;
int ret = 0;
- if (file == NULL)
- {
- error (0, errno, "Can't open configuration file %s", config);
- return 1;
- }
-
implicit = 1;
- do
+ for (c = config_lines; c; c = c->next)
{
- ssize_t i = getline (&line, &len, file);
int deref = 0;
int onefs = 0;
int blacklist = 0;
- 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");
+ char *p = c->line;
while (*p == '-')
{
@@ -1437,10 +1476,8 @@ blacklist_from_config (const char *config)
break;
}
}
- } while (!feof (file));
+ }
- free (line);
- fclose (file);
implicit = 0;
return ret;
}
diff --git a/trunk/src/get.c b/trunk/src/get.c
index 0ae418b..001bb1e 100644
--- a/trunk/src/get.c
+++ b/trunk/src/get.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001, 2002, 2003, 2004, 2005 Red Hat, Inc.
+/* 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
@@ -39,6 +39,27 @@ is_ldso_soname (const char *soname)
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)
@@ -208,18 +229,20 @@ prelink_record_relocations (struct prelink_info *info, FILE *f,
if (dso->ehdr.e_type == ET_EXEC || dso->arch->create_opd)
{
- info->conflicts = (struct prelink_conflict **)
- calloc (sizeof (struct prelink_conflict *), ndeps);
+ 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;
+ int reloc_class, len, type = 1, ifunc = 0;
char *symname;
r = strchr (buffer, '\n');
@@ -253,14 +276,26 @@ prelink_record_relocations (struct prelink_info *info, FILE *f,
if (type)
reloc_class = dso->arch->reloc_class (reloc_class);
else
- reloc_class |= RTYPE_CLASS_VALID;
+ {
+ 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 && info->conflicts))
+ || ((reloc_class == RTYPE_CLASS_TLS || ifunc)
+ && info->conflicts))
{
for (i = 0; i < ndeps; i++)
if (deps[i].start == valstart[0])
@@ -289,7 +324,7 @@ prelink_record_relocations (struct prelink_info *info, FILE *f,
}
}
- if (symstart == deps[0].start)
+ 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)
@@ -299,7 +334,8 @@ prelink_record_relocations (struct prelink_info *info, FILE *f,
goto error_out;
}
- if (ent == info->ent && reloc_class != RTYPE_CLASS_TLS)
+ 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)
@@ -344,12 +380,14 @@ prelink_record_relocations (struct prelink_info *info, FILE *f,
s->next = NULL;
}
}
- else if (reloc_class == RTYPE_CLASS_TLS && info->conflicts)
+ else if ((reloc_class == RTYPE_CLASS_TLS || ifunc)
+ && info->conflicts)
{
struct prelink_conflict *conflict;
int symowner;
+ size_t idx;
- for (symowner = 1; symowner < ndeps; symowner++)
+ for (symowner = 0; symowner < ndeps; symowner++)
if (deps[symowner].start == symstart)
break;
if (symowner == ndeps)
@@ -359,13 +397,20 @@ prelink_record_relocations (struct prelink_info *info, FILE *f,
goto error_out;
}
- for (conflict = info->conflicts[symowner]; conflict;
+ 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 (conflict->lookup.tls != tls
- || conflict->conflict.tls != tls
+ 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])
{
@@ -384,15 +429,27 @@ prelink_record_relocations (struct prelink_info *info, FILE *f,
goto error_out;
}
- conflict->next = info->conflicts[symowner];
- info->conflicts[symowner] = conflict;
- conflict->lookup.tls = tls;
- conflict->conflict.tls = tls;
+ 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;
+ if (++info->conflicts[symowner].count == 16)
+ conflict_hash_init (&info->conflicts[symowner]);
}
}
}
@@ -423,7 +480,18 @@ prelink_record_relocations (struct prelink_info *info, FILE *f,
if (type)
reloc_class = dso->arch->reloc_class (reloc_class);
else
- reloc_class |= RTYPE_CLASS_VALID;
+ {
+ 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;
@@ -439,6 +507,7 @@ prelink_record_relocations (struct prelink_info *info, FILE *f,
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)
@@ -480,7 +549,11 @@ prelink_record_relocations (struct prelink_info *info, FILE *f,
}
}
- for (conflict = info->conflicts[symowner]; conflict;
+ 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)
@@ -509,8 +582,9 @@ prelink_record_relocations (struct prelink_info *info, FILE *f,
goto error_out;
}
- conflict->next = info->conflicts[symowner];
- info->conflicts[symowner] = conflict;
+ 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];
@@ -526,6 +600,9 @@ prelink_record_relocations (struct prelink_info *info, FILE *f,
conflict->symoff = symoff;
conflict->reloc_class = reloc_class;
conflict->used = 0;
+ conflict->ifunc = ifunc;
+ if (++info->conflicts[symowner].count == 16)
+ conflict_hash_init (&info->conflicts[symowner]);
}
}
}
diff --git a/trunk/src/main.c b/trunk/src/main.c
index 7c3e1a4..2c442e8 100644
--- a/trunk/src/main.c
+++ b/trunk/src/main.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001, 2002, 2003, 2004, 2005 Red Hat, Inc.
+/* Copyright (C) 2001, 2002, 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
@@ -453,13 +453,16 @@ main (int argc, char *argv[])
return failures;
}
- if (blacklist_from_config (prelink_conf))
+ if (read_config (prelink_conf))
+ return EXIT_FAILURE;
+
+ if (blacklist_from_config ())
return EXIT_FAILURE;
if (quick)
prelink_load_cache ();
- if (gather_config (prelink_conf))
+ if (gather_config ())
return EXIT_FAILURE;
while (remaining < argc)
diff --git a/trunk/src/prelink.c b/trunk/src/prelink.c
index 663a071..0798811 100644
--- a/trunk/src/prelink.c
+++ b/trunk/src/prelink.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006 Red Hat, Inc.
+/* 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
@@ -817,15 +817,37 @@ free_info (struct prelink_info *info)
{
for (i = 0; i < info->ent->ndepends + 1; ++i)
{
- struct prelink_conflict *c = info->conflicts[i];
- void *f;
+ if (info->conflicts[i].hash == &info->conflicts[i].first)
+ {
+ struct prelink_conflict *c = info->conflicts[i].first;
+ void *f;
- while (c != NULL)
+ while (c != NULL)
+ {
+ f = c;
+ c = c->next;
+ free (f);
+ }
+ }
+ else
{
- f = c;
- c = c->next;
- free (f);
+ 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);
}
diff --git a/trunk/src/prelink.h b/trunk/src/prelink.h
index a50ddfe..78f775d 100644
--- a/trunk/src/prelink.h
+++ b/trunk/src/prelink.h
@@ -1,4 +1,5 @@
-/* Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006 Red Hat, Inc.
+/* Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2009
+ Red Hat, Inc.
Written by Jakub Jelinek <jakub@redhat.com>, 2001.
Updated by Maciej W. Rozycki <macro@codesourcery.com>, 2008.
@@ -103,6 +104,20 @@ typedef uint8_t Elf64_Byte;
#define RSS_UNDEF 0
#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
+
struct prelink_entry;
struct prelink_info;
struct PLArch;
@@ -180,6 +195,7 @@ struct PLArch
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,
@@ -198,7 +214,7 @@ struct PLArch
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);
+ 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);
@@ -416,6 +432,7 @@ struct prelink_symbol
struct prelink_conflict
{
struct prelink_conflict *next;
+ struct prelink_conflict *next2;
/* Object which it was relocated to. */
union
{
@@ -431,7 +448,16 @@ struct prelink_conflict
/* Value it has in conflict.ent. */
GElf_Addr conflictval;
int reloc_class;
- int used;
+ unsigned char used;
+ unsigned char ifunc;
+};
+
+struct prelink_conflicts
+{
+ struct prelink_conflict *first;
+ struct prelink_conflict **hash;
+ struct prelink_conflict **hash2;
+ size_t count;
};
#define conflict_lookup_value(cfl) \
@@ -444,8 +470,8 @@ struct prelink_info
DSO **dsos;
struct prelink_entry *ent;
struct prelink_symbol *symbols;
- struct prelink_conflict **conflicts;
- struct prelink_conflict *curconflicts;
+ struct prelink_conflicts *conflicts;
+ struct prelink_conflicts *curconflicts;
struct prelink_tls *tls, *curtls;
const char **sonames;
char *dynbss, *sdynbss;
@@ -488,17 +514,18 @@ int prelink_undo (DSO *dso);
int prelink_verify (const char *filename);
int gather_object (const char *dir, int deref, int onefs);
-int gather_config (const char *config);
+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 (const char *config);
+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);
+ char *buf, GElf_Word size, GElf_Addr dest_addr);
int layout_libs (void);
diff --git a/trunk/src/space.c b/trunk/src/space.c
index 35bcfc7..4bd4760 100644
--- a/trunk/src/space.c
+++ b/trunk/src/space.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001, 2002, 2003, 2004, 2006 Red Hat, Inc.
+/* 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
@@ -412,14 +412,20 @@ find_readonly_space (DSO *dso, GElf_Shdr *add, GElf_Ehdr *ehdr,
if (shdr[k].sh_addr > add->sh_addr)
{
/* Don't allow inserting in between reloc sections
- if they are adjacent. */
- if (shdr[k].sh_type != SHT_REL
- && shdr[k].sh_type != SHT_RELA)
+ 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 (shdr[k - 1].sh_type != SHT_REL
- && shdr[k - 1].sh_type != SHT_RELA)
+
+ if (sh_type1 != SHT_REL && sh_type1 != SHT_NOTE)
break;
- if (shdr[k - 1].sh_addr + shdr[k - 1].sh_size
+ if ((shdr[k - 1].sh_addr
+ + ((shdr[k - 1].sh_size + 3) & -4))
!= shdr[k].sh_addr)
break;
}
@@ -512,150 +518,208 @@ find_readonly_space (DSO *dso, GElf_Shdr *add, GElf_Ehdr *ehdr,
{
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;
- }
-
- 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;
- }
+ {
+ 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;
+ }
- 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)
+ 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)
{
- if (phdr[e].p_filesz != shdr[k].sh_size
- || phdr[e].p_memsz != shdr[k].sh_size)
+ 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)
{
- error (0, 0, "%s: Non-PT_LOAD segment spanning more than one section",
- dso->filename);
- return 0;
+ minsize = endaddr - addstart - add->sh_size;
+ movesec = j;
}
- 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;
+ 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 (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)
+ 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;
- 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;
- }
- }
- }
+ }
+
+ 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)
diff --git a/trunk/src/verify.c b/trunk/src/verify.c
index 8a3d89a..b04709b 100644
--- a/trunk/src/verify.c
+++ b/trunk/src/verify.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2002, 2003, 2006 Red Hat, Inc.
+/* Copyright (C) 2002, 2003, 2006, 2007 Red Hat, Inc.
Written by Jakub Jelinek <jakub@redhat.com>, 2002.
This program is free software; you can redistribute it and/or modify
@@ -227,7 +227,10 @@ prelink_verify (const char *filename)
goto failure;
}
- if (gather_config (prelink_conf))
+ if (read_config (prelink_conf))
+ goto failure;
+
+ if (gather_config ())
goto failure;
if (gather_object (filename, 0, 0))
diff --git a/trunk/testsuite/Makefile.am b/trunk/testsuite/Makefile.am
index 3af929b..0de603c 100644
--- a/trunk/testsuite/Makefile.am
+++ b/trunk/testsuite/Makefile.am
@@ -9,11 +9,12 @@ TESTS = movelibs.sh \
reloc1.sh reloc2.sh reloc3.sh reloc4.sh reloc5.sh reloc6.sh \
reloc7.sh reloc8.sh reloc9.sh reloc10.sh reloc11.sh \
shuffle1.sh shuffle2.sh shuffle3.sh shuffle4.sh shuffle5.sh \
- shuffle6.sh shuffle7.sh shuffle8.sh undo1.sh \
+ shuffle6.sh shuffle7.sh shuffle8.sh shuffle9.sh undo1.sh \
layout1.sh layout2.sh \
tls1.sh tls2.sh tls3.sh tls4.sh tls5.sh tls6.sh tls7.sh \
- cxx1.sh quick1.sh quick2.sh quick3.sh cycle1.sh cycle2.sh \
+ cxx1.sh cxx2.sh quick1.sh quick2.sh quick3.sh cycle1.sh cycle2.sh \
deps1.sh deps2.sh \
+ ifunc1.sh ifunc2.sh ifunc3.sh \
undosyslibs.sh
TESTS_ENVIRONMENT = \
PRELINK="../src/prelink -c ./prelink.conf -C ./prelink.cache --ld-library-path=. --dynamic-linker=`echo ./ld*.so.*[0-9]`" \
diff --git a/trunk/testsuite/Makefile.in b/trunk/testsuite/Makefile.in
index 205f6e3..395899f 100644
--- a/trunk/testsuite/Makefile.in
+++ b/trunk/testsuite/Makefile.in
@@ -104,11 +104,12 @@ TESTS = movelibs.sh \
reloc1.sh reloc2.sh reloc3.sh reloc4.sh reloc5.sh reloc6.sh \
reloc7.sh reloc8.sh reloc9.sh reloc10.sh reloc11.sh \
shuffle1.sh shuffle2.sh shuffle3.sh shuffle4.sh shuffle5.sh \
- shuffle6.sh shuffle7.sh shuffle8.sh undo1.sh \
+ shuffle6.sh shuffle7.sh shuffle8.sh shuffle9.sh undo1.sh \
layout1.sh layout2.sh \
tls1.sh tls2.sh tls3.sh tls4.sh tls5.sh tls6.sh tls7.sh \
- cxx1.sh quick1.sh quick2.sh quick3.sh cycle1.sh cycle2.sh \
+ cxx1.sh cxx2.sh quick1.sh quick2.sh quick3.sh cycle1.sh cycle2.sh \
deps1.sh deps2.sh \
+ ifunc1.sh ifunc2.sh ifunc3.sh \
undosyslibs.sh
TESTS_ENVIRONMENT = \
diff --git a/trunk/testsuite/cxx1.sh b/trunk/testsuite/cxx1.sh
index 81428c2..33f876d 100755
--- a/trunk/testsuite/cxx1.sh
+++ b/trunk/testsuite/cxx1.sh
@@ -11,10 +11,11 @@ savelibs
echo $PRELINK -vvvv ${PRELINK_OPTS--vm} ./cxx1 > cxx1.log
$PRELINK -vvvv ${PRELINK_OPTS--vm} ./cxx1 >> cxx1.log 2>&1 || exit 1
grep ^`echo $PRELINK | sed 's/ .*$/: /'` cxx1.log | grep -q -v 'C++ conflict' && exit 2
+[ $( grep ^`echo $PRELINK | sed 's/ .*$/: /'` cxx1.log | grep 'Removing C++ conflict' | wc -l ) -ge 5 ] || exit 3
if [ "x$CROSS" = "x" ]; then
- LD_LIBRARY_PATH=. ./cxx1 || exit 3
+ LD_LIBRARY_PATH=. ./cxx1 || exit 4
fi
-readelf -a ./cxx1 >> cxx1.log 2>&1 || exit 4
+readelf -a ./cxx1 >> cxx1.log 2>&1 || exit 5
# So that it is not prelinked again
chmod -x ./cxx1
-comparelibs >> cxx1.log 2>&1 || exit 5
+comparelibs >> cxx1.log 2>&1 || exit 6
diff --git a/trunk/testsuite/cxx2.C b/trunk/testsuite/cxx2.C
new file mode 100644
index 0000000..8b6e0bf
--- /dev/null
+++ b/trunk/testsuite/cxx2.C
@@ -0,0 +1,51 @@
+#include "cxx1.h"
+extern "C" void abort (void);
+
+int A::a ()
+{
+ return 30;
+}
+
+int A::b ()
+{
+ return 31;
+}
+
+int B::a ()
+{
+ return 32;
+}
+
+int C::a ()
+{
+ return 33;
+}
+
+int C::b ()
+{
+ return 34;
+}
+
+void
+check (A *x, B *y)
+{
+ C d;
+ if (x->b () != 31)
+ abort ();
+ if (y->B::a () != 32)
+ abort ();
+ if (d.a () != 33)
+ abort ();
+ if (d.C::b () != 34)
+ abort ();
+}
+
+int
+main ()
+{
+ A x;
+ if (x.a () != 30)
+ abort ();
+ do_check (check, &x);
+ return 0;
+}
diff --git a/trunk/testsuite/cxx2.sh b/trunk/testsuite/cxx2.sh
new file mode 100755
index 0000000..edad081
--- /dev/null
+++ b/trunk/testsuite/cxx2.sh
@@ -0,0 +1,19 @@
+#!/bin/bash
+. `dirname $0`/functions.sh
+rm -f cxx2 cxx2lib*.so cxx2.log
+rm -f prelink.cache
+$CXX -shared -O2 -fpic -o cxx2lib1.so $srcdir/cxx1lib1.C
+$CXX -shared -O2 -fpic -o cxx2lib2.so $srcdir/cxx1lib2.C cxx2lib1.so
+BINS="cxx2"
+LIBS="cxx2lib1.so cxx2lib2.so"
+$CXXLINK -o cxx2 $srcdir/cxx2.C -Wl,--rpath-link,. cxx2lib2.so
+savelibs
+echo $PRELINK -vvvv ${PRELINK_OPTS--vm} ./cxx2 > cxx2.log
+$PRELINK -vvvv ${PRELINK_OPTS--vm} ./cxx2 >> cxx2.log 2>&1 || exit 1
+grep ^`echo $PRELINK | sed 's/ .*$/: /'` cxx2.log | grep -q -v 'C++ conflict' && exit 2
+[ $( grep ^`echo $PRELINK | sed 's/ .*$/: /'` cxx2.log | grep 'Removing C++ conflict' | wc -l ) -ge 9 ] || exit 3
+LD_LIBRARY_PATH=. ./cxx2 || exit 4
+readelf -a ./cxx2 >> cxx2.log 2>&1 || exit 5
+# So that it is not prelinked again
+chmod -x ./cxx2
+comparelibs >> cxx2.log 2>&1 || exit 6
diff --git a/trunk/testsuite/ifunc.h b/trunk/testsuite/ifunc.h
new file mode 100644
index 0000000..3593396
--- /dev/null
+++ b/trunk/testsuite/ifunc.h
@@ -0,0 +1,33 @@
+#ifndef PICKNO
+# define PICKNO 1
+#endif
+#if PICKNO == 2
+# define PICK(fn1, fn2) #fn2
+#else
+# define PICK(fn1, fn2) #fn1
+#endif
+#ifdef __x86_64__
+# define IFUNC_ASM(fn) "\tleaq " fn "(%rip), %rax\n\tretq\n"
+#elif defined __i386__
+# ifdef __PIC__
+# define IFUNC_ASM(fn) "\tcall 1f\n1:\tpopl %ecx\n" \
+ "\taddl $_GLOBAL_OFFSET_TABLE_+[.-1b], %ecx\n" \
+ "\tleal " fn "@GOTOFF(%ecx), %eax\n\tret\n"
+# else
+# define IFUNC_ASM(fn) "\tmovl $" fn ", %eax\n\tret\n"
+# endif
+#else
+# error Architecture not supported
+#endif
+#define IFUNC(name, hidden, fn1, fn2) \
+extern __typeof (fn1) fn1 __attribute__((used)); \
+extern __typeof (fn2) fn2 __attribute__((used)); \
+extern __typeof (fn1) name; \
+asm (".globl " #name "\n" \
+ "\t" hidden " " #name "\n" \
+ "\t.type " #name ", @gnu_indirect_function\n" \
+ #name ":\n" \
+ IFUNC_ASM (PICK (fn1, fn2)) \
+ "\t.size " #name ", .-" #name "\n")
+#define IFUNC_LOCAL(name, fn1, fn2) IFUNC(name, ".hidden", fn1, fn2)
+#define IFUNC_GLOBAL(name, fn1, fn2) IFUNC(name, ".globl", fn1, fn2)
diff --git a/trunk/testsuite/ifunc1.c b/trunk/testsuite/ifunc1.c
new file mode 100644
index 0000000..f5500df
--- /dev/null
+++ b/trunk/testsuite/ifunc1.c
@@ -0,0 +1,29 @@
+#include "ifunc.h"
+
+static int bint11 (void) { return 1; }
+static int bint12 (void) { return 2; }
+
+IFUNC_LOCAL (bint1, bint11, bint12);
+
+static int lib2t21 (void) { return 1; }
+static int lib2t22 (void) { return 2; }
+
+IFUNC_GLOBAL (lib2t2, lib2t21, lib2t22);
+
+extern int lib1t2 (void);
+extern int lib1test (void);
+extern int lib2test (void);
+
+extern void abort (void);
+
+int
+main (void)
+{
+ lib1test ();
+ lib2test ();
+ if (bint1 () != PICKNO)
+ abort ();
+ if (lib1t2 () != PICKNO)
+ abort ();
+ return 0;
+}
diff --git a/trunk/testsuite/ifunc1.sh b/trunk/testsuite/ifunc1.sh
new file mode 100755
index 0000000..7746234
--- /dev/null
+++ b/trunk/testsuite/ifunc1.sh
@@ -0,0 +1,21 @@
+#!/bin/bash
+. `dirname $0`/functions.sh
+# First check if __thread is supported by ld.so/gcc/ld/as:
+$CCLINK -o ifunctest $srcdir/ifunctest.c -Wl,--rpath-link,. > /dev/null 2>&1 || exit 77
+( ./ifunctest || { rm -f ifunctest; exit 77; } ) 2>/dev/null || exit 77
+rm -f ifunctest ifunc1 ifunc1lib*.so ifunc1.log
+rm -f prelink.cache
+$CC -shared -O2 -fpic -o ifunc1lib1.so $srcdir/ifunc1lib1.c
+$CC -shared -O2 -fpic -o ifunc1lib2.so $srcdir/ifunc1lib2.c ifunc1lib1.so
+BINS="ifunc1"
+LIBS="ifunc1lib1.so ifunc1lib2.so"
+$CCLINK -o ifunc1 $srcdir/ifunc1.c -Wl,--rpath-link,. ifunc1lib2.so
+savelibs
+echo $PRELINK ${PRELINK_OPTS--vm} ./ifunc1 >> ifunc1.log
+$PRELINK ${PRELINK_OPTS--vm} ./ifunc1 >> ifunc1.log 2>&1 || exit 1
+grep -q ^`echo $PRELINK | sed 's/ .*$/: /'` ifunc1.log && exit 2
+LD_LIBRARY_PATH=. ./ifunc1 || exit 3
+readelf -a ./ifunc1 >> ifunc1.log 2>&1 || exit 4
+# So that it is not prelinked again
+chmod -x ./ifunc1
+comparelibs >> ifunc1.log 2>&1 || exit 5
diff --git a/trunk/testsuite/ifunc1lib1.c b/trunk/testsuite/ifunc1lib1.c
new file mode 100644
index 0000000..27a3f03
--- /dev/null
+++ b/trunk/testsuite/ifunc1lib1.c
@@ -0,0 +1,32 @@
+#include "ifunc.h"
+
+static int lib1t11 (void) { return 11; }
+static int lib1t12 (void) { return 12; }
+
+IFUNC_LOCAL (lib1t1, lib1t11, lib1t12);
+
+static int lib1t21 (void) { return 1; }
+static int lib1t22 (void) { return 2; }
+
+IFUNC_GLOBAL (lib1t2, lib1t21, lib1t22);
+
+static int lib1t31 (void) { return 3; }
+static int lib1t32 (void) { return 4; }
+
+IFUNC_GLOBAL (lib1t3, lib1t31, lib1t32);
+
+extern void abort (void);
+
+int (*lib1p1) (void) = lib1t1;
+
+int
+lib1test (void)
+{
+ if (lib1t1 () != PICKNO + 10)
+ abort ();
+ if (lib1t3 () != PICKNO)
+ abort ();
+ if (lib1p1 () != PICKNO + 10)
+ abort ();
+ return 0;
+}
diff --git a/trunk/testsuite/ifunc1lib2.c b/trunk/testsuite/ifunc1lib2.c
new file mode 100644
index 0000000..ca12e3d
--- /dev/null
+++ b/trunk/testsuite/ifunc1lib2.c
@@ -0,0 +1,39 @@
+#include "ifunc.h"
+
+static int lib2t11 (void) { return 1; }
+static int lib2t12 (void) { return 2; }
+
+IFUNC_LOCAL (lib2t1, lib2t11, lib2t12);
+
+static int lib2t21 (void) { return 3; }
+static int lib2t22 (void) { return 4; }
+
+IFUNC_GLOBAL (lib2t2, lib2t21, lib2t22);
+
+static int lib2t31 (void) { return 1; }
+static int lib2t32 (void) { return 2; }
+
+IFUNC_GLOBAL (lib2t3, lib2t31, lib2t32);
+
+static int lib1t31 (void) { return 1; }
+static int lib1t32 (void) { return 2; }
+
+IFUNC_GLOBAL (lib1t3, lib1t31, lib1t32);
+
+int (*lib2p1) (void) = lib2t2;
+
+extern void abort (void);
+
+int
+lib2test (void)
+{
+ if (lib2t1 () != PICKNO)
+ abort ();
+ if (lib2t2 () != PICKNO)
+ abort ();
+ if (lib2t3 () != PICKNO)
+ abort ();
+ if (lib2p1 () != PICKNO)
+ abort ();
+ return 0;
+}
diff --git a/trunk/testsuite/ifunc2.sh b/trunk/testsuite/ifunc2.sh
new file mode 100755
index 0000000..dea5bf4
--- /dev/null
+++ b/trunk/testsuite/ifunc2.sh
@@ -0,0 +1,21 @@
+#!/bin/bash
+. `dirname $0`/functions.sh
+# First check if __thread is supported by ld.so/gcc/ld/as:
+$CCLINK -o ifunctest $srcdir/ifunctest.c -Wl,--rpath-link,. > /dev/null 2>&1 || exit 77
+( ./ifunctest || { rm -f ifunctest; exit 77; } ) 2>/dev/null || exit 77
+rm -f ifunctest ifunc2 ifunc2lib*.so ifunc2.log
+rm -f prelink.cache
+$CC -shared -O2 -fpic -o ifunc2lib1.so $srcdir/ifunc1lib1.c -DPICKNO=2
+$CC -shared -O2 -fpic -o ifunc2lib2.so $srcdir/ifunc1lib2.c ifunc2lib1.so -DPICKNO=2
+BINS="ifunc2"
+LIBS="ifunc2lib1.so ifunc2lib2.so"
+$CCLINK -o ifunc2 $srcdir/ifunc1.c -Wl,--rpath-link,. ifunc2lib2.so -DPICKNO=2
+savelibs
+echo $PRELINK ${PRELINK_OPTS--vm} ./ifunc2 >> ifunc2.log
+$PRELINK ${PRELINK_OPTS--vm} ./ifunc2 >> ifunc2.log 2>&1 || exit 1
+grep -q ^`echo $PRELINK | sed 's/ .*$/: /'` ifunc2.log && exit 2
+LD_LIBRARY_PATH=. ./ifunc2 || exit 3
+readelf -a ./ifunc2 >> ifunc2.log 2>&1 || exit 4
+# So that it is not prelinked again
+chmod -x ./ifunc2
+comparelibs >> ifunc2.log 2>&1 || exit 5
diff --git a/trunk/testsuite/ifunc3.c b/trunk/testsuite/ifunc3.c
new file mode 100644
index 0000000..1f243d8
--- /dev/null
+++ b/trunk/testsuite/ifunc3.c
@@ -0,0 +1,32 @@
+#include "ifunc.h"
+
+static int bint11 (void) { return 1; }
+static int bint12 (void) { return 2; }
+
+IFUNC_LOCAL (bint1, bint11, bint12);
+
+static int lib2t21 (void) { return 1; }
+static int lib2t22 (void) { return 2; }
+
+IFUNC_GLOBAL (lib2t2, lib2t21, lib2t22);
+
+extern int lib1t2 (void);
+extern int lib1test (void);
+extern int lib2test (void);
+extern int (*lib1p1) (void);
+
+extern void abort (void);
+
+int
+main (void)
+{
+ lib1test ();
+ lib2test ();
+ if (bint1 () != PICKNO)
+ abort ();
+ if (lib1t2 () != PICKNO)
+ abort ();
+ if (lib1p1 () != PICKNO + 10)
+ abort ();
+ return 0;
+}
diff --git a/trunk/testsuite/ifunc3.sh b/trunk/testsuite/ifunc3.sh
new file mode 100755
index 0000000..a54d4ec
--- /dev/null
+++ b/trunk/testsuite/ifunc3.sh
@@ -0,0 +1,21 @@
+#!/bin/bash
+. `dirname $0`/functions.sh
+# First check if __thread is supported by ld.so/gcc/ld/as:
+$CCLINK -o ifunctest $srcdir/ifunctest.c -Wl,--rpath-link,. > /dev/null 2>&1 || exit 77
+( ./ifunctest || { rm -f ifunctest; exit 77; } ) 2>/dev/null || exit 77
+rm -f ifunctest ifunc3 ifunc3lib*.so ifunc3.log
+rm -f prelink.cache
+$CC -shared -O2 -fpic -o ifunc3lib1.so $srcdir/ifunc3lib1.c
+$CC -shared -O2 -fpic -o ifunc3lib2.so $srcdir/ifunc1lib2.c ifunc3lib1.so
+BINS="ifunc3"
+LIBS="ifunc3lib1.so ifunc3lib2.so"
+$CCLINK -o ifunc3 $srcdir/ifunc3.c -Wl,--rpath-link,. ifunc3lib2.so
+savelibs
+echo $PRELINK ${PRELINK_OPTS--vm} ./ifunc3 >> ifunc3.log
+$PRELINK ${PRELINK_OPTS--vm} ./ifunc3 >> ifunc3.log 2>&1 || exit 1
+grep -q ^`echo $PRELINK | sed 's/ .*$/: /'` ifunc3.log && exit 2
+LD_LIBRARY_PATH=. ./ifunc3 || exit 3
+readelf -a ./ifunc3 >> ifunc3.log 2>&1 || exit 4
+# So that it is not prelinked again
+chmod -x ./ifunc3
+comparelibs >> ifunc3.log 2>&1 || exit 5
diff --git a/trunk/testsuite/ifunc3lib1.c b/trunk/testsuite/ifunc3lib1.c
new file mode 100644
index 0000000..133b389
--- /dev/null
+++ b/trunk/testsuite/ifunc3lib1.c
@@ -0,0 +1,37 @@
+#include "ifunc.h"
+
+static int lib1t11 (void) { return 11; }
+static int lib1t12 (void) { return 12; }
+
+IFUNC_LOCAL (lib1t1, lib1t11, lib1t12);
+
+static int lib1t21 (void) { return 1; }
+static int lib1t22 (void) { return 2; }
+
+IFUNC_GLOBAL (lib1t2, lib1t21, lib1t22);
+
+static int lib1t31 (void) { return 3; }
+static int lib1t32 (void) { return 4; }
+
+IFUNC_GLOBAL (lib1t3, lib1t31, lib1t32);
+
+char lib1b1[4];
+char *lib1b2 = &lib1b1[2];
+
+extern void abort (void);
+
+int (*lib1p1) (void) = lib1t1;
+
+int
+lib1test (void)
+{
+ if (lib1t1 () != PICKNO + 10)
+ abort ();
+ if (lib1t3 () != PICKNO)
+ abort ();
+ if (lib1p1 () != PICKNO + 10)
+ abort ();
+ if (lib1b2 != lib1b1 + 2)
+ abort ();
+ return 0;
+}
diff --git a/trunk/testsuite/ifunctest.c b/trunk/testsuite/ifunctest.c
new file mode 100644
index 0000000..9ce7b1a
--- /dev/null
+++ b/trunk/testsuite/ifunctest.c
@@ -0,0 +1,16 @@
+#include "ifunc.h"
+
+static int foo1 (void) { return 1; }
+static int foo2 (void) { return 2; }
+
+IFUNC_LOCAL (foo, foo1, foo2);
+
+extern void abort (void);
+
+int
+main (void)
+{
+ if (foo () != PICKNO)
+ abort ();
+ return 0;
+}
diff --git a/trunk/testsuite/quick2.sh b/trunk/testsuite/quick2.sh
index 87138ae..1d64941 100755
--- a/trunk/testsuite/quick2.sh
+++ b/trunk/testsuite/quick2.sh
@@ -126,8 +126,12 @@ else
fi
cat > quick2.tree/etc/prelink.conf <<EOF
-b *.sh
--b *.py
--b b*11*r[hijk]*t
+-c quick2.tree/etc/prelink.conf.d/*.conf
+EOF
+mkdir quick2.tree/etc/prelink.conf.d
+echo '-b *.py' > quick2.tree/etc/prelink.conf.d/py.conf
+echo '-b b*11*r[hijk]*t' > quick2.tree/etc/prelink.conf.d/script.conf
+cat > quick2.tree/etc/prelink.conf.d/rest.conf <<EOF
quick2.tree/usr/bin
quick2.tree/lib
quick2.tree/usr/lib
diff --git a/trunk/testsuite/reloc2.sh b/trunk/testsuite/reloc2.sh
index 4d180c6..0ab76cd 100755
--- a/trunk/testsuite/reloc2.sh
+++ b/trunk/testsuite/reloc2.sh
@@ -2,9 +2,11 @@
. `dirname $0`/functions.sh
SHFLAGS=
case "`uname -m`" in
- ia64|ppc*|x86_64|mips*) SHFLAGS=-fpic;; # Does not support non-pic shared libs
+ ia64|ppc*|x86_64|mips*|arm*) SHFLAGS=-fpic;; # Does not support non-pic shared libs
s390*) if file reloc1lib1.so | grep -q 64-bit; then SHFLAGS=-fpic; fi;;
esac
+# Disable this test under SELinux if textrel
+test -z "$SHFLAGS" -a -x /usr/sbin/getenforce -a "`/usr/sbin/getenforce`" = Enforcing && exit 77
rm -f reloc2 reloc2lib*.so reloc2.log
$CC -shared $SHFLAGS -O2 -o reloc2lib1.so $srcdir/reloc2lib1.c
$CC -shared $SHFLAGS -O2 -o reloc2lib2.so $srcdir/reloc2lib2.c \
diff --git a/trunk/testsuite/reloc5.c b/trunk/testsuite/reloc5.c
index b174bcf..2caaf64 100644
--- a/trunk/testsuite/reloc5.c
+++ b/trunk/testsuite/reloc5.c
@@ -20,5 +20,6 @@ int main (void)
printf ("asm (\".section nonalloced,\\\"aw\\\",@nobits\\n\\t\"\n");
printf ("#endif\n");
printf (" \".globl testzero\\n\\t\"\n");
- printf (" \"testzero: .skip 16384\");\n");
+ printf (" \"testzero: .skip 16384\\n\\t\"\n");
+ printf (" \".previous\");\n");
}
diff --git a/trunk/testsuite/shuffle2.c b/trunk/testsuite/shuffle2.c
index c9f03ce..ed1af21 100644
--- a/trunk/testsuite/shuffle2.c
+++ b/trunk/testsuite/shuffle2.c
@@ -19,9 +19,11 @@ int main()
#ifdef __arm__
asm (".section nonalloced,\"aw\",%nobits\n\t"
".globl testzero\n\t"
- "testzero: .skip 16384");
+ "testzero: .skip 16384\n\t"
+ ".previous");
#else
asm (".section nonalloced,\"aw\",@nobits\n\t"
".globl testzero\n\t"
- "testzero: .skip 16384");
+ "testzero: .skip 16384\n\t"
+ ".previous");
#endif
diff --git a/trunk/testsuite/shuffle9.c b/trunk/testsuite/shuffle9.c
new file mode 100644
index 0000000..21ac534
--- /dev/null
+++ b/trunk/testsuite/shuffle9.c
@@ -0,0 +1,58 @@
+#include "reloc1.h"
+#include <stdlib.h>
+
+extern char testzero[16384];
+
+int main()
+{
+ int i;
+ if (foo.a != 1 || foo.b != &foo || foo.c != &bar || bar != 26)
+ abort ();
+ if (f1 () != 11 || f2 () != 12)
+ abort ();
+ for (i = 0; i < 16384; ++i)
+ if (testzero[i])
+ abort ();
+ exit (0);
+}
+
+asm (".section nonalloced,\"aw\",@nobits\n\t"
+ ".globl testzero\n\t"
+ "testzero: .skip 16384\n\t"
+ ".previous\n");
+
+asm (".section \".note.PRELINK.1\", \"a\"\n\t"
+ ".balign 4\n\t"
+ ".long 1f - 0f\n\t"
+ ".long 3f - 2f\n\t"
+ ".long 1\n"
+ "0:\t.asciz \"PRELINK\"\n"
+ "1:\t.balign 4\n"
+ "2:\t.long 12\n\t"
+ ".long 17\n"
+ "3:\t.balign 4\n\t"
+ ".previous\n");
+
+asm (".section \".note.PRELINK.2\", \"a\"\n\t"
+ ".balign 4\n\t"
+ ".long 1f - 0f\n\t"
+ ".long 3f - 2f\n\t"
+ ".long 2\n"
+ "0:\t.asciz \"PRELINK\"\n"
+ "1:\t.balign 4\n"
+ "2:\t.long 12\n\t"
+ ".long 17\n"
+ "3:\t.balign 4\n\t"
+ ".previous\n");
+
+asm (".section \".note.PRELINK.3\", \"a\"\n\t"
+ ".balign 4\n\t"
+ ".long 1f - 0f\n\t"
+ ".long 3f - 2f\n\t"
+ ".long 3\n"
+ "0:\t.asciz \"PRELINK\"\n"
+ "1:\t.balign 4\n"
+ "2:\t.long 12\n\t"
+ ".long 17\n"
+ "3:\t.balign 4\n\t"
+ ".previous\n");
diff --git a/trunk/testsuite/shuffle9.sh b/trunk/testsuite/shuffle9.sh
new file mode 100755
index 0000000..5768890
--- /dev/null
+++ b/trunk/testsuite/shuffle9.sh
@@ -0,0 +1,18 @@
+#!/bin/bash
+. `dirname $0`/functions.sh
+# Kernels before 2.4.10 are known not to work
+case "`uname -r`" in
+ [01].*|2.[0-3].*|2.4.[0-9]|2.4.[0-9][^0-9]*) exit 77;;
+esac
+rm -f shuffle9 shuffle9.log
+BINS="shuffle9"
+$CCLINK -o shuffle9 $srcdir/shuffle9.c -Wl,--rpath-link,. shuffle3lib2.so
+savelibs
+echo $PRELINK ${PRELINK_OPTS--vm} ./shuffle9 > shuffle9.log
+$PRELINK ${PRELINK_OPTS--vm} ./shuffle9 >> shuffle9.log 2>&1 || exit 1
+grep -q ^`echo $PRELINK | sed 's/ .*$/: /'` shuffle9.log && exit 2
+LD_LIBRARY_PATH=. ./shuffle9 || exit 3
+readelf -a ./shuffle9 >> shuffle9.log 2>&1 || exit 4
+# So that it is not prelinked again
+chmod -x ./shuffle9
+comparelibs >> shuffle9.log 2>&1 || exit 5
diff --git a/trunk/testsuite/tls3.sh b/trunk/testsuite/tls3.sh
index e7270e9..8d015d9 100755
--- a/trunk/testsuite/tls3.sh
+++ b/trunk/testsuite/tls3.sh
@@ -7,8 +7,10 @@ rm -f tlstest
#( ./tlstest || { rm -f tlstest; exit 77; } ) 2>/dev/null || exit 77
SHFLAGS=
case "`uname -m`" in
- ia64|ppc*|x86_64|alpha*|s390*|mips*) SHFLAGS=-fpic;; # Does not support non-pic shared libs
+ ia64|ppc*|x86_64|alpha*|s390*|mips*|arm*) SHFLAGS=-fpic;; # Does not support non-pic shared libs
esac
+# Disable this test under SELinux if textrel
+test -z "$SHFLAGS" -a -x /usr/sbin/getenforce -a "`/usr/sbin/getenforce`" = Enforcing && exit 77
rm -f tls3 tls3lib*.so tls3.log
rm -f prelink.cache
$CC -shared -O2 -fpic -o tls3lib1.so $srcdir/tls1lib1.c