diff options
Diffstat (limited to 'ldso')
-rw-r--r-- | ldso/ldso/metag/dl-debug.h | 8 | ||||
-rw-r--r-- | ldso/ldso/metag/dl-startup.h | 5 | ||||
-rw-r--r-- | ldso/ldso/metag/dl-sysdep.h | 19 | ||||
-rw-r--r-- | ldso/ldso/metag/elfinterp.c | 119 | ||||
-rw-r--r-- | ldso/ldso/metag/metag_load_tp.S | 20 |
5 files changed, 112 insertions, 59 deletions
diff --git a/ldso/ldso/metag/dl-debug.h b/ldso/ldso/metag/dl-debug.h index 5981d7c73..46c257c5c 100644 --- a/ldso/ldso/metag/dl-debug.h +++ b/ldso/ldso/metag/dl-debug.h @@ -17,11 +17,17 @@ static const char *_dl_reltypes_tab[] = { [6] "R_METAG_REG32OP1", "R_METAG_REG32OP2", "R_METAG_REG32OP3", [9] "R_METAG_REG16OP1", "R_METAG_REG16OP2", "R_METAG_REG16OP3", [12] "R_METAG_REG32OP4", "R_METAG_HIOG", "R_METAG_LOOG", - [30] "R_METAG_VTINHERIT", "R_METAG_VTENTRY", + [30] "R_METAG_GNU_VTINHERIT", "R_METAG_GNU_VTENTRY", [32] "R_METAG_HI16_GOTOFF", "R_METAG_LO16_GOTOFF", [34] "R_METAG_GETSET_GOTOFF", "R_METAG_GETSET_GOT", [36] "R_METAG_HI16_GOTPC", "R_METAG_LO16_GOTPC", [38] "R_METAG_HI16_PLT", "R_METAG_LO16_PLT", [40] "R_METAG_RELBRANCH_PLT", "R_METAG_GOTOFF", [42] "R_METAG_PLT", "R_METAG_COPY", "R_METAG_JMP_SLOT", + [45] "R_METAG_RELATIVE", "R_METAG_GLOB_DAT", "R_METAG_TLS_GD", + [48] "R_METAG_TLS_LDM", "R_METAG_TLS_LDO_HI16", "R_METAG_TLS_LDO_LO16", + [51] "R_METAG_TLS_LDO", "R_METAG_TLS_IE", "R_METAG_TLS_IENONPIC", + [54] "R_METAG_TLS_IENONPIC_HI16", "R_METAG_TLS_IENONPIC_LO16", + [56] "R_METAG_TLS_TPOFF", "R_METAG_TLS_DTPMOD", "R_METAG_TLS_DTPOFF", + [59] "R_METAG_TLS_LE", "R_METAG_TLS_LE_HI16", "R_METAG_TLS_LE_LO16" }; diff --git a/ldso/ldso/metag/dl-startup.h b/ldso/ldso/metag/dl-startup.h index 8dbf747e1..32b2e4b74 100644 --- a/ldso/ldso/metag/dl-startup.h +++ b/ldso/ldso/metag/dl-startup.h @@ -21,6 +21,11 @@ __asm__ ( " CALLR D1RtP,__dl_start\n" " GETL D0Ar2,D1Ar1,[A0StP+#-(1*8)]\n" " GETL D0Ar4,D1Ar3,[A0StP+#-(2*8)]\n" +" ADDT A1LbP,CPC1,#HI(__GLOBAL_OFFSET_TABLE__)\n" +" ADD A1LbP,A1LbP,#LO(__GLOBAL_OFFSET_TABLE__+4)\n" +" ADDT A1LbP,A1LbP,#HI(__dl_fini@GOTOFF)\n" +" ADD A1LbP,A1LbP,#LO(__dl_fini@GOTOFF)\n" +" MOV D0Ar4, A1LbP\n" " SUB A0StP,A0StP,#(2*8)\n" " MOV PC,D0Re0\n" " .size __start,.-__start\n" diff --git a/ldso/ldso/metag/dl-sysdep.h b/ldso/ldso/metag/dl-sysdep.h index 29547cb34..257ca610f 100644 --- a/ldso/ldso/metag/dl-sysdep.h +++ b/ldso/ldso/metag/dl-sysdep.h @@ -36,14 +36,17 @@ extern unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entr #define PAGE_ALIGN (~ADDR_ALIGN) #define OFFS_ALIGN (PAGE_ALIGN & ~(1ul << (sizeof(_dl_pagesize) * 8 - 1))) -/* The union of reloc-type-classes where the reloc TYPE is a member. - - TYPE is in the class ELF_RTYPE_CLASS_NOCOPY if it should not be allowed - to resolve to one of the main executable's symbols, as for a COPY - reloc. */ -#define elf_machine_type_class(type) \ - (((((type) == R_METAG_JMP_SLOT)) * ELF_RTYPE_CLASS_PLT) \ - | (((type) == R_METAG_COPY) * ELF_RTYPE_CLASS_COPY)) +/* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry or + TLS variable, so undefined references should not be allowed to + define the value. + + ELF_RTYPE_CLASS_NOCOPY iff TYPE should not be allowed to resolve to one + of the main executable's symbols, as for a COPY reloc. */ +#define elf_machine_type_class(type) \ + ((((type) == R_METAG_JMP_SLOT || (type) == R_METAG_TLS_DTPMOD \ + || (type) == R_METAG_TLS_DTPOFF || (type) == R_METAG_TLS_TPOFF) \ + * ELF_RTYPE_CLASS_PLT) \ + | (((type) == R_METAG_COPY) * ELF_RTYPE_CLASS_COPY)) static inline Elf32_Addr elf_machine_dynamic(Elf32_Ehdr *header) diff --git a/ldso/ldso/metag/elfinterp.c b/ldso/ldso/metag/elfinterp.c index 78434167b..e0f981741 100644 --- a/ldso/ldso/metag/elfinterp.c +++ b/ldso/ldso/metag/elfinterp.c @@ -43,43 +43,36 @@ static inline void __put_unaligned_reloc(unsigned long *addr, unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry) { - int reloc_type; int symtab_index; char *strtab; char *symname; char *new_addr; char *rel_addr; char **got_addr; - Elf32_Sym *symtab; + ElfW(Sym) *symtab; ELF_RELOC *this_reloc; unsigned long instr_addr; 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_index = ELF_R_SYM(this_reloc->r_info); - symtab = (Elf32_Sym *)(intptr_t)tpnt->dynamic_info[DT_SYMTAB]; + symtab = (ElfW(Sym) *)(intptr_t)tpnt->dynamic_info[DT_SYMTAB]; strtab = (char *)tpnt->dynamic_info[DT_STRTAB]; symname = strtab + symtab[symtab_index].st_name; - if (unlikely(reloc_type != R_METAG_JMP_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 = ((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, + 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_dprintf(2, "%s: Can't resolve symbol '%s'\n", + _dl_progname, symname); _dl_exit(1); } @@ -102,28 +95,28 @@ _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, - ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)) + int (*reloc_fnc)(struct elf_resolve *tpnt, struct r_scope_elem *scope, + ELF_RELOC *rpnt, ElfW(Sym) *symtab, char *strtab)) { int symtab_index; unsigned int i; char *strtab; - Elf32_Sym *symtab; + ElfW(Sym) *symtab; ELF_RELOC *rpnt; /* Parse the relocation information. */ rpnt = (ELF_RELOC *)(intptr_t)rel_addr; rel_size /= sizeof(ELF_RELOC); - symtab = (Elf32_Sym *)(intptr_t)tpnt->dynamic_info[DT_SYMTAB]; + symtab = (ElfW(Sym) *)(intptr_t)tpnt->dynamic_info[DT_SYMTAB]; strtab = (char *)tpnt->dynamic_info[DT_STRTAB]; for (i = 0; i < rel_size; i++, rpnt++) { int res; - symtab_index = ELF32_R_SYM(rpnt->r_info); + symtab_index = ELF_R_SYM(rpnt->r_info); debug_sym(symtab, strtab, symtab_index); debug_reloc(symtab, strtab, rpnt); @@ -141,7 +134,7 @@ _dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope, strtab + symtab[symtab_index].st_name); if (unlikely(res < 0)) { - int reloc_type = ELF32_R_TYPE(rpnt->r_info); + int reloc_type = ELF_R_TYPE(rpnt->r_info); #if defined (__SUPPORT_LD_DEBUG__) _dl_dprintf(2, "can't handle reloc type %s\n", @@ -161,8 +154,8 @@ _dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope, } static int -_dl_do_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope, - ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab) +_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; @@ -170,30 +163,35 @@ _dl_do_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope, unsigned long *reloc_addr; unsigned long symbol_addr; #if defined (__SUPPORT_LD_DEBUG__) - unsigned long old_val; + unsigned long old_val = 0; #endif + struct elf_resolve *tls_tpnt = NULL; + struct symbol_ref sym_ref; - reloc_addr = (unsigned long *)(intptr_t)(tpnt->loadaddr + (unsigned long)rpnt->r_offset); - reloc_type = ELF32_R_TYPE(rpnt->r_info); - symtab_index = ELF32_R_SYM(rpnt->r_info); + reloc_addr = (unsigned long *)(tpnt->loadaddr + rpnt->r_offset); + reloc_type = ELF_R_TYPE(rpnt->r_info); + symtab_index = ELF_R_SYM(rpnt->r_info); symbol_addr = 0; - symname = strtab + symtab[symtab_index].st_name; + sym_ref.sym = &symtab[symtab_index]; + sym_ref.tpnt = NULL; if (symtab_index) { - if (symtab[symtab_index].st_shndx != SHN_UNDEF && - ELF32_ST_BIND(symtab[symtab_index].st_info) == STB_LOCAL) { - symbol_addr = (unsigned long)tpnt->loadaddr; - } else { - symbol_addr = (unsigned long)_dl_find_hash(symname, scope, tpnt, - elf_machine_type_class(reloc_type), NULL); - } - - if (unlikely(!symbol_addr && ELF32_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); + symname = strtab + symtab[symtab_index].st_name; + symbol_addr = (unsigned long)_dl_find_hash(symname, scope, tpnt, + elf_machine_type_class(reloc_type), &sym_ref); + + if (!symbol_addr + && ELF_ST_TYPE(symtab[symtab_index].st_info) != STT_TLS + && ELF_ST_BIND(symtab[symtab_index].st_info) != STB_WEAK) { + _dl_dprintf(2, "%s: can't resolve symbol '%s'\n", + _dl_progname, symname); + return 1; }; - - symbol_addr += rpnt->r_addend; + 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; } #if defined (__SUPPORT_LD_DEBUG__) @@ -201,13 +199,21 @@ _dl_do_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope, old_val = __get_unaligned_reloc(reloc_addr); #endif +#if defined USE_TLS && USE_TLS + /* In case of a TLS reloc, tls_tpnt NULL means we have an 'anonymous' + symbol. This is the case for a static tls variable, so the lookup + module is just that one is referencing the tls variable. */ + if (!tls_tpnt) + tls_tpnt = tpnt; +#endif switch (reloc_type) { case R_METAG_NONE: break; case R_METAG_GLOB_DAT: case R_METAG_JMP_SLOT: case R_METAG_ADDR32: - __put_unaligned_reloc(reloc_addr, symbol_addr); + __put_unaligned_reloc(reloc_addr, + symbol_addr + rpnt->r_addend); break; case R_METAG_COPY: #if defined (__SUPPORT_LD_DEBUG__) @@ -215,11 +221,12 @@ _dl_do_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope, _dl_dprintf(_dl_debug_file, "\t%s move %d bytes from %x to %x\n", symname, symtab[symtab_index].st_size, - symbol_addr, reloc_addr); + symbol_addr + rpnt->r_addend, + reloc_addr); #endif _dl_memcpy((char *)reloc_addr, - (char *)symbol_addr, + (char *)symbol_addr + rpnt->r_addend, symtab[symtab_index].st_size); break; case R_METAG_RELATIVE: @@ -227,13 +234,24 @@ _dl_do_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope, (unsigned long)tpnt->loadaddr + rpnt->r_addend); break; +#if defined USE_TLS && USE_TLS + case R_METAG_TLS_DTPMOD: + *reloc_addr = tls_tpnt->l_tls_modid; + break; + case R_METAG_TLS_DTPOFF: + *reloc_addr = symbol_addr; + break; + case R_METAG_TLS_TPOFF: + CHECK_STATIC_TLS ((struct link_map *) tls_tpnt); + *reloc_addr = tls_tpnt->l_tls_offset + symbol_addr + rpnt->r_addend; + break; +#endif default: return -1; /* Calls _dl_exit(1). */ } #if defined (__SUPPORT_LD_DEBUG__) - if (_dl_debug_reloc && _dl_debug_detail && - (reloc_type != R_METAG_NONE)) { + if (_dl_debug_reloc && _dl_debug_detail && reloc_type != R_METAG_NONE) { unsigned long new_val = __get_unaligned_reloc(reloc_addr); _dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x\n", old_val, new_val, reloc_addr); @@ -244,8 +262,8 @@ _dl_do_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope, } static int -_dl_do_lazy_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope, - ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab) +_dl_do_lazy_reloc(struct elf_resolve *tpnt, struct r_scope_elem *scope, + ELF_RELOC *rpnt, ElfW(Sym) *symtab, char *strtab) { int reloc_type; unsigned long *reloc_addr; @@ -253,8 +271,8 @@ _dl_do_lazy_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope, unsigned long old_val; #endif - reloc_addr = (unsigned long *)(intptr_t)(tpnt->loadaddr + (unsigned long)rpnt->r_offset); - reloc_type = ELF32_R_TYPE(rpnt->r_info); + reloc_addr = (unsigned long *)(tpnt->loadaddr + rpnt->r_offset); + reloc_type = ELF_R_TYPE(rpnt->r_info); #if defined (__SUPPORT_LD_DEBUG__) old_val = *reloc_addr; @@ -291,9 +309,10 @@ _dl_parse_lazy_relocation_information(struct dyn_elf *rpnt, 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, + return _dl_parse(rpnt->dyn, scope, rel_addr, rel_size, _dl_do_reloc); } diff --git a/ldso/ldso/metag/metag_load_tp.S b/ldso/ldso/metag/metag_load_tp.S new file mode 100644 index 000000000..2f00a9fef --- /dev/null +++ b/ldso/ldso/metag/metag_load_tp.S @@ -0,0 +1,20 @@ +! Copyright (C) 2013 Imagination Technologies Ltd. + +! Licensed under LGPL v2.1 or later, see the file COPYING.LIB in this tarball. + +#include <features.h> + +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ + +#include <sysdep.h> + + .text + .global ___metag_load_tp + .type ___metag_load_tp,@function + +___metag_load_tp: + MOVT D1Ar1,#HI(0x6ffff000) + JUMP D1Ar1,#LO(0x6ffff000) + .size ___metag_load_tp,.-___metag_load_tp + +#endif /* __UCLIBC_HAS_THREADS_NATIVE__ */ |