|
@@ -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
|