diff options
Diffstat (limited to 'trunk')
-rw-r--r-- | trunk/ChangeLog.cross | 98 | ||||
-rw-r--r-- | trunk/configure.in | 5 | ||||
-rw-r--r-- | trunk/src/Makefile.am | 5 | ||||
-rw-r--r-- | trunk/src/arch-alpha.c | 2 | ||||
-rw-r--r-- | trunk/src/arch-arm.c | 2 | ||||
-rw-r--r-- | trunk/src/arch-cris.c | 2 | ||||
-rw-r--r-- | trunk/src/arch-i386.c | 2 | ||||
-rw-r--r-- | trunk/src/arch-ia64.c | 2 | ||||
-rw-r--r-- | trunk/src/arch-mips.c | 550 | ||||
-rw-r--r-- | trunk/src/arch-ppc.c | 2 | ||||
-rw-r--r-- | trunk/src/arch-ppc64.c | 2 | ||||
-rw-r--r-- | trunk/src/arch-s390.c | 2 | ||||
-rw-r--r-- | trunk/src/arch-s390x.c | 2 | ||||
-rw-r--r-- | trunk/src/arch-sh.c | 2 | ||||
-rw-r--r-- | trunk/src/arch-sparc.c | 2 | ||||
-rw-r--r-- | trunk/src/arch-sparc64.c | 2 | ||||
-rw-r--r-- | trunk/src/arch-x86_64.c | 2 | ||||
-rw-r--r-- | trunk/src/conflict.c | 34 | ||||
-rw-r--r-- | trunk/src/cxx.c | 12 | ||||
-rw-r--r-- | trunk/src/ld-libs.c | 9 | ||||
-rw-r--r-- | trunk/src/prelink.c | 1 | ||||
-rw-r--r-- | trunk/src/prelink.h | 13 | ||||
-rw-r--r-- | trunk/src/reloc-info.c | 215 | ||||
-rw-r--r-- | trunk/src/reloc-info.h | 35 |
24 files changed, 833 insertions, 170 deletions
diff --git a/trunk/ChangeLog.cross b/trunk/ChangeLog.cross index e57c8de..c8b30be 100644 --- a/trunk/ChangeLog.cross +++ b/trunk/ChangeLog.cross @@ -2,6 +2,104 @@ * Integrate prelinker/cross-prelinking patches + 2008-10-02 Maciej W. Rozycki <macro@codesourcery.com> + + * src/arch-mips.c (mips_prelink_reloc): Do not complain about + TLS_DTPMOD32 or TLS_DTPMOD64 relocations found in executables. + + 2008-09-03 Maciej W. Rozycki <macro@codesourcery.com> + + * src/prelink.h (Elf64_Byte): New definition. + (R_MIPS_TLS_DTPMOD64): New macro. + (R_MIPS_TLS_DTPREL64): Likewise. + (R_MIPS_TLS_TPREL64): Likewise. + (RSS_UNDEF): Likewise. + (PL_ARCH): Use plarch_##F as the name of the struct in all + variants. + * src/reloc-info.c: New file. + * src/reloc-info.h: Likewise. + * src/arch-mips.c (mips_buf_read_addr): New function. + (mips_buf_write_addr): Likewise. + (mips_arch_adjust): Replace calls to buf_read_une32() and + buf_write_ne32() with ones to mips_buf_read_addr() and + mips_buf_write_addr() respectively. + (mips_read_addend): Rename to... + (mips_read_32bit_addend): ... this. + (mips_write_addend): Rename to... + (mips_write_32bit_addend): ... this. + (mips_read_64bit_addend): New function. + (mips_write_64bit_addend): Likewise. + (mips_adjust_reloc): Handle 64-bit REL relocations. Use + reloc_r_sym() and reloc_r_type() in place of GELF_R_SYM() and + GELF_R_TYPE() respectively. + (mips_prelink_64bit_reloc): New function. + (mips_prelink_reloc): Handle 64-bit REL and GLOB_DAT relocations. + Handle TLS_DTPMOD64, TLS_DTPREL64 and TLS_TPREL64 relocations. + Use reloc_r_sym() and reloc_r_type(). + (mips_prelink_rel): Handle 64-bit REL relocations. Use + reloc_r_sym(), reloc_r_type() and reloc_r_info_ext() (replacing + GELF_R_INFO()). + (mips_prelink_conflict_reloc): Handle 64-bit REL relocations. + Handle TLS_DTPMOD64, TLS_DTPREL64 and TLS_TPREL64 relocations. + Use reloc_r_sym(), reloc_r_type() and reloc_r_info_ext(). + (mips_arch_prelink_conflict): Use mips_buf_read_addr(). Use + reloc_r_info_ext(). + (mips_apply_conflict_rela): Handle 64-bit REL relocations. Use + reloc_r_type(). Use mips_buf_read_addr() and + mips_buf_write_addr(). + (mips_apply_reloc): Handle 64-bit REL relocations. Use + reloc_r_sym() and reloc_r_type(). + (mips_rel_to_rela): Handle 64-bit REL relocations. Handle + TLS_DTPMOD64, TLS_DTPREL64 and TLS_TPREL64 relocations. Use + reloc_r_sym() and reloc_r_type(). + (mips_rela_to_rel): Handle 64-bit REL and GLOB_DAT relocations. + Handle TLS_DTPMOD64, TLS_DTPREL64 and TLS_TPREL64 relocations. + Use reloc_r_sym() and reloc_r_type(). + (mips_need_rel_to_rela): Use data obtained with gelfx_getshdr() to + determine the size of a relocation entry. Use gelfx_getrel() to + retrieve them. Handle 64-bit REL relocations. Handle + TLS_DTPMOD64, TLS_DTPREL64 and TLS_TPREL64 relocations. Use + reloc_r_sym() and reloc_r_type() instead of ELF32_R_SYM() and + ELF32_R_TYPE() respectively. + (mips_reloc_class): Handle TLS_DTPMOD64, TLS_DTPREL64 and + TLS_TPREL64 relocations. + (mips_arch_prelink): Use mips_buf_read_addr() and + mips_buf_write_addr(). + (mips_arch_undo_prelink): Likewise. + (mips_undo_prelink_rel): Handle 64-bit GLOB_DAT relocations. Use + reloc_r_sym(), reloc_r_type() and reloc_r_info_ext(). + (mips64): New PL_ARCH. + * src/prelink.c (prelink_prepare): Handle SHT_MIPS_OPTIONS. + * src/conflict.c (conflict_rela_cmp_dso): New variable. + (conflict_rela_cmp): Use conflict_rela_cmp_dso and reloc_r_sym(). + (get_relocated_mem): Use reloc_r_type(). + (prelink_add_copy_rel): Use reloc_r_sym() and reloc_r_type(). + (prelink_build_conflicts): Use reloc_r_sym(), reloc_r_type() and + reloc_r_info(). Pass dso to conflict_rela_cmp() through + conflict_rela_cmp_dso. + (prelink_find_copy_rela): Use reloc_r_type(). + * src/cxx.c (remove_redundant_cxx_conflicts): Use reloc_r_sym(), + reloc_r_type() and reloc_r_info(). + * src/ld-libs.c (do_rel_section): Use reloc_r_sym() and + reloc_r_type(). + * src/Makefile.am (common_SOURCES): Add reloc-info.c and + reloc-info.h. + (prelink_rtld_SOURCES): Likewise. + * src/Makefile.in: Regenerate. + * configure.in: Check for the Elf64_Byte type. Require autoconf + 2.50. + * configure: Regenerate. + + 2008-09-03 Maciej W. Rozycki <macro@codesourcery.com> + + * src/arch-mips.c (mips_undo_prelink_rel): Fix formatting. + + 2008-09-03 Maciej W. Rozycki <macro@codesourcery.com> + + * src/arch-mips.c (mips_init_local_got_iterator): Use ELF_T_ADDR + to determine the width of GOT entries. + (mips_init_global_got_iterator): Likewise. + 2008-09-03 Maciej W. Rozycki <macro@codesourcery.com> * src/data.c (buf_read_une##nn): Fix the width of the data diff --git a/trunk/configure.in b/trunk/configure.in index 724262b..5998659 100644 --- a/trunk/configure.in +++ b/trunk/configure.in @@ -1,7 +1,7 @@ dnl Process this file with autoconf to produce a configure script. -*-m4-*- AC_INIT(src/prelink.c) AM_CONFIG_HEADER(config.h) -AC_PREREQ(2.13) dnl Minimum Autoconf version required. +AC_PREREQ(2.50) dnl Minimum Autoconf version required. AC_CANONICAL_SYSTEM AC_ARG_PROGRAM @@ -93,6 +93,9 @@ fi AC_LIBELF_SXWORD +dnl Elf64_Byte is specific to the 64-bit MIPS psABI and may not be defined. +AC_CHECK_TYPES([Elf64_Byte], [], [], [#include <libelf.h>]) + # Package version. AC_ARG_WITH(pkgversion, AS_HELP_STRING([--with-pkgversion=PKG], diff --git a/trunk/src/Makefile.am b/trunk/src/Makefile.am index 5afb671..64dad8f 100644 --- a/trunk/src/Makefile.am +++ b/trunk/src/Makefile.am @@ -25,7 +25,7 @@ arch_SOURCES = arch-i386.c arch-alpha.c arch-ppc.c arch-ppc64.c \ arch-s390.c arch-s390x.c arch-arm.c arch-sh.c arch-ia64.c common_SOURCES = checksum.c data.c dso.c dwarf2.c dwarf2.h fptr.c fptr.h \ hashtab.c hashtab.h mdebug.c prelink.h stabs.c crc32.c \ - wrap-file.c canonicalize.c + wrap-file.c canonicalize.c reloc-info.c reloc-info.h prelink_SOURCES = cache.c conflict.c cxx.c doit.c exec.c execle_open.c get.c \ gather.c layout.c main.c prelink.c \ prelinktab.h reloc.c reloc.h space.c undo.c undoall.c \ @@ -39,7 +39,8 @@ execstack_LDADD = -liberty execstack_LDFLAGS = prelink_rtld_SOURCES = data.c dso-readonly.c ld-libs.c ld-lookup.c \ - canonicalize.c wrap-file.c ld-lookup64.c + canonicalize.c wrap-file.c ld-lookup64.c \ + reloc-info.c reloc-info.h prelink_rtld_LDADD = @LIBGELF@ -liberty prelink_rtld_LDFLAGS = diff --git a/trunk/src/arch-alpha.c b/trunk/src/arch-alpha.c index 51182ed..f35ee18 100644 --- a/trunk/src/arch-alpha.c +++ b/trunk/src/arch-alpha.c @@ -459,7 +459,7 @@ alpha_reloc_class (int reloc_type) } } -PL_ARCH = { +PL_ARCH(alpha) = { .name = "Alpha", .class = ELFCLASS64, .machine = EM_ALPHA, diff --git a/trunk/src/arch-arm.c b/trunk/src/arch-arm.c index 12b8f3d..be1982a 100644 --- a/trunk/src/arch-arm.c +++ b/trunk/src/arch-arm.c @@ -815,7 +815,7 @@ arm_reloc_class (int reloc_type) } } -PL_ARCH = { +PL_ARCH(arm) = { .name = "ARM", .class = ELFCLASS32, .machine = EM_ARM, diff --git a/trunk/src/arch-cris.c b/trunk/src/arch-cris.c index 6b56016..b110539 100644 --- a/trunk/src/arch-cris.c +++ b/trunk/src/arch-cris.c @@ -367,7 +367,7 @@ cris_reloc_class (int reloc_type) } } -PL_ARCH = { +PL_ARCH(cris) = { .name = "CRIS", .class = ELFCLASS32, .machine = EM_CRIS, diff --git a/trunk/src/arch-i386.c b/trunk/src/arch-i386.c index d5211b2..37b5c67 100644 --- a/trunk/src/arch-i386.c +++ b/trunk/src/arch-i386.c @@ -1044,7 +1044,7 @@ i386_layout_libs_post (struct layout_libs *l) return 0; } -PL_ARCH = { +PL_ARCH(i386) = { .name = "i386", .class = ELFCLASS32, .machine = EM_386, diff --git a/trunk/src/arch-ia64.c b/trunk/src/arch-ia64.c index 0be672c..89df85e 100644 --- a/trunk/src/arch-ia64.c +++ b/trunk/src/arch-ia64.c @@ -485,7 +485,7 @@ ia64_reloc_class (int reloc_type) } } -PL_ARCH = { +PL_ARCH(ia64) = { .name = "IA-64", .class = ELFCLASS64, .machine = EM_IA_64, diff --git a/trunk/src/arch-mips.c b/trunk/src/arch-mips.c index cf583aa..b85616e 100644 --- a/trunk/src/arch-mips.c +++ b/trunk/src/arch-mips.c @@ -1,5 +1,6 @@ -/* Copyright (C) 2006 CodeSourcery +/* Copyright (C) 2006, 2008 CodeSourcery. Written by Richard Sandiford <richard@codesourcery.com>, 2006 + Updated by Maciej W. Rozycki <macro@codesourcery.com>, 2008. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -90,6 +91,7 @@ #include "prelink.h" #include "layout.h" +#include "reloc-info.h" /* The thread pointer points 0x7000 past the first static TLS block. */ #define TLS_TP_OFFSET 0x7000 @@ -124,6 +126,28 @@ struct mips_local_got_iterator { struct data_iterator got_iterator; }; +/* Read native-endian address-type data. */ + +static uint64_t +mips_buf_read_addr (DSO *dso, unsigned char *data) +{ + if (dso->ehdr.e_ident[EI_CLASS] == ELFCLASS64) + return buf_read_une64 (dso, data); + else + return buf_read_une32 (dso, data); +} + +/* Write native-endian address-type data. */ + +static void +mips_buf_write_addr (DSO *dso, unsigned char *data, uint64_t val) +{ + if (dso->ehdr.e_ident[EI_CLASS] == ELFCLASS64) + buf_write_ne64 (dso, data, val); + else + buf_write_ne32 (dso, data, val); +} + /* Set up LGI to iterate over DSO's local GOT. The caller should use mips_get_local_got_entry to read the first entry. */ @@ -131,7 +155,7 @@ static inline void mips_init_local_got_iterator (struct mips_local_got_iterator *lgi, DSO *dso) { lgi->dso = dso; - lgi->entry_size = gelf_fsize (dso->elf, ELF_T_WORD, 1, EV_CURRENT); + lgi->entry_size = gelf_fsize (dso->elf, ELF_T_ADDR, 1, EV_CURRENT); lgi->got_index = RESERVED_GOTNO - 1; lgi->failed = 0; init_data_iterator (&lgi->got_iterator, dso, @@ -199,7 +223,7 @@ mips_init_global_got_iterator (struct mips_global_got_iterator *ggi, DSO *dso) GElf_Word sym_size; ggi->dso = dso; - ggi->entry_size = gelf_fsize (dso->elf, ELF_T_WORD, 1, EV_CURRENT); + ggi->entry_size = gelf_fsize (dso->elf, ELF_T_ADDR, 1, EV_CURRENT); ggi->got_addr = (dso->info[DT_PLTGOT] + (dso->info_DT_MIPS_LOCAL_GOTNO - 1) * ggi->entry_size); ggi->sym_index = dso->info_DT_MIPS_GOTSYM - 1; @@ -252,8 +276,8 @@ mips_arch_adjust (DSO *dso, GElf_Addr start, GElf_Addr adjust) mips_init_local_got_iterator (&lgi, dso); while (mips_get_local_got_entry (&lgi)) { - value = buf_read_une32 (dso, lgi.got_entry); - buf_write_ne32 (dso, lgi.got_entry, value + adjust); + value = mips_buf_read_addr (dso, lgi.got_entry); + mips_buf_write_addr (dso, lgi.got_entry, value + adjust); } /* Adjust every global GOT entry. Referring to the table above: @@ -269,13 +293,13 @@ mips_arch_adjust (DSO *dso, GElf_Addr start, GElf_Addr adjust) mips_init_global_got_iterator (&ggi, dso); while (mips_get_global_got_entry (&ggi)) { - value = buf_read_une32 (dso, ggi.got_entry); + value = mips_buf_read_addr (dso, ggi.got_entry); if (ggi.sym.st_shndx != SHN_COMMON && value >= start && (value == ggi.sym.st_value ? adjust_symbol_p (dso, &ggi.sym) : ggi.sym.st_shndx != SHN_UNDEF)) - buf_write_ne32 (dso, ggi.got_entry, value + adjust); + mips_buf_write_addr (dso, ggi.got_entry, value + adjust); } return lgi.failed || ggi.failed; @@ -325,16 +349,16 @@ mips_adjust_dyn (DSO *dso, int n, GElf_Dyn *dyn, GElf_Addr start, address R_OFFSET. */ static inline uint32_t -mips_read_addend (DSO *dso, GElf_Addr r_offset, GElf_Rela *rela) +mips_read_32bit_addend (DSO *dso, GElf_Addr r_offset, GElf_Rela *rela) { return rela ? rela->r_addend : read_une32 (dso, r_offset); } -/* Like mips_read_addend, but change the addend to VALUE. */ +/* Like mips_read_32bit_addend, but change the addend to VALUE. */ static inline void -mips_write_addend (DSO *dso, GElf_Addr r_offset, GElf_Rela *rela, - uint32_t value) +mips_write_32bit_addend (DSO *dso, GElf_Addr r_offset, GElf_Rela *rela, + uint32_t value) { if (rela) rela->r_addend = (int32_t) value; @@ -342,6 +366,26 @@ mips_write_addend (DSO *dso, GElf_Addr r_offset, GElf_Rela *rela, write_ne32 (dso, r_offset, value); } +/* Like mips_read_32bit_addend, but 64-bit. */ + +static inline uint64_t +mips_read_64bit_addend (DSO *dso, GElf_Addr r_offset, GElf_Rela *rela) +{ + return rela ? rela->r_addend : read_une64 (dso, r_offset); +} + +/* Like mips_read_64bit_addend, but change the addend to VALUE. */ + +static inline void +mips_write_64bit_addend (DSO *dso, GElf_Addr r_offset, GElf_Rela *rela, + uint64_t value) +{ + if (rela) + rela->r_addend = value; + else + write_ne64 (dso, r_offset, value); +} + /* There is a relocation of type R_INFO against address R_OFFSET in DSO. Adjust it so that virtual addresses >= START are increased by ADJUST If the relocation is in a RELA section, RELA points to the relocation, @@ -354,9 +398,9 @@ mips_adjust_reloc (DSO *dso, GElf_Addr r_offset, GElf_Xword r_info, GElf_Addr value; GElf_Word r_sym; - if (GELF_R_TYPE (r_info) == R_MIPS_REL32) + if (reloc_r_type (dso, r_info) == R_MIPS_REL32) { - r_sym = GELF_R_SYM (r_info); + r_sym = reloc_r_sym (dso, r_info); if (r_sym < dso->info_DT_MIPS_GOTSYM) { /* glibc's dynamic linker adds the symbol's st_value and the @@ -388,8 +432,18 @@ mips_adjust_reloc (DSO *dso, GElf_Addr r_offset, GElf_Xword r_info, " relocs against local symbols", dso->filename); return 1; } - value = mips_read_addend (dso, r_offset, rela); - mips_write_addend (dso, r_offset, rela, value + adjust); + if (reloc_r_type2 (dso, r_info) == R_MIPS_64) + { + assert (reloc_r_type3 (dso, r_info) == R_MIPS_NONE); + assert (reloc_r_ssym (dso, r_info) == RSS_UNDEF); + value = mips_read_64bit_addend (dso, r_offset, rela); + mips_write_64bit_addend (dso, r_offset, rela, value + adjust); + } + else + { + value = mips_read_32bit_addend (dso, r_offset, rela); + mips_write_32bit_addend (dso, r_offset, rela, value + adjust); + } } } return 0; @@ -418,6 +472,13 @@ mips_prelink_32bit_reloc (DSO *dso, GElf_Rela *rela, GElf_Addr value) write_ne32 (dso, rela->r_offset, value + rela->r_addend); } +static void +mips_prelink_64bit_reloc (DSO *dso, GElf_Rela *rela, GElf_Addr value) +{ + assert (rela != NULL); + write_ne64 (dso, rela->r_offset, value + rela->r_addend); +} + /* There is a relocation of type R_INFO against address R_OFFSET in DSO. Prelink the relocation field, using INFO to look up symbol values. If the relocation is in a RELA section, RELA points to the relocation, @@ -433,8 +494,8 @@ mips_prelink_reloc (struct prelink_info *info, GElf_Addr r_offset, int r_type; dso = info->dso; - r_sym = GELF_R_SYM (r_info); - r_type = GELF_R_TYPE (r_info); + r_sym = reloc_r_sym (dso, r_info); + r_type = reloc_r_type (dso, r_info); switch (r_type) { case R_MIPS_NONE: @@ -443,15 +504,29 @@ mips_prelink_reloc (struct prelink_info *info, GElf_Addr r_offset, case R_MIPS_REL32: /* An in-place R_MIPS_REL32 relocation against symbol 0 needs no adjustment. */ - if (rela != NULL || GELF_R_SYM (r_info) != 0) + if (rela != NULL || r_sym != 0) { value = info->resolve (info, r_sym, r_type); - mips_prelink_32bit_reloc (dso, rela, value); + if (reloc_r_type2 (dso, r_info) == R_MIPS_64) + { + assert (reloc_r_type3 (dso, r_info) == R_MIPS_NONE); + assert (reloc_r_ssym (dso, r_info) == RSS_UNDEF); + mips_prelink_64bit_reloc (dso, rela, value); + } + else + mips_prelink_32bit_reloc (dso, rela, value); } break; case R_MIPS_GLOB_DAT: - write_ne32 (dso, r_offset, info->resolve (info, r_sym, r_type)); + if (reloc_r_type2 (dso, r_info) == R_MIPS_64) + { + assert (reloc_r_type3 (dso, r_info) == R_MIPS_NONE); + assert (reloc_r_ssym (dso, r_info) == RSS_UNDEF); + write_ne64 (dso, r_offset, info->resolve (info, r_sym, r_type)); + } + else + write_ne32 (dso, r_offset, info->resolve (info, r_sym, r_type)); break; case R_MIPS_JUMP_SLOT: @@ -459,29 +534,32 @@ mips_prelink_reloc (struct prelink_info *info, GElf_Addr r_offset, break; case R_MIPS_TLS_DTPMOD32: - if (dso->ehdr.e_type == ET_EXEC) - { - error (0, 0, "%s: R_MIPS_TLS_DTPMOD32 reloc in executable?", - dso->filename); - return 1; - } + case R_MIPS_TLS_DTPMOD64: /* These relocations will be resolved using a conflict. We need not change the field value here. */ break; case R_MIPS_TLS_DTPREL32: + case R_MIPS_TLS_DTPREL64: value = info->resolve (info, r_sym, r_type); - mips_prelink_32bit_reloc (dso, rela, value - TLS_DTV_OFFSET); + if (r_type == R_MIPS_TLS_DTPREL32) + mips_prelink_32bit_reloc (dso, rela, value - TLS_DTV_OFFSET); + else + mips_prelink_64bit_reloc (dso, rela, value - TLS_DTV_OFFSET); break; case R_MIPS_TLS_TPREL32: + case R_MIPS_TLS_TPREL64: /* Relocations in a shared library will be resolved using a conflict. We need not change the relocation field here. */ if (dso->ehdr.e_type == ET_EXEC) { value = info->resolve (info, r_sym, r_type); value += info->resolvetls->offset - TLS_TP_OFFSET; - mips_prelink_32bit_reloc (dso, rela, value); + if (r_type == R_MIPS_TLS_TPREL32) + mips_prelink_32bit_reloc (dso, rela, value); + else + mips_prelink_64bit_reloc (dso, rela, value); } break; @@ -494,7 +572,7 @@ mips_prelink_reloc (struct prelink_info *info, GElf_Addr r_offset, default: error (0, 0, "%s: Unknown MIPS relocation type %d", - dso->filename, (int) GELF_R_TYPE (r_info)); + dso->filename, (int) reloc_r_type (dso, r_info)); return 1; } return 0; @@ -503,20 +581,41 @@ mips_prelink_reloc (struct prelink_info *info, GElf_Addr r_offset, static int mips_prelink_rel (struct prelink_info *info, GElf_Rel *rel, GElf_Addr reladdr) { + GElf_Xword r_info; + GElf_Word r_sym; + int r_type; DSO *dso; /* Convert R_MIPS_REL32 relocations against global symbols into R_MIPS_GLOB_DAT if the addend is zero. */ dso = info->dso; - if (GELF_R_TYPE (rel->r_info) == R_MIPS_REL32 - && GELF_R_SYM (rel->r_info) >= dso->info_DT_MIPS_GOTSYM - && read_une32 (dso, rel->r_offset) == 0) + r_sym = reloc_r_sym (dso, rel->r_info); + r_type = reloc_r_type (dso, rel->r_info); + if (r_type == R_MIPS_REL32 && r_sym >= dso->info_DT_MIPS_GOTSYM) { - rel->r_info = GELF_R_INFO (GELF_R_SYM (rel->r_info), R_MIPS_GLOB_DAT); - write_ne32 (dso, rel->r_offset, - info->resolve (info, GELF_R_SYM (rel->r_info), - GELF_R_TYPE (rel->r_info))); - return 2; + r_type = R_MIPS_GLOB_DAT; + r_info = reloc_r_info_ext (dso, r_sym, reloc_r_ssym (dso, rel->r_info), + r_type, + reloc_r_type2 (dso, rel->r_info), + reloc_r_type3 (dso, rel->r_info)); + if (reloc_r_type2 (dso, rel->r_info) == R_MIPS_64) + { + assert (reloc_r_type3 (dso, rel->r_info) == R_MIPS_NONE); + assert (reloc_r_ssym (dso, rel->r_info) == RSS_UNDEF); + if (read_une64 (dso, rel->r_offset) == 0) + { + rel->r_info = r_info; + write_ne64 (dso, rel->r_offset, + info->resolve (info, r_sym, r_type)); + return 2; + } + } + else if (read_une32 (dso, rel->r_offset) == 0) + { + rel->r_info = r_info; + write_ne32 (dso, rel->r_offset, info->resolve (info, r_sym, r_type)); + return 2; + } } return mips_prelink_reloc (info, rel->r_offset, rel->r_info, NULL); } @@ -563,15 +662,20 @@ mips_prelink_conflict_reloc (DSO *dso, struct prelink_info *info, struct prelink_conflict *conflict; struct prelink_tls *tls; GElf_Rela *entry; + GElf_Word r_sym; + int r_type; - conflict = prelink_conflict (info, GELF_R_SYM (r_info), - GELF_R_TYPE (r_info)); + r_sym = reloc_r_sym (dso, r_info); + r_type = reloc_r_type (dso, r_info); + conflict = prelink_conflict (info, r_sym, r_type); if (conflict == NULL) { - switch (GELF_R_TYPE (r_info)) + switch (r_type) { case R_MIPS_TLS_DTPMOD32: + case R_MIPS_TLS_DTPMOD64: case R_MIPS_TLS_TPREL32: + case R_MIPS_TLS_TPREL64: tls = info->curtls; if (tls == NULL) return 0; @@ -586,10 +690,11 @@ mips_prelink_conflict_reloc (DSO *dso, struct prelink_info *info, } else { - /* DTPREL32 relocations just involve the symbol value; no other - TLS information is needed. Ignore conflicts created from a - lookup of type RTYPE_CLASS_TLS if no real conflict exists. */ - if (GELF_R_TYPE (r_info) == R_MIPS_TLS_DTPREL32 + /* DTPREL32/DTPREL64 relocations just involve the symbol value; + no other TLS information is needed. Ignore conflicts created + from a lookup of type RTYPE_CLASS_TLS if no real conflict + exists. */ + if ((r_type == R_MIPS_TLS_DTPREL32 || r_type == R_MIPS_TLS_DTPREL64) && conflict->lookup.tls == conflict->conflict.tls && conflict->lookupval == conflict->conflictval) return 0; @@ -598,10 +703,17 @@ mips_prelink_conflict_reloc (DSO *dso, struct prelink_info *info, } /* VALUE now contains the final symbol value. Change it to the value we want to store at R_OFFSET. */ - switch (GELF_R_TYPE (r_info)) + switch (r_type) { case R_MIPS_REL32: - value += mips_read_addend (dso, r_offset, rela); + if (reloc_r_type2 (dso, r_info) == R_MIPS_64) + { + assert (reloc_r_type3 (dso, r_info) == R_MIPS_NONE); + assert (reloc_r_ssym (dso, r_info) == RSS_UNDEF); + value += mips_read_64bit_addend (dso, r_offset, rela); + } + else + value += mips_read_32bit_addend (dso, r_offset, rela); break; case R_MIPS_GLOB_DAT: @@ -612,34 +724,46 @@ mips_prelink_conflict_reloc (DSO *dso, struct prelink_info *info, return 1; case R_MIPS_TLS_DTPMOD32: + case R_MIPS_TLS_DTPMOD64: if (conflict != NULL && mips_get_tls (dso, conflict, &tls) == 1) return 1; value = tls->modid; break; case R_MIPS_TLS_DTPREL32: - value += mips_read_addend (dso, r_offset, rela) - TLS_DTV_OFFSET; + value += mips_read_32bit_addend (dso, r_offset, rela) - TLS_DTV_OFFSET; + break; + case R_MIPS_TLS_DTPREL64: + value += mips_read_64bit_addend (dso, r_offset, rela) - TLS_DTV_OFFSET; break; case R_MIPS_TLS_TPREL32: + case R_MIPS_TLS_TPREL64: if (conflict != NULL && mips_get_tls (dso, conflict, &tls) == 1) return 1; - value += (mips_read_addend (dso, r_offset, rela) - + tls->offset - TLS_TP_OFFSET); + if (r_type == R_MIPS_TLS_TPREL32) + value += mips_read_32bit_addend (dso, r_offset, rela); + else + value += mips_read_64bit_addend (dso, r_offset, rela); + value += tls->offset - TLS_TP_OFFSET; break; default: error (0, 0, "%s: Unknown MIPS relocation type %d", dso->filename, - (int) GELF_R_TYPE (r_info)); + r_type); return 1; } /* Create and initialize a conflict entry. */ entry = prelink_conflict_add_rela (info); if (entry == NULL) return 1; - entry->r_addend = (int32_t) value; entry->r_offset = r_offset; - entry->r_info = GELF_R_INFO (0, R_MIPS_REL32); + entry->r_info = reloc_r_info_ext (dso, 0, RSS_UNDEF, + R_MIPS_REL32, R_MIPS_64, R_MIPS_NONE); + if (reloc_r_type2 (dso, entry->r_info) == R_MIPS_64) + entry->r_addend = value; + else + entry->r_addend = (int32_t) value; return 0; } @@ -684,14 +808,19 @@ mips_arch_prelink_conflict (DSO *dso, struct prelink_info *info) value = ggi.sym.st_value; else continue; - if (buf_read_une32 (dso, ggi.got_entry) != value) + if (mips_buf_read_addr (dso, ggi.got_entry) != value) { entry = prelink_conflict_add_rela (info); if (entry == NULL) return 1; - entry->r_addend = (int32_t) value; entry->r_offset = ggi.got_addr; - entry->r_info = GELF_R_INFO (0, R_MIPS_REL32); + entry->r_info = reloc_r_info_ext (dso, 0, RSS_UNDEF, + R_MIPS_REL32, R_MIPS_64, + R_MIPS_NONE); + if (reloc_r_type2 (dso, entry->r_info) == R_MIPS_64) + entry->r_addend = value; + else + entry->r_addend = (int32_t) value; } } @@ -702,10 +831,20 @@ static int mips_apply_conflict_rela (struct prelink_info *info, GElf_Rela *rela, char *buf) { - switch (GELF_R_TYPE (rela->r_info)) + DSO *dso; + + dso = info->dso; + switch (reloc_r_type (dso, rela->r_info)) { case R_MIPS_REL32: - buf_write_ne32 (info->dso, buf, rela->r_addend); + if (reloc_r_type2 (dso, rela->r_info) == R_MIPS_64) + { + assert (reloc_r_ssym (dso, rela->r_info) == RSS_UNDEF); + assert (reloc_r_type3 (dso, rela->r_info) == R_MIPS_NONE); + buf_write_ne64 (info->dso, buf, rela->r_addend); + } + else + buf_write_ne32 (info->dso, buf, rela->r_addend); break; case R_MIPS_JUMP_SLOT: @@ -730,18 +869,24 @@ mips_apply_adjustment (DSO *dso, GElf_Rela *rela, char *buf, if (rela) adjustment += rela->r_addend; else - adjustment += buf_read_une32 (dso, buf); - buf_write_ne32 (dso, buf, adjustment); + adjustment += mips_buf_read_addr (dso, buf); + mips_buf_write_addr (dso, buf, adjustment); } static int mips_apply_reloc (struct prelink_info *info, GElf_Xword r_info, GElf_Rela *rela, char *buf) { + GElf_Addr value; + GElf_Word r_sym; + int r_type; DSO *dso; dso = info->dso; - switch (GELF_R_TYPE (r_info)) + r_sym = reloc_r_sym (dso, r_info); + r_type = reloc_r_type (dso, r_info); + value = info->resolve (info, r_sym, r_type); + switch (r_type) { case R_MIPS_NONE: break; @@ -756,9 +901,12 @@ mips_apply_reloc (struct prelink_info *info, GElf_Xword r_info, abort (); case R_MIPS_REL32: - mips_apply_adjustment (dso, rela, buf, - info->resolve (info, GELF_R_SYM (r_info), - GELF_R_TYPE (r_info))); + if (reloc_r_type2 (dso, r_info) == R_MIPS_64) + { + assert (reloc_r_type3 (dso, r_info) == R_MIPS_NONE); + assert (reloc_r_ssym (dso, r_info) == RSS_UNDEF); + } + mips_apply_adjustment (dso, rela, buf, value); break; default: @@ -782,28 +930,50 @@ mips_apply_rela (struct prelink_info *info, GElf_Rela *rela, char *buf) static int mips_rel_to_rela (DSO *dso, GElf_Rel *rel, GElf_Rela *rela) { + GElf_Word r_sym; + int r_type; + + r_sym = reloc_r_sym (dso, rel->r_info); + r_type = reloc_r_type (dso, rel->r_info); rela->r_offset = rel->r_offset; rela->r_info = rel->r_info; - switch (GELF_R_TYPE (rel->r_info)) + switch (r_type) { case R_MIPS_REL32: + /* This relocation has an in-place addend. */ + if (reloc_r_type2 (dso, rel->r_info) == R_MIPS_64) + { + assert (reloc_r_type3 (dso, rel->r_info) == R_MIPS_NONE); + assert (reloc_r_ssym (dso, rel->r_info) == RSS_UNDEF); + rela->r_addend = read_une64 (dso, rel->r_offset); + } + else + rela->r_addend = (int32_t) read_une32 (dso, rel->r_offset); + break; + case R_MIPS_TLS_DTPREL32: case R_MIPS_TLS_TPREL32: /* These relocations have an in-place addend. */ rela->r_addend = (int32_t) read_une32 (dso, rel->r_offset); break; + case R_MIPS_TLS_DTPREL64: + case R_MIPS_TLS_TPREL64: + /* These relocations have an in-place addend. */ + rela->r_addend = read_une64 (dso, rel->r_offset); + break; case R_MIPS_NONE: case R_MIPS_COPY: case R_MIPS_GLOB_DAT: case R_MIPS_TLS_DTPMOD32: + case R_MIPS_TLS_DTPMOD64: /* These relocations have no addend. */ rela->r_addend = 0; break; default: error (0, 0, "%s: Unknown MIPS relocation type %d", dso->filename, - (int) GELF_R_TYPE (rel->r_info)); + r_type); return 1; } return 0; @@ -812,30 +982,60 @@ mips_rel_to_rela (DSO *dso, GElf_Rel *rel, GElf_Rela *rela) static int mips_rela_to_rel (DSO *dso, GElf_Rela *rela, GElf_Rel *rel) { + GElf_Sxword r_addend; + GElf_Word r_sym; + int r_type; + + r_sym = reloc_r_sym (dso, rela->r_info); + r_type = reloc_r_type (dso, rela->r_info); + r_addend = rela->r_addend; rel->r_offset = rela->r_offset; rel->r_info = rela->r_info; - switch (GELF_R_TYPE (rela->r_info)) + switch (r_type) { case R_MIPS_NONE: case R_MIPS_COPY: break; + case R_MIPS_GLOB_DAT: + /* This relocation has no addend. */ + r_addend = 0; + /* FALLTHROUGH */ case R_MIPS_REL32: + /* This relocation has an in-place addend. */ + if (reloc_r_type2 (dso, rel->r_info) == R_MIPS_64) + { + assert (reloc_r_type3 (dso, rel->r_info) == R_MIPS_NONE); + assert (reloc_r_ssym (dso, rel->r_info) == RSS_UNDEF); + write_ne64 (dso, rela->r_offset, rela->r_addend); + } + else + write_ne32 (dso, rela->r_offset, rela->r_addend); + break; + + case R_MIPS_TLS_DTPMOD32: + /* This relocation has no addend. */ + r_addend = 0; + /* FALLTHROUGH */ case R_MIPS_TLS_DTPREL32: case R_MIPS_TLS_TPREL32: /* These relocations have an in-place addend. */ write_ne32 (dso, rela->r_offset, rela->r_addend); break; - - case R_MIPS_GLOB_DAT: - case R_MIPS_TLS_DTPMOD32: - /* These relocations have no addend. */ - write_ne32 (dso, rela->r_offset, 0); + case R_MIPS_TLS_DTPMOD64: + /* This relocation has no addend. */ + r_addend = 0; + /* FALLTHROUGH */ + case R_MIPS_TLS_DTPREL64: + case R_MIPS_TLS_TPREL64: + /* These relocations have an in-place addend. */ + write_ne64 (dso, rela->r_offset, rela->r_addend); + break; break; default: error (0, 0, "%s: Unknown MIPS relocation type %d", dso->filename, - (int) GELF_R_TYPE (rela->r_info)); + r_type); return 1; } return 0; @@ -846,66 +1046,91 @@ mips_need_rel_to_rela (DSO *dso, int first, int last) { Elf_Data *data; Elf_Scn *scn; - Elf32_Rel *rel, *relend; + GElf_Shdr shdr; + GElf_Rel rel; + GElf_Word r_sym; + int r_type; + int count; + int i; int n; for (n = first; n <= last; n++) { data = NULL; scn = dso->scn[n]; + gelfx_getshdr (dso->elf, scn, &shdr); while ((data = elf_getdata (scn, data)) != NULL) { - rel = (Elf32_Rel *) data->d_buf; - relend = rel + data->d_size / sizeof (Elf32_Rel); - for (; rel < relend; rel++) - switch (ELF32_R_TYPE (rel->r_info)) - { - case R_MIPS_NONE: - case R_MIPS_COPY: - case R_MIPS_JUMP_SLOT: - break; - - case R_MIPS_REL32: - /* The SVR4 definition was designed to allow exactly the - sort of prelinking we want to do here, in combination - with Quickstart. Unfortunately, glibc's definition - makes it impossible for relocations against anything - other than the null symbol. We get around this for - zero addends by using a R_MIPS_GLOB_DAT relocation - instead, where R_MIPS_GLOB_DAT is a GNU extension - added specifically for this purpose. */ - if (ELF32_R_SYM (rel->r_info) != 0 - && (ELF32_R_SYM (rel->r_info) < dso->info_DT_MIPS_GOTSYM - || read_une32 (dso, rel->r_offset) != 0)) - return 1; - break; - - case R_MIPS_GLOB_DAT: - /* This relocation has no addend. */ - break; - - case R_MIPS_TLS_DTPMOD32: - /* The relocation will be resolved using a conflict. */ - break; - - case R_MIPS_TLS_DTPREL32: - /* We can prelink these fields, and the addend is relative - to the symbol value. A RELA entry is needed. */ - return 1; - - case R_MIPS_TLS_TPREL32: - /* Relocations in shared libraries will be resolved by a - conflict. Relocations in executables will not, and the - addend is relative to the symbol value. */ - if (dso->ehdr.e_type == ET_EXEC) + count = data->d_size / shdr.sh_entsize; + for (i = 0; i < count; i++) + { + gelfx_getrel (dso->elf, data, i, &rel); + r_type = reloc_r_type (dso, rel.r_info); + r_sym = reloc_r_sym (dso, rel.r_info); + switch (r_type) + { + case R_MIPS_NONE: + case R_MIPS_COPY: + case R_MIPS_JUMP_SLOT: + break; + + case R_MIPS_REL32: + /* The SVR4 definition was designed to allow exactly the + sort of prelinking we want to do here, in combination + with Quickstart. Unfortunately, glibc's definition + makes it impossible for relocations against anything + other than the null symbol. We get around this for + zero addends by using a R_MIPS_GLOB_DAT relocation + instead, where R_MIPS_GLOB_DAT is a GNU extension + added specifically for this purpose. */ + if (r_sym != 0) + { + if (r_sym < dso->info_DT_MIPS_GOTSYM) + return 1; + if (reloc_r_type2 (dso, rel.r_info) == R_MIPS_64) + { + assert (reloc_r_type3 (dso, rel.r_info) + == R_MIPS_NONE); + assert (reloc_r_ssym (dso, rel.r_info) + == RSS_UNDEF); + if (read_une64 (dso, rel.r_offset) != 0) + return 1; + } + else if (read_une32 (dso, rel.r_offset) != 0) + return 1; + } + break; + + case R_MIPS_GLOB_DAT: + /* This relocation has no addend. */ + break; + + case R_MIPS_TLS_DTPMOD32: + case R_MIPS_TLS_DTPMOD64: + /* The relocation will be resolved using a conflict. */ + break; + + case R_MIPS_TLS_DTPREL32: + case R_MIPS_TLS_DTPREL64: + /* We can prelink these fields, and the addend is relative + to the symbol value. A RELA entry is needed. */ return 1; - break; - - default: - error (0, 0, "%s: Unknown MIPS relocation type %d", - dso->filename, (int) GELF_R_TYPE (rel->r_info)); + + case R_MIPS_TLS_TPREL32: + case R_MIPS_TLS_TPREL64: + /* Relocations in shared libraries will be resolved by a + conflict. Relocations in executables will not, and the + addend is relative to the symbol value. */ + if (dso->ehdr.e_type == ET_EXEC) + return 1; + break; + + default: + error (0, 0, "%s: Unknown MIPS relocation type %d", + dso->filename, r_type); return 1; - } + } + } } } return 0; @@ -927,8 +1152,11 @@ mips_reloc_class (int reloc_type) case R_MIPS_JUMP_SLOT: return RTYPE_CLASS_PLT; case R_MIPS_TLS_DTPMOD32: + case R_MIPS_TLS_DTPMOD64: case R_MIPS_TLS_DTPREL32: + case R_MIPS_TLS_DTPREL64: case R_MIPS_TLS_TPREL32: + case R_MIPS_TLS_TPREL64: return RTYPE_CLASS_TLS; default: return RTYPE_CLASS_VALID; @@ -944,6 +1172,7 @@ mips_arch_prelink (struct prelink_info *info) int i; dso = info->dso; + if (dso->info_DT_MIPS_PLTGOT) { /* Write address of .plt into gotplt[1]. This is in each @@ -960,6 +1189,7 @@ mips_arch_prelink (struct prelink_info *info) dso->shdr[i].sh_name), ".plt")) break; + if (i == dso->ehdr.e_shnum) return 0; data = dso->shdr[i].sh_addr; @@ -977,7 +1207,7 @@ mips_arch_prelink (struct prelink_info *info) value = info->resolve (info, ggi.sym_index, R_MIPS_REL32); if (ggi.sym.st_shndx == SHN_UNDEF || ggi.sym.st_shndx == SHN_COMMON) - buf_write_ne32 (dso, ggi.got_entry, value); + mips_buf_write_addr (dso, ggi.got_entry, value); else { /* Type E and F in the table above. We cannot install Quickstart @@ -995,7 +1225,7 @@ mips_arch_prelink (struct prelink_info *info) code will cope correctly with malformed type F entries in shared libraries, so we only complain about executables here. */ if (dso->ehdr.e_type == ET_EXEC - && value != buf_read_une32 (dso, ggi.got_entry)) + && value != mips_buf_read_addr (dso, ggi.got_entry)) { error (0, 0, "%s: The global GOT entries for defined symbols" " do not match their st_values\n", dso->filename); @@ -1042,10 +1272,10 @@ mips_arch_undo_prelink (DSO *dso) while (mips_get_global_got_entry (&ggi)) if (ggi.sym.st_shndx == SHN_UNDEF) /* Types A-C in the table above. */ - buf_write_ne32 (dso, ggi.got_entry, ggi.sym.st_value); + mips_buf_write_addr (dso, ggi.got_entry, ggi.sym.st_value); else if (ggi.sym.st_shndx == SHN_COMMON) /* Type D in the table above. */ - buf_write_ne32 (dso, ggi.got_entry, 0); + mips_buf_write_addr (dso, ggi.got_entry, 0); return ggi.failed; } @@ -1054,6 +1284,8 @@ mips_undo_prelink_rel (DSO *dso, GElf_Rel *rel, GElf_Addr reladdr) { int sec; const char *name; + GElf_Word r_sym; + int r_type; /* Convert R_MIPS_GLOB_DAT relocations back into R_MIPS_REL32 relocations. Ideally we'd have some mechanism for recording @@ -1061,13 +1293,26 @@ mips_undo_prelink_rel (DSO *dso, GElf_Rel *rel, GElf_Addr reladdr) it's better to assume that the original relocation was R_MIPS_REL32; R_MIPS_GLOB_DAT was added specifically for the prelinker and shouldn't be used in non-prelinked binaries. */ - if (GELF_R_TYPE (rel->r_info) == R_MIPS_GLOB_DAT) + r_sym = reloc_r_sym (dso, rel->r_info); + r_type = reloc_r_type (dso, rel->r_info); + if (r_type == R_MIPS_GLOB_DAT) { - write_ne32 (dso, rel->r_offset, 0); - rel->r_info = GELF_R_INFO (GELF_R_SYM (rel->r_info), R_MIPS_REL32); + if (reloc_r_type2 (dso, rel->r_info) == R_MIPS_64) + { + assert (reloc_r_type3 (dso, rel->r_info) == R_MIPS_NONE); + assert (reloc_r_ssym (dso, rel->r_info) == RSS_UNDEF); + write_ne64 (dso, rel->r_offset, 0); + } + else + write_ne32 (dso, rel->r_offset, 0); + rel->r_info = reloc_r_info_ext (dso, + r_sym, reloc_r_ssym (dso, rel->r_info), + R_MIPS_REL32, + reloc_r_type2 (dso, rel->r_info), + reloc_r_type3 (dso, rel->r_info)); return 2; } - else if (GELF_R_TYPE (rel->r_info) == R_MIPS_JUMP_SLOT) + else if (r_type == R_MIPS_JUMP_SLOT) { sec = addr_to_sec (dso, rel->r_offset); name = strptr (dso, dso->ehdr.e_shstrndx, dso->shdr[sec].sh_name); @@ -1091,7 +1336,7 @@ mips_undo_prelink_rel (DSO *dso, GElf_Rel *rel, GElf_Addr reladdr) return 0; } -PL_ARCH = { +PL_ARCH(mips) = { .name = "MIPS", .class = ELFCLASS32, .machine = EM_MIPS, @@ -1133,3 +1378,46 @@ PL_ARCH = { .max_page_size = 0x10000, .page_size = 0x1000 }; + +PL_ARCH(mips64) = { + .name = "MIPS64", + .class = ELFCLASS64, + .machine = EM_MIPS, + .max_reloc_size = 8, + .dynamic_linker = "/lib/ld.so.1", + .dynamic_linker_alt = "/lib64/ld.so.1", + .R_COPY = R_MIPS_COPY, + .R_JMP_SLOT = R_MIPS_JUMP_SLOT, + /* R_MIPS_REL32 relocations against symbol 0 do act as relative relocs, + but those against other symbols don't. */ + .R_RELATIVE = ~0U, + .arch_adjust = mips_arch_adjust, + .adjust_dyn = mips_adjust_dyn, + .adjust_rel = mips_adjust_rel, + .adjust_rela = mips_adjust_rela, + .prelink_rel = mips_prelink_rel, + .prelink_rela = mips_prelink_rela, + .prelink_conflict_rel = mips_prelink_conflict_rel, + .prelink_conflict_rela = mips_prelink_conflict_rela, + .arch_prelink_conflict = mips_arch_prelink_conflict, + .apply_conflict_rela = mips_apply_conflict_rela, + .apply_rel = mips_apply_rel, + .apply_rela = mips_apply_rela, + .rel_to_rela = mips_rel_to_rela, + .rela_to_rel = mips_rela_to_rel, + .need_rel_to_rela = mips_need_rel_to_rela, + .reloc_size = mips_reloc_size, + .reloc_class = mips_reloc_class, + .arch_prelink = mips_arch_prelink, + .arch_undo_prelink = mips_arch_undo_prelink, + .undo_prelink_rel = mips_undo_prelink_rel, + /* Although TASK_UNMAPPED_BASE is 0x5555556000, we leave some + area so that mmap of /etc/ld.so.cache and ld.so's malloc + does not take some library's VA slot. + Also, if this guard area isn't too small, typically + even dlopened libraries will get the slots they desire. */ + .mmap_base = 0x5800000000LL, + .mmap_end = 0x9800000000LL, + .max_page_size = 0x10000, + .page_size = 0x1000 +}; diff --git a/trunk/src/arch-ppc.c b/trunk/src/arch-ppc.c index 5608750..4bf5aca 100644 --- a/trunk/src/arch-ppc.c +++ b/trunk/src/arch-ppc.c @@ -1114,7 +1114,7 @@ ppc_layout_libs_post (struct layout_libs *l) return 0; } -PL_ARCH = { +PL_ARCH(ppc) = { .name = "PowerPC", .class = ELFCLASS32, .machine = EM_PPC, diff --git a/trunk/src/arch-ppc64.c b/trunk/src/arch-ppc64.c index 3b12dbe..ec28ee8 100644 --- a/trunk/src/arch-ppc64.c +++ b/trunk/src/arch-ppc64.c @@ -816,7 +816,7 @@ ppc64_free_opd (struct prelink_entry *ent) return 0; } -PL_ARCH = { +PL_ARCH(ppc64) = { .name = "PowerPC", .class = ELFCLASS64, .machine = EM_PPC64, diff --git a/trunk/src/arch-s390.c b/trunk/src/arch-s390.c index 4be0dcb..f2ca7e1 100644 --- a/trunk/src/arch-s390.c +++ b/trunk/src/arch-s390.c @@ -474,7 +474,7 @@ s390_reloc_class (int reloc_type) } } -PL_ARCH = { +PL_ARCH(s390) = { .name = "S390", .class = ELFCLASS32, .machine = EM_S390, diff --git a/trunk/src/arch-s390x.c b/trunk/src/arch-s390x.c index 1e381c7..e1c213b 100644 --- a/trunk/src/arch-s390x.c +++ b/trunk/src/arch-s390x.c @@ -590,7 +590,7 @@ s390x_reloc_class (int reloc_type) } } -PL_ARCH = { +PL_ARCH(s390x) = { .name = "S390", .class = ELFCLASS64, .machine = EM_S390, diff --git a/trunk/src/arch-sh.c b/trunk/src/arch-sh.c index 6ddf5f6..d851a4d 100644 --- a/trunk/src/arch-sh.c +++ b/trunk/src/arch-sh.c @@ -406,7 +406,7 @@ sh_reloc_class (int reloc_type) } } -PL_ARCH = { +PL_ARCH(sh) = { .name = "SuperH", .class = ELFCLASS32, .machine = EM_SH, diff --git a/trunk/src/arch-sparc.c b/trunk/src/arch-sparc.c index 98bacac..6594c8f 100644 --- a/trunk/src/arch-sparc.c +++ b/trunk/src/arch-sparc.c @@ -599,7 +599,7 @@ sparc_reloc_class (int reloc_type) } } -PL_ARCH = { +PL_ARCH(sparc) = { .name = "SPARC", .class = ELFCLASS32, .machine = EM_SPARC, diff --git a/trunk/src/arch-sparc64.c b/trunk/src/arch-sparc64.c index e673e99..866294b 100644 --- a/trunk/src/arch-sparc64.c +++ b/trunk/src/arch-sparc64.c @@ -683,7 +683,7 @@ sparc64_reloc_class (int reloc_type) } } -PL_ARCH = { +PL_ARCH(sparc64) = { .name = "SPARC", .class = ELFCLASS64, .machine = EM_SPARCV9, diff --git a/trunk/src/arch-x86_64.c b/trunk/src/arch-x86_64.c index 8079f1a..8846672 100644 --- a/trunk/src/arch-x86_64.c +++ b/trunk/src/arch-x86_64.c @@ -497,7 +497,7 @@ x86_64_reloc_class (int reloc_type) } } -PL_ARCH = { +PL_ARCH(x86_64) = { .name = "x86-64", .class = ELFCLASS64, .machine = EM_X86_64, diff --git a/trunk/src/conflict.c b/trunk/src/conflict.c index db36054..cb0ba80 100644 --- a/trunk/src/conflict.c +++ b/trunk/src/conflict.c @@ -1,5 +1,7 @@ /* Copyright (C) 2001, 2002, 2003, 2004 Red Hat, Inc. + Copyright (C) 2008 CodeSourcery. Written by Jakub Jelinek <jakub@redhat.com>, 2001. + Updated by Maciej W. Rozycki <macro@codesourcery.com>, 2008. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -25,6 +27,7 @@ #include <unistd.h> #include "prelink.h" #include "reloc.h" +#include "reloc-info.h" struct prelink_conflict * prelink_conflict (struct prelink_info *info, GElf_Word r_sym, @@ -139,7 +142,7 @@ prelink_add_copy_rel (DSO *dso, int n, GElf_Rel *rel, struct copy_relocs *cr) Elf_Scn *scn = dso->scn[symsec]; GElf_Sym sym; size_t entsize = dso->shdr[symsec].sh_entsize; - off_t off = GELF_R_SYM (rel->r_info) * entsize; + off_t off = reloc_r_sym (dso, rel->r_info) * entsize; while ((data = elf_getdata (scn, data)) != NULL) { @@ -195,7 +198,7 @@ prelink_find_copy_rel (DSO *dso, int n, struct copy_relocs *cr) if (sec == -1) continue; - if (GELF_R_TYPE (rel.r_info) == dso->arch->R_COPY + if (reloc_r_type (dso, rel.r_info) == dso->arch->R_COPY && prelink_add_copy_rel (dso, n, &rel, cr)) return 1; } @@ -224,7 +227,7 @@ prelink_find_copy_rela (DSO *dso, int n, struct copy_relocs *cr) if (sec == -1) continue; - if (GELF_R_TYPE (u.rela.r_info) == dso->arch->R_COPY) + if (reloc_r_type (dso, u.rela.r_info) == dso->arch->R_COPY) { if (u.rela.r_addend != 0) { @@ -253,15 +256,18 @@ rela_cmp (const void *A, const void *B) return 0; } +static DSO *conflict_rela_cmp_dso; + static int conflict_rela_cmp (const void *A, const void *B) { + DSO *dso = conflict_rela_cmp_dso; GElf_Rela *a = (GElf_Rela *)A; GElf_Rela *b = (GElf_Rela *)B; - if (GELF_R_SYM (a->r_info) < GELF_R_SYM (b->r_info)) + if (reloc_r_sym (dso, a->r_info) < reloc_r_sym (dso, b->r_info)) return -1; - if (GELF_R_SYM (a->r_info) > GELF_R_SYM (b->r_info)) + if (reloc_r_sym (dso, a->r_info) > reloc_r_sym (dso, b->r_info)) return 1; if (a->r_offset < b->r_offset) return -1; @@ -326,7 +332,7 @@ get_relocated_mem (struct prelink_info *info, DSO *dso, GElf_Addr addr, <= addr) continue; - reloc_type = GELF_R_TYPE (info->conflict_rela[j].r_info); + reloc_type = reloc_r_type (dso, info->conflict_rela[j].r_info); reloc_size = dso->arch->reloc_size (reloc_type); if (info->conflict_rela[j].r_offset + reloc_size <= addr) continue; @@ -406,7 +412,7 @@ get_relocated_mem (struct prelink_info *info, DSO *dso, GElf_Addr addr, if (u.rel.r_offset + dso->arch->max_reloc_size <= addr) continue; - reloc_type = GELF_R_TYPE (u.rel.r_info); + reloc_type = reloc_r_type (dso, u.rel.r_info); reloc_size = dso->arch->reloc_size (reloc_type); if (u.rel.r_offset + reloc_size <= addr) continue; @@ -587,7 +593,9 @@ prelink_build_conflicts (struct prelink_info *info) /* 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)); + = 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) @@ -643,7 +651,7 @@ prelink_build_conflicts (struct prelink_info *info) { for (i = 1; i < cr.count; ++i) if (cr.rela[i].r_offset - > dso->shdr[bss1].sh_addr + dso->shdr[bss1].sh_size) + >= dso->shdr[bss1].sh_addr + dso->shdr[bss1].sh_size) break; if (cr.rela[i].r_offset < dso->shdr[bss2].sh_addr) { @@ -720,11 +728,11 @@ prelink_build_conflicts (struct prelink_info *info) int j, reloc_class; reloc_class - = dso->arch->reloc_class (GELF_R_TYPE (cr.rela[i].r_info)); + = dso->arch->reloc_class (reloc_r_type (dso, cr.rela[i].r_info)); assert (reloc_class != RTYPE_CLASS_TLS); - for (s = & info->symbols[GELF_R_SYM (cr.rela[i].r_info)]; s; + for (s = & info->symbols[reloc_r_sym (dso, cr.rela[i].r_info)]; s; s = s->next) if (s->reloc_class == reloc_class) break; @@ -771,13 +779,15 @@ prelink_build_conflicts (struct prelink_info *info) if (info->conflict_rela_size) { + conflict_rela_cmp_dso = dso; qsort (info->conflict_rela, info->conflict_rela_size, sizeof (GElf_Rela), conflict_rela_cmp); /* Now make sure all conflict RELA's are against absolute 0 symbol. */ for (i = 0; i < info->conflict_rela_size; ++i) info->conflict_rela[i].r_info - = GELF_R_INFO (0, GELF_R_TYPE (info->conflict_rela[i].r_info)); + = reloc_r_info (dso, 0, + reloc_r_type (dso, info->conflict_rela[i].r_info)); if (enable_cxx_optimizations && remove_redundant_cxx_conflicts (info)) goto error_out; diff --git a/trunk/src/cxx.c b/trunk/src/cxx.c index b3530f0..abb97a5 100644 --- a/trunk/src/cxx.c +++ b/trunk/src/cxx.c @@ -25,6 +25,7 @@ #include <unistd.h> #include <sys/wait.h> #include "prelink.h" +#include "reloc-info.h" struct find_cxx_sym { @@ -166,10 +167,10 @@ remove_redundant_cxx_conflicts (struct prelink_info *info) memset (&fcs2, 0, sizeof (fcs2)); for (i = 0; i < info->conflict_rela_size; ++i) { - reloc_type = GELF_R_TYPE (info->conflict_rela[i].r_info); + reloc_type = reloc_r_type (info->dso, info->conflict_rela[i].r_info); reloc_size = info->dso->arch->reloc_size (reloc_type); - if (GELF_R_SYM (info->conflict_rela[i].r_info) != 0) + if (reloc_r_sym (info->dso, info->conflict_rela[i].r_info) != 0) continue; if (state @@ -296,7 +297,8 @@ remove_noref: (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)); + reloc_r_info (info->dso, 1, + reloc_r_type (info->dso, info->conflict_rela[i].r_info)); ++removed; continue; @@ -350,7 +352,7 @@ check_pltref: - fcs1.sym.st_value)); info->conflict_rela[i].r_info = - GELF_R_INFO (1, GELF_R_TYPE (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; @@ -364,7 +366,7 @@ check_pltref: if (removed) { for (i = 0, j = 0; i < info->conflict_rela_size; ++i) - if (GELF_R_SYM (info->conflict_rela[i].r_info) == 0) + if (reloc_r_sym (info->dso, info->conflict_rela[i].r_info) == 0) { if (i != j) info->conflict_rela[j] = info->conflict_rela[i]; diff --git a/trunk/src/ld-libs.c b/trunk/src/ld-libs.c index c84cbb0..3954cca 100644 --- a/trunk/src/ld-libs.c +++ b/trunk/src/ld-libs.c @@ -30,6 +30,7 @@ #include "prelinktab.h" #include "reloc.h" +#include "reloc-info.h" #include "ld-libs.h" @@ -944,15 +945,15 @@ do_rel_section (DSO *dso, struct ldlibs_link_map *map, { GElf_Rel rel; gelfx_getrel (dso->elf, data, ndx, &rel); - sym = GELF_R_SYM (rel.r_info); - type = GELF_R_TYPE (rel.r_info); + sym = reloc_r_sym (dso, rel.r_info); + type = reloc_r_type (dso, rel.r_info); } else { GElf_Rela rela; gelfx_getrela (dso->elf, data, ndx, &rela); - sym = GELF_R_SYM (rela.r_info); - type = GELF_R_TYPE (rela.r_info); + sym = reloc_r_sym (dso, rela.r_info); + type = reloc_r_type (dso, rela.r_info); } if (sym != 0) do_reloc (dso, map, scope, sym, type); diff --git a/trunk/src/prelink.c b/trunk/src/prelink.c index 1a2260e..663a071 100644 --- a/trunk/src/prelink.c +++ b/trunk/src/prelink.c @@ -440,6 +440,7 @@ prelink_prepare (DSO *dso) break; case SHT_DYNAMIC: case SHT_MIPS_REGINFO: + case SHT_MIPS_OPTIONS: /* The same applies to these sections on MIPS. The convention is to put .dynamic and .reginfo near the beginning of the read-only segment, before the program text. No relocations diff --git a/trunk/src/prelink.h b/trunk/src/prelink.h index 5507eda..a50ddfe 100644 --- a/trunk/src/prelink.h +++ b/trunk/src/prelink.h @@ -1,5 +1,6 @@ /* Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006 Red Hat, Inc. Written by Jakub Jelinek <jakub@redhat.com>, 2001. + Updated by Maciej W. Rozycki <macro@codesourcery.com>, 2008. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -28,6 +29,10 @@ #include <sys/stat.h> #include <utime.h> +#ifndef HAVE_ELF64_BYTE +typedef uint8_t Elf64_Byte; +#endif + #ifndef DT_GNU_LIBLIST #define DT_GNU_LIBLIST 0x6ffffef9 #define DT_GNU_LIBLISTSZ 0x6ffffdf7 @@ -94,6 +99,10 @@ #define DT_MIPS_RWPLT 0x70000034 #endif +#ifndef RSS_UNDEF +#define RSS_UNDEF 0 +#endif + struct prelink_entry; struct prelink_info; struct PLArch; @@ -304,8 +313,8 @@ unsigned char *get_data_from_iterator (struct data_iterator *it, GElf_Addr size); int get_sym_from_iterator (struct data_iterator *it, GElf_Sym *sym); -#define PL_ARCH \ -static struct PLArch plarch __attribute__((section("pl_arch"),used)) +#define PL_ARCH(F) \ +static struct PLArch plarch_##F __attribute__((section("pl_arch"),used)) #define addr_adjust(addr, start, adjust) \ do { \ diff --git a/trunk/src/reloc-info.c b/trunk/src/reloc-info.c new file mode 100644 index 0000000..4ce333c --- /dev/null +++ b/trunk/src/reloc-info.c @@ -0,0 +1,215 @@ +/* Copyright (C) 2008 CodeSourcery + Written by Maciej W. Rozycki <macro@codesourcery.com>, 2008. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include <config.h> + +#include "prelink.h" +#include "reloc-info.h" + +/* A structure to lay out generic relocation information + * in a way specific to 64-bit MIPS. */ +union mips64_r_info +{ + /* Generic r_info interpretation. */ + Elf64_Xword r_info; + + /* 64-bit MIPS r_info interpretation. */ + struct + { + /* Symbol index for the first relocation. */ + Elf64_Word r_sym; + + /* Special symbol for the second relocation. */ + Elf64_Byte r_ssym; + + /* Third relocation. */ + Elf64_Byte r_type3; + + /* Second relocation. */ + Elf64_Byte r_type2; + + /* First relocation. */ + Elf64_Byte r_type; + } + s_info; +}; + +/* Extract the symbol index from 64-bit MIPS reloc info. */ + +static GElf_Xword +mips64_r_sym (DSO *dso, GElf_Xword r_info) +{ + union mips64_r_info mips64_r_info; + + buf_write_ne64 (dso, (unsigned char *) &mips64_r_info.r_info, r_info); + return buf_read_une32 (dso, (unsigned char *) &mips64_r_info.s_info.r_sym); +} + +/* Extract the special symbol index from 64-bit MIPS reloc info. */ + +static GElf_Xword +mips64_r_ssym (DSO *dso, GElf_Xword r_info) +{ + union mips64_r_info mips64_r_info; + + buf_write_ne64 (dso, (unsigned char *) &mips64_r_info.r_info, r_info); + return mips64_r_info.s_info.r_ssym; +} + +/* Extract the first reloc type from 64-bit MIPS reloc info. */ + +static GElf_Xword +mips64_r_type (DSO *dso, GElf_Xword r_info) +{ + union mips64_r_info mips64_r_info; + + buf_write_ne64 (dso, (unsigned char *) &mips64_r_info.r_info, r_info); + return mips64_r_info.s_info.r_type; +} + +/* Extract the second reloc type from 64-bit MIPS reloc info. */ + +static GElf_Xword +mips64_r_type2 (DSO *dso, GElf_Xword r_info) +{ + union mips64_r_info mips64_r_info; + + buf_write_ne64 (dso, (unsigned char *) &mips64_r_info.r_info, r_info); + return mips64_r_info.s_info.r_type2; +} + +/* Extract the third reloc type from 64-bit MIPS reloc info. */ + +static GElf_Xword +mips64_r_type3 (DSO *dso, GElf_Xword r_info) +{ + union mips64_r_info mips64_r_info; + + buf_write_ne64 (dso, (unsigned char *) &mips64_r_info.r_info, r_info); + return mips64_r_info.s_info.r_type3; +} + +/* Construct 64-bit MIPS reloc info from symbol indices and reloc types. */ + +static GElf_Xword +mips64_r_info_ext (DSO *dso, GElf_Word r_sym, Elf64_Byte r_ssym, + Elf64_Byte r_type, Elf64_Byte r_type2, Elf64_Byte r_type3) +{ + union mips64_r_info mips64_r_info; + + buf_write_ne32 (dso, (unsigned char *) &mips64_r_info.s_info.r_sym, r_sym); + mips64_r_info.s_info.r_ssym = r_ssym; + mips64_r_info.s_info.r_type = r_type; + mips64_r_info.s_info.r_type2 = r_type2; + mips64_r_info.s_info.r_type3 = r_type3; + return buf_read_une64 (dso, (unsigned char *) &mips64_r_info.r_info); +} + + +/* Extract the symbol index from reloc info. */ + +GElf_Xword +reloc_r_sym (DSO *dso, GElf_Xword r_info) +{ + if (dso->ehdr.e_ident[EI_CLASS] == ELFCLASS64 + && dso->ehdr.e_machine == EM_MIPS) + return mips64_r_sym (dso, r_info); + else + return GELF_R_SYM (r_info); +} + +/* Extract the special symbol index from reloc info. */ + +GElf_Xword +reloc_r_ssym (DSO *dso, GElf_Xword r_info) +{ + if (dso->ehdr.e_ident[EI_CLASS] == ELFCLASS64 + && dso->ehdr.e_machine == EM_MIPS) + return mips64_r_ssym (dso, r_info); + else + return RSS_UNDEF; +} + +/* Extract the first reloc type from reloc info. */ + +GElf_Xword +reloc_r_type (DSO *dso, GElf_Xword r_info) +{ + if (dso->ehdr.e_ident[EI_CLASS] == ELFCLASS64 + && dso->ehdr.e_machine == EM_MIPS) + return mips64_r_type (dso, r_info); + else + return GELF_R_TYPE (r_info); +} + +/* Extract the second reloc type from reloc info. */ + +GElf_Xword +reloc_r_type2 (DSO *dso, GElf_Xword r_info) +{ + if (dso->ehdr.e_ident[EI_CLASS] == ELFCLASS64 + && dso->ehdr.e_machine == EM_MIPS) + return mips64_r_type2 (dso, r_info); + else + return 0; +} + +/* Extract the third reloc type from reloc info. */ + +GElf_Xword +reloc_r_type3 (DSO *dso, GElf_Xword r_info) +{ + if (dso->ehdr.e_ident[EI_CLASS] == ELFCLASS64 + && dso->ehdr.e_machine == EM_MIPS) + return mips64_r_type3 (dso, r_info); + else + return 0; +} + +/* Construct reloc info from symbol index and reloc type. */ + +GElf_Xword +reloc_r_info (DSO *dso, GElf_Word r_sym, GElf_Word r_type) +{ + if (dso->ehdr.e_ident[EI_CLASS] == ELFCLASS64 + && dso->ehdr.e_machine == EM_MIPS) + switch (r_type) + { + case R_MIPS_REL32: + case R_MIPS_GLOB_DAT: + return mips64_r_info_ext (dso, r_sym, RSS_UNDEF, + r_type, R_MIPS_64, R_MIPS_NONE); + default: + return mips64_r_info_ext (dso, r_sym, RSS_UNDEF, + r_type, R_MIPS_NONE, R_MIPS_NONE); + } + else + return GELF_R_INFO (r_sym, r_type); +} + +/* Construct reloc info from symbol index and reloc type. */ + +GElf_Xword +reloc_r_info_ext (DSO *dso, GElf_Word r_sym, Elf64_Byte r_ssym, + Elf64_Byte r_type, Elf64_Byte r_type2, Elf64_Byte r_type3) +{ + if (dso->ehdr.e_ident[EI_CLASS] == ELFCLASS64 + && dso->ehdr.e_machine == EM_MIPS) + return mips64_r_info_ext (dso, r_sym, r_ssym, r_type, r_type2, r_type3); + else + return GELF_R_INFO (r_sym, r_type); +} diff --git a/trunk/src/reloc-info.h b/trunk/src/reloc-info.h new file mode 100644 index 0000000..a8f8b7c --- /dev/null +++ b/trunk/src/reloc-info.h @@ -0,0 +1,35 @@ +/* Copyright (C) 2008 CodeSourcery + Written by Maciej W. Rozycki <macro@codesourcery.com>, 2008. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef RELOC_INFO_H +#define RELOC_INFO_H + +#include "prelink.h" + +/* Reloc info primitives. */ +GElf_Xword reloc_r_sym (DSO *dso, GElf_Xword r_info); +GElf_Xword reloc_r_ssym (DSO *dso, GElf_Xword r_info); +GElf_Xword reloc_r_type (DSO *dso, GElf_Xword r_info); +GElf_Xword reloc_r_type2 (DSO *dso, GElf_Xword r_info); +GElf_Xword reloc_r_type3 (DSO *dso, GElf_Xword r_info); + +GElf_Xword reloc_r_info (DSO *dso, GElf_Word r_sym, GElf_Word r_type); +GElf_Xword reloc_r_info_ext (DSO *dso, GElf_Word r_sym, Elf64_Byte r_ssym, + Elf64_Byte r_type, Elf64_Byte r_type2, + Elf64_Byte r_type3); + +#endif /* RELOC_INFO_H */ |