summaryrefslogtreecommitdiffstats
path: root/lld/COFF/Chunks.cpp
diff options
context:
space:
mode:
authorMartin Storsjo <martin@martin.st>2018-05-04 06:06:27 +0000
committerMartin Storsjo <martin@martin.st>2018-05-04 06:06:27 +0000
commitcc80776effccf0854c66ec9b0b5d4fd73892539a (patch)
treee34f339186ed826db943f2cb64e48155603ff20d /lld/COFF/Chunks.cpp
parent665c7a44798435daa239984db552d9941e8dbdc3 (diff)
downloadbcm5719-llvm-cc80776effccf0854c66ec9b0b5d4fd73892539a.tar.gz
bcm5719-llvm-cc80776effccf0854c66ec9b0b5d4fd73892539a.zip
[COFF] Implement the remaining ARM64 relocations
Now only IMAGE_REL_ARM64_ABSOLUTE and IMAGE_REL_ARM64_TOKEN are unhandled. Also add range checks for the existing BRANCH26 relocation. Differential Revision: https://reviews.llvm.org/D46354 llvm-svn: 331505
Diffstat (limited to 'lld/COFF/Chunks.cpp')
-rw-r--r--lld/COFF/Chunks.cpp32
1 files changed, 27 insertions, 5 deletions
diff --git a/lld/COFF/Chunks.cpp b/lld/COFF/Chunks.cpp
index 6d8a0c7c1f4..5f673f8f3eb 100644
--- a/lld/COFF/Chunks.cpp
+++ b/lld/COFF/Chunks.cpp
@@ -181,11 +181,11 @@ void SectionChunk::applyRelARM(uint8_t *Off, uint16_t Type, OutputSection *OS,
// Interpret the existing immediate value as a byte offset to the
// target symbol, then update the instruction with the immediate as
// the page offset from the current instruction to the target.
-static void applyArm64Addr(uint8_t *Off, uint64_t S, uint64_t P) {
+static void applyArm64Addr(uint8_t *Off, uint64_t S, uint64_t P, int Shift) {
uint32_t Orig = read32le(Off);
uint64_t Imm = ((Orig >> 29) & 0x3) | ((Orig >> 3) & 0x1FFFFC);
S += Imm;
- Imm = (S >> 12) - (P >> 12);
+ Imm = (S >> Shift) - (P >> Shift);
uint32_t ImmLo = (Imm & 0x3) << 29;
uint32_t ImmHi = (Imm & 0x1FFFFC) << 3;
uint64_t Mask = (0x3 << 29) | (0x1FFFFC << 3);
@@ -247,13 +247,34 @@ static void applySecRelLdr(const SectionChunk *Sec, uint8_t *Off,
applyArm64Ldr(Off, (S - OS->getRVA()) & 0xfff);
}
+static void applyArm64Branch26(uint8_t *Off, int64_t V) {
+ if (!isInt<28>(V))
+ fatal("relocation out of range");
+ or32(Off, (V & 0x0FFFFFFC) >> 2);
+}
+
+static void applyArm64Branch19(uint8_t *Off, int64_t V) {
+ if (!isInt<21>(V))
+ fatal("relocation out of range");
+ or32(Off, (V & 0x001FFFFC) << 3);
+}
+
+static void applyArm64Branch14(uint8_t *Off, int64_t V) {
+ if (!isInt<16>(V))
+ fatal("relocation out of range");
+ or32(Off, (V & 0x0000FFFC) << 3);
+}
+
void SectionChunk::applyRelARM64(uint8_t *Off, uint16_t Type, OutputSection *OS,
uint64_t S, uint64_t P) const {
switch (Type) {
- case IMAGE_REL_ARM64_PAGEBASE_REL21: applyArm64Addr(Off, S, P); break;
+ case IMAGE_REL_ARM64_PAGEBASE_REL21: applyArm64Addr(Off, S, P, 12); break;
+ case IMAGE_REL_ARM64_REL21: applyArm64Addr(Off, S, P, 0); break;
case IMAGE_REL_ARM64_PAGEOFFSET_12A: applyArm64Imm(Off, S & 0xfff, 0); break;
case IMAGE_REL_ARM64_PAGEOFFSET_12L: applyArm64Ldr(Off, S & 0xfff); break;
- case IMAGE_REL_ARM64_BRANCH26: or32(Off, ((S - P) & 0x0FFFFFFC) >> 2); break;
+ case IMAGE_REL_ARM64_BRANCH26: applyArm64Branch26(Off, S - P); break;
+ case IMAGE_REL_ARM64_BRANCH19: applyArm64Branch19(Off, S - P); break;
+ case IMAGE_REL_ARM64_BRANCH14: applyArm64Branch14(Off, S - P); break;
case IMAGE_REL_ARM64_ADDR32: add32(Off, S + Config->ImageBase); break;
case IMAGE_REL_ARM64_ADDR32NB: add32(Off, S); break;
case IMAGE_REL_ARM64_ADDR64: add64(Off, S + Config->ImageBase); break;
@@ -261,6 +282,7 @@ void SectionChunk::applyRelARM64(uint8_t *Off, uint16_t Type, OutputSection *OS,
case IMAGE_REL_ARM64_SECREL_LOW12A: applySecRelLow12A(this, Off, OS, S); break;
case IMAGE_REL_ARM64_SECREL_HIGH12A: applySecRelHigh12A(this, Off, OS, S); break;
case IMAGE_REL_ARM64_SECREL_LOW12L: applySecRelLdr(this, Off, OS, S); break;
+ case IMAGE_REL_ARM64_SECTION: applySecIdx(Off, OS); break;
default:
fatal("unsupported relocation type 0x" + Twine::utohexstr(Type));
}
@@ -471,7 +493,7 @@ void ImportThunkChunkARM::writeTo(uint8_t *Buf) const {
void ImportThunkChunkARM64::writeTo(uint8_t *Buf) const {
int64_t Off = ImpSymbol->getRVA() & 0xfff;
memcpy(Buf + OutputSectionOff, ImportThunkARM64, sizeof(ImportThunkARM64));
- applyArm64Addr(Buf + OutputSectionOff, ImpSymbol->getRVA(), RVA);
+ applyArm64Addr(Buf + OutputSectionOff, ImpSymbol->getRVA(), RVA, 12);
applyArm64Ldr(Buf + OutputSectionOff + 4, Off);
}
OpenPOWER on IntegriCloud