summaryrefslogtreecommitdiffstats
path: root/lld/COFF/Chunks.cpp
diff options
context:
space:
mode:
authorMartin Storsjo <martin@martin.st>2019-02-01 22:08:09 +0000
committerMartin Storsjo <martin@martin.st>2019-02-01 22:08:09 +0000
commitc9f4d25f269819b5abb38b66a813335c681a76cc (patch)
treea80e52626869eb33ab5f85dfca935d2593123abd /lld/COFF/Chunks.cpp
parentb2b0cab0c3de25fece534e67ad0d79af4009c4d1 (diff)
downloadbcm5719-llvm-c9f4d25f269819b5abb38b66a813335c681a76cc.tar.gz
bcm5719-llvm-c9f4d25f269819b5abb38b66a813335c681a76cc.zip
[COFF] Create range extension thunks for ARM64
On ARM64, this is normally necessary only after a module exceeds 128 MB in size (while the limit for thumb is 16 MB). For conditional branches, the range limit is only 1 MB though (the same as for thumb), and for the tbz instruction, the range is only 32 KB, which allows for a test much smaller than the full 128 MB. This fixes PR40467. Differential Revision: https://reviews.llvm.org/D57575 llvm-svn: 352929
Diffstat (limited to 'lld/COFF/Chunks.cpp')
-rw-r--r--lld/COFF/Chunks.cpp24
1 files changed, 22 insertions, 2 deletions
diff --git a/lld/COFF/Chunks.cpp b/lld/COFF/Chunks.cpp
index 083a87a561c..8c73bda7ceb 100644
--- a/lld/COFF/Chunks.cpp
+++ b/lld/COFF/Chunks.cpp
@@ -670,18 +670,38 @@ const uint8_t ArmThunk[] = {
0xe7, 0x44, // L1: add pc, ip
};
-size_t RangeExtensionThunk::getSize() const {
+size_t RangeExtensionThunkARM::getSize() const {
assert(Config->Machine == ARMNT);
return sizeof(ArmThunk);
}
-void RangeExtensionThunk::writeTo(uint8_t *Buf) const {
+void RangeExtensionThunkARM::writeTo(uint8_t *Buf) const {
assert(Config->Machine == ARMNT);
uint64_t Offset = Target->getRVA() - RVA - 12;
memcpy(Buf + OutputSectionOff, ArmThunk, sizeof(ArmThunk));
applyMOV32T(Buf + OutputSectionOff, uint32_t(Offset));
}
+// A position independent ARM64 adrp+add thunk, with a maximum range of
+// +/- 4 GB, which is enough for any PE-COFF.
+const uint8_t Arm64Thunk[] = {
+ 0x10, 0x00, 0x00, 0x90, // adrp x16, Dest
+ 0x10, 0x02, 0x00, 0x91, // add x16, x16, :lo12:Dest
+ 0x00, 0x02, 0x1f, 0xd6, // br x16
+};
+
+size_t RangeExtensionThunkARM64::getSize() const {
+ assert(Config->Machine == ARM64);
+ return sizeof(Arm64Thunk);
+}
+
+void RangeExtensionThunkARM64::writeTo(uint8_t *Buf) const {
+ assert(Config->Machine == ARM64);
+ memcpy(Buf + OutputSectionOff, Arm64Thunk, sizeof(Arm64Thunk));
+ applyArm64Addr(Buf + OutputSectionOff + 0, Target->getRVA(), RVA, 12);
+ applyArm64Imm(Buf + OutputSectionOff + 4, Target->getRVA() & 0xfff, 0);
+}
+
void LocalImportChunk::getBaserels(std::vector<Baserel> *Res) {
Res->emplace_back(getRVA());
}
OpenPOWER on IntegriCloud