Message ID | 1383303307-1280-4-git-send-email-vgupta@synopsys.com |
---|---|
State | Superseded |
Headers | show |
On Fri, Nov 01, 2013 at 04:25:04PM +0530, Vineet Gupta wrote: >Signed-off-by: Vineet Gupta <vgupta@synopsys.com> >--- > ldso/ldso/arc/dl-debug.h | 68 +++++++++++ > ldso/ldso/arc/dl-startup.h | 88 ++++++++++++++ > ldso/ldso/arc/dl-syscalls.h | 8 ++ > ldso/ldso/arc/dl-sysdep.h | 156 ++++++++++++++++++++++++ > ldso/ldso/arc/elfinterp.c | 284 ++++++++++++++++++++++++++++++++++++++++++++ > ldso/ldso/arc/resolve.S | 59 +++++++++ > 6 files changed, 663 insertions(+) > create mode 100644 ldso/ldso/arc/dl-debug.h > create mode 100644 ldso/ldso/arc/dl-startup.h > create mode 100644 ldso/ldso/arc/dl-syscalls.h > create mode 100644 ldso/ldso/arc/dl-sysdep.h > create mode 100644 ldso/ldso/arc/elfinterp.c > create mode 100644 ldso/ldso/arc/resolve.S > >diff --git a/ldso/ldso/arc/dl-debug.h b/ldso/ldso/arc/dl-debug.h >new file mode 100644 >index 000000000000..93ce1e6c729d >--- /dev/null >+++ b/ldso/ldso/arc/dl-debug.h >@@ -0,0 +1,68 @@ >+/* >+ * Copyright (C) 2013 Synopsys, Inc. (www.synopsys.com) >+ * >+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. >+ */ I take it you double-checked the table below against the defines in include/elf.h >+static const char *_dl_reltypes_tab[] = >+{ >+}; >diff --git a/ldso/ldso/arc/dl-startup.h b/ldso/ldso/arc/dl-startup.h >new file mode 100644 >index 000000000000..0d7d44abf2fa >--- /dev/null >+++ b/ldso/ldso/arc/dl-startup.h >@@ -0,0 +1,88 @@ >+/* >+ * Copyright (C) 2013 Synopsys, Inc. (www.synopsys.com) >+ * >+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. >+ */ >+ >+/* >+ * vineetg: Refactoring/cleanup of loader entry point >+ * Removed 6 useless insns >+ * Joern Improved it even further: >+ * -better insn scheduling >+ * -no need for conditional code for _dl_skip_args >+ * -use of assembler .&2 expressions vs. @gotpc refs (avoids need for GP) >+ * >+ * What this code does: >+ * -ldso starts execution here when kernel returns from execve() >+ * -calls into generic ldso entry point _dl_start( ) >+ * -optionally adjusts argc for executable if exec passed as cmd >+ * -calls into app main with address of finaliser >+ */ >+__asm__( >+ ".section .text \n" >+ ".balign 4 \n" >+ ".global _start \n" .hidden _start ? >+ ".type _start,@function \n" >+ >+ "_start: \n" >+ " ; ldso entry point, returns app entry point \n" >+ " bl.d _dl_start \n" >+ " mov_s r0, sp ; pass ptr to aux vector tbl \n" >+ >+ " ; If ldso ran as cmd with executable file nm as arg \n" >+ " ; as arg, skip the extra args calc by dl_start() \n" >+ " ld_s r1, [sp] ; orig argc from aux-vec Tbl \n" >+#ifdef STAR_9000535888_FIXED >+ " ld r12, [pcl, _dl_skip_args-.+(.&2)] \n" >+#else >+ " add r12, pcl, _dl_skip_args-.+(.&2) \n" >+ " ld r12, [r12] \n" >+#endif >+ >+ " add r2, pcl, _dl_fini-.+(.&2) ; finalizer \n" >+ >+ " add2 sp, sp, r12 ; discard argv entries from stack\n" >+ " sub_s r1, r1, r12 ; adjusted argc, on stack \n" >+ " st_s r1, [sp] \n" >+ >+ " j_s.d [r0] ; app entry point \n" >+ " mov_s r0, r2 ; ptr to finalizer _dl_fini \n" >+ >+ ".size _start,.-_start \n" >+ ".previous \n" >+); >+ >+/* >+ * Get a pointer to the argv array. On many platforms this can be just >+ * the address if the first argument, on other platforms we need to >+ * do something a little more subtle here. >+ */ >+#define GET_ARGV(ARGVP, ARGS) ARGVP = ((unsigned long*) ARGS + 1) >+ >+/* >+ * Dynamic loader bootstrapping: >+ * Since we don't modify text at runtime, these can only be data relos >+ * (so safe to assume that they are word aligned). >+ * And also they HAVE to be RELATIVE relos only >+ * @RELP is the relo entry being processed >+ * @REL is the pointer to the address we are relocating. >+ * @SYMBOL is the symbol involved in the relocation >+ * @LOAD is the load address. >+ */ >+ >+#define PERFORM_BOOTSTRAP_RELOC(RELP,REL,SYMBOL,LOAD,SYMTAB) \ >+do { \ >+ int type = ELF32_R_TYPE((RELP)->r_info); \ >+ if (likely(type == R_ARC_RELATIVE)) \ >+ *REL += (unsigned long) LOAD; \ >+ else \ >+ _dl_exit(1); \ >+}while(0) >+ >+/* >+ * This will go away once we have DT_RELACOUNT >+ */ >+#define ARCH_NEEDS_BOOTSTRAP_RELOCS >+ >+/* we dont need to spit out argc, argv etc for debugging */ >+#define NO_EARLY_SEND_STDERR 1 >diff --git a/ldso/ldso/arc/dl-syscalls.h b/ldso/ldso/arc/dl-syscalls.h >new file mode 100644 >index 000000000000..1ab7b552a217 >--- /dev/null >+++ b/ldso/ldso/arc/dl-syscalls.h >@@ -0,0 +1,8 @@ >+/* >+ * Copyright (C) 2013 Synopsys, Inc. (www.synopsys.com) >+ * >+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. >+ */ >+ >+#include "sys/syscall.h" >+#include <bits/uClibc_page.h> Sounds like it could go with the stub only? >diff --git a/ldso/ldso/arc/dl-sysdep.h b/ldso/ldso/arc/dl-sysdep.h >new file mode 100644 >index 000000000000..642f020f42e1 >--- /dev/null >+++ b/ldso/ldso/arc/dl-sysdep.h >@@ -0,0 +1,156 @@ >+/* >+ * Copyright (C) 2013 Synopsys, Inc. (www.synopsys.com) >+ * >+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. >+ */ >+ >+#include "elf.h" >+ >+/* >+ * Define this if the system uses RELOCA. >+ */ >+#define ELF_USES_RELOCA >+ >+/* >+ * Dynamic Linking ABI for ARCompact ISA >+ * >+ * PLT >+ * -------------------------------- >+ * | ld r11, [pcl, off-to-GOT[1] | 0 (20 bytes) >+ * | | 4 >+ * plt0 | ld r10, [pcl, off-to-GOT[2] | 8 table layout seems to be broken here >+ * | | 12 >+ * | j [r10] | 16 >+ * -------------------------------- >+ * | Base address of GOT | 20 >+ * -------------------------------- >+ * | ld r12, [pcl, off-to-GOT[3] | 24 (12 bytes each) >+ * plt1 | | .. and here. >+ * | j_s.d [r12] | 32 >+ * | mov_s r12, pcl | 34 >+ * -------------------------------- >+ * | | 36 >+ * ~ ~ >+ * ~ ~ >+ * | | >+ * -------------------------------- >+ * >+ * GOT >+ * -------------- >+ * | [0] | >+ * -------------- >+ * | [1] | Module info - setup by ldso >+ * -------------- >+ * | [2] | resolver entry point >+ * -------------- >+ * | [3] | >+ * | ... | Runtime address for function symbols >+ * | [f] | >+ * -------------- >+ * | [f+1] | >+ * | ... | Runtime address for data symbols >+ * | [last] | >+ * -------------- >+ */ >+ >+/* >+ * Initialization sequence for a GOT. >+ * Caller elf_resolve() seeds @GOT_BASE from DT_PLTGOT - which essentially is >+ * pointer to first PLT entry. The actual GOT base is 5th word in PLT >+ * >+ */ >+#define INIT_GOT(GOT_BASE,MODULE) \ >+do { \ >+ unsigned long *__plt_base = (unsigned long *)GOT_BASE; \ >+ if(MODULE->libtype != program_interpreter) \ you sure you need the above? >+ GOT_BASE = (unsigned long *)(__plt_base[5] + \ >+ (unsigned long)MODULE->loadaddr); \ >+ GOT_BASE[1] = (unsigned long) MODULE; \ >+ GOT_BASE[2] = (unsigned long) _dl_linux_resolve; \ >+} while(0) >+ >+/* Here we define the magic numbers that this dynamic loader should accept */ >+#define MAGIC1 EM_ARCOMPACT >+#undef MAGIC2 >+ >+/* Used for error messages */ >+#define ELF_TARGET "ARC" >+ >+struct elf_resolve; >+extern unsigned long _dl_linux_resolver(struct elf_resolve * tpnt, >+ unsigned int plt_pc); >+ >+extern unsigned __udivmodsi4 (unsigned, unsigned) >+ __attribute ((visibility("hidden"))); yuck ;) And please use __foo__ throughout, for attribute, inline. >+ >+#define do_rem(result, n, base) ((result) = \ >+ \ >+ __builtin_constant_p (base) ? (n) % (unsigned) (base) : \ I'd prefer if you marked that as (__extension__ ({ >+ ({ \ >+ register unsigned r1 __asm__ ("r1") = (base); \ >+ \ >+ __asm("bl.d @__udivmodsi4` mov r0,%1" \ >+ : "=r" (r1) \ >+ : "r" (n), "r" (r1) \ >+ : "r0", "r2", "r3", "r4", "lp_count", "blink", "cc"); \ >+ \ >+ r1; \ >+ }) \ >+) >+ >+/* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry, so >+ PLT entries 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_ARC_JMP_SLOT) * ELF_RTYPE_CLASS_PLT) \ >+ | (((type) == R_ARC_COPY) * ELF_RTYPE_CLASS_COPY)) >+ >+/* >+ * Get the runtime address of GOT[0] >+ */ >+static inline Elf32_Addr elf_machine_dynamic (void) attribute_unused; >+static inline Elf32_Addr Perhaps you want __always_inline and in similar spots? >+elf_machine_dynamic (void) >+{ >+ Elf32_Addr dyn; >+ >+ __asm__("ld %0,[pcl,_DYNAMIC@gotpc]\n\t" : "=r" (dyn)); >+ return dyn; >+ >+/* >+ * Another way would have been to simply return GP, which due to some >+ * PIC reference would be automatically setup by gcc in caller >+ * register Elf32_Addr *got __asm__ ("gp"); return *got; >+ */ >+} >+ >+/* Return the run-time load address of the shared object. */ >+static inline Elf32_Addr elf_machine_load_address (void) attribute_unused; >+static inline Elf32_Addr >+elf_machine_load_address (void) >+{ >+ /* To find the loadaddr we subtract the runtime addr of any symbol >+ * say _dl_start from it's build-time addr. >+ */ >+ Elf32_Addr addr, tmp; >+ __asm__ ( >+ "ld %1, [pcl, _dl_start@gotpc] ;build addr of _dl_start \n" >+ "add %0, pcl, _dl_start-.+(.&2) ;runtime addr of _dl_start \n" >+ "sub %0, %0, %1 ;delta \n" >+ : "=&r" (addr), "=r"(tmp) >+ ); >+ return addr; >+} >+ >+static inline void >+elf_machine_relative (Elf32_Addr load_off, const Elf32_Addr rel_addr, >+ Elf32_Word relative_count) >+{ >+ Elf32_Rel * rpnt = (void *) rel_addr; >+ --rpnt; >+ do { >+ Elf32_Addr *const reloc_addr = (void *) (load_off + (++rpnt)->r_offset); >+ *reloc_addr += load_off; >+ } while (--relative_count); >+} >diff --git a/ldso/ldso/arc/elfinterp.c b/ldso/ldso/arc/elfinterp.c >new file mode 100644 >index 000000000000..ee6496659a3a >--- /dev/null >+++ b/ldso/ldso/arc/elfinterp.c >@@ -0,0 +1,284 @@ >+/* >+ * Copyright (C) 2013 Synopsys, Inc. (www.synopsys.com) >+ * >+ * Lots of code copied from ../i386/elfinterp.c, so: >+ * Copyright (c) 1994-2000 Eric Youngdale, Peter MacDonald, >+ * David Engel, Hongjiu Lu and Mitch D'Souza >+ * Copyright (C) 2001-2002, Erik Andersen >+ * All rights reserved. >+ * >+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. >+ */ >+#include "ldso.h" >+ >+unsigned long >+_dl_linux_resolver(struct elf_resolve *tpnt, unsigned int plt_pc) >+{ >+ ELF_RELOC *this_reloc, *rel_base; >+ char *strtab, *symname, *new_addr; >+ ElfW(Sym) *symtab; >+ int symtab_index; >+ unsigned int *got_addr; >+ unsigned long plt_base; >+ int plt_idx; >+ >+ /* start of .rela.plt */ >+ rel_base = (ELF_RELOC *)(tpnt->dynamic_info[DT_JMPREL]); >+ >+ /* starts of .plt (addr of PLT0) */ >+ plt_base = tpnt->dynamic_info[DT_PLTGOT]; >+ >+ /* >+ * compute the idx of the yet-unresolved PLT entry in .plt >+ * Same idx will be used to find the relo entry in .rela.plt >+ */ whitespace damage above >+ plt_idx = (plt_pc - plt_base)/0xc - 2; /* ignoring 2 dummy PLTs */ magic 12 ? >+ >+ this_reloc = rel_base + plt_idx; >+ >+ symtab_index = ELF_R_SYM(this_reloc->r_info); >+ symtab = (ElfW(Sym) *)(intptr_t) (tpnt->dynamic_info[DT_SYMTAB]); >+ strtab = (char *) (tpnt->dynamic_info[DT_STRTAB]); >+ symname= strtab + symtab[symtab_index].st_name; >+ >+ /* relo-offset to fixup, shd be a .got entry */ >+ got_addr = (unsigned int *)(this_reloc->r_offset + tpnt->loadaddr); >+ >+ /* Get the address of the GOT entry */ >+ 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); >+ } >+ >+ >+#if defined (__SUPPORT_LD_DEBUG__) please remove braces >+ 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 ==> %pc @ %pl\n", >+ *got_addr, new_addr, got_addr); >+ } >+ >+ if (!_dl_debug_nofixups) >+ *got_addr = (unsigned int)new_addr; >+#else >+ /* Update the .got entry with the runtime address of symbol */ >+ *got_addr = (unsigned int)new_addr; >+#endif >+ >+ /* >+ * Return the new addres, where the asm trampoline will jump to >+ * after re-setting up the orig args >+ */ >+ return (unsigned long) new_addr; >+} >+ >+static int >+_dl_do_lazy_reloc (struct elf_resolve *tpnt, struct r_scope_elem *scope, >+ ELF_RELOC *rpnt); >+ >+static int >+_dl_do_reloc (struct elf_resolve *tpnt, struct r_scope_elem *scope, >+ ELF_RELOC *rpnt, ElfW(Sym) *symtab, char *strtab); Please restructure so you don't need these forward declarations. Also, it would be nice if you could switch to using a function pointer for the real handler, see all other arches. >+ >+#define ___DO_LAZY 1 >+#define ___DO_NOW 2 >+ >+static int __attribute__((always_inline)) >+_dl_parse(struct elf_resolve *tpnt, struct r_scope_elem *scope, >+ unsigned long rel_addr, unsigned long rel_size, int type) >+{ >+ unsigned int i; >+ char *strtab; >+ ElfW(Sym) *symtab; >+ ELF_RELOC *rpnt; >+ int symtab_index; >+ int res = 0; >+ >+ /* Now parse the relocation information */ >+ rpnt = (ELF_RELOC *)(intptr_t) (rel_addr); >+ rel_size = rel_size / sizeof(ELF_RELOC); >+ >+ 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++) { >+ >+ symtab_index = ELF_R_SYM(rpnt->r_info); >+ >+ debug_sym(symtab,strtab,symtab_index); >+ debug_reloc(symtab,strtab,rpnt); >+ >+ /* constant propagation subsumes the 'if' */ >+ if (type == ___DO_LAZY) >+ res = _dl_do_lazy_reloc(tpnt, scope, rpnt); >+ else >+ res = _dl_do_reloc(tpnt, scope, rpnt, symtab, strtab); >+ >+ if (res != 0) >+ break; >+ } >+ >+ if (unlikely(res != 0)) { >+ if (res < 0) { >+ int reloc_type = ELF_R_TYPE(rpnt->r_info); >+#if defined (__SUPPORT_LD_DEBUG__) >+ _dl_dprintf(2, "can't handle reloc type %s\n ", >+ _dl_reltypes(reloc_type)); >+#else >+ _dl_dprintf(2, "can't handle reloc type %x\n", >+ reloc_type); >+#endif >+ _dl_exit(-res); >+ } else { >+ _dl_dprintf(2, "can't resolve symbol\n"); >+ /* Fall thru to return res */ >+ } >+ } >+ >+ return res; >+} >+ >+static int >+_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; >+ unsigned long *reloc_addr; >+ unsigned long symbol_addr; >+#if defined (__SUPPORT_LD_DEBUG__) >+ unsigned long old_val = 0; >+#endif >+ struct symbol_ref sym_ref; >+ >+ 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; >+ >+ sym_ref.sym = &symtab[symtab_index]; >+ sym_ref.tpnt = NULL; >+ >+#if defined (__SUPPORT_LD_DEBUG__) >+ if (reloc_addr) >+ old_val = *reloc_addr; >+#endif >+ >+ if (symtab_index) { >+ 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); >+ >+ /* >+ * 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)) { >+ /* Non-fatal if called from dlopen, hence different ret code */ >+ return 1; >+ } >+ } else if (reloc_type == R_ARC_RELATIVE ) { >+ *reloc_addr += tpnt->loadaddr; >+ goto log_entry; >+ } >+ >+ switch (reloc_type) { >+ case R_ARC_32: >+ *reloc_addr += symbol_addr + rpnt->r_addend; >+ break; >+ case R_ARC_PC32: >+ *reloc_addr += symbol_addr + rpnt->r_addend - (unsigned long) reloc_addr; >+ break; >+ case R_ARC_GLOB_DAT: >+ case R_ARC_JMP_SLOT: >+ *reloc_addr = symbol_addr; >+ break; >+ case R_ARC_COPY: >+ _dl_memcpy((void *) reloc_addr,(void *) symbol_addr, >+ symtab[symtab_index].st_size); >+ break; >+ default: >+ return -1; >+ } >+ >+log_entry: >+#if defined (__SUPPORT_LD_DEBUG__) >+ if(_dl_debug_detail) >+ _dl_dprintf(_dl_debug_file,"\tpatched: %lx ==> %lx @ %pl: addend %x ", >+ old_val, *reloc_addr, reloc_addr, rpnt->r_addend); >+#endif >+ >+ return 0; >+} >+ >+static int >+_dl_do_lazy_reloc(struct elf_resolve *tpnt, struct r_scope_elem *scope, >+ ELF_RELOC *rpnt) >+{ >+ int reloc_type; >+ unsigned long *reloc_addr; >+#if defined (__SUPPORT_LD_DEBUG__) >+ unsigned long old_val; >+#endif >+ >+ 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; >+#endif >+ >+ switch (reloc_type) { >+ case R_ARC_JMP_SLOT: >+ *reloc_addr += tpnt->loadaddr; >+ break; >+ default: >+ return -1; >+ } >+ >+#if defined (__SUPPORT_LD_DEBUG__) >+ if(_dl_debug_reloc && _dl_debug_detail) >+ _dl_dprintf(_dl_debug_file, "\tpatched: %lx ==> %lx @ %pl\n", >+ old_val, *reloc_addr, reloc_addr); >+#endif >+ >+ return 0; >+} >+ >+void >+_dl_parse_lazy_relocation_information(struct dyn_elf *rpnt, >+ unsigned long rel_addr, >+ unsigned long rel_size) >+{ >+ /* This func is called for processing .rela.plt of loaded module(s) >+ * The relo entries handled are JMP_SLOT type for fixing up .got slots for >+ * external function calls. >+ * This function doesn't resolve the slots: that is done lazily at runtime. >+ * The build linker (at least thats what happens for ARC) had pre-init the >+ * .got slots to point to PLT0. All that is done here is to fix them up to >+ * point to load value of PLT0 (as opposed to the build value). >+ * On ARC, the loadaddr of dyn exec is zero, thus elfaddr == loadaddr >+ * Thus there is no point in adding "0" to values and un-necessarily stir >+ * up the caches and TLB. >+ * For lsdo processing busybox binary, this skips over 380 relo entries >+ */ >+ if (rpnt->dyn->loadaddr != 0) >+ _dl_parse(rpnt->dyn, NULL, rel_addr, rel_size, ___DO_LAZY); >+} >+ >+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, scope, rel_addr, rel_size, ___DO_NOW); >+} >diff --git a/ldso/ldso/arc/resolve.S b/ldso/ldso/arc/resolve.S >new file mode 100644 >index 000000000000..8609b339effa >--- /dev/null >+++ b/ldso/ldso/arc/resolve.S >@@ -0,0 +1,59 @@ >+/* >+ * Copyright (C) 2013 Synopsys, Inc. (www.synopsys.com) >+ * >+ * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. >+ */ >+ >+#define __ASSEMBLY__ please remove that define. >+ >+#include <bits/asm.h> Can you instead of asm.h use ENTRY and PLTJMP et al from sysdep.h please? Everywhere. >+#include <sys/syscall.h> >+ >+; Save the registers which resolver could possibly clobber >+; r0-r9: args to the function - symbol being resolved >+; r10-r12 are already clobbered by PLTn, PLT0 thus neednot be saved >+ >+.macro SAVE_CALLER_SAVED >+ push_s r0 >+ push_s r1 >+ push_s r2 >+ push_s r3 >+ st.a r4, [sp, -4] >+ st.a r5, [sp, -4] >+ st.a r6, [sp, -4] >+ st.a r7, [sp, -4] >+ st.a r8, [sp, -4] >+ st.a r9, [sp, -4] >+ push_s blink >+.endm >+ >+.macro RESTORE_CALLER_SAVED_BUT_R0 >+ ld.ab blink,[sp, 4] >+ ld.ab r9, [sp, 4] >+ ld.ab r8, [sp, 4] >+ ld.ab r7, [sp, 4] >+ ld.ab r6, [sp, 4] >+ ld.ab r5, [sp, 4] >+ ld.ab r4, [sp, 4] >+ pop_s r3 >+ pop_s r2 >+ pop_s r1 >+.endm >+ >+; Upon entry, PLTn, which led us here, sets up the following regs >+; r11 = Module info (tpnt pointer as expected by resolver) >+; r12 = PC of the PLTn itself - needed by resolver to find >+; corresponding .rela.plt entry >+ >+ENTRY(_dl_linux_resolve) >+ ; args to func being resolved, which resolver might clobber >+ SAVE_CALLER_SAVED >+ >+ mov_s r1, r12 >+ bl.d _dl_linux_resolver >+ mov r0, r11 >+ >+ RESTORE_CALLER_SAVED_BUT_R0 >+ j_s.d [r0] ; r0 has resolved function addr >+ pop_s r0 ; restore first arg to resolved call >+ENDFUNC(_dl_linux_resolve) >-- >1.8.1.2 > >_______________________________________________ >uClibc mailing list >uClibc@uclibc.org >http://lists.busybox.net/mailman/listinfo/uclibc
On 11/12/2013 07:34 PM, Bernhard Reutner-Fischer wrote: > I take it you double-checked the table below against the defines in > include/elf.h Yes. >> +static const char *_dl_reltypes_tab[] = >> +{ > +__asm__( > + ".section .text \n" > + ".balign 4 \n" > + ".global _start \n" > .hidden _start ? yes both global + hidden. Otherwise ld can't seem to find it. >> diff --git a/ldso/ldso/arc/dl-syscalls.h b/ldso/ldso/arc/dl-syscalls.h >> new file mode 100644 >> index 000000000000..1ab7b552a217 >> --- /dev/null >> +++ b/ldso/ldso/arc/dl-syscalls.h >> @@ -0,0 +1,8 @@ >> +/* >> + * Copyright (C) 2013 Synopsys, Inc. (www.synopsys.com) >> + * >> + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. >> + */ >> + >> +#include "sys/syscall.h" >> +#include <bits/uClibc_page.h> > Sounds like it could go with the stub only? Done. >> diff --git a/ldso/ldso/arc/dl-sysdep.h b/ldso/ldso/arc/dl-sysdep.h >> new file mode 100644 >> index 000000000000..642f020f42e1 >> --- /dev/null >> +++ b/ldso/ldso/arc/dl-sysdep.h >> @@ -0,0 +1,156 @@ >> +/* >> + * Copyright (C) 2013 Synopsys, Inc. (www.synopsys.com) >> + * >> + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. >> + */ >> + >> +#include "elf.h" >> + >> +/* >> + * Define this if the system uses RELOCA. >> + */ >> +#define ELF_USES_RELOCA >> + >> +/* >> + * Dynamic Linking ABI for ARCompact ISA >> + * >> + * PLT >> + * -------------------------------- >> + * | ld r11, [pcl, off-to-GOT[1] | 0 (20 bytes) >> + * | | 4 >> + * plt0 | ld r10, [pcl, off-to-GOT[2] | 8 > table layout seems to be broken here > >> + * | | 12 >> + * | j [r10] | 16 >> + * -------------------------------- >> + * | Base address of GOT | 20 >> + * -------------------------------- >> + * | ld r12, [pcl, off-to-GOT[3] | 24 (12 bytes each) >> + * plt1 | | > .. and here. All fixed. > >> + * | j_s.d [r12] | 32 >> + * | mov_s r12, pcl | 34 >> + * -------------------------------- >> + * | | 36 >> + * ~ ~ >> + * ~ ~ >> + * | | >> + * -------------------------------- >> + * >> + * GOT >> + * -------------- >> + * | [0] | >> + * -------------- >> + * | [1] | Module info - setup by ldso >> + * -------------- >> + * | [2] | resolver entry point >> + * -------------- >> + * | [3] | >> + * | ... | Runtime address for function symbols >> + * | [f] | >> + * -------------- >> + * | [f+1] | >> + * | ... | Runtime address for data symbols >> + * | [last] | >> + * -------------- >> + */ >> + >> +/* >> + * Initialization sequence for a GOT. >> + * Caller elf_resolve() seeds @GOT_BASE from DT_PLTGOT - which essentially is >> + * pointer to first PLT entry. The actual GOT base is 5th word in PLT >> + * >> + */ >> +#define INIT_GOT(GOT_BASE,MODULE) \ >> +do { \ >> + unsigned long *__plt_base = (unsigned long *)GOT_BASE; \ >> + if(MODULE->libtype != program_interpreter) \ > you sure you need the above? Nope, Now removed. >> + GOT_BASE = (unsigned long *)(__plt_base[5] + \ >> + (unsigned long)MODULE->loadaddr); \ >> + GOT_BASE[1] = (unsigned long) MODULE; \ >> + GOT_BASE[2] = (unsigned long) _dl_linux_resolve; \ >> +} while(0) >> + >> +/* Here we define the magic numbers that this dynamic loader should accept */ >> +#define MAGIC1 EM_ARCOMPACT >> +#undef MAGIC2 >> + >> +/* Used for error messages */ >> +#define ELF_TARGET "ARC" >> + >> +struct elf_resolve; >> +extern unsigned long _dl_linux_resolver(struct elf_resolve * tpnt, >> + unsigned int plt_pc); >> + >> +extern unsigned __udivmodsi4 (unsigned, unsigned) >> + __attribute ((visibility("hidden"))); > yuck ;) > And please use __foo__ throughout, for attribute, inline. OK. >> + >> +#define do_rem(result, n, base) ((result) = \ >> + \ >> + __builtin_constant_p (base) ? (n) % (unsigned) (base) : \ > I'd prefer if you marked that as (__extension__ ({ You mean - ({ \ + __extension__ ({ \ If so, done. However I read man gcc for __extension__, but not sure how it applies here (and only here). >> + */ >> +static inline Elf32_Addr elf_machine_dynamic (void) attribute_unused; >> +static inline Elf32_Addr > Perhaps you want __always_inline and in similar spots? Done for all three >> +++ b/ldso/ldso/arc/elfinterp.c >> @@ -0,0 +1,284 @@ >> +/* >> + * Copyright (C) 2013 Synopsys, Inc. (www.synopsys.com) >> + * >> + * Lots of code copied from ../i386/elfinterp.c, so: >> + * Copyright (c) 1994-2000 Eric Youngdale, Peter MacDonald, >> + * David Engel, Hongjiu Lu and Mitch D'Souza >> + * Copyright (C) 2001-2002, Erik Andersen >> + * All rights reserved. >> + * >> + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. >> + */ >> +#include "ldso.h" >> + >> +unsigned long >> +_dl_linux_resolver(struct elf_resolve *tpnt, unsigned int plt_pc) >> +{ >> + ELF_RELOC *this_reloc, *rel_base; >> + char *strtab, *symname, *new_addr; >> + ElfW(Sym) *symtab; >> + int symtab_index; >> + unsigned int *got_addr; >> + unsigned long plt_base; >> + int plt_idx; >> + >> + /* start of .rela.plt */ >> + rel_base = (ELF_RELOC *)(tpnt->dynamic_info[DT_JMPREL]); >> + >> + /* starts of .plt (addr of PLT0) */ >> + plt_base = tpnt->dynamic_info[DT_PLTGOT]; >> + >> + /* >> + * compute the idx of the yet-unresolved PLT entry in .plt >> + * Same idx will be used to find the relo entry in .rela.plt >> + */ > whitespace damage above Oops - fixed now. >> + plt_idx = (plt_pc - plt_base)/0xc - 2; /* ignoring 2 dummy PLTs */ > magic 12 ? Added/used #define ARC_PLT_SIZE 12 >> + >> + this_reloc = rel_base + plt_idx; >> + >> + symtab_index = ELF_R_SYM(this_reloc->r_info); >> + symtab = (ElfW(Sym) *)(intptr_t) (tpnt->dynamic_info[DT_SYMTAB]); >> + strtab = (char *) (tpnt->dynamic_info[DT_STRTAB]); >> + symname= strtab + symtab[symtab_index].st_name; >> + >> + /* relo-offset to fixup, shd be a .got entry */ >> + got_addr = (unsigned int *)(this_reloc->r_offset + tpnt->loadaddr); >> + >> + /* Get the address of the GOT entry */ >> + 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); >> + } >> + >> + >> +#if defined (__SUPPORT_LD_DEBUG__) > please remove braces All fixed. >> +static int >> +_dl_do_lazy_reloc (struct elf_resolve *tpnt, struct r_scope_elem *scope, >> + ELF_RELOC *rpnt); >> + >> +static int >> +_dl_do_reloc (struct elf_resolve *tpnt, struct r_scope_elem *scope, >> + ELF_RELOC *rpnt, ElfW(Sym) *symtab, char *strtab); > Please restructure so you don't need these forward declarations. Done. > > Also, it would be nice if you could switch to using a function pointer > for the real handler, see all other arches. I consciously did that micro-optimization to avoid the overhead of an indirect function pointer for processing each symbol relo. >> +} >> diff --git a/ldso/ldso/arc/resolve.S b/ldso/ldso/arc/resolve.S >> new file mode 100644 >> index 000000000000..8609b339effa >> --- /dev/null >> +++ b/ldso/ldso/arc/resolve.S >> @@ -0,0 +1,59 @@ >> +/* >> + * Copyright (C) 2013 Synopsys, Inc. (www.synopsys.com) >> + * >> + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. >> + */ >> + >> +#define __ASSEMBLY__ > please remove that define. Done. >> + >> +#include <bits/asm.h> > Can you instead of asm.h use ENTRY and PLTJMP et al from sysdep.h please? > Everywhere. I was afraid this will come up :-) Fixed now. Also while at it, converted ENDFUNC -> END to make it more conventional. Thanks for your review. -Vineet
diff --git a/ldso/ldso/arc/dl-debug.h b/ldso/ldso/arc/dl-debug.h new file mode 100644 index 000000000000..93ce1e6c729d --- /dev/null +++ b/ldso/ldso/arc/dl-debug.h @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2013 Synopsys, Inc. (www.synopsys.com) + * + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ +static const char *_dl_reltypes_tab[] = +{ + "R_ARC_NONE", /* 0 */ + "R_ARC_8", + "R_ARC_16", + "R_ARC_24", + "R_ARC_32", + "R_ARC_B26", /* 5 */ + "R_ARC_B22_PCREL", + "R_ARC_H30", + "R_ARC_N8", + "R_ARC_N16", + "R_ARC_N24", /* 10 */ + "R_ARC_N32", + "R_ARC_SDA", + "R_ARC_SECTOFF", + "R_ARC_S21H_PCREL", + "R_ARC_S21W_PCREL", /* 15 */ + "R_ARC_S25H_PCREL", + "R_ARC_S25W_PCREL", + "R_ARC_SDA32", + "R_ARC_SDA_LDST", + "R_ARC_SDA_LDST1", /* 20 */ + "R_ARC_SDA_LDST2", + "R_ARC_SDA16_LD", + "R_ARC_SDA16_LD1", + "R_ARC_SDA16_LD2", + "R_ARC_S13_PCREL", /* 25 */ + "R_ARC_W", + "R_ARC_32_ME", + "R_ARC_N32_ME", + "R_ARC_SECTOFF_ME", + "R_ARC_SDA32_ME", /* 30 */ + "R_ARC_W_ME", + "R_ARC_H30_ME", + "R_ARC_SECTOFF_U8", + "R_ARC_SECTOFF_S9", + "R_AC_SECTOFF_U8", /* 35 */ + "R_AC_SECTOFF_U8_1", + "R_AC_SECTOFF_U8_2", + "R_AC_SECTOFF_S9", + "R_AC_SECTOFF_S9_1", + "R_AC_SECTOFF_S9_2", /* 40 */ + "R_ARC_SECTOFF_ME_1", + "R_ARC_SECTOFF_ME_2", + "R_ARC_SECTOFF_1", + "R_ARC_SECTOFF_2", + "", /* 45 */ + "", + "", + "", + "", + "R_ARC_PC32", /* 50 */ + "R_ARC_GOTPC32", + "R_ARC_PLT32", + "R_ARC_COPY", + "R_ARC_GLOB_DAT", + "R_ARC_JMP_SLOT", /* 55 */ + "R_ARC_RELATIVE", + "R_ARC_GOTOFF", + "R_ARC_GOTPC", + "R_ARC_GOT32", +}; diff --git a/ldso/ldso/arc/dl-startup.h b/ldso/ldso/arc/dl-startup.h new file mode 100644 index 000000000000..0d7d44abf2fa --- /dev/null +++ b/ldso/ldso/arc/dl-startup.h @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2013 Synopsys, Inc. (www.synopsys.com) + * + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +/* + * vineetg: Refactoring/cleanup of loader entry point + * Removed 6 useless insns + * Joern Improved it even further: + * -better insn scheduling + * -no need for conditional code for _dl_skip_args + * -use of assembler .&2 expressions vs. @gotpc refs (avoids need for GP) + * + * What this code does: + * -ldso starts execution here when kernel returns from execve() + * -calls into generic ldso entry point _dl_start( ) + * -optionally adjusts argc for executable if exec passed as cmd + * -calls into app main with address of finaliser + */ +__asm__( + ".section .text \n" + ".balign 4 \n" + ".global _start \n" + ".type _start,@function \n" + + "_start: \n" + " ; ldso entry point, returns app entry point \n" + " bl.d _dl_start \n" + " mov_s r0, sp ; pass ptr to aux vector tbl \n" + + " ; If ldso ran as cmd with executable file nm as arg \n" + " ; as arg, skip the extra args calc by dl_start() \n" + " ld_s r1, [sp] ; orig argc from aux-vec Tbl \n" +#ifdef STAR_9000535888_FIXED + " ld r12, [pcl, _dl_skip_args-.+(.&2)] \n" +#else + " add r12, pcl, _dl_skip_args-.+(.&2) \n" + " ld r12, [r12] \n" +#endif + + " add r2, pcl, _dl_fini-.+(.&2) ; finalizer \n" + + " add2 sp, sp, r12 ; discard argv entries from stack\n" + " sub_s r1, r1, r12 ; adjusted argc, on stack \n" + " st_s r1, [sp] \n" + + " j_s.d [r0] ; app entry point \n" + " mov_s r0, r2 ; ptr to finalizer _dl_fini \n" + + ".size _start,.-_start \n" + ".previous \n" +); + +/* + * Get a pointer to the argv array. On many platforms this can be just + * the address if the first argument, on other platforms we need to + * do something a little more subtle here. + */ +#define GET_ARGV(ARGVP, ARGS) ARGVP = ((unsigned long*) ARGS + 1) + +/* + * Dynamic loader bootstrapping: + * Since we don't modify text at runtime, these can only be data relos + * (so safe to assume that they are word aligned). + * And also they HAVE to be RELATIVE relos only + * @RELP is the relo entry being processed + * @REL is the pointer to the address we are relocating. + * @SYMBOL is the symbol involved in the relocation + * @LOAD is the load address. + */ + +#define PERFORM_BOOTSTRAP_RELOC(RELP,REL,SYMBOL,LOAD,SYMTAB) \ +do { \ + int type = ELF32_R_TYPE((RELP)->r_info); \ + if (likely(type == R_ARC_RELATIVE)) \ + *REL += (unsigned long) LOAD; \ + else \ + _dl_exit(1); \ +}while(0) + +/* + * This will go away once we have DT_RELACOUNT + */ +#define ARCH_NEEDS_BOOTSTRAP_RELOCS + +/* we dont need to spit out argc, argv etc for debugging */ +#define NO_EARLY_SEND_STDERR 1 diff --git a/ldso/ldso/arc/dl-syscalls.h b/ldso/ldso/arc/dl-syscalls.h new file mode 100644 index 000000000000..1ab7b552a217 --- /dev/null +++ b/ldso/ldso/arc/dl-syscalls.h @@ -0,0 +1,8 @@ +/* + * Copyright (C) 2013 Synopsys, Inc. (www.synopsys.com) + * + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +#include "sys/syscall.h" +#include <bits/uClibc_page.h> diff --git a/ldso/ldso/arc/dl-sysdep.h b/ldso/ldso/arc/dl-sysdep.h new file mode 100644 index 000000000000..642f020f42e1 --- /dev/null +++ b/ldso/ldso/arc/dl-sysdep.h @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2013 Synopsys, Inc. (www.synopsys.com) + * + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +#include "elf.h" + +/* + * Define this if the system uses RELOCA. + */ +#define ELF_USES_RELOCA + +/* + * Dynamic Linking ABI for ARCompact ISA + * + * PLT + * -------------------------------- + * | ld r11, [pcl, off-to-GOT[1] | 0 (20 bytes) + * | | 4 + * plt0 | ld r10, [pcl, off-to-GOT[2] | 8 + * | | 12 + * | j [r10] | 16 + * -------------------------------- + * | Base address of GOT | 20 + * -------------------------------- + * | ld r12, [pcl, off-to-GOT[3] | 24 (12 bytes each) + * plt1 | | + * | j_s.d [r12] | 32 + * | mov_s r12, pcl | 34 + * -------------------------------- + * | | 36 + * ~ ~ + * ~ ~ + * | | + * -------------------------------- + * + * GOT + * -------------- + * | [0] | + * -------------- + * | [1] | Module info - setup by ldso + * -------------- + * | [2] | resolver entry point + * -------------- + * | [3] | + * | ... | Runtime address for function symbols + * | [f] | + * -------------- + * | [f+1] | + * | ... | Runtime address for data symbols + * | [last] | + * -------------- + */ + +/* + * Initialization sequence for a GOT. + * Caller elf_resolve() seeds @GOT_BASE from DT_PLTGOT - which essentially is + * pointer to first PLT entry. The actual GOT base is 5th word in PLT + * + */ +#define INIT_GOT(GOT_BASE,MODULE) \ +do { \ + unsigned long *__plt_base = (unsigned long *)GOT_BASE; \ + if(MODULE->libtype != program_interpreter) \ + GOT_BASE = (unsigned long *)(__plt_base[5] + \ + (unsigned long)MODULE->loadaddr); \ + GOT_BASE[1] = (unsigned long) MODULE; \ + GOT_BASE[2] = (unsigned long) _dl_linux_resolve; \ +} while(0) + +/* Here we define the magic numbers that this dynamic loader should accept */ +#define MAGIC1 EM_ARCOMPACT +#undef MAGIC2 + +/* Used for error messages */ +#define ELF_TARGET "ARC" + +struct elf_resolve; +extern unsigned long _dl_linux_resolver(struct elf_resolve * tpnt, + unsigned int plt_pc); + +extern unsigned __udivmodsi4 (unsigned, unsigned) + __attribute ((visibility("hidden"))); + +#define do_rem(result, n, base) ((result) = \ + \ + __builtin_constant_p (base) ? (n) % (unsigned) (base) : \ + ({ \ + register unsigned r1 __asm__ ("r1") = (base); \ + \ + __asm("bl.d @__udivmodsi4` mov r0,%1" \ + : "=r" (r1) \ + : "r" (n), "r" (r1) \ + : "r0", "r2", "r3", "r4", "lp_count", "blink", "cc"); \ + \ + r1; \ + }) \ +) + +/* ELF_RTYPE_CLASS_PLT iff TYPE describes relocation of a PLT entry, so + PLT entries 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_ARC_JMP_SLOT) * ELF_RTYPE_CLASS_PLT) \ + | (((type) == R_ARC_COPY) * ELF_RTYPE_CLASS_COPY)) + +/* + * Get the runtime address of GOT[0] + */ +static inline Elf32_Addr elf_machine_dynamic (void) attribute_unused; +static inline Elf32_Addr +elf_machine_dynamic (void) +{ + Elf32_Addr dyn; + + __asm__("ld %0,[pcl,_DYNAMIC@gotpc]\n\t" : "=r" (dyn)); + return dyn; + +/* + * Another way would have been to simply return GP, which due to some + * PIC reference would be automatically setup by gcc in caller + * register Elf32_Addr *got __asm__ ("gp"); return *got; + */ +} + +/* Return the run-time load address of the shared object. */ +static inline Elf32_Addr elf_machine_load_address (void) attribute_unused; +static inline Elf32_Addr +elf_machine_load_address (void) +{ + /* To find the loadaddr we subtract the runtime addr of any symbol + * say _dl_start from it's build-time addr. + */ + Elf32_Addr addr, tmp; + __asm__ ( + "ld %1, [pcl, _dl_start@gotpc] ;build addr of _dl_start \n" + "add %0, pcl, _dl_start-.+(.&2) ;runtime addr of _dl_start \n" + "sub %0, %0, %1 ;delta \n" + : "=&r" (addr), "=r"(tmp) + ); + return addr; +} + +static inline void +elf_machine_relative (Elf32_Addr load_off, const Elf32_Addr rel_addr, + Elf32_Word relative_count) +{ + Elf32_Rel * rpnt = (void *) rel_addr; + --rpnt; + do { + Elf32_Addr *const reloc_addr = (void *) (load_off + (++rpnt)->r_offset); + *reloc_addr += load_off; + } while (--relative_count); +} diff --git a/ldso/ldso/arc/elfinterp.c b/ldso/ldso/arc/elfinterp.c new file mode 100644 index 000000000000..ee6496659a3a --- /dev/null +++ b/ldso/ldso/arc/elfinterp.c @@ -0,0 +1,284 @@ +/* + * Copyright (C) 2013 Synopsys, Inc. (www.synopsys.com) + * + * Lots of code copied from ../i386/elfinterp.c, so: + * Copyright (c) 1994-2000 Eric Youngdale, Peter MacDonald, + * David Engel, Hongjiu Lu and Mitch D'Souza + * Copyright (C) 2001-2002, Erik Andersen + * All rights reserved. + * + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ +#include "ldso.h" + +unsigned long +_dl_linux_resolver(struct elf_resolve *tpnt, unsigned int plt_pc) +{ + ELF_RELOC *this_reloc, *rel_base; + char *strtab, *symname, *new_addr; + ElfW(Sym) *symtab; + int symtab_index; + unsigned int *got_addr; + unsigned long plt_base; + int plt_idx; + + /* start of .rela.plt */ + rel_base = (ELF_RELOC *)(tpnt->dynamic_info[DT_JMPREL]); + + /* starts of .plt (addr of PLT0) */ + plt_base = tpnt->dynamic_info[DT_PLTGOT]; + + /* + * compute the idx of the yet-unresolved PLT entry in .plt + * Same idx will be used to find the relo entry in .rela.plt + */ + plt_idx = (plt_pc - plt_base)/0xc - 2; /* ignoring 2 dummy PLTs */ + + this_reloc = rel_base + plt_idx; + + symtab_index = ELF_R_SYM(this_reloc->r_info); + symtab = (ElfW(Sym) *)(intptr_t) (tpnt->dynamic_info[DT_SYMTAB]); + strtab = (char *) (tpnt->dynamic_info[DT_STRTAB]); + symname= strtab + symtab[symtab_index].st_name; + + /* relo-offset to fixup, shd be a .got entry */ + got_addr = (unsigned int *)(this_reloc->r_offset + tpnt->loadaddr); + + /* Get the address of the GOT entry */ + 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); + } + + +#if defined (__SUPPORT_LD_DEBUG__) + 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 ==> %pc @ %pl\n", + *got_addr, new_addr, got_addr); + } + + if (!_dl_debug_nofixups) + *got_addr = (unsigned int)new_addr; +#else + /* Update the .got entry with the runtime address of symbol */ + *got_addr = (unsigned int)new_addr; +#endif + + /* + * Return the new addres, where the asm trampoline will jump to + * after re-setting up the orig args + */ + return (unsigned long) new_addr; +} + +static int +_dl_do_lazy_reloc (struct elf_resolve *tpnt, struct r_scope_elem *scope, + ELF_RELOC *rpnt); + +static int +_dl_do_reloc (struct elf_resolve *tpnt, struct r_scope_elem *scope, + ELF_RELOC *rpnt, ElfW(Sym) *symtab, char *strtab); + +#define ___DO_LAZY 1 +#define ___DO_NOW 2 + +static int __attribute__((always_inline)) +_dl_parse(struct elf_resolve *tpnt, struct r_scope_elem *scope, + unsigned long rel_addr, unsigned long rel_size, int type) +{ + unsigned int i; + char *strtab; + ElfW(Sym) *symtab; + ELF_RELOC *rpnt; + int symtab_index; + int res = 0; + + /* Now parse the relocation information */ + rpnt = (ELF_RELOC *)(intptr_t) (rel_addr); + rel_size = rel_size / sizeof(ELF_RELOC); + + 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++) { + + symtab_index = ELF_R_SYM(rpnt->r_info); + + debug_sym(symtab,strtab,symtab_index); + debug_reloc(symtab,strtab,rpnt); + + /* constant propagation subsumes the 'if' */ + if (type == ___DO_LAZY) + res = _dl_do_lazy_reloc(tpnt, scope, rpnt); + else + res = _dl_do_reloc(tpnt, scope, rpnt, symtab, strtab); + + if (res != 0) + break; + } + + if (unlikely(res != 0)) { + if (res < 0) { + int reloc_type = ELF_R_TYPE(rpnt->r_info); +#if defined (__SUPPORT_LD_DEBUG__) + _dl_dprintf(2, "can't handle reloc type %s\n ", + _dl_reltypes(reloc_type)); +#else + _dl_dprintf(2, "can't handle reloc type %x\n", + reloc_type); +#endif + _dl_exit(-res); + } else { + _dl_dprintf(2, "can't resolve symbol\n"); + /* Fall thru to return res */ + } + } + + return res; +} + +static int +_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; + unsigned long *reloc_addr; + unsigned long symbol_addr; +#if defined (__SUPPORT_LD_DEBUG__) + unsigned long old_val = 0; +#endif + struct symbol_ref sym_ref; + + 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; + + sym_ref.sym = &symtab[symtab_index]; + sym_ref.tpnt = NULL; + +#if defined (__SUPPORT_LD_DEBUG__) + if (reloc_addr) + old_val = *reloc_addr; +#endif + + if (symtab_index) { + 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); + + /* + * 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)) { + /* Non-fatal if called from dlopen, hence different ret code */ + return 1; + } + } else if (reloc_type == R_ARC_RELATIVE ) { + *reloc_addr += tpnt->loadaddr; + goto log_entry; + } + + switch (reloc_type) { + case R_ARC_32: + *reloc_addr += symbol_addr + rpnt->r_addend; + break; + case R_ARC_PC32: + *reloc_addr += symbol_addr + rpnt->r_addend - (unsigned long) reloc_addr; + break; + case R_ARC_GLOB_DAT: + case R_ARC_JMP_SLOT: + *reloc_addr = symbol_addr; + break; + case R_ARC_COPY: + _dl_memcpy((void *) reloc_addr,(void *) symbol_addr, + symtab[symtab_index].st_size); + break; + default: + return -1; + } + +log_entry: +#if defined (__SUPPORT_LD_DEBUG__) + if(_dl_debug_detail) + _dl_dprintf(_dl_debug_file,"\tpatched: %lx ==> %lx @ %pl: addend %x ", + old_val, *reloc_addr, reloc_addr, rpnt->r_addend); +#endif + + return 0; +} + +static int +_dl_do_lazy_reloc(struct elf_resolve *tpnt, struct r_scope_elem *scope, + ELF_RELOC *rpnt) +{ + int reloc_type; + unsigned long *reloc_addr; +#if defined (__SUPPORT_LD_DEBUG__) + unsigned long old_val; +#endif + + 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; +#endif + + switch (reloc_type) { + case R_ARC_JMP_SLOT: + *reloc_addr += tpnt->loadaddr; + break; + default: + return -1; + } + +#if defined (__SUPPORT_LD_DEBUG__) + if(_dl_debug_reloc && _dl_debug_detail) + _dl_dprintf(_dl_debug_file, "\tpatched: %lx ==> %lx @ %pl\n", + old_val, *reloc_addr, reloc_addr); +#endif + + return 0; +} + +void +_dl_parse_lazy_relocation_information(struct dyn_elf *rpnt, + unsigned long rel_addr, + unsigned long rel_size) +{ + /* This func is called for processing .rela.plt of loaded module(s) + * The relo entries handled are JMP_SLOT type for fixing up .got slots for + * external function calls. + * This function doesn't resolve the slots: that is done lazily at runtime. + * The build linker (at least thats what happens for ARC) had pre-init the + * .got slots to point to PLT0. All that is done here is to fix them up to + * point to load value of PLT0 (as opposed to the build value). + * On ARC, the loadaddr of dyn exec is zero, thus elfaddr == loadaddr + * Thus there is no point in adding "0" to values and un-necessarily stir + * up the caches and TLB. + * For lsdo processing busybox binary, this skips over 380 relo entries + */ + if (rpnt->dyn->loadaddr != 0) + _dl_parse(rpnt->dyn, NULL, rel_addr, rel_size, ___DO_LAZY); +} + +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, scope, rel_addr, rel_size, ___DO_NOW); +} diff --git a/ldso/ldso/arc/resolve.S b/ldso/ldso/arc/resolve.S new file mode 100644 index 000000000000..8609b339effa --- /dev/null +++ b/ldso/ldso/arc/resolve.S @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2013 Synopsys, Inc. (www.synopsys.com) + * + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ + +#define __ASSEMBLY__ + +#include <bits/asm.h> +#include <sys/syscall.h> + +; Save the registers which resolver could possibly clobber +; r0-r9: args to the function - symbol being resolved +; r10-r12 are already clobbered by PLTn, PLT0 thus neednot be saved + +.macro SAVE_CALLER_SAVED + push_s r0 + push_s r1 + push_s r2 + push_s r3 + st.a r4, [sp, -4] + st.a r5, [sp, -4] + st.a r6, [sp, -4] + st.a r7, [sp, -4] + st.a r8, [sp, -4] + st.a r9, [sp, -4] + push_s blink +.endm + +.macro RESTORE_CALLER_SAVED_BUT_R0 + ld.ab blink,[sp, 4] + ld.ab r9, [sp, 4] + ld.ab r8, [sp, 4] + ld.ab r7, [sp, 4] + ld.ab r6, [sp, 4] + ld.ab r5, [sp, 4] + ld.ab r4, [sp, 4] + pop_s r3 + pop_s r2 + pop_s r1 +.endm + +; Upon entry, PLTn, which led us here, sets up the following regs +; r11 = Module info (tpnt pointer as expected by resolver) +; r12 = PC of the PLTn itself - needed by resolver to find +; corresponding .rela.plt entry + +ENTRY(_dl_linux_resolve) + ; args to func being resolved, which resolver might clobber + SAVE_CALLER_SAVED + + mov_s r1, r12 + bl.d _dl_linux_resolver + mov r0, r11 + + RESTORE_CALLER_SAVED_BUT_R0 + j_s.d [r0] ; r0 has resolved function addr + pop_s r0 ; restore first arg to resolved call +ENDFUNC(_dl_linux_resolve)
Signed-off-by: Vineet Gupta <vgupta@synopsys.com> --- ldso/ldso/arc/dl-debug.h | 68 +++++++++++ ldso/ldso/arc/dl-startup.h | 88 ++++++++++++++ ldso/ldso/arc/dl-syscalls.h | 8 ++ ldso/ldso/arc/dl-sysdep.h | 156 ++++++++++++++++++++++++ ldso/ldso/arc/elfinterp.c | 284 ++++++++++++++++++++++++++++++++++++++++++++ ldso/ldso/arc/resolve.S | 59 +++++++++ 6 files changed, 663 insertions(+) create mode 100644 ldso/ldso/arc/dl-debug.h create mode 100644 ldso/ldso/arc/dl-startup.h create mode 100644 ldso/ldso/arc/dl-syscalls.h create mode 100644 ldso/ldso/arc/dl-sysdep.h create mode 100644 ldso/ldso/arc/elfinterp.c create mode 100644 ldso/ldso/arc/resolve.S