summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavide Italiano <davide@freebsd.org>2015-10-02 22:00:42 +0000
committerDavide Italiano <davide@freebsd.org>2015-10-02 22:00:42 +0000
commit1f31a2c11c1aa56431c43bfe62f8465635801058 (patch)
tree386944dc3960513261b4c63eb6ea660f2658f3c1
parent65d0a1458fb9a77d98cb974df556ae8830a00969 (diff)
downloadbcm5719-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.cpp28
-rw-r--r--lld/test/elf2/aarch64-relocs.s14
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
OpenPOWER on IntegriCloud