diff options
author | Davide Italiano <davide@freebsd.org> | 2015-10-02 22:00:42 +0000 |
---|---|---|
committer | Davide Italiano <davide@freebsd.org> | 2015-10-02 22:00:42 +0000 |
commit | 1f31a2c11c1aa56431c43bfe62f8465635801058 (patch) | |
tree | 386944dc3960513261b4c63eb6ea660f2658f3c1 | |
parent | 65d0a1458fb9a77d98cb974df556ae8830a00969 (diff) | |
download | bcm5719-llvm-1f31a2c11c1aa56431c43bfe62f8465635801058.tar.gz bcm5719-llvm-1f31a2c11c1aa56431c43bfe62f8465635801058.zip |
[ELF2/AArch64] Add support for R_AARCH64_ADR_PREL_PG_H121
llvm-svn: 249195
-rw-r--r-- | lld/ELF/Target.cpp | 28 | ||||
-rw-r--r-- | lld/test/elf2/aarch64-relocs.s | 14 |
2 files changed, 37 insertions, 5 deletions
diff --git a/lld/ELF/Target.cpp b/lld/ELF/Target.cpp index ef58b986296..d59f1304a73 100644 --- a/lld/ELF/Target.cpp +++ b/lld/ELF/Target.cpp @@ -253,16 +253,31 @@ bool AArch64TargetInfo::relocNeedsPlt(uint32_t Type, return false; } +static void AArch64UpdateAdr(uint8_t *Location, uint64_t Imm) { + uint32_t ImmLo = (Imm & 0x3) << 29; + uint32_t ImmHi = ((Imm & 0x1FFFFC) >> 2) << 5; + uint64_t Mask = (0x3 << 29) | (0x7FFFF << 5); + write32le(Location, (read32le(Location) & ~Mask) | ImmLo | ImmHi); +} + +static uint64_t AArch64GetPage(uint64_t Address) { + return (Address & (~static_cast<uint64_t>(0xFFF))); +} + static void handle_ADR_PREL_LO21(uint8_t *Location, uint64_t S, int64_t A, uint64_t P) { uint64_t X = S + A - P; if (!isInt<21>(X)) error("Relocation R_AARCH64_ADR_PREL_LO21 out of range"); - uint32_t Imm = X & 0x1FFFFF; - uint32_t ImmLo = (Imm & 0x3) << 29; - uint32_t ImmHi = ((Imm & 0x1FFFFC) >> 2) << 5; - uint64_t Mask = (0x3 << 29) | (0x7FFFF << 5); - write32le(Location, (read32le(Location) & ~Mask) | ImmLo | ImmHi); + AArch64UpdateAdr(Location, X & 0x1FFFFF); +} + +static void handle_ADR_PREL_PG_HI21(uint8_t *Location, uint64_t S, int64_t A, + uint64_t P) { + uint64_t X = AArch64GetPage(S + A) - AArch64GetPage(P); + if (!isInt<33>(X)) + error("Relocation R_AARCH64_ADR_PREL_PG_HI21 out of range"); + AArch64UpdateAdr(Location, (X >> 12) & 0x1FFFFF); // X[32:12] } void AArch64TargetInfo::relocateOne(uint8_t *Buf, const void *RelP, @@ -279,6 +294,9 @@ void AArch64TargetInfo::relocateOne(uint8_t *Buf, const void *RelP, case R_AARCH64_ADR_PREL_LO21: handle_ADR_PREL_LO21(Location, S, A, P); break; + case R_AARCH64_ADR_PREL_PG_HI21: + handle_ADR_PREL_PG_HI21(Location, S, A, P); + break; default: error(Twine("unrecognized reloc ") + Twine(Type)); break; diff --git a/lld/test/elf2/aarch64-relocs.s b/lld/test/elf2/aarch64-relocs.s index cf6cd6df337..b28d5ea769c 100644 --- a/lld/test/elf2/aarch64-relocs.s +++ b/lld/test/elf2/aarch64-relocs.s @@ -16,3 +16,17 @@ msgend: # CHECK: msg: # CHECK: 4: # #4 is the adr immediate value. + +.section .R_AARCH64_ADR_PREL_PG_H121,"ax",@progbits + adrp x1,mystr +mystr: + .asciz "blah" + .size mystr, 4 + +# S = 0x11012, A = 0x4, P = 0x11012 +# PAGE(S + A) = 0x11000 +# PAGE(P) = 0x11000 +# +# CHECK: Disassembly of section .R_AARCH64_ADR_PREL_PG_H121: +# CHECK-NEXT: $x.2: +# CHECK-NEXT: 11012: 01 00 00 90 adrp x1, #0 |