summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--rts/linker/Elf.c33
-rw-r--r--rts/linker/elf_got.c10
2 files changed, 38 insertions, 5 deletions
diff --git a/rts/linker/Elf.c b/rts/linker/Elf.c
index 4378032c3e..7e5386e178 100644
--- a/rts/linker/Elf.c
+++ b/rts/linker/Elf.c
@@ -1019,6 +1019,19 @@ do_Elf_Rel_relocations ( ObjectCode* oc, char* ehdrC,
return 1;
}
+ /* The following nomenclature is used for the operation:
+ * - S -- (when used on its own) is the address of the symbol.
+ * - A -- is the addend for the relocation.
+ * - P -- is the address of the place being relocated (derived from r_offset).
+ * - Pa - is the adjusted address of the place being relocated, defined as (P & 0xFFFFFFFC).
+ * - T -- is 1 if the target symbol S has type STT_FUNC and the symbol addresses a Thumb instruction; it is 0 otherwise.
+ * - B(S) is the addressing origin of the output segment defining the symbol S. The origin is not required to be the
+ * base address of the segment. This value must always be word-aligned.
+ * - GOT_ORG is the addressing origin of the Global Offset Table (the indirection table for imported data addresses).
+ * This value must always be word-aligned. See ยง4.6.1.8, Proxy generating relocations.
+ * - GOT(S) is the address of the GOT entry for the symbol S.
+ */
+
for (j = 0; j < nent; j++) {
Elf_Addr offset = rtab[j].r_offset;
Elf_Addr info = rtab[j].r_info;
@@ -1113,19 +1126,35 @@ do_Elf_Rel_relocations ( ObjectCode* oc, char* ehdrC,
# endif
# ifdef arm_HOST_ARCH
- case COMPAT_R_ARM_ABS32:
+ case COMPAT_R_ARM_ABS32: /* (S + A) | T */
// Specified by Linux ARM ABI to be equivalent to ABS32
case COMPAT_R_ARM_TARGET1:
*(Elf32_Word *)P += S;
*(Elf32_Word *)P |= T;
break;
- case COMPAT_R_ARM_REL32:
+ case COMPAT_R_ARM_REL32: /* ((S + A) | T) โ€“ P */
*(Elf32_Word *)P += S;
*(Elf32_Word *)P |= T;
*(Elf32_Word *)P -= P;
break;
+ case COMPAT_R_ARM_BASE_PREL: /* B(S) + A โ€“ P */
+ {
+ int32_t A = *pP;
+ // bfd used to encode sb (B(S)) as 0.
+ *(uint32_t *)P += 0 + A - P;
+ break;
+ }
+
+ case COMPAT_R_ARM_GOT_BREL: /* GOT(S) + A โ€“ GOT_ORG */
+ {
+ int32_t A = *pP;
+ void* GOT_S = symbol->got_addr;
+ *(uint32_t *)P = (uint32_t) GOT_S + A - (uint32_t) oc->info->got_start;
+ break;
+ }
+
case COMPAT_R_ARM_CALL:
case COMPAT_R_ARM_JUMP24:
{
diff --git a/rts/linker/elf_got.c b/rts/linker/elf_got.c
index 9be2490a17..83d0f39a4e 100644
--- a/rts/linker/elf_got.c
+++ b/rts/linker/elf_got.c
@@ -86,9 +86,13 @@ fillGot(ObjectCode * oc) {
if(0x0 == symbol->addr) {
symbol->addr = lookupSymbol_(symbol->name);
if(0x0 == symbol->addr) {
- errorBelch("Failed to lookup symbol: %s\n",
- symbol->name);
- return EXIT_FAILURE;
+ if(0 == strncmp(symbol->name,"_GLOBAL_OFFSET_TABLE_",21)) {
+ symbol->addr = oc->info->got_start;
+ } else {
+ errorBelch("Failed to lookup symbol: %s\n",
+ symbol->name);
+ return EXIT_FAILURE;
+ }
}
} else {
// we already have the address.