[uClibc] [PATCH] ldso: sh64 updates and fixes

Paul Mundt lethal at linux-sh.org
Wed Mar 30 12:44:00 UTC 2005


Here are a number of updates to get the sh64 ldso backend beaten back
into submission. This gets it working again with Jocke's recent ldso
changes, and also fixes up some other issues.

We ended up getting lucky in the elf_machine_relative() case, in that we
don't need to take the LSB under advisement for these specific relocs, so
this simplifies things quite a lot.

 include/elf.h                |   13 +++
 ldso/ldso/sh64/dl-startup.h  |   62 +++++------------
 ldso/ldso/sh64/dl-syscalls.h |   18 +++++
 ldso/ldso/sh64/dl-sysdep.h   |  153 ++++++++++++++++++++++++++++---------------
 ldso/ldso/sh64/elfinterp.c   |   22 +++---
 5 files changed, 163 insertions(+), 105 deletions(-)

Index: include/elf.h
===================================================================
--- include/elf.h	(revision 10061)
+++ include/elf.h	(working copy)
@@ -2311,6 +2311,12 @@
 
 /* SH specific declarations */
 
+/* SH specific values for `st_other'.  */
+
+/* If set, this is a symbol pointing to SHmedia code, which will be branched
+   to, so need to add 1 to the symbol value. */
+#define STO_SH5_ISA32 (1 << 2)
+
 /* SH relocs.  */
 #define	R_SH_NONE		0
 #define	R_SH_DIR32		1
@@ -2349,6 +2355,13 @@
 #define	R_SH_RELATIVE		165
 #define	R_SH_GOTOFF		166
 #define	R_SH_GOTPC		167
+#define	R_SH_RELATIVE_LOW16	197
+#define	R_SH_RELATIVE_MEDLOW16	198
+#define	R_SH_IMM_LOW16		246
+#define	R_SH_IMM_LOW16_PCREL	247
+#define	R_SH_IMM_MEDLOW16	248
+#define	R_SH_IMM_MEDLOW16_PCREL	249
+
 /* Keep this the last entry.  */
 #define	R_SH_NUM		256
 
Index: ldso/ldso/sh64/dl-syscalls.h
===================================================================
--- ldso/ldso/sh64/dl-syscalls.h	(revision 10061)
+++ ldso/ldso/sh64/dl-syscalls.h	(working copy)
@@ -4,3 +4,21 @@
 #define __set_errno(X) {(_dl_errno) = (X);}
 #include "sys/syscall.h"
 
+#undef __syscall_return
+#define __syscall_return(type, res)					\
+do {									\
+	/*								\
+	 * Note: when returning from kernel the return value is in r9	\
+	 *								\
+	 * This prevents conflicts between return value and arg1	\
+	 * when dispatching signal handler, in other words makes	\
+	 * life easier in the system call epilogue (see entry.S)	\
+	 */								\
+	register unsigned long __sr2 __asm__ ("r2") = res;		\
+	if ((unsigned long)(res) >= (unsigned long)(-125)) {		\
+		_dl_errno = -(res);					\
+		__sr2 = -1;						\
+	}								\
+	return (type)(__sr2);						\
+} while (0)
+
Index: ldso/ldso/sh64/dl-startup.h
===================================================================
--- ldso/ldso/sh64/dl-startup.h	(revision 10061)
+++ ldso/ldso/sh64/dl-startup.h	(working copy)
@@ -5,30 +5,37 @@
 
 asm("" \
 "	.section .text..SHmedia32,\"ax\"\n"				\
-"	.globl _dl_boot\n"						\
-"	.type _dl_boot, @function\n"					\
+"	.globl _start\n"						\
+"	.type _start, @function\n"					\
 "	.align 5\n"							\
-"_dl_boot:\n"								\
+"_start:\n"								\
 "	! Set r12 to point to GOT\n"					\
-"	movi	(((datalabel _GLOBAL_OFFSET_TABLE_-(.LZZZ3-.)) >> 16) & 65535), r12\n"	\
-"	shori	((datalabel _GLOBAL_OFFSET_TABLE_-(.LZZZ3-.)) & 65535), r12\n"		\
+"	movi	(((datalabel _GLOBAL_OFFSET_TABLE_-(.LZZZ3-.)) >> 16) & 0xffff), r12\n"	\
+"	shori	((datalabel _GLOBAL_OFFSET_TABLE_-(.LZZZ3-.)) & 0xffff), r12\n"		\
 ".LZZZ3:\n"								\
 "	ptrel/u	r12, tr0\n"						\
 "	gettr	tr0, r12	! GOT address\n"			\
 "	add	r18, r63, r11	! save return address - needed?\n"	\
 "	add	r15, r63, r2	! arg = stack pointer\n"		\
-"	pt	_dl_boot2, tr0	! should work even if PIC\n"		\
-"	blink	tr0, r18	! call _dl_boot2 - user EP is in r2\n"	\
+"	pt	_dl_start, tr0	! should work even if PIC\n"		\
+"	blink	tr0, r18	! call _dl_start - user EP is in r2\n"	\
+"	add	r2, r63, r28\n"						\
+"	movi	(((_dl_fini at GOT) >> 16) & 0xffff), r1\n"		\
+"	shori	((_dl_fini at GOT) & 0xffff), r1\n"			\
+"	ldx.l	r1, r12, r2\n"						\
+"	add	r11, r63, r18\n"					\
+"	ptabs/l r28, tr0\n"						\
+"	blink	tr0, r63\n"						\
+"	.size	_start,.-_start\n"
+"	.previous\n"
 );
 
-#define DL_BOOT(X)   static void __attribute_used__ _dl_boot2 (X)
-
 /*
  * 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)
+#define GET_ARGV(ARGVP, ARGS) ARGVP = (((unsigned long *)ARGS)+1)
 
 /*
  * Here is a macro to perform a relocation.  This is only used when
@@ -38,43 +45,11 @@
  * load address.
  */
 
-/*
- * We need to do this stupidity here as the preprocessor will choke when
- * SYMTAB is NULL if we do this in PERFORM_BOOTSTRAP_RELOC().
- */
-
 #include <elf.h>
 
-static inline int __extract_lsb_from_symtab(Elf32_Sym *symtab)
-{
-	static int lsb = 0;
-
-	/* Check for SHmedia/SHcompact */
-	if (symtab)
-		lsb = symtab->st_other & 4;
-
-	return lsb;
-}
-
-/*
- * While on the subject of stupidity, there appear to be some conflicts with
- * regards to several relocation types as far as binutils is concerned
- * (Barcelona and Madrid both appear to use an out of date elf.h, whereas
- * native Catalonia has all of the necessary definitions. As a workaround,
- * we'll just define them here for sanity..
- */
-#ifndef R_SH_RELATIVE_LOW16
-#  define R_SH_RELATIVE_LOW16		197
-#  define R_SH_RELATIVE_MEDLOW16	198
-#  define R_SH_IMM_LOW16		246
-#  define R_SH_IMM_LOW16_PCREL		247
-#  define R_SH_IMM_MEDLOW16		248
-#  define R_SH_IMM_MEDLOW16_PCREL	249
-#endif
-
 #define PERFORM_BOOTSTRAP_RELOC(RELP,REL,SYMBOL,LOAD,SYMTAB)		\
 	const unsigned int r_type = ELF32_R_TYPE((RELP)->r_info);	\
-	int lsb = __extract_lsb_from_symtab(SYMTAB);			\
+	int lsb = !!((SYMTAB)->st_other & STO_SH5_ISA32);		\
 									\
 	switch (r_type)	{						\
 	case R_SH_REL32:						\
@@ -157,4 +132,3 @@
 
 #define START()   return _dl_elf_main;
 
-
Index: ldso/ldso/sh64/elfinterp.c
===================================================================
--- ldso/ldso/sh64/elfinterp.c	(revision 10061)
+++ ldso/ldso/sh64/elfinterp.c	(working copy)
@@ -4,7 +4,7 @@
  *
  * SuperH (sh64) ELF shared library loader suppport
  *
- * Copyright (C) 2003  Paul Mundt <lethal at linux-sh.org>
+ * Copyright (C) 2003, 2004, 2005  Paul Mundt <lethal at linux-sh.org>
  *
  * All rights reserved.
  *
@@ -34,16 +34,16 @@
 static const char *_dl_reltypes_tab[] = {
 	/* SHcompact relocs */
 	  [0] =	"R_SH_NONE",		"R_SH_DIR32",
-	  	"R_SH_REL32",		"R_SH_DIR8WPN",
+		"R_SH_REL32",		"R_SH_DIR8WPN",
 	  [4] = "R_SH_IND12W",		"R_SH_DIR8WPL",
-	  	"R_SH_DIR8WPZ",		"R_SH_DIR8BP",
+		"R_SH_DIR8WPZ",		"R_SH_DIR8BP",
 	  [8] = "R_SH_DIR8W",		"R_SH_DIR8L",
 	 [25] = "R_SH_SWITCH16",	"R_SH_SWITCH32",
-	 	"R_SH_USES",		"R_SH_COUNT",
+		"R_SH_USES",		"R_SH_COUNT",
 	 [29] = "R_SH_ALIGN",		"R_SH_CODE",
-	 	"R_SH_DATA",		"R_SH_LABEL",
+		"R_SH_DATA",		"R_SH_LABEL",
 	 [33] = "R_SH_SWITCH8",		"R_SH_GNU_VTINHERIT",
-	 	"R_SH_GNU_VTENTRY",
+		"R_SH_GNU_VTENTRY",
 	[160] = "R_SH_GOT32",		"R_SH_PLT32",
 		"R_SH_COPY",		"R_SH_GLOB_DAT",
 	[164] = "R_SH_JMP_SLOT",	"R_SH_RELATIVE",
@@ -88,7 +88,7 @@
 	tabsize = sizeof(_dl_reltypes_tab)/sizeof(_dl_reltypes_tab[0]);
 	str	= _dl_reltypes_tab[type];
 
-  	if (type >= tabsize || str == NULL)
+	if (type >= tabsize || str == NULL)
 		str =_dl_simple_ltoa(buf, (unsigned long)(type));
 
 	return str;
@@ -295,7 +295,7 @@
 	reloc_type   = ELF32_R_TYPE(rpnt->r_info);
 	symtab_index = ELF32_R_SYM(rpnt->r_info);
 	symbol_addr  = 0;
-	lsb          = symtab[symtab_index].st_other & 4;
+	lsb          = !!(symtab[symtab_index].st_other & STO_SH5_ISA32);
 	symname      = strtab + symtab[symtab_index].st_name;
 	reloc_addr   = (unsigned long *)(intptr_t)
 		(tpnt->loadaddr + (unsigned long)rpnt->r_offset);
@@ -362,7 +362,7 @@
 	case R_SH_IMM_LOW16:
 	case R_SH_IMM_MEDLOW16:
 	    {
-	    	unsigned long word, value;
+		unsigned long word, value;
 
 		word = (unsigned long)reloc_addr & ~0x3fffc00;
 		value = (symbol_addr + rpnt->r_addend) | lsb;
@@ -378,7 +378,7 @@
 	case R_SH_IMM_LOW16_PCREL:
 	case R_SH_IMM_MEDLOW16_PCREL:
 	    {
-	    	unsigned long word, value;
+		unsigned long word, value;
 
 		word = (unsigned long)reloc_addr & ~0x3fffc00;
 		value = symbol_addr + rpnt->r_addend -
@@ -416,7 +416,7 @@
 
 	reloc_type   = ELF32_R_TYPE(rpnt->r_info);
 	symtab_index = ELF32_R_SYM(rpnt->r_info);
-	lsb          = symtab[symtab_index].st_other & 4;
+	lsb          = !!(symtab[symtab_index].st_other & STO_SH5_ISA32);
 	reloc_addr   = (unsigned long *)(intptr_t)
 		(tpnt->loadaddr + (unsigned long)rpnt->r_offset);
 
Index: ldso/ldso/sh64/dl-sysdep.h
===================================================================
--- ldso/ldso/sh64/dl-sysdep.h	(revision 10061)
+++ ldso/ldso/sh64/dl-sysdep.h	(working copy)
@@ -44,74 +44,127 @@
 /* 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 __attribute__ ((unused))
-elf_machine_dynamic (void)
+static inline Elf32_Addr elf_machine_dynamic(void)
 {
 	register Elf32_Addr *got;
-	asm ("mov r12,%0" :"=r" (got));
+
+	/*
+	 * The toolchain adds 32768 to the GOT address, we compensate for
+	 * that in the movi/sub pair.
+	 *
+	 * XXX: If this is cleaned up in the toolchain, we can end up
+	 * saving 2 instructions and subsequently free up r1 from the
+	 * clobber list..
+	 */
+	__asm__ (
+		"movi\t(((datalabel _GLOBAL_OFFSET_TABLE_-(.LZZZ1-.)) >> 16) & 0xffff), r2\n\t"
+		"shori\t((datalabel _GLOBAL_OFFSET_TABLE_-(.LZZZ1-.)) & 0xffff), r2\n\t"
+		".LZZZ1:\tptrel/u r2, tr0\n\t"
+		"movi\t32768, r1\n\t"
+		"gettr\ttr0, r2\n\t"
+		"sub\tr2, r1, %0\n\t"
+		: "=r" (got)
+		: /* no inputs */
+		: "r1", "r2", "tr0"
+	);
+
 	return *got;
 }
 
 /* Return the run-time load address of the shared object.  */
-static inline Elf32_Addr __attribute__ ((unused))
-elf_machine_load_address (void)
+static inline Elf32_Addr elf_machine_load_address(void)
 {
 	Elf32_Addr addr;
-	asm ("mov.l 1f,r0\n\
-        mov.l 3f,r2\n\
-        add r12,r2\n\
-        mov.l @(r0,r12),r0\n\
-        bra 2f\n\
-         sub r0,r2\n\
-        .align 2\n\
-        1: .long _dl_boot at GOT\n\
-        3: .long _dl_boot at GOTOFF\n\
-        2: mov r2,%0"
-	     : "=r" (addr) : : "r0", "r1", "r2");
+
+	__asm__ (
+		"movi\t(((datalabel _GLOBAL_OFFSET_TABLE_-(.LZZZ2-.)) >> 16) & 0xffff), r0\n\t"
+		"shori\t((datalabel _GLOBAL_OFFSET_TABLE_-(.LZZZ2-.)) & 0xffff), r0\n\t"
+		".LZZZ2:\tptrel/u r0, tr0\n\t"
+		"movi\t(((_dl_start at GOTOFF) >> 16) & 0xffff), r2\n\t"
+		"shori\t((_dl_start at GOTOFF) & 0xffff), r2\n\t"
+		"gettr\ttr0, r0\n\t"
+		"add\tr2, r0, r2\n\t"
+		"movi\t(((_dl_start at GOT) >> 16) & 0xffff), r1\n\t"
+		"shori\t((_dl_start at GOT) & 0xffff), r1\n\t"
+		"ldx.l\tr1, r0, r1\n\t"
+		"sub\tr2, r1, %0\n\t"
+		: "=r" (addr)
+		: /* no inputs */
+		: "r0", "r1", "r2", "tr0"
+	);
+
 	return addr;
 }
 
-#define COPY_UNALIGNED_WORD(swp, twp, align) \
-  { \
-    void *__s = (swp), *__t = (twp); \
-    unsigned char *__s1 = __s, *__t1 = __t; \
-    unsigned short *__s2 = __s, *__t2 = __t; \
-    unsigned long *__s4 = __s, *__t4 = __t; \
-    switch ((align)) \
-    { \
-    case 0: \
-      *__t4 = *__s4; \
-      break; \
-    case 2: \
-      *__t2++ = *__s2++; \
-      *__t2 = *__s2; \
-      break; \
-    default: \
-      *__t1++ = *__s1++; \
-      *__t1++ = *__s1++; \
-      *__t1++ = *__s1++; \
-      *__t1 = *__s1; \
-      break; \
-    } \
-  }
+/*
+ * XXX: As we don't need to worry about r25 clobbering, we could probably
+ * get away with inlining {st,ld}{x,}.l and friends here instead and
+ * forego gcc's idea of code generation.
+ */
+#define COPY_UNALIGNED_WORD(swp, twp, align)		\
+{							\
+	void *__s = (swp), *__t = (twp);		\
+	unsigned char *__s1 = __s, *__t1 = __t;		\
+	unsigned short *__s2 = __s, *__t2 = __t;	\
+	unsigned long *__s4 = __s, *__t4 = __t;		\
+							\
+	switch ((align)) {				\
+	case 0:						\
+		*__t4 = *__s4;				\
+		break;					\
+	case 2:						\
+		*__t2++ = *__s2++;			\
+		*__t2 = *__s2;				\
+		break;					\
+	default:					\
+		*__t1++ = *__s1++;			\
+		*__t1++ = *__s1++;			\
+		*__t1++ = *__s1++;			\
+		*__t1 = *__s1;				\
+		break;					\
+	}						\
+}
 
 static inline void
-elf_machine_relative (Elf32_Addr load_off, const Elf32_Addr rel_addr,
-		      Elf32_Word relative_count)
+elf_machine_relative(Elf32_Addr load_off, const Elf32_Addr rel_addr,
+		     Elf32_Word relative_count)
 {
-	Elf32_Addr value;
-	Elf32_Rela * rpnt = (void *)rel_addr;
+	Elf32_Addr value, word;
+	Elf32_Rela *rpnt = (void *)rel_addr;
+	int reloc_type = ELF32_R_TYPE(rpnt->r_info);
 
 	do {
-		Elf32_Addr *const reloc_addr = (void *) (load_off + rpnt->r_offset);
+		Elf32_Addr *const reloc_addr =
+			(void *)(load_off + rpnt->r_offset);
+		int align = (int)reloc_addr & 3;
 
-		if (rpnt->r_addend)
-			value = load_off + rpnt->r_addend;
-		else {
-			COPY_UNALIGNED_WORD (reloc_addr, &value, (int) reloc_addr & 3);
-			value += load_off;
+		switch (reloc_type) {
+		case R_SH_RELATIVE_LOW16:
+			COPY_UNALIGNED_WORD(reloc_addr, &word, align);
+			word &= ~0x3fffc00;
+			value = (rpnt->r_addend + load_off);
+			word |= (value & 0xffff) << 10;
+			COPY_UNALIGNED_WORD(&word, reloc_addr, align);
+			break;
+		case R_SH_RELATIVE_MEDLOW16:
+			COPY_UNALIGNED_WORD(reloc_addr, &word, align);
+			word &= ~0x3fffc00;
+			value = (rpnt->r_addend + load_off) >> 16;
+			word |= (value & 0xffff) << 10;
+			COPY_UNALIGNED_WORD(&word, reloc_addr, align);
+			break;
+		default:
+			if (rpnt->r_addend) {
+				value = load_off + rpnt->r_addend;
+			} else {
+				COPY_UNALIGNED_WORD(reloc_addr, &value, align);
+				value += load_off;
+			}
+
+			COPY_UNALIGNED_WORD(&value, reloc_addr, align);
+			break;
 		}
-		COPY_UNALIGNED_WORD (&value, reloc_addr, (int) reloc_addr & 3);
+
 		rpnt++;
 	} while (--relative_count);
 #undef COPY_UNALIGNED_WORD
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: not available
Url : http://lists.busybox.net/pipermail/uclibc/attachments/20050330/01185229/attachment-0002.pgp 


More information about the uClibc mailing list