[PATCH v2 5/5] microblaze mmu/elf/shared lib support

Steve Bennett steveb at workware.net.au
Tue Oct 4 00:50:49 UTC 2011


From: Ryan Flux <ryan.flux at emsolutions.com.au>

microblaze can either be with mmu or without
If with, use elf rather than flat, and support shared libs

Signed-off-by: Ryan Flux <ryan.flux at emsolutions.com.au>
Signed-off-by: Steve Bennett <steveb at workware.net.au>
---
 extra/Configs/Config.microblaze                  |    5 -
 include/elf.h                                    |   33 +++
 ldso/include/dl-string.h                         |    2 +-
 ldso/ldso/microblaze/dl-debug.h                  |   54 ++++
 ldso/ldso/microblaze/dl-startup.h                |  102 +++++++
 ldso/ldso/microblaze/dl-syscalls.h               |    6 +
 ldso/ldso/microblaze/dl-sysdep.h                 |   85 ++++++
 ldso/ldso/microblaze/elfinterp.c                 |  330 ++++++++++++++++++++++
 ldso/ldso/microblaze/resolve.S                   |   52 ++++
 libc/sysdeps/linux/microblaze/bits/uClibc_page.h |    2 +
 libc/sysdeps/linux/microblaze/setjmp.S           |   32 ++-
 libc/sysdeps/linux/microblaze/vfork.S            |    7 +
 utils/ldd.c                                      |    5 +
 13 files changed, 708 insertions(+), 7 deletions(-)
 create mode 100644 ldso/ldso/microblaze/dl-debug.h
 create mode 100644 ldso/ldso/microblaze/dl-startup.h
 create mode 100644 ldso/ldso/microblaze/dl-syscalls.h
 create mode 100644 ldso/ldso/microblaze/dl-sysdep.h
 create mode 100644 ldso/ldso/microblaze/elfinterp.c
 create mode 100644 ldso/ldso/microblaze/resolve.S

diff --git a/extra/Configs/Config.microblaze b/extra/Configs/Config.microblaze
index dbcf1d5..2dfd4a7 100644
--- a/extra/Configs/Config.microblaze
+++ b/extra/Configs/Config.microblaze
@@ -6,8 +6,3 @@
 config TARGET_ARCH
 	string
 	default "microblaze"
-
-config FORCE_OPTIONS_FOR_ARCH
-	bool
-	default y
-	select ARCH_HAS_NO_MMU
diff --git a/include/elf.h b/include/elf.h
index d71691e..ba3e804 100644
--- a/include/elf.h
+++ b/include/elf.h
@@ -368,6 +368,14 @@ typedef struct
 /* V850 backend magic number.  Written in the absense of an ABI.  */
 #define EM_CYGNUS_V850 0x9080
 
+/* Xilinx Microblaze (unofficial). Note that there is now an official microblaze
+ * magic number, but all the toolchains currently in existence use the old number
+ */
+#define EM_MICROBLAZE_OLD   0xbaab
+
+/* Xilinx Microblaze (official) */
+#define EM_MICROBLAZE   189
+
 /* Legal values for e_version (version).  */
 
 #define EV_NONE		0		/* Invalid ELF version */
@@ -3108,6 +3116,31 @@ typedef Elf32_Addr Elf32_Conflict;
 
 #define DT_C6000_NUM    4
 
+/* microblaze specific relocs */
+#define R_MICROBLAZE_NONE 0
+#define R_MICROBLAZE_32 1
+#define R_MICROBLAZE_32_PCREL 2
+#define R_MICROBLAZE_64_PCREL 3
+#define R_MICROBLAZE_32_PCREL_LO 4
+#define R_MICROBLAZE_64 5
+#define R_MICROBLAZE_32_LO 6
+#define R_MICROBLAZE_SRO32 7
+#define R_MICROBLAZE_SRW32 8
+#define R_MICROBLAZE_64_NONE 9
+#define R_MICROBLAZE_32_SYM_OP_SYM 10
+#define R_MICROBLAZE_GNU_VTINHERIT 11
+#define R_MICROBLAZE_GNU_VTENTRY 12
+#define R_MICROBLAZE_GOTPC_64 13  /* PC-relative GOT offset */
+#define R_MICROBLAZE_GOT_64 14  /* GOT entry offset */
+#define R_MICROBLAZE_PLT_64 15  /* PLT offset (PC-relative  */
+#define R_MICROBLAZE_REL 16  /* adjust by program base */
+#define R_MICROBLAZE_JUMP_SLOT 17  /* create PLT entry */
+#define R_MICROBLAZE_GLOB_DAT 18  /* create GOT entry */
+#define R_MICROBLAZE_GOTOFF_64 19  /* offset relative to GOT */
+#define R_MICROBLAZE_GOTOFF_32 20  /* offset relative to GOT */
+#define R_MICROBLAZE_COPY 21  /* runtime copy */
+#define R_MICROBLAZE_NUM 22
+
 #ifdef	__cplusplus
 }
 #endif
diff --git a/ldso/include/dl-string.h b/ldso/include/dl-string.h
index 01ab50e..a7e2f47 100644
--- a/ldso/include/dl-string.h
+++ b/ldso/include/dl-string.h
@@ -286,7 +286,7 @@ static __always_inline char * _dl_simple_ltoahex(char *local, unsigned long i)
  * This requires that load_addr must already be defined... */
 #if defined(mc68000)  || defined(__arm__) || defined(__thumb__) || \
     defined(__mips__) || defined(__sh__)  || defined(__powerpc__) || \
-    defined(__avr32__) || defined(__xtensa__) || defined(__sparc__)
+    defined(__avr32__) || defined(__xtensa__) || defined(__sparc__) || defined(__microblaze__)
 # define CONSTANT_STRING_GOT_FIXUP(X) \
 	if ((X) < (const char *) load_addr) (X) += load_addr
 # define NO_EARLY_SEND_STDERR
diff --git a/ldso/ldso/microblaze/dl-debug.h b/ldso/ldso/microblaze/dl-debug.h
new file mode 100644
index 0000000..6fd7bd5
--- /dev/null
+++ b/ldso/ldso/microblaze/dl-debug.h
@@ -0,0 +1,54 @@
+/* vi: set sw=4 ts=4: */
+/* microblaze shared library loader suppport
+ *
+ * Copyright (C) 2011 Ryan Flux
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. The name of the above contributors may not be
+ *    used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+static const char * const _dl_reltypes_tab[] =
+	{
+		"R_MICROBLAZE_NONE",
+		"R_MICROBLAZE_32",
+		"R_MICROBLAZE_32_PCREL",
+		"R_MICROBLAZE_64_PCREL",
+		"R_MICROBLAZE_32_PCREL_LO",
+		"R_MICROBLAZE_64",
+		"R_MICROBLAZE_32_LO",
+		"R_MICROBLAZE_SRO32",
+		"R_MICROBLAZE_SRW32",
+		"R_MICROBLAZE_64_NONE",
+		"R_MICROBLAZE_32_SYM_OP_SYM",
+		"R_MICROBLAZE_GNU_VTINHERIT",
+		"R_MICROBLAZE_GNU_VTENTRY",
+		"R_MICROBLAZE_GOTPC_64",
+		"R_MICROBLAZE_GOT_64",
+		"R_MICROBLAZE_PLT_64",
+		"R_MICROBLAZE_REL",
+		"R_MICROBLAZE_JUMP_SLOT",
+		"R_MICROBLAZE_GLOB_DAT",
+		"R_MICROBLAZE_GOTOFF_64",
+		"R_MICROBLAZE_GOTOFF_32",
+		"R_MICROBLAZE_COPY",
+	};
diff --git a/ldso/ldso/microblaze/dl-startup.h b/ldso/ldso/microblaze/dl-startup.h
new file mode 100644
index 0000000..0d3f3bf
--- /dev/null
+++ b/ldso/ldso/microblaze/dl-startup.h
@@ -0,0 +1,102 @@
+/* Startup code for the microblaze platform, based on glibc 2.3.6, dl-machine.h */
+
+/*
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+__asm__ ("\
+	.text\n\
+	.globl _start\n\
+	.type _start, at function\n\
+_start:\n\
+	addk  r5,r0,r1\n\
+	addk  r3,r0,r0\n\
+1:\n\
+	addik r5,r5,4\n\
+	lw    r4,r5,r0\n\
+	bneid r4,1b\n\
+	addik r3,r3,1\n\
+	addik r3,r3,-1\n\
+	addk  r5,r0,r1\n\
+	sw    r3,r5,r0\n\
+	addik r1,r1,-24\n\
+	sw    r15,r1,r0\n\
+	brlid r15,_dl_start\n\
+	nop\n\
+	/* FALLTHRU */\n\
+\n\
+	.globl _dl_start_user\n\
+	.type _dl_start_user, at function\n\
+_dl_start_user:\n\
+	mfs   r20,rpc\n\
+	addik r20,r20,_GLOBAL_OFFSET_TABLE_+8\n\
+	lwi   r4,r20,_dl_skip_args at GOTOFF\n\
+	lwi   r5,r1,24\n\
+	rsubk r5,r4,r5\n\
+	addk  r4,r4,r4\n\
+	addk  r4,r4,r4\n\
+	addk  r1,r1,r4\n\
+	swi   r5,r1,24\n\
+	swi   r3,r1,20\n\
+	addk  r6,r5,r0\n\
+	addk  r5,r5,r5\n\
+	addk  r5,r5,r5\n\
+	addik r7,r1,28\n\
+	addk  r8,r7,r5\n\
+	addik r8,r8,4\n\
+	lwi   r5,r1,24\n\
+	lwi   r3,r1,20\n\
+	addk  r4,r5,r5\n\
+	addk  r4,r4,r4\n\
+	addik r6,r1,28\n\
+	addk  r7,r6,r4\n\
+	addik r7,r7,4\n\
+	addik r15,r20,_dl_fini at GOTOFF\n\
+	addik r15,r15,-8\n\
+	brad  r3\n\
+	addik r1,r1,24\n\
+	nop\n\
+	.size _dl_start_user, . - _dl_start_user\n\
+	.previous");
+
+/*
+ * Get a pointer to the argv array.  On many platforms this can be just
+ * the address of 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)
+
+/* The ld.so library requires relocations */
+#define ARCH_NEEDS_BOOTSTRAP_RELOCS
+
+static __always_inline
+void PERFORM_BOOTSTRAP_RELOC(ELF_RELOC *rpnt, unsigned long *reloc_addr,
+	unsigned long symbol_addr, unsigned long load_addr, attribute_unused Elf32_Sym *symtab)
+{
+
+	switch (ELF32_R_TYPE(rpnt->r_info))
+	{
+		case R_MICROBLAZE_REL:
+
+			*reloc_addr = load_addr + rpnt->r_addend;
+			break;
+
+		default:
+			_dl_exit(1);
+			break;
+
+	}
+
+}
diff --git a/ldso/ldso/microblaze/dl-syscalls.h b/ldso/ldso/microblaze/dl-syscalls.h
new file mode 100644
index 0000000..996bb87
--- /dev/null
+++ b/ldso/ldso/microblaze/dl-syscalls.h
@@ -0,0 +1,6 @@
+/* We can't use the real errno in ldso, since it has not yet
+ * been dynamicly linked in yet. */
+#include "sys/syscall.h"
+extern int _dl_errno;
+#undef __set_errno
+#define __set_errno(X) {(_dl_errno) = (X);}
diff --git a/ldso/ldso/microblaze/dl-sysdep.h b/ldso/ldso/microblaze/dl-sysdep.h
new file mode 100644
index 0000000..1f89673
--- /dev/null
+++ b/ldso/ldso/microblaze/dl-sysdep.h
@@ -0,0 +1,85 @@
+/* elf reloc code for the microblaze platform, based on glibc 2.3.6, dl-machine.h */
+
+/*
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+/* Use reloca */
+#define ELF_USES_RELOCA
+
+#include <elf.h>
+
+
+/* Initialise the GOT */
+#define INIT_GOT(GOT_BASE,MODULE)							\
+do {														\
+	GOT_BASE[2] = (unsigned long) _dl_linux_resolve;		\
+	GOT_BASE[1] = (unsigned long) MODULE;					\
+} while(0)
+
+/* Here we define the magic numbers that this dynamic loader should accept */
+
+#define MAGIC1 EM_MICROBLAZE_OLD
+#undef  MAGIC2
+/* Used for error messages */
+#define ELF_TARGET "microblaze"
+
+#define elf_machine_type_class(type) \
+  (((type) == R_MICROBLAZE_JUMP_SLOT) * ELF_RTYPE_CLASS_PLT \
+   | ((type) == R_MICROBLAZE_COPY) * ELF_RTYPE_CLASS_COPY)
+
+/* Return the link-time address of _DYNAMIC.  Conveniently, this is the
+   first element of the GOT.  This must be inlined in a function which
+   uses global data.  */
+static inline Elf32_Addr
+elf_machine_dynamic (void)
+{
+  Elf32_Addr got_entry_0;
+  __asm__ __volatile__(
+    "lwi %0,r20,0"
+    :"=r"(got_entry_0)
+    );
+  return got_entry_0;
+}
+
+
+/* Return the run-time load address of the shared object.  */
+static inline Elf32_Addr
+elf_machine_load_address (void)
+{
+  /* Compute the difference between the runtime address of _DYNAMIC as seen
+     by a GOTOFF reference, and the link-time address found in the special
+     unrelocated first GOT entry.  */
+  Elf32_Addr dyn;
+  __asm__ __volatile__ (
+    "addik %0,r20,_DYNAMIC at GOTOFF"
+    : "=r"(dyn)
+    );
+  return dyn - elf_machine_dynamic ();
+}
+
+
+
+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;
+	do {
+		Elf32_Addr *const reloc_addr = (void *) (load_off + (rpnt)->r_offset);
+
+		*reloc_addr += load_off;
+	} while (--relative_count);
+}
diff --git a/ldso/ldso/microblaze/elfinterp.c b/ldso/ldso/microblaze/elfinterp.c
new file mode 100644
index 0000000..1f6aeff
--- /dev/null
+++ b/ldso/ldso/microblaze/elfinterp.c
@@ -0,0 +1,330 @@
+/* vi: set sw=4 ts=4: */
+/* microblaze ELF shared library loader suppport
+ *
+ * Copyright (c) 1994-2000 Eric Youngdale, Peter MacDonald,
+ *                              David Engel, Hongjiu Lu and Mitch D'Souza
+ * Copyright (C) 2001-2004 Erik Andersen
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. The name of the above contributors may not be
+ *    used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "ldso.h"
+
+/* Program to load an ELF binary on a linux system, and run it.
+   References to symbols in sharable libraries can be resolved by either
+   an ELF sharable library or a linux style of shared library. */
+
+/* Disclaimer:  I have never seen any AT&T source code for SVr4, nor have
+   I ever taken any courses on internals.  This program was developed using
+   information available through the book "UNIX SYSTEM V RELEASE 4,
+   Programmers guide: Ansi C and Programming Support Tools", which did
+   a more than adequate job of explaining everything required to get this
+   working. */
+
+extern int _dl_linux_resolve(void);
+
+unsigned long
+_dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)
+{
+	ELF_RELOC *this_reloc;
+	char *strtab;
+	ElfW(Sym) *symtab;
+	int symtab_index;
+	char *rel_addr;
+	char *new_addr;
+	char **got_addr;
+	ElfW(Addr) instr_addr;
+	char *symname;
+
+	rel_addr = (char *)tpnt->dynamic_info[DT_JMPREL];
+	this_reloc = (ELF_RELOC *)(rel_addr + reloc_entry);
+	symtab_index = ELF_R_SYM(this_reloc->r_info);
+
+	symtab = (ElfW(Sym) *)tpnt->dynamic_info[DT_SYMTAB];
+	strtab = (char *)tpnt->dynamic_info[DT_STRTAB];
+	symname = strtab + symtab[symtab_index].st_name;
+
+	/* Address of the jump instruction to fix up. */
+	instr_addr = (this_reloc->r_offset + tpnt->loadaddr);
+	got_addr = (char **)instr_addr;
+
+	/* 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 ((unsigned long)got_addr < 0x40000000) {
+		if (_dl_debug_bindings) {
+			_dl_dprintf(_dl_debug_file, "\nresolve function: %s", symname);
+			if (_dl_debug_detail)
+				_dl_dprintf(_dl_debug_file,
+				            "\tpatched: %x ==> %x @ %x\n",
+				            *got_addr, new_addr, got_addr);
+		}
+	}
+	if (!_dl_debug_nofixups)
+#endif
+		*got_addr = new_addr;
+
+	return (unsigned long)new_addr;
+}
+
+static int
+_dl_parse(struct elf_resolve *tpnt, struct r_scope_elem *scope,
+	  unsigned long rel_addr, unsigned long rel_size,
+	  int (*reloc_fnc)(struct elf_resolve *tpnt, struct r_scope_elem *scope,
+			   ELF_RELOC *rpnt, ElfW(Sym) *symtab, char *strtab))
+{
+	unsigned int i;
+	char *strtab;
+	ElfW(Sym) *symtab;
+	ELF_RELOC *rpnt;
+	int symtab_index;
+
+	/* Parse the relocation information. */
+	rpnt = (ELF_RELOC *)rel_addr;
+	rel_size /= sizeof(ELF_RELOC);
+
+	symtab = (ElfW(Sym) *)tpnt->dynamic_info[DT_SYMTAB];
+	strtab = (char *)tpnt->dynamic_info[DT_STRTAB];
+
+	for (i = 0; i < rel_size; i++, rpnt++) {
+		int res;
+
+		symtab_index = ELF_R_SYM(rpnt->r_info);
+
+		debug_sym(symtab, strtab, symtab_index);
+		debug_reloc(symtab, strtab, rpnt);
+
+		res = reloc_fnc(tpnt, scope, rpnt, symtab, strtab);
+
+		if (res == 0)
+			continue;
+
+		_dl_dprintf(2, "\n%s: ", _dl_progname);
+
+		if (symtab_index)
+			_dl_dprintf(2, "symbol '%s': ",
+				    strtab + symtab[symtab_index].st_name);
+
+		if (unlikely(res < 0)) {
+			int reloc_type = ELF_R_TYPE(rpnt->r_info);
+
+			_dl_dprintf(2, "can't handle reloc type "
+#if defined (__SUPPORT_LD_DEBUG__)
+				    "%s\n", _dl_reltypes(reloc_type));
+#else
+				    "%x\n", reloc_type);
+#endif
+			_dl_exit(-res);
+		} else if (unlikely(res > 0)) {
+			_dl_dprintf(2, "can't resolve symbol\n");
+			return res;
+		}
+	}
+
+	return 0;
+}
+
+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;
+#if defined USE_TLS && USE_TLS
+	struct elf_resolve *tls_tpnt;
+#endif
+	struct symbol_ref sym_ref;
+	ElfW(Addr) *reloc_addr;
+	ElfW(Addr) symbol_addr;
+#if defined (__SUPPORT_LD_DEBUG__)
+	ElfW(Addr) old_val;
+#endif
+
+	reloc_addr = (ElfW(Addr)*)(tpnt->loadaddr + (unsigned long)rpnt->r_offset);
+	reloc_type = ELF_R_TYPE(rpnt->r_info);
+	symtab_index = ELF_R_SYM(rpnt->r_info);
+	sym_ref.sym = &symtab[symtab_index];
+	sym_ref.tpnt = NULL;
+	symbol_addr = 0;
+	symname = strtab + sym_ref.sym->st_name;
+
+	if (symtab_index) {
+		symbol_addr = (ElfW(Addr))_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_TYPE(sym_ref.sym->st_info) != STT_TLS)
+					&& (ELF_ST_BIND(sym_ref.sym->st_info) != STB_WEAK))) {
+			/* This may be non-fatal if called from dlopen. */
+			return 1;
+		}
+#if defined USE_TLS && USE_TLS
+		tls_tpnt = sym_ref.tpnt;
+#endif
+	} else {
+		/* Relocs against STN_UNDEF are usually treated as using a
+		 * symbol value of zero, and using the module containing the
+		 * reloc itself. */
+		symbol_addr = sym_ref.sym->st_value;
+#if defined USE_TLS && USE_TLS
+		tls_tpnt = tpnt;
+#endif
+	}
+
+
+#if defined (__SUPPORT_LD_DEBUG__)
+	if (reloc_addr) {
+		old_val = *reloc_addr;
+	} else {
+		old_val = 0;
+	}
+#endif
+
+	switch (reloc_type) {
+		case R_MICROBLAZE_NONE:
+		case R_MICROBLAZE_64_NONE:
+			break;
+
+		case R_MICROBLAZE_64:
+			*reloc_addr = symbol_addr + rpnt->r_addend;
+			break;
+
+		case R_MICROBLAZE_32:
+		case R_MICROBLAZE_32_LO:
+			*reloc_addr = symbol_addr + rpnt->r_addend;
+			break;
+
+		case R_MICROBLAZE_32_PCREL:
+		case R_MICROBLAZE_32_PCREL_LO:
+		case R_MICROBLAZE_64_PCREL:
+		case R_MICROBLAZE_SRO32:
+		case R_MICROBLAZE_SRW32:
+			*reloc_addr = symbol_addr + rpnt->r_addend;
+			break;
+
+		case R_MICROBLAZE_GLOB_DAT:
+		case R_MICROBLAZE_JUMP_SLOT:
+			*reloc_addr = symbol_addr + rpnt->r_addend;
+			break;
+/* Handled by elf_machine_relative */
+		case R_MICROBLAZE_REL:
+			*reloc_addr = (unsigned long)tpnt->loadaddr + rpnt->r_addend;
+			break;
+
+		case R_MICROBLAZE_COPY:
+			if (symbol_addr) {
+#if defined (__SUPPORT_LD_DEBUG__)
+				if (_dl_debug_move)
+					_dl_dprintf(_dl_debug_file,
+						    "\t%s move %d bytes from %x to %x\n",
+						    symname, sym_ref.sym->st_size,
+						    symbol_addr, reloc_addr);
+#endif
+
+				_dl_memcpy((char *)reloc_addr,
+					   (char *)symbol_addr,
+					   sym_ref.sym->st_size);
+			}
+#if defined (__SUPPORT_LD_DEBUG__)
+			else
+				_dl_dprintf(_dl_debug_file, "no symbol_addr to copy !?\n");
+#endif
+			break;
+
+		default:
+			return -1;	/* Calls _dl_exit(1). */
+	}
+
+#if defined (__SUPPORT_LD_DEBUG__)
+	if (_dl_debug_reloc && _dl_debug_detail)
+		_dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x\n",
+			    old_val, *reloc_addr, reloc_addr);
+#endif
+
+	return 0;
+}
+
+static int
+_dl_do_lazy_reloc(struct elf_resolve *tpnt, struct r_scope_elem *scope,
+		  ELF_RELOC *rpnt, ElfW(Sym) *symtab, char *strtab)
+{
+	int reloc_type;
+	int symtab_index;
+	ElfW(Addr) *reloc_addr;
+#if defined (__SUPPORT_LD_DEBUG__)
+	ElfW(Addr) old_val;
+#endif
+
+	(void)scope;
+	symtab_index = ELF_R_SYM(rpnt->r_info);
+	(void)strtab;
+
+	reloc_addr = (ElfW(Addr)*)(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_MICROBLAZE_NONE:
+			break;
+		case R_MICROBLAZE_JUMP_SLOT:
+			*reloc_addr += (unsigned long)tpnt->loadaddr;
+			break;
+		default:
+			_dl_exit(1);
+	}
+
+#if defined (__SUPPORT_LD_DEBUG__)
+	if (_dl_debug_reloc && _dl_debug_detail)
+		_dl_dprintf(_dl_debug_file, "\tpatched_lazy: %x ==> %x @ %x\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)
+{
+	(void)_dl_parse(rpnt->dyn, NULL, rel_addr, rel_size, _dl_do_lazy_reloc);
+}
+
+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, _dl_do_reloc);
+}
diff --git a/ldso/ldso/microblaze/resolve.S b/ldso/ldso/microblaze/resolve.S
new file mode 100644
index 0000000..8ad94fe
--- /dev/null
+++ b/ldso/ldso/microblaze/resolve.S
@@ -0,0 +1,52 @@
+
+/* This code is used in dl-runtime.c to call the `fixup' function
+   and then redirect to the address it returns. */
+/* We assume that R3 contain relocation offset and R4 contains
+   link_map (_DYNAMIC). This must be consistent with the JUMP_SLOT
+   layout generated by binutils. */
+
+/* Based on glibc 2.3.6, dl-machine.h */
+/*
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+.text
+.align 4
+.globl _dl_linux_resolver
+.globl _dl_linux_resolve
+.type  _dl_linux_resolve, at function
+
+_dl_linux_resolve:
+    addik r1,r1,-40
+    swi   r5,r1,12
+    swi   r6,r1,16
+    swi   r7,r1,20
+    swi   r8,r1,24
+    swi   r9,r1,28
+    swi   r10,r1,32
+    swi   r15,r1,0
+    addk r5,r0,r4
+    brlid r15, _dl_linux_resolver
+    addk r6,r0,r3; /* delay slot */
+    lwi   r10,r1,32
+    lwi   r9,r1,28
+    lwi   r8,r1,24
+    lwi   r7,r1,20
+    lwi   r6,r1,16
+    lwi   r5,r1,12
+    lwi   r15,r1,0
+    brad  r3
+    addik r1,r1,40; /* delay slot */
+    .size _dl_linux_resolve, . - _dl_linux_resolve
diff --git a/libc/sysdeps/linux/microblaze/bits/uClibc_page.h b/libc/sysdeps/linux/microblaze/bits/uClibc_page.h
index 8fc81ae..41b0422 100644
--- a/libc/sysdeps/linux/microblaze/bits/uClibc_page.h
+++ b/libc/sysdeps/linux/microblaze/bits/uClibc_page.h
@@ -31,7 +31,9 @@
 #elif defined(CONFIG_MICROBLAZE_4K_PAGES)
 #define PAGE_SHIFT		12
 #else
+#if !defined(CONFIG_MMU)
 #warning Missing CONFIG_MICROBLAZE_nnK_PAGES, assuming 4K
+#endif
 #define PAGE_SHIFT		12
 #endif
 
diff --git a/libc/sysdeps/linux/microblaze/setjmp.S b/libc/sysdeps/linux/microblaze/setjmp.S
index 7acb9ea..d01c745 100644
--- a/libc/sysdeps/linux/microblaze/setjmp.S
+++ b/libc/sysdeps/linux/microblaze/setjmp.S
@@ -10,7 +10,24 @@
  * directory of this archive for more details.
  *
  * Written by Miles Bader <miles at gnu.org>
- */
+ *
+ * PIC code based on glibc 2.3.6 */
+
+/*
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
 
 #define _SETJMP_H
 #define _ASM
@@ -22,7 +39,11 @@
 	.globl C_SYMBOL_NAME(setjmp)
 	.align 4
 C_SYMBOL_NAME(setjmp):
+#ifdef __PIC__
+	brid	1f
+#else
 	braid	C_SYMBOL_NAME(__sigsetjmp)
+#endif
 	addi	r6, r0, 1			/* Save the signal mask.  */
 
 	.globl C_SYMBOL_NAME(_setjmp)
@@ -31,6 +52,7 @@ C_SYMBOL_NAME(_setjmp):
 
 	.globl C_SYMBOL_NAME(__sigsetjmp)
 C_SYMBOL_NAME(__sigsetjmp):
+1:
 	/* Save registers relative to r5 (arg0)*/
 	swi	r1, r5, 0			/* stack pointer */
 	swi	r15, r5, 4			/* link register */
@@ -52,5 +74,13 @@ C_SYMBOL_NAME(__sigsetjmp):
 	swi	r31, r5, 68
 
 	/* Make a tail call to __sigjmp_save; it takes the same args.  */
+#ifdef __PIC__
+	mfs   r12,rpc
+	addik r12,r12,_GLOBAL_OFFSET_TABLE_+8
+	lwi   r12,r12,__sigjmp_save at GOT
+	brad  r12
+	nop
+#else
 	braid	C_SYMBOL_NAME(__sigjmp_save)
 	nop
+#endif
diff --git a/libc/sysdeps/linux/microblaze/vfork.S b/libc/sysdeps/linux/microblaze/vfork.S
index c4b4dbf..57db5e5 100644
--- a/libc/sysdeps/linux/microblaze/vfork.S
+++ b/libc/sysdeps/linux/microblaze/vfork.S
@@ -36,7 +36,14 @@ __vfork:
 	blti	r4, 1f			/* is r3 < -125? */
 	bri	2f			/* normal return */
 1:	sub 	r3, r3, r0		/* r3 = -r3 */
+#ifdef __PIC__
+	mfs	r3,rpc
+	addik	r3,r3,_GLOBAL_OFFSET_TABLE_+8
+	lwi	r3,r3,C_SYMBOL_NAME(errno)@GOT
+	sw	r3, r0, r3
+#else
 	swi	r3, r0, C_SYMBOL_NAME(errno);
+#endif
 					/* state restore etc */
 2:	rtsd	r15, 8			/* error return */
 	nop
diff --git a/utils/ldd.c b/utils/ldd.c
index 904075c..6d08efd 100644
--- a/utils/ldd.c
+++ b/utils/ldd.c
@@ -101,6 +101,11 @@
 #define ELFCLASSM	ELFCLASS64
 #endif
 
+#if defined(__microblaze__)
+#define MATCH_MACHINE(x) (x == EM_MICROBLAZE_OLD)
+#define ELFCLASSM	ELFCLASS32
+#endif
+
 #ifndef MATCH_MACHINE
 # ifdef __linux__
 #  include <asm/elf.h>
-- 
1.7.6



More information about the uClibc mailing list