uClibc: add support for mips non-pic relocations in ldso
authorFelix Fietkau <nbd@openwrt.org>
Mon, 19 Oct 2009 07:41:29 +0000 (07:41 +0000)
committerFelix Fietkau <nbd@openwrt.org>
Mon, 19 Oct 2009 07:41:29 +0000 (07:41 +0000)
SVN-Revision: 18069

toolchain/uClibc/patches-0.9.30.1/440-backport_mips_nonpic.patch [new file with mode: 0644]

diff --git a/toolchain/uClibc/patches-0.9.30.1/440-backport_mips_nonpic.patch b/toolchain/uClibc/patches-0.9.30.1/440-backport_mips_nonpic.patch
new file mode 100644 (file)
index 0000000..abcd6ec
--- /dev/null
@@ -0,0 +1,289 @@
+--- a/include/elf.h
++++ b/include/elf.h
+@@ -1547,6 +1547,7 @@ typedef struct
+ #define STO_MIPS_INTERNAL             0x1
+ #define STO_MIPS_HIDDEN                       0x2
+ #define STO_MIPS_PROTECTED            0x3
++#define STO_MIPS_PLT                  0x8
+ #define STO_MIPS_SC_ALIGN_UNUSED      0xff
+ /* MIPS specific values for `st_info'.  */
+@@ -1692,8 +1693,11 @@ typedef struct
+ #define R_MIPS_TLS_TPREL64    48      /* TP-relative offset, 64 bit */
+ #define R_MIPS_TLS_TPREL_HI16 49      /* TP-relative offset, high 16 bits */
+ #define R_MIPS_TLS_TPREL_LO16 50      /* TP-relative offset, low 16 bits */
++#define R_MIPS_GLOB_DAT               51
++#define R_MIPS_COPY           126
++#define R_MIPS_JUMP_SLOT        127
+ /* Keep this the last entry.  */
+-#define R_MIPS_NUM            51
++#define R_MIPS_NUM            128
+ /* Legal values for p_type field of Elf32_Phdr.  */
+@@ -1759,7 +1763,13 @@ typedef struct
+ #define DT_MIPS_COMPACT_SIZE 0x7000002f /* (O32)Size of compact rel section. */
+ #define DT_MIPS_GP_VALUE     0x70000030 /* GP value for aux GOTs.  */
+ #define DT_MIPS_AUX_DYNAMIC  0x70000031 /* Address of aux .dynamic.  */
+-#define DT_MIPS_NUM        0x32
++/* The address of .got.plt in an executable using the new non-PIC ABI.  */
++#define DT_MIPS_PLTGOT             0x70000032
++/* The base of the PLT in an executable using the new non-PIC ABI if that
++   PLT is writable.  For a non-writable PLT, this is omitted or has a zero
++   value.  */
++#define DT_MIPS_RWPLT        0x70000034
++#define DT_MIPS_NUM        0x35
+ /* Legal values for DT_MIPS_FLAGS Elf32_Dyn entry.  */
+--- a/ldso/ldso/dl-hash.c
++++ b/ldso/ldso/dl-hash.c
+@@ -160,6 +160,11 @@ check_match (const ElfW(Sym) *sym, char 
+               /* undefined symbol itself */
+               return NULL;
++#ifdef __mips__
++    if (sym->st_shndx == SHN_UNDEF && !(sym->st_other & STO_MIPS_PLT))
++        return NULL;
++#endif
++
+       if (sym->st_value == 0)
+               /* No value */
+               return NULL;
+--- a/ldso/ldso/mips/dl-sysdep.h
++++ b/ldso/ldso/mips/dl-sysdep.h
+@@ -93,10 +93,11 @@ typedef struct
+ #include <link.h>
+-#define ARCH_NUM 3
++#define ARCH_NUM 4
+ #define DT_MIPS_GOTSYM_IDX    (DT_NUM + OS_NUM)
+ #define DT_MIPS_LOCAL_GOTNO_IDX       (DT_NUM + OS_NUM +1)
+ #define DT_MIPS_SYMTABNO_IDX  (DT_NUM + OS_NUM +2)
++#define DT_MIPS_PLTGOT_IDX    (DT_NUM + OS_NUM +3)
+ #define ARCH_DYNAMIC_INFO(dpnt,  dynamic, debug_addr) \
+ do { \
+@@ -106,6 +107,8 @@ else if (dpnt->d_tag == DT_MIPS_LOCAL_GO
+      dynamic[DT_MIPS_LOCAL_GOTNO_IDX] = dpnt->d_un.d_val; \
+ else if (dpnt->d_tag == DT_MIPS_SYMTABNO) \
+      dynamic[DT_MIPS_SYMTABNO_IDX] = dpnt->d_un.d_val; \
++else if (dpnt->d_tag == DT_MIPS_PLTGOT) \
++     dynamic[DT_MIPS_PLTGOT_IDX] = dpnt->d_un.d_val; \
+ else if (dpnt->d_tag == DT_MIPS_RLD_MAP) \
+      *(ElfW(Addr) *)(dpnt->d_un.d_ptr) =  (ElfW(Addr)) debug_addr; \
+ } while (0)
+@@ -114,6 +117,7 @@ else if (dpnt->d_tag == DT_MIPS_RLD_MAP)
+ #define INIT_GOT(GOT_BASE,MODULE)                                             \
+ do {                                                                          \
+       unsigned long idx;                                                      \
++      unsigned long *pltgot;                                                  \
+                                                                               \
+       /* Check if this is the dynamic linker itself */                        \
+       if (MODULE->libtype == program_interpreter)                             \
+@@ -123,6 +127,12 @@ do {                                                                              \
+       GOT_BASE[0] = (unsigned long) _dl_runtime_resolve;                      \
+       GOT_BASE[1] = (unsigned long) MODULE;                                   \
+                                                                               \
++      pltgot = MODULE->dynamic_info[DT_MIPS_PLTGOT_IDX];                      \
++      if (pltgot) {                                                           \
++              pltgot[0] = (unsigned long) _dl_runtime_pltresolve;             \
++              pltgot[1] = (unsigned long) MODULE;                             \
++      }                                                                       \
++                                                                              \
+       /* Add load address displacement to all local GOT entries */            \
+       idx = 2;                                                                        \
+       while (idx < MODULE->dynamic_info[DT_MIPS_LOCAL_GOTNO_IDX])             \
+@@ -157,9 +167,9 @@ void _dl_perform_mips_global_got_relocat
+ #define OFFS_ALIGN 0x7ffff000
+ #endif        /* O32 || N32 */
+-#define elf_machine_type_class(type)          ELF_RTYPE_CLASS_PLT
+-/* MIPS does not have COPY relocs */
+-#define DL_NO_COPY_RELOCS
++#define elf_machine_type_class(type) \
++  ((((type) == R_MIPS_JUMP_SLOT) * ELF_RTYPE_CLASS_PLT)       \
++   | (((type) == R_MIPS_COPY) * ELF_RTYPE_CLASS_COPY))
+ #define OFFSET_GP_GOT 0x7ff0
+--- a/ldso/ldso/mips/elfinterp.c
++++ b/ldso/ldso/mips/elfinterp.c
+@@ -30,6 +30,7 @@
+ #include "ldso.h"
+ extern int _dl_runtime_resolve(void);
++extern int _dl_runtime_pltresolve(void);
+ #define OFFSET_GP_GOT 0x7ff0
+@@ -83,6 +84,61 @@ unsigned long __dl_runtime_resolve(unsig
+       return new_addr;
+ }
++unsigned long
++__dl_runtime_pltresolve(struct elf_resolve *tpnt, int reloc_entry)
++{
++      int reloc_type;
++      ELF_RELOC *this_reloc;
++      char *strtab;
++      Elf32_Sym *symtab;
++      int symtab_index;
++      char *rel_addr;
++      char *new_addr;
++      char **got_addr;
++      unsigned long instr_addr;
++      char *symname;
++
++      rel_addr = (char *)tpnt->dynamic_info[DT_JMPREL];
++      this_reloc = (ELF_RELOC *)(intptr_t)(rel_addr + reloc_entry);
++      reloc_type = ELF32_R_TYPE(this_reloc->r_info);
++      symtab_index = ELF32_R_SYM(this_reloc->r_info);
++
++      symtab = (Elf32_Sym *)(intptr_t)tpnt->dynamic_info[DT_SYMTAB];
++      strtab = (char *)tpnt->dynamic_info[DT_STRTAB];
++      symname = strtab + symtab[symtab_index].st_name;
++
++      /* Address of the jump instruction to fix up. */
++      instr_addr = ((unsigned long)this_reloc->r_offset +
++                    (unsigned long)tpnt->loadaddr);
++      got_addr = (char **)instr_addr;
++
++      /* Get the address of the GOT entry. */
++      new_addr = _dl_find_hash(symname, tpnt->symbol_scope, tpnt, ELF_RTYPE_CLASS_PLT);
++      if (unlikely(!new_addr)) {
++              _dl_dprintf(2, "%s: can't resolve symbol '%s' in lib '%s'.\n", _dl_progname, symname, tpnt->libname);
++              _dl_exit(1);
++      }
++
++#if defined (__SUPPORT_LD_DEBUG__)
++      if ((unsigned long)got_addr < 0x40000000) {
++              if (_dl_debug_bindings) {
++                      _dl_dprintf(_dl_debug_file, "\nresolve function: %s", symname);
++                      if (_dl_debug_detail)
++                              _dl_dprintf(_dl_debug_file,
++                                          "\n\tpatched: %x ==> %x @ %x",
++                                          *got_addr, new_addr, got_addr);
++              }
++      }
++      if (!_dl_debug_nofixups) {
++              *got_addr = new_addr;
++      }
++#else
++      *got_addr = new_addr;
++#endif
++
++      return (unsigned long)new_addr;
++}
++
+ void _dl_parse_lazy_relocation_information(struct dyn_elf *rpnt,
+       unsigned long rel_addr, unsigned long rel_size)
+ {
+@@ -115,6 +171,7 @@ int _dl_parse_relocation_information(str
+       got = (unsigned long *) tpnt->dynamic_info[DT_PLTGOT];
+       for (i = 0; i < rel_size; i++, rpnt++) {
++              char *symname = NULL;
+               reloc_addr = (unsigned long *) (tpnt->loadaddr +
+                       (unsigned long) rpnt->r_offset);
+               reloc_type = ELF_R_TYPE(rpnt->r_info);
+@@ -128,6 +185,16 @@ int _dl_parse_relocation_information(str
+                       old_val = *reloc_addr;
+ #endif
++              if (reloc_type == R_MIPS_JUMP_SLOT || reloc_type == R_MIPS_COPY) {
++                      symname = strtab + symtab[symtab_index].st_name;
++                      symbol_addr = (unsigned long)_dl_find_hash(symname,
++                                                                 tpnt->symbol_scope,
++                                                                 tpnt,
++                                                                 elf_machine_type_class(reloc_type));
++                      if (unlikely(!symbol_addr && ELF32_ST_BIND(symtab[symtab_index].st_info) != STB_WEAK))
++                              return 1;
++              }
++
+               switch (reloc_type) {
+ #if _MIPS_SIM == _MIPS_SIM_ABI64
+               case (R_MIPS_64 << 8) | R_MIPS_REL32:
+@@ -148,6 +215,24 @@ int _dl_parse_relocation_information(str
+                               *reloc_addr += (unsigned long) tpnt->loadaddr;
+                       }
+                       break;
++              case R_MIPS_JUMP_SLOT:
++                      *reloc_addr = symbol_addr;
++                      break;
++              case R_MIPS_COPY:
++                      if (symbol_addr) {
++#if defined (__SUPPORT_LD_DEBUG__)
++                              if (_dl_debug_move)
++                                      _dl_dprintf(_dl_debug_file,
++                                                  "\n%s move %d bytes from %x to %x",
++                                                  symname, symtab[symtab_index].st_size,
++                                                  symbol_addr, reloc_addr);
++#endif
++
++                              _dl_memcpy((char *)reloc_addr,
++                                         (char *)symbol_addr,
++                                         symtab[symtab_index].st_size);
++                      }
++                      break;
+               case R_MIPS_NONE:
+                       break;
+               default:
+--- a/ldso/ldso/mips/resolve.S
++++ b/ldso/ldso/mips/resolve.S
+@@ -112,3 +112,54 @@ _dl_runtime_resolve:
+ .end  _dl_runtime_resolve
+ .previous
++/* Assembler veneer called from the PLT header code when using the
++   non-PIC ABI.
++
++   Code in each PLT entry puts the caller's return address into t7 ($15),
++   the PLT entry index into t8 ($24), the address of _dl_runtime_pltresolve
++   into t9 ($25) and the address of .got.plt into gp ($28).  __dl_runtime_pltresolve
++   needs a0 ($4) to hold the link map and a1 ($5) to hold the index into
++   .rel.plt (== PLT entry index * 4).  */
++
++      .text
++      .align  2
++      .globl  _dl_runtime_pltresolve
++      .type   _dl_runtime_pltresolve,@function
++      .ent    _dl_runtime_pltresolve
++_dl_runtime_pltresolve:
++      .frame  $29, 40, $31
++      .set noreorder
++      # Save arguments and sp value in stack.
++      subu    $29, 40
++      lw      $10, 4($28)
++      # Modify t9 ($25) so as to point .cpload instruction.
++      addiu   $25, 12
++      # Compute GP.
++      .cpload $25
++      .set reorder
++
++      /* Store function arguments from registers to stack */
++      sw      $15, 36($29)
++      sw      $4, 16($29)
++      sw      $5, 20($29)
++      sw      $6, 24($29)
++      sw      $7, 28($29)
++
++      /* Setup functions args and call __dl_runtime_pltresolve.  */
++      move    $4, $10
++      sll     $5, $24, 3
++      jal     __dl_runtime_pltresolve
++
++      /* Restore function arguments from stack to registers */
++      lw      $31, 36($29)
++      lw      $4, 16($29)
++      lw      $5, 20($29)
++      lw      $6, 24($29)
++      lw      $7, 28($29)
++
++      /* Do a tail call to the original function */
++      addiu   $29, 40
++      move    $25, $2
++      jr      $25
++      .end    _dl_runtime_pltresolve
++      .previous