From 5ec586eb37f61e57f19ac60b58af61f167ca054a Mon Sep 17 00:00:00 2001 From: Christophe Lyon Date: Fri, 18 Jan 2013 15:08:04 +0100 Subject: rtld: Add FDPIC code for arm MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add FDPIC dynamic relocations support, similar to what other FDPIC targets do. Lazy binding is implemented in a folllow-up patch. Disable the SEND* macros because they involve relocations to access constant strings that are unsupported by the existing arm version. Define DL_START, START, ARCH_NEEDS_BOOTSTRAP_RELOCS, DL_CHECK_LIB_TYPE similarly to what other FDPIC targets do. Define raise() because _dl_find_hash references __aeabi_uidivmod, which uses __aeabi_idiv0 which in turn references raise. * include/elf.h (R_ARM_FUNCDESC): Define. (R_ARM_FUNCDESC_VALUE): Define. * ldso/include/dl-string.h (SEND_STDERR, SEND_ADDRESS_STDERR) (SEND_NUMBER_STDERR): Define empty for __FDPIC__. * ldso/ldso/arm/dl-inlines.h: New file. * ldso/ldso/arm/dl-startup.h (PERFORM_BOOTSTRAP_RELOC): Fix type of load_addr. Fix handling of R_ARM_RELATIVE, add support for R_ARM_FUNCDESC_VALUE. (DL_START, START): Define for __FDPIC__. (raise): Define. * ldso/ldso/arm/dl-sysdep.h (ARCH_NEEDS_BOOTSTRAP_RELOCS): Define. (DL_CHECK_LIB_TYPE): Define. (elf_machine_type_class): Take into account FDPIC related relocations. (elf_machine_load_address): Support __FDPIC__. (elf_machine_relative): Likewise. * ldso/ldso/arm/elfinterp.c (_dl_linux_resolver): Dummy support for __FDPIC__, implemented in a later patch. (_dl_do_reloc): Fix reloc_adr computation for __FDPIC__, fix handling of local symbols. Fix handling of R_ARM_RELATIVE, add support for R_ARM_FUNCDESC_VALUE, R_ARM_FUNCDESC. * ldso/ldso/arm/resolve.S: Make _dl_linux_resolve hidden. * ldso/ldso/fdpic/dl-inlines.h (htab_delete): Declare. * libc/sysdeps/linux/arm/bits/elf-fdpic.h: New file, similar to bfin's. * libc/sysdeps/linux/arm/crtreloc.c: Likewise. * libc/sysdeps/linux/arm/find_exidx.c (__dl_addr_in_loadaddr) Define. (find_exidx_callback): Support __FDPIC__. Signed-off-by: Mickaël Guêné Signed-off-by: Christophe Lyon --- ldso/include/dl-string.h | 3 +- ldso/ldso/arm/dl-inlines.h | 1 + ldso/ldso/arm/dl-startup.h | 47 ++++++++++++++++++++++-- ldso/ldso/arm/dl-sysdep.h | 67 ++++++++++++++++++++++++++++++---- ldso/ldso/arm/elfinterp.c | 85 +++++++++++++++++++++++++++++++++----------- ldso/ldso/arm/resolve.S | 1 + ldso/ldso/fdpic/dl-inlines.h | 2 ++ 7 files changed, 176 insertions(+), 30 deletions(-) create mode 100644 ldso/ldso/arm/dl-inlines.h (limited to 'ldso') diff --git a/ldso/include/dl-string.h b/ldso/include/dl-string.h index fc1d1fccd..bf6997188 100644 --- a/ldso/include/dl-string.h +++ b/ldso/include/dl-string.h @@ -256,7 +256,8 @@ static __always_inline char * _dl_simple_ltoahex(char *local, unsigned long i) /* On some (wierd) arches, none of this stuff works at all, so * disable the whole lot... */ -#if defined(__mips__) +/* The same applies for ARM FDPIC at least for the moment. */ +#if defined(__mips__) || (__FDPIC__) # define SEND_STDERR(X) # define SEND_ADDRESS_STDERR(X, add_a_newline) diff --git a/ldso/ldso/arm/dl-inlines.h b/ldso/ldso/arm/dl-inlines.h new file mode 100644 index 000000000..8fdf6eb48 --- /dev/null +++ b/ldso/ldso/arm/dl-inlines.h @@ -0,0 +1 @@ +#include "../fdpic/dl-inlines.h" diff --git a/ldso/ldso/arm/dl-startup.h b/ldso/ldso/arm/dl-startup.h index 371dc2293..ea1e9f6f9 100644 --- a/ldso/ldso/arm/dl-startup.h +++ b/ldso/ldso/arm/dl-startup.h @@ -131,7 +131,7 @@ __asm__( /* Handle relocation of the symbols in the dynamic loader. */ static __always_inline void PERFORM_BOOTSTRAP_RELOC(ELF_RELOC *rpnt, unsigned long *reloc_addr, - unsigned long symbol_addr, unsigned long load_addr, Elf32_Sym *symtab) + unsigned long symbol_addr, DL_LOADADDR_TYPE load_addr, Elf32_Sym *symtab) { switch (ELF_R_TYPE(rpnt->r_info)) { case R_ARM_NONE: @@ -176,12 +176,55 @@ void PERFORM_BOOTSTRAP_RELOC(ELF_RELOC *rpnt, unsigned long *reloc_addr, *reloc_addr = symbol_addr; break; case R_ARM_RELATIVE: - *reloc_addr += load_addr; + *reloc_addr = DL_RELOC_ADDR(load_addr, *reloc_addr); break; case R_ARM_COPY: break; +#ifdef __FDPIC__ + case R_ARM_FUNCDESC_VALUE: + { + struct funcdesc_value *dst = (struct funcdesc_value *) reloc_addr; + + dst->entry_point += symbol_addr; + dst->got_value = load_addr.got_value; + } + break; +#endif default: SEND_STDERR("Unsupported relocation type\n"); _dl_exit(1); } } + +#ifdef __FDPIC__ +#undef DL_START +#define DL_START(X) \ +static void __attribute__ ((used)) \ +_dl_start (Elf32_Addr dl_boot_got_pointer, \ + struct elf32_fdpic_loadmap *dl_boot_progmap, \ + struct elf32_fdpic_loadmap *dl_boot_ldsomap, \ + Elf32_Dyn *dl_boot_ldso_dyn_pointer, \ + struct funcdesc_value *dl_main_funcdesc, \ + X) + +/* + * Transfer control to the user's application, once the dynamic loader + * is done. We return the address of the function's entry point to + * _dl_boot, see boot1_arch.h. + */ +#define START() do { \ + struct elf_resolve *exec_mod = _dl_loaded_modules; \ + dl_main_funcdesc->entry_point = _dl_elf_main; \ + while (exec_mod->libtype != elf_executable) \ + exec_mod = exec_mod->next; \ + dl_main_funcdesc->got_value = exec_mod->loadaddr.got_value; \ + return; \ +} while (0) + +/* We use __aeabi_idiv0 in _dl_find_hash, so we need to have the raise + symbol. */ +int raise(int sig) +{ + _dl_exit(1); +} +#endif /* __FDPIC__ */ diff --git a/ldso/ldso/arm/dl-sysdep.h b/ldso/ldso/arm/dl-sysdep.h index a47a55213..0f783e1c4 100644 --- a/ldso/ldso/arm/dl-sysdep.h +++ b/ldso/ldso/arm/dl-sysdep.h @@ -10,6 +10,19 @@ /* Define this if the system uses RELOCA. */ #undef ELF_USES_RELOCA #include + +#ifdef __FDPIC__ +/* Need bootstrap relocations */ +#define ARCH_NEEDS_BOOTSTRAP_RELOCS + +#define DL_CHECK_LIB_TYPE(epnt, piclib, _dl_progname, libname) \ +do \ +{ \ + (piclib) = 2; \ +} \ +while (0) +#endif /* __FDPIC__ */ + /* Initialization sequence for the GOT. */ #define INIT_GOT(GOT_BASE,MODULE) \ { \ @@ -63,11 +76,25 @@ unsigned long _dl_linux_resolver(struct elf_resolve * tpnt, int reloc_entry); 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. */ + +#ifdef __FDPIC__ +/* Avoid R_ARM_ABS32 to go through the PLT so that R_ARM_TARGET1 + translated to R_ARM_ABS32 doesn't use the PLT: otherwise, this + breaks init_array because functions are referenced through the + PLT. */ +#define elf_machine_type_class(type) \ + ((((type) == R_ARM_JUMP_SLOT || (type) == R_ARM_TLS_DTPMOD32 \ + || (type) == R_ARM_FUNCDESC_VALUE || (type) == R_ARM_FUNCDESC || (type) == R_ARM_ABS32 \ + || (type) == R_ARM_TLS_DTPOFF32 || (type) == R_ARM_TLS_TPOFF32) \ + * ELF_RTYPE_CLASS_PLT) \ + | (((type) == R_ARM_COPY) * ELF_RTYPE_CLASS_COPY)) +#else #define elf_machine_type_class(type) \ ((((type) == R_ARM_JUMP_SLOT || (type) == R_ARM_TLS_DTPMOD32 \ || (type) == R_ARM_TLS_DTPOFF32 || (type) == R_ARM_TLS_TPOFF32) \ * ELF_RTYPE_CLASS_PLT) \ | (((type) == R_ARM_COPY) * ELF_RTYPE_CLASS_COPY)) +#endif /* __FDPIC__ */ /* Return the link-time address of _DYNAMIC. Conveniently, this is the first element of the GOT. We used to use the PIC register to do this @@ -106,10 +133,24 @@ elf_machine_dynamic (void) extern char __dl_start[] __asm__("_dl_start"); +#ifdef __FDPIC__ +/* We must force strings used early in the bootstrap into the data + segment. */ +#undef SEND_EARLY_STDERR +#define SEND_EARLY_STDERR(S) \ + do { /* FIXME: implement */; } while (0) + +#undef INIT_GOT +#include "../fdpic/dl-sysdep.h" +#endif /* __FDPIC__ */ + /* Return the run-time load address of the shared object. */ static __always_inline Elf32_Addr __attribute__ ((unused)) elf_machine_load_address (void) { +#if defined(__FDPIC__) + return 0; +#else Elf32_Addr got_addr = (Elf32_Addr) &__dl_start; Elf32_Addr pcrel_addr; #if defined __OPTIMIZE__ && !defined __thumb__ @@ -128,19 +169,33 @@ elf_machine_load_address (void) : "=r" (pcrel_addr), "=r" (tmp)); #endif return pcrel_addr - got_addr; +#endif } static __always_inline void +#ifdef __FDPIC__ +elf_machine_relative (DL_LOADADDR_TYPE load_off, const Elf32_Addr rel_addr, +#else elf_machine_relative (Elf32_Addr load_off, const Elf32_Addr rel_addr, +#endif Elf32_Word relative_count) { - Elf32_Rel * rpnt = (void *) rel_addr; - --rpnt; - do { - Elf32_Addr *const reloc_addr = (void *) (load_off + (++rpnt)->r_offset); +#if defined(__FDPIC__) + Elf32_Rel *rpnt = (void *) rel_addr; + + do { + unsigned long *reloc_addr = (unsigned long *) DL_RELOC_ADDR(load_off, rpnt->r_offset); - *reloc_addr += load_off; - } while (--relative_count); + *reloc_addr = DL_RELOC_ADDR(load_off, *reloc_addr); + rpnt++; +#else + Elf32_Rel * rpnt = (void *) rel_addr; + --rpnt; + do { + Elf32_Addr *const reloc_addr = (void *) (load_off + (++rpnt)->r_offset); + *reloc_addr += load_off; +#endif + } while(--relative_count); } #endif /* !_ARCH_DL_SYSDEP */ diff --git a/ldso/ldso/arm/elfinterp.c b/ldso/ldso/arm/elfinterp.c index 96809a9ae..402ba9618 100644 --- a/ldso/ldso/arm/elfinterp.c +++ b/ldso/ldso/arm/elfinterp.c @@ -36,6 +36,11 @@ extern int _dl_linux_resolve(void); unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry) { +#if __FDPIC__ + /* FIXME: implement. */ + while(1) ; + return 0; +#else ELF_RELOC *this_reloc; char *strtab; char *symname; @@ -88,6 +93,7 @@ unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry) #endif return new_addr; +#endif } static int @@ -181,7 +187,7 @@ _dl_do_reloc (struct elf_resolve *tpnt,struct r_scope_elem *scope, struct elf_resolve *def_mod = 0; int goof = 0; - reloc_addr = (unsigned long *) (tpnt->loadaddr + (unsigned long) rpnt->r_offset); + reloc_addr = (unsigned long *) DL_RELOC_ADDR(tpnt->loadaddr, rpnt->r_offset); reloc_type = ELF_R_TYPE(rpnt->r_info); symtab_index = ELF_R_SYM(rpnt->r_info); @@ -191,25 +197,30 @@ _dl_do_reloc (struct elf_resolve *tpnt,struct r_scope_elem *scope, symname = strtab + symtab[symtab_index].st_name; if (symtab_index) { - symbol_addr = (unsigned long)_dl_find_hash(symname, scope, tpnt, - 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 (!symbol_addr && (ELF_ST_TYPE(symtab[symtab_index].st_info) != STT_TLS) - && (ELF_ST_BIND(symtab[symtab_index].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)); + if (ELF_ST_BIND (symtab[symtab_index].st_info) == STB_LOCAL) { + symbol_addr = (unsigned long) DL_RELOC_ADDR(tpnt->loadaddr, symtab[symtab_index].st_value); + def_mod = tpnt; + } else { + symbol_addr = (unsigned long)_dl_find_hash(symname, scope, tpnt, + 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 (!symbol_addr && (ELF_ST_TYPE(symtab[symtab_index].st_info) != STT_TLS) + && (ELF_ST_BIND(symtab[symtab_index].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)); + } + def_mod = sym_ref.tpnt; } - def_mod = sym_ref.tpnt; } else { /* * Relocs against STN_UNDEF are usually treated as using a @@ -267,12 +278,42 @@ _dl_do_reloc (struct elf_resolve *tpnt,struct r_scope_elem *scope, *reloc_addr = symbol_addr; break; case R_ARM_RELATIVE: - *reloc_addr += (unsigned long) tpnt->loadaddr; + *reloc_addr = DL_RELOC_ADDR(tpnt->loadaddr, *reloc_addr); break; case R_ARM_COPY: _dl_memcpy((void *) reloc_addr, (void *) symbol_addr, symtab[symtab_index].st_size); break; +#ifdef __FDPIC__ + case R_ARM_FUNCDESC_VALUE: + { + struct funcdesc_value funcval; + struct funcdesc_value *dst = (struct funcdesc_value *) reloc_addr; + + funcval.entry_point = (void*)symbol_addr; + /* Add offset to section address for local symbols. */ + if (ELF_ST_BIND(symtab[symtab_index].st_info) == STB_LOCAL) + funcval.entry_point += *reloc_addr; + funcval.got_value = def_mod->loadaddr.got_value; + *dst = funcval; + } + break; + case R_ARM_FUNCDESC: + { + unsigned long reloc_value = *reloc_addr; + + if (symbol_addr) + reloc_value = (unsigned long) _dl_funcdesc_for(symbol_addr + reloc_value, sym_ref.tpnt->loadaddr.got_value); + else + /* Relocation against an + undefined weak symbol: + set funcdesc to zero. */ + reloc_value = 0; + + *reloc_addr = reloc_value; + } + break; +#endif #if defined USE_TLS && USE_TLS case R_ARM_TLS_DTPMOD32: *reloc_addr = def_mod->l_tls_modid; @@ -330,7 +371,6 @@ _dl_do_lazy_reloc (struct elf_resolve *tpnt, struct r_scope_elem *scope, #endif return 0; - } void _dl_parse_lazy_relocation_information(struct dyn_elf *rpnt, @@ -345,3 +385,6 @@ int _dl_parse_relocation_information(struct dyn_elf *rpnt, return _dl_parse(rpnt->dyn, scope, rel_addr, rel_size, _dl_do_reloc); } +#ifndef IS_IN_libdl +# include "../../libc/sysdeps/linux/arm/crtreloc.c" +#endif diff --git a/ldso/ldso/arm/resolve.S b/ldso/ldso/arm/resolve.S index 7e0058e0d..2a516436e 100644 --- a/ldso/ldso/arm/resolve.S +++ b/ldso/ldso/arm/resolve.S @@ -102,6 +102,7 @@ .align 4 @ 16 byte boundary and there are 32 bytes below (arm case) #if 1 /*(!defined(__thumb__) || defined __THUMB_INTERWORK__) || defined(__thumb2__)*/ .arm + .hidden _dl_linux_resolve .globl _dl_linux_resolve .type _dl_linux_resolve,%function .align 4; diff --git a/ldso/ldso/fdpic/dl-inlines.h b/ldso/ldso/fdpic/dl-inlines.h index f59087568..89e7a9a68 100644 --- a/ldso/ldso/fdpic/dl-inlines.h +++ b/ldso/ldso/fdpic/dl-inlines.h @@ -7,6 +7,8 @@ #include +static __always_inline void htab_delete(struct funcdesc_ht *htab); + /* Initialize a DL_LOADADDR_TYPE given a got pointer and a complete load map. */ static __always_inline void __dl_init_loadaddr_map(struct elf32_fdpic_loadaddr *loadaddr, Elf32_Addr dl_boot_got_pointer, -- cgit v1.2.3