Patchwork [3/6] ldso: Add ARC support

login
register
mail settings
Submitter Vineet Gupta
Date Nov. 1, 2013, 10:55 a.m.
Message ID <1383303307-1280-4-git-send-email-vgupta@synopsys.com>
Download mbox | patch
Permalink /patch/287786/
State Superseded
Headers show

Comments

Vineet Gupta - Nov. 1, 2013, 10:55 a.m.
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
aldot - Nov. 12, 2013, 2:04 p.m.
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
Vineet Gupta - Nov. 15, 2013, 9:37 a.m.
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

Patch

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)