diff options
author | Paul Mundt <lethal@linux-sh.org> | 2005-03-31 19:30:38 +0000 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2005-03-31 19:30:38 +0000 |
commit | 0560005b6bb699e195e7334d6908b53db7b2c943 (patch) | |
tree | 2d3884f524d121af3b590c86f192e55aa283de0f /ldso | |
parent | e643bb46c58a9eaf0dfb77e60c47539b487435be (diff) |
sh64 ldso updates and fixes.
Update the sh64 ldso backend to work with Jocke's ldso changes.
We also handle a few more relative relocations, and fix a few spots where
the LSB was being set incorrectly for SHmedia branches.
Diffstat (limited to 'ldso')
-rw-r--r-- | ldso/ldso/sh64/dl-startup.h | 62 | ||||
-rw-r--r-- | ldso/ldso/sh64/dl-syscalls.h | 18 | ||||
-rw-r--r-- | ldso/ldso/sh64/dl-sysdep.h | 153 | ||||
-rw-r--r-- | ldso/ldso/sh64/elfinterp.c | 22 |
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); |