aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMark Hatle <mark.hatle@windriver.com>2010-06-14 17:52:54 -0500
committerMark Hatle <mark.hatle@windriver.com>2010-07-22 18:02:47 -0500
commitbc90f2b06c14da517688c0c4db37b3467ea5df08 (patch)
tree9d9ebea6e7a0897181d0387f3ff4614252faa431
parent8ac4ed1b0645f9d6d51d999dfa3604d873a53e30 (diff)
downloadprelink-cross-bc90f2b06c14da517688c0c4db37b3467ea5df08.tar.gz
prelink-cross-bc90f2b06c14da517688c0c4db37b3467ea5df08.tar.bz2
prelink-cross-bc90f2b06c14da517688c0c4db37b3467ea5df08.zip
Add MIPS64 prelinking and other associated items
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. 200?-??-?? CodeSourcery, LLC. * src/prelink.h: define PL_ARCH(arch) macro * update each arch-<arch>.c file to use the new macro Add attribution
-rw-r--r--trunk/ChangeLog.cross98
-rw-r--r--trunk/configure.in5
-rw-r--r--trunk/src/Makefile.am5
-rw-r--r--trunk/src/arch-alpha.c2
-rw-r--r--trunk/src/arch-arm.c2
-rw-r--r--trunk/src/arch-cris.c2
-rw-r--r--trunk/src/arch-i386.c2
-rw-r--r--trunk/src/arch-ia64.c2
-rw-r--r--trunk/src/arch-mips.c550
-rw-r--r--trunk/src/arch-ppc.c2
-rw-r--r--trunk/src/arch-ppc64.c2
-rw-r--r--trunk/src/arch-s390.c2
-rw-r--r--trunk/src/arch-s390x.c2
-rw-r--r--trunk/src/arch-sh.c2
-rw-r--r--trunk/src/arch-sparc.c2
-rw-r--r--trunk/src/arch-sparc64.c2
-rw-r--r--trunk/src/arch-x86_64.c2
-rw-r--r--trunk/src/conflict.c34
-rw-r--r--trunk/src/cxx.c12
-rw-r--r--trunk/src/ld-libs.c9
-rw-r--r--trunk/src/prelink.c1
-rw-r--r--trunk/src/prelink.h13
-rw-r--r--trunk/src/reloc-info.c215
-rw-r--r--trunk/src/reloc-info.h35
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 */