diff options
author | "Steven J. Hill" <sjhill@realitydiluted.com> | 2006-01-14 19:18:52 +0000 |
---|---|---|
committer | "Steven J. Hill" <sjhill@realitydiluted.com> | 2006-01-14 19:18:52 +0000 |
commit | ad842abbb4a49f5c89092a6844f1535c933381ba (patch) | |
tree | 98903649805fd3ac0b517bf1c206e3b82ba44eb9 | |
parent | 04c3ae8212af7ae1152116a8c632f1df5c4f5a75 (diff) | |
download | uClibc-alpine-ad842abbb4a49f5c89092a6844f1535c933381ba.tar.bz2 uClibc-alpine-ad842abbb4a49f5c89092a6844f1535c933381ba.tar.xz |
Merge from trunk.
-rw-r--r-- | ldso/ldso/x86_64/dl-debug.h | 9 | ||||
-rw-r--r-- | ldso/ldso/x86_64/elfinterp.c | 29 | ||||
-rw-r--r-- | ldso/ldso/x86_64/resolve.S | 63 |
3 files changed, 82 insertions, 19 deletions
diff --git a/ldso/ldso/x86_64/dl-debug.h b/ldso/ldso/x86_64/dl-debug.h index 21412bd03..d605a0385 100644 --- a/ldso/ldso/x86_64/dl-debug.h +++ b/ldso/ldso/x86_64/dl-debug.h @@ -30,7 +30,10 @@ */ static const char *_dl_reltypes_tab[] = { - [0] "R_X86_64_NONE", "R_X86_64_64", "R_X86_64_PC32", "R_X86_64_GOT32", - [4] "R_X86_64_PLT32", "R_X86_64_COPY", "R_X86_64_GLOB_DAT", "R_X86_64_JUMP_SLOT", - [8] "R_X86_64_RELATIVE", "R_X86_64_GOTPCREL", "R_X86_64_32" + [ 0] "R_X86_64_NONE", "R_X86_64_64", "R_X86_64_PC32", "R_X86_64_GOT32", + [ 4] "R_X86_64_PLT32", "R_X86_64_COPY", "R_X86_64_GLOB_DAT", "R_X86_64_JUMP_SLOT", + [ 8] "R_X86_64_RELATIVE", "R_X86_64_GOTPCREL", "R_X86_64_32", "R_X86_64_32S", + [12] "R_X86_64_16", "R_X86_64_PC16", "R_X86_64_8", "R_X86_64_PC8", + [16] "R_X86_64_DTPMOD64", "R_X86_64_DTPOFF64", "R_X86_64_TPOFF64", "R_X86_64_TLSGD", + [20] "R_X86_64_TLSLD", "R_X86_64_DTPOFF32", "R_X86_64_GOTTPOFF", "R_X86_64_TPOFF32" }; diff --git a/ldso/ldso/x86_64/elfinterp.c b/ldso/ldso/x86_64/elfinterp.c index 66552d879..ef0fcb4e4 100644 --- a/ldso/ldso/x86_64/elfinterp.c +++ b/ldso/ldso/x86_64/elfinterp.c @@ -165,6 +165,7 @@ _dl_do_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope, int reloc_type; int symtab_index; char *symname; + ElfW(Sym) *sym; ElfW(Addr) *reloc_addr; ElfW(Addr) symbol_addr; #if defined (__SUPPORT_LD_DEBUG__) @@ -174,8 +175,9 @@ _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 = &symtab[symtab_index]; symbol_addr = 0; - symname = strtab + symtab[symtab_index].st_name; + symname = strtab + sym->st_name; if (symtab_index) { symbol_addr = (ElfW(Addr))_dl_find_hash(symname, scope, tpnt, @@ -185,7 +187,7 @@ _dl_do_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope, * 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)) { + if (unlikely(!symbol_addr && ELF_ST_BIND(sym->st_info) != STB_WEAK)) { _dl_dprintf(2, "%s: can't resolve symbol '%s'\n", _dl_progname, symname); _dl_exit(1); }; @@ -209,7 +211,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 +219,33 @@ _dl_do_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope, *reloc_addr = map->l_addr + rpnt->r_addend; break; */ -#if 0 case R_X86_64_DTPMOD64: + *reloc_addr = 1; break; case R_X86_64_DTPOFF64: - *reloc_addr = symbol_addr + rpnt->r_addend; + *reloc_addr = sym->st_value + rpnt->r_addend; break; case R_X86_64_TPOFF64: - *reloc_addr = symbol_addr + rpnt->r_addend; + *reloc_addr = sym->st_value + rpnt->r_addend - symbol_addr; break; 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->st_size, symbol_addr, reloc_addr); #endif _dl_memcpy((char *)reloc_addr, (char *)symbol_addr, - symtab[symtab_index].st_size); + sym->st_size); } else _dl_dprintf(_dl_debug_file, "no symbol_addr to copy !?\n"); break; @@ -261,7 +263,6 @@ _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, ELF_RELOC *rpnt, ElfW(Sym) *symtab, char *strtab) @@ -288,7 +289,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,17 +303,13 @@ _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 diff --git a/ldso/ldso/x86_64/resolve.S b/ldso/ldso/x86_64/resolve.S new file mode 100644 index 000000000..5d55d0c73 --- /dev/null +++ b/ldso/ldso/x86_64/resolve.S @@ -0,0 +1,63 @@ +/* + * This function is _not_ called directly. It is jumped to (so no return + * address is on the stack) when attempting to use a symbol that has not yet + * been resolved. The first time a jump symbol (such as a function call inside + * a shared library) is used (before it gets resolved) it will jump here to + * _dl_linux_resolve. When we get called the stack looks like this: + * reloc_entry + * tpnt + * + * This function saves all the registers, puts a copy of reloc_entry and tpnt + * on the stack (as function arguments) then make the function call + * _dl_linux_resolver(tpnt, reloc_entry). _dl_linux_resolver() figures out + * where the jump symbol is _really_ supposed to have jumped to and returns + * that to us. Once we have that, we overwrite tpnt with this fixed up + * address. We then clean up after ourselves, put all the registers back how we + * found them, then we jump to where the fixed up address, which is where the + * jump symbol that got us here really wanted to jump to in the first place. + * found them, then we jump to the fixed up address, which is where the jump + * symbol that got us here really wanted to jump to in the first place. + * -Erik Andersen + */ + +/* more info taken from glibc/sysdeps/x86_64/dl-trampoline.S */ + +.text + +.global _dl_linux_resolve +.type _dl_linux_resolve,%function +.align 16 + +_dl_linux_resolve: + subq $56,%rsp + /* Preserve registers otherwise clobbered. */ + movq %rax, (%rsp) + movq %rcx, 8(%rsp) + movq %rdx, 16(%rsp) + movq %rsi, 24(%rsp) + movq %rdi, 32(%rsp) + movq %r8, 40(%rsp) + movq %r9, 48(%rsp) + + movq 64(%rsp), %rsi /* Copy args pushed by PLT in register. */ + movq %rsi, %r11 /* Multiply by 24 */ + addq %r11, %rsi + addq %r11, %rsi + shlq $3, %rsi + movq 56(%rsp), %rdi /* %rdi: link_map, %rsi: reloc_offset */ + call _dl_linux_resolver /* Call resolver. */ + movq %rax, %r11 /* Save return value */ + + /* Get register content back. */ + movq 48(%rsp), %r9 + movq 40(%rsp), %r8 + movq 32(%rsp), %rdi + movq 24(%rsp), %rsi + movq 16(%rsp), %rdx + movq 8(%rsp), %rcx + movq (%rsp), %rax + + addq $72, %rsp /* Adjust stack(PLT did 2 pushes) */ + jmp *%r11 /* Jump to function address. */ + +.size _dl_linux_resolve,.-_dl_linux_resolve |