OSDN Git Service

Merge remote-tracking branch 'origin/master' into prelink
[uclinux-h8/uClibc.git] / ldso / ldso / x86_64 / elfinterp.c
index 66552d8..44e2c66 100644 (file)
@@ -47,7 +47,6 @@ extern int _dl_linux_resolve(void);
 unsigned long
 _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)
 {
-       int reloc_type;
        ELF_RELOC *this_reloc;
        char *strtab;
        ElfW(Sym) *symtab;
@@ -60,25 +59,18 @@ _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)
 
        rel_addr = (char *)tpnt->dynamic_info[DT_JMPREL];
        this_reloc = (ELF_RELOC *)(rel_addr + reloc_entry);
-       reloc_type = ELF_R_TYPE(this_reloc->r_info);
        symtab_index = ELF_R_SYM(this_reloc->r_info);
 
        symtab = (ElfW(Sym) *)tpnt->dynamic_info[DT_SYMTAB];
        strtab = (char *)tpnt->dynamic_info[DT_STRTAB];
        symname = strtab + symtab[symtab_index].st_name;
 
-       if (unlikely(reloc_type != R_X86_64_JUMP_SLOT)) {
-               _dl_dprintf(2, "%s: Incorrect relocation type in jump relocations\n",
-                           _dl_progname);
-               _dl_exit(1);
-       }
-
        /* Address of the jump instruction to fix up. */
        instr_addr = (this_reloc->r_offset + 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);
+       new_addr = _dl_find_hash(symname, &_dl_loaded_modules->symbol_scope, tpnt, ELF_RTYPE_CLASS_PLT, NULL);
        if (unlikely(!new_addr)) {
                _dl_dprintf(2, "%s: Can't resolve symbol '%s'\n", _dl_progname, symname);
                _dl_exit(1);
@@ -102,9 +94,9 @@ _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)
 }
 
 static int
-_dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope,
+_dl_parse(struct elf_resolve *tpnt, struct r_scope_elem *scope,
          unsigned long rel_addr, unsigned long rel_size,
-         int (*reloc_fnc)(struct elf_resolve *tpnt, struct dyn_elf *scope,
+         int (*reloc_fnc)(struct elf_resolve *tpnt, struct r_scope_elem *scope,
                           ELF_RELOC *rpnt, ElfW(Sym) *symtab, char *strtab))
 {
        unsigned int i;
@@ -159,12 +151,14 @@ _dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope,
 }
 
 static int
-_dl_do_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope,
+_dl_do_reloc(struct elf_resolve *tpnt, struct r_scope_elem *scope,
             ELF_RELOC *rpnt, ElfW(Sym) *symtab, char *strtab)
 {
        int reloc_type;
        int symtab_index;
        char *symname;
+       struct elf_resolve *tls_tpnt = NULL;
+       struct symbol_ref sym_ref;
        ElfW(Addr) *reloc_addr;
        ElfW(Addr) symbol_addr;
 #if defined (__SUPPORT_LD_DEBUG__)
@@ -174,21 +168,34 @@ _dl_do_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope,
        reloc_addr = (ElfW(Addr)*)(tpnt->loadaddr + (unsigned long)rpnt->r_offset);
        reloc_type = ELF_R_TYPE(rpnt->r_info);
        symtab_index = ELF_R_SYM(rpnt->r_info);
+       sym_ref.sym = &symtab[symtab_index];
+       sym_ref.tpnt = NULL;
        symbol_addr = 0;
-       symname = strtab + symtab[symtab_index].st_name;
+       symname = strtab + sym_ref.sym->st_name;
 
        if (symtab_index) {
                symbol_addr = (ElfW(Addr))_dl_find_hash(symname, scope, tpnt,
-                                                           elf_machine_type_class(reloc_type));
+                               elf_machine_type_class(reloc_type), &sym_ref);
                /*
                 * We want to allow undefined references to weak symbols - this
                 * might have been intentional.  We should not be linking local
                 * symbols here, so all bases should be covered.
                 */
-               if (unlikely(!symbol_addr && ELF_ST_BIND(symtab[symtab_index].st_info) != STB_WEAK)) {
-                       _dl_dprintf(2, "%s: can't resolve symbol '%s'\n", _dl_progname, symname);
-                       _dl_exit(1);
-               };
+               if (unlikely(!symbol_addr && (ELF_ST_TYPE(sym_ref.sym->st_info) != STT_TLS)
+                                       && (ELF_ST_BIND(sym_ref.sym->st_info) != STB_WEAK))) {
+                       /* This may be non-fatal if called from dlopen. */
+                       return 1;
+               }
+               if (_dl_trace_prelink)
+                       _dl_debug_lookup (symname, tpnt, &symtab[symtab_index],
+                                               &sym_ref, elf_machine_type_class(reloc_type));
+               tls_tpnt = sym_ref.tpnt;
+       } else {
+               /* Relocs against STN_UNDEF are usually treated as using a
+                * symbol value of zero, and using the module containing the
+                * reloc itself. */
+               symbol_addr = sym_ref.sym->st_value;
+               tls_tpnt = tpnt;
        }
 
 #if defined (__SUPPORT_LD_DEBUG__)
@@ -209,7 +216,7 @@ _dl_do_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope,
 
                case R_X86_64_GLOB_DAT:
                case R_X86_64_JUMP_SLOT:
-                       *reloc_addr = symbol_addr;
+                       *reloc_addr = symbol_addr + rpnt->r_addend;
                        break;
 
                /* handled by elf_machine_relative()
@@ -217,33 +224,42 @@ _dl_do_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope,
                        *reloc_addr = map->l_addr + rpnt->r_addend;
                        break;
                */
-#if 0
+#if defined USE_TLS && USE_TLS
                case R_X86_64_DTPMOD64:
+                       *reloc_addr = tls_tpnt->l_tls_modid;
                        break;
                case R_X86_64_DTPOFF64:
+                       /* During relocation all TLS symbols are defined and used.
+                        * Therefore the offset is already correct.  */
                        *reloc_addr = symbol_addr + rpnt->r_addend;
                        break;
                case R_X86_64_TPOFF64:
-                       *reloc_addr = symbol_addr + rpnt->r_addend;
+                       /* The offset is negative, forward from the thread pointer.
+                        * We know the offset of the object the symbol is contained in.
+                        * It is a negative value which will be added to the
+                        * thread pointer.  */
+                       CHECK_STATIC_TLS ((struct link_map *) tls_tpnt);
+                       *reloc_addr = symbol_addr - tls_tpnt->l_tls_offset + rpnt->r_addend;
                        break;
+#endif
                case R_X86_64_32:
-                       *reloc_addr = symbol_addr + rpnt->r_addend;
+                       *(unsigned int *) reloc_addr = symbol_addr + rpnt->r_addend;
+                       /* XXX: should check for overflow eh ? */
                        break;
 
-#endif
                case R_X86_64_COPY:
                        if (symbol_addr) {
 #if defined (__SUPPORT_LD_DEBUG__)
                                if (_dl_debug_move)
                                        _dl_dprintf(_dl_debug_file,
                                                    "\t%s move %d bytes from %x to %x\n",
-                                                   symname, symtab[symtab_index].st_size,
+                                                   symname, sym_ref.sym->st_size,
                                                    symbol_addr, reloc_addr);
 #endif
 
                                _dl_memcpy((char *)reloc_addr,
                                           (char *)symbol_addr,
-                                          symtab[symtab_index].st_size);
+                                          sym_ref.sym->st_size);
                        } else
                                _dl_dprintf(_dl_debug_file, "no symbol_addr to copy !?\n");
                        break;
@@ -261,9 +277,8 @@ _dl_do_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope,
        return 0;
 }
 
-#if 0
 static int
-_dl_do_lazy_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope,
+_dl_do_lazy_reloc(struct elf_resolve *tpnt, struct r_scope_elem *scope,
                  ELF_RELOC *rpnt, ElfW(Sym) *symtab, char *strtab)
 {
        int reloc_type;
@@ -288,7 +303,7 @@ _dl_do_lazy_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope,
                case R_X86_64_NONE:
                        break;
                case R_X86_64_JUMP_SLOT:
-                       *reloc_addr = tpnt->loadaddr + symtab[symtab_index].st_value;
+                       *reloc_addr += (unsigned long)tpnt->loadaddr;
                        break;
                default:
                        _dl_exit(1);
@@ -302,23 +317,20 @@ _dl_do_lazy_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope,
 
        return 0;
 }
-#endif
 
 void
 _dl_parse_lazy_relocation_information(struct dyn_elf *rpnt,
                                      unsigned long rel_addr,
                                      unsigned long rel_size)
 {
-       _dl_parse_relocation_information(rpnt, rel_addr, rel_size);
-/*     jump slot isnt working
        (void)_dl_parse(rpnt->dyn, NULL, rel_addr, rel_size, _dl_do_lazy_reloc);
-*/
 }
 
 int
 _dl_parse_relocation_information(struct dyn_elf *rpnt,
+                                struct r_scope_elem *scope,
                                 unsigned long rel_addr,
                                 unsigned long rel_size)
 {
-       return _dl_parse(rpnt->dyn, rpnt->dyn->symbol_scope, rel_addr, rel_size, _dl_do_reloc);
+       return _dl_parse(rpnt->dyn, scope, rel_addr, rel_size, _dl_do_reloc);
 }