summaryrefslogtreecommitdiff
path: root/ldso/ldso/sh64/dl-sysdep.h
diff options
context:
space:
mode:
authorPaul Mundt <lethal@linux-sh.org>2005-03-31 19:30:38 +0000
committerPaul Mundt <lethal@linux-sh.org>2005-03-31 19:30:38 +0000
commit0560005b6bb699e195e7334d6908b53db7b2c943 (patch)
tree2d3884f524d121af3b590c86f192e55aa283de0f /ldso/ldso/sh64/dl-sysdep.h
parente643bb46c58a9eaf0dfb77e60c47539b487435be (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/ldso/sh64/dl-sysdep.h')
-rw-r--r--ldso/ldso/sh64/dl-sysdep.h153
1 files changed, 103 insertions, 50 deletions
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