[PATCH v3 3/7] ldso: Add ARC support
Bernhard Reutner-Fischer
rep.dot.nop at gmail.com
Fri Dec 20 13:29:37 UTC 2013
On Fri, Dec 13, 2013 at 02:49:22PM +0530, Vineet Gupta wrote:
> Signed-off-by: Vineet Gupta <vgupta at synopsys.com>
> ---
> ldso/ldso/arc/dl-debug.h | 68 +++++++++++
> ldso/ldso/arc/dl-startup.h | 89 ++++++++++++++
> ldso/ldso/arc/dl-syscalls.h | 5 +
> ldso/ldso/arc/dl-sysdep.h | 150 ++++++++++++++++++++++++
> ldso/ldso/arc/elfinterp.c | 279 ++++++++++++++++++++++++++++++++++++++++++++
> ldso/ldso/arc/resolve.S | 57 +++++++++
> 6 files changed, 648 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..ff559f27fa31
> --- /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 or later, 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..4a8d5d786b63
> --- /dev/null
> +++ b/ldso/ldso/arc/dl-startup.h
> @@ -0,0 +1,89 @@
> +/*
> + * Copyright (C) 2013 Synopsys, Inc. (www.synopsys.com)
> + *
> + * Licensed under the LGPL v2.1 or later, 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"
> + ".align 4 \n"
> + ".global _start \n"
> + ".hidden _start \n"
> + ".type _start, at 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"
too many "as arg"
> + " ld_s r1, [sp] ; orig argc from aux-vec Tbl \n"
> +#ifdef STAR_9000535888_FIXED
what is that STAR_9000535888_FIXED thing, can we remove this?
> + " 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..a0b5afc9ec78
> --- /dev/null
> +++ b/ldso/ldso/arc/dl-syscalls.h
> @@ -0,0 +1,5 @@
> +/*
> + * Copyright (C) 2013 Synopsys, Inc. (www.synopsys.com)
> + *
> + * Licensed under the LGPL v2.1 or later, see the file COPYING.LIB in this tarball.
> + */
I would have added a
/* stub for arch-specific syscall issues */
but ok as is.
> diff --git a/ldso/ldso/arc/dl-sysdep.h b/ldso/ldso/arc/dl-sysdep.h
> new file mode 100644
> index 000000000000..dfde3323373b
> --- /dev/null
> +++ b/ldso/ldso/arc/dl-sysdep.h
> @@ -0,0 +1,150 @@
> +/*
> + * Copyright (C) 2013 Synopsys, Inc. (www.synopsys.com)
> + *
> + * Licensed under the LGPL v2.1 or later, 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
plt0 and plt1 lines are still broken, please fix.
> + * | 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; \
> + 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_hidden;
> +
> +#define do_rem(result, n, base) ((result) = \
> + \
> + __builtin_constant_p (base) ? (n) % (unsigned) (base) : \
> + __extension__ ({ \
> + register unsigned r1 __asm__ ("r1") = (base); \
> + \
> + __asm("bl.d @__udivmodsi4` mov r0,%1" \
__asm__
> + : "=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 __always_inline Elf32_Addr elf_machine_dynamic(void)
> +{
> + Elf32_Addr dyn;
> +
> + __asm__("ld %0,[pcl,_DYNAMIC at 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 __always_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 at 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 __always_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..a3d741b65c4e
> --- /dev/null
> +++ b/ldso/ldso/arc/elfinterp.c
> @@ -0,0 +1,279 @@
> +/*
> + * 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 or later, see the file COPYING.LIB in this tarball.
> + */
> +#include "ldso.h"
> +
> +#define ARC_PLT_SIZE 12
> +
> +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)/ARC_PLT_SIZE - 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_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)
missing space after if
> + _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;
> +}
> +
> +#define ___DO_LAZY 1
> +#define ___DO_NOW 2
> +
> +static int _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;
> +}
> +
> +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..891f66b97008
> --- /dev/null
> +++ b/ldso/ldso/arc/resolve.S
> @@ -0,0 +1,57 @@
> +/*
> + * Copyright (C) 2013 Synopsys, Inc. (www.synopsys.com)
> + *
> + * Licensed under the LGPL v2.1 or later, see the file COPYING.LIB in this tarball.
> + */
> +
> +#include <sysdep.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
> +END(_dl_linux_resolve)
> --
> 1.8.1.2
>
More information about the uClibc
mailing list