summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ldso/ldso/sh64/dl-startup.h62
-rw-r--r--ldso/ldso/sh64/dl-syscalls.h18
-rw-r--r--ldso/ldso/sh64/dl-sysdep.h153
-rw-r--r--ldso/ldso/sh64/elfinterp.c22
4 files changed, 150 insertions, 105 deletions
diff --git a/ldso/ldso/sh64/dl-startup.h b/ldso/ldso/sh64/dl-startup.h
index 6f420aa7b..e53b0a88a 100644
--- a/ldso/ldso/sh64/dl-startup.h
+++ b/ldso/ldso/sh64/dl-startup.h
@@ -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@GOT) >> 16) & 0xffff), r1\n" \
+" shori ((_dl_fini@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 @@ asm("" \
* 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 @@ static inline int __extract_lsb_from_symtab(Elf32_Sym *symtab)
#define START() return _dl_elf_main;
-
diff --git a/ldso/ldso/sh64/dl-syscalls.h b/ldso/ldso/sh64/dl-syscalls.h
index f0f4baed8..1db7b6719 100644
--- a/ldso/ldso/sh64/dl-syscalls.h
+++ b/ldso/ldso/sh64/dl-syscalls.h
@@ -4,3 +4,21 @@ extern int _dl_errno;
#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)
+
diff --git a/ldso/ldso/sh64/dl-sysdep.h b/ldso/ldso/sh64/dl-sysdep.h
index 852cb0d41..506e9ece2 100644
--- a/ldso/ldso/sh64/dl-sysdep.h
+++ b/ldso/ldso/sh64/dl-sysdep.h
@@ -44,74 +44,127 @@ extern unsigned long _dl_linux_resolver(struct elf_resolve * tpnt, int reloc_ent
/* 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@GOT\n\
- 3: .long _dl_boot@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@GOTOFF) >> 16) & 0xffff), r2\n\t"
+ "shori\t((_dl_start@GOTOFF) & 0xffff), r2\n\t"
+ "gettr\ttr0, r0\n\t"
+ "add\tr2, r0, r2\n\t"
+ "movi\t(((_dl_start@GOT) >> 16) & 0xffff), r1\n\t"
+ "shori\t((_dl_start@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
diff --git a/ldso/ldso/sh64/elfinterp.c b/ldso/ldso/sh64/elfinterp.c
index 7b5aaee7d..6ac096b32 100644
--- a/ldso/ldso/sh64/elfinterp.c
+++ b/ldso/ldso/sh64/elfinterp.c
@@ -4,7 +4,7 @@
*
* SuperH (sh64) ELF shared library loader suppport
*
- * Copyright (C) 2003 Paul Mundt <lethal@linux-sh.org>
+ * Copyright (C) 2003, 2004, 2005 Paul Mundt <lethal@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 @@ static const char *_dl_reltypes(int type)
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 @@ static int _dl_do_reloc(struct elf_resolve *tpnt,struct dyn_elf *scope,
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 @@ static int _dl_do_reloc(struct elf_resolve *tpnt,struct dyn_elf *scope,
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 @@ static int _dl_do_reloc(struct elf_resolve *tpnt,struct dyn_elf *scope,
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 @@ static int _dl_do_lazy_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope,
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);