diff options
-rw-r--r-- | rts/linker/Elf.c | 33 | ||||
-rw-r--r-- | rts/linker/elf_got.c | 10 |
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. |