|
@@ -8,7 +8,9 @@
|
|
|
#include <asm-generic/sections.h>
|
|
|
|
|
|
extern ulong __image_copy_start;
|
|
|
+extern ulong __ivt_start;
|
|
|
extern ulong __ivt_end;
|
|
|
+extern ulong __text_end;
|
|
|
|
|
|
DECLARE_GLOBAL_DATA_PTR;
|
|
|
|
|
@@ -48,7 +50,7 @@ int do_elf_reloc_fixups(void)
|
|
|
debug("Section .rela.dyn is located at %08x-%08x\n",
|
|
|
(unsigned int)re_src, (unsigned int)re_end);
|
|
|
|
|
|
- Elf32_Addr *offset_ptr_rom, *last_offset = NULL;
|
|
|
+ Elf32_Addr *offset_ptr_rom;
|
|
|
Elf32_Addr *offset_ptr_ram;
|
|
|
|
|
|
do {
|
|
@@ -57,15 +59,28 @@ int do_elf_reloc_fixups(void)
|
|
|
|
|
|
/* Check that the location of the relocation is in .text */
|
|
|
if (offset_ptr_rom >= (Elf32_Addr *)&__image_copy_start &&
|
|
|
- offset_ptr_rom > last_offset) {
|
|
|
- unsigned int val;
|
|
|
+ offset_ptr_rom < (Elf32_Addr *)&__image_copy_end) {
|
|
|
+ unsigned int val, do_swap = 0;
|
|
|
/* Switch to the in-RAM version */
|
|
|
offset_ptr_ram = (Elf32_Addr *)((ulong)offset_ptr_rom +
|
|
|
gd->reloc_off);
|
|
|
|
|
|
- debug("Patching value @ %08x (relocated to %08x)\n",
|
|
|
+#ifdef __LITTLE_ENDIAN__
|
|
|
+ /* If location in ".text" section swap value */
|
|
|
+ if (((u32)offset_ptr_rom >= (u32)&__text_start &&
|
|
|
+ (u32)offset_ptr_rom <= (u32)&__text_end)
|
|
|
+#if defined(__ARC700__) || defined(__ARC600__)
|
|
|
+ || ((u32)offset_ptr_rom >= (u32)&__ivt_start &&
|
|
|
+ (u32)offset_ptr_rom <= (u32)&__ivt_end)
|
|
|
+#endif
|
|
|
+ )
|
|
|
+ do_swap = 1;
|
|
|
+#endif
|
|
|
+
|
|
|
+ debug("Patching value @ %08x (relocated to %08x)%s\n",
|
|
|
(unsigned int)offset_ptr_rom,
|
|
|
- (unsigned int)offset_ptr_ram);
|
|
|
+ (unsigned int)offset_ptr_ram,
|
|
|
+ do_swap ? ", middle-endian encoded" : "");
|
|
|
|
|
|
/*
|
|
|
* Use "memcpy" because target location might be
|
|
@@ -75,28 +90,45 @@ int do_elf_reloc_fixups(void)
|
|
|
*/
|
|
|
memcpy(&val, offset_ptr_ram, sizeof(int));
|
|
|
|
|
|
-#ifdef __LITTLE_ENDIAN__
|
|
|
- /* If location in ".text" section swap value */
|
|
|
- if ((unsigned int)offset_ptr_rom <
|
|
|
- (unsigned int)&__ivt_end)
|
|
|
+ if (do_swap)
|
|
|
val = (val << 16) | (val >> 16);
|
|
|
-#endif
|
|
|
|
|
|
/* Check that the target points into executable */
|
|
|
- if (val >= (unsigned int)&__image_copy_start && val <=
|
|
|
- (unsigned int)&__image_copy_end) {
|
|
|
- val += gd->reloc_off;
|
|
|
-#ifdef __LITTLE_ENDIAN__
|
|
|
- /* If location in ".text" section swap value */
|
|
|
- if ((unsigned int)offset_ptr_rom <
|
|
|
- (unsigned int)&__ivt_end)
|
|
|
- val = (val << 16) | (val >> 16);
|
|
|
-#endif
|
|
|
- memcpy(offset_ptr_ram, &val, sizeof(int));
|
|
|
+ if (val < (unsigned int)&__image_copy_start ||
|
|
|
+ val > (unsigned int)&__image_copy_end) {
|
|
|
+ /* TODO: Use panic() instead of debug()
|
|
|
+ *
|
|
|
+ * For some reason GCC might generate
|
|
|
+ * fake relocation even for LD/SC of constant
|
|
|
+ * inderectly. See an example below:
|
|
|
+ * ----------------------->8--------------------
|
|
|
+ * static int setup_mon_len(void)
|
|
|
+ * {
|
|
|
+ * gd->mon_len = (ulong)&__bss_end - CONFIG_SYS_MONITOR_BASE;
|
|
|
+ * return 0;
|
|
|
+ * }
|
|
|
+ * ----------------------->8--------------------
|
|
|
+ *
|
|
|
+ * And that's what we get in the binary:
|
|
|
+ * ----------------------->8--------------------
|
|
|
+ * 10005cb4 <setup_mon_len>:
|
|
|
+ * 10005cb4: 193c 3f80 0003 2f80 st 0x32f80,[r25,60]
|
|
|
+ * 10005cb8: R_ARC_RELATIVE *ABS*-0x10000000
|
|
|
+ * 10005cbc: 7fe0 j_s.d [blink]
|
|
|
+ * 10005cbe: 700c mov_s r0,0
|
|
|
+ * ----------------------->8--------------------
|
|
|
+ */
|
|
|
+ debug("Relocation target %08x points outside of image\n",
|
|
|
+ val);
|
|
|
}
|
|
|
- }
|
|
|
- last_offset = offset_ptr_rom;
|
|
|
|
|
|
+ val += gd->reloc_off;
|
|
|
+
|
|
|
+ if (do_swap)
|
|
|
+ val = (val << 16) | (val >> 16);
|
|
|
+
|
|
|
+ memcpy(offset_ptr_ram, &val, sizeof(int));
|
|
|
+ }
|
|
|
} while (++re_src < re_end);
|
|
|
|
|
|
return 0;
|