aboutsummaryrefslogtreecommitdiffstats
path: root/ELF/Arch/AArch64.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'ELF/Arch/AArch64.cpp')
-rw-r--r--ELF/Arch/AArch64.cpp108
1 files changed, 102 insertions, 6 deletions
diff --git a/ELF/Arch/AArch64.cpp b/ELF/Arch/AArch64.cpp
index 4d4789702f03..5cf07029fa1d 100644
--- a/ELF/Arch/AArch64.cpp
+++ b/ELF/Arch/AArch64.cpp
@@ -17,13 +17,14 @@
using namespace llvm;
using namespace llvm::support::endian;
using namespace llvm::ELF;
-using namespace lld;
-using namespace lld::elf;
+
+namespace lld {
+namespace elf {
// Page(Expr) is the page address of the expression Expr, defined
// as (Expr & ~0xFFF). (This applies even if the machine page size
// supported by the platform has a different value.)
-uint64_t elf::getAArch64Page(uint64_t expr) {
+uint64_t getAArch64Page(uint64_t expr) {
return expr & ~static_cast<uint64_t>(0xFFF);
}
@@ -76,6 +77,26 @@ AArch64::AArch64() {
RelExpr AArch64::getRelExpr(RelType type, const Symbol &s,
const uint8_t *loc) const {
switch (type) {
+ case R_AARCH64_ABS16:
+ case R_AARCH64_ABS32:
+ case R_AARCH64_ABS64:
+ case R_AARCH64_ADD_ABS_LO12_NC:
+ case R_AARCH64_LDST128_ABS_LO12_NC:
+ case R_AARCH64_LDST16_ABS_LO12_NC:
+ case R_AARCH64_LDST32_ABS_LO12_NC:
+ case R_AARCH64_LDST64_ABS_LO12_NC:
+ case R_AARCH64_LDST8_ABS_LO12_NC:
+ case R_AARCH64_MOVW_SABS_G0:
+ case R_AARCH64_MOVW_SABS_G1:
+ case R_AARCH64_MOVW_SABS_G2:
+ case R_AARCH64_MOVW_UABS_G0:
+ case R_AARCH64_MOVW_UABS_G0_NC:
+ case R_AARCH64_MOVW_UABS_G1:
+ case R_AARCH64_MOVW_UABS_G1_NC:
+ case R_AARCH64_MOVW_UABS_G2:
+ case R_AARCH64_MOVW_UABS_G2_NC:
+ case R_AARCH64_MOVW_UABS_G3:
+ return R_ABS;
case R_AARCH64_TLSDESC_ADR_PAGE21:
return R_AARCH64_TLSDESC_PAGE;
case R_AARCH64_TLSDESC_LD64_LO12:
@@ -90,6 +111,11 @@ RelExpr AArch64::getRelExpr(RelType type, const Symbol &s,
case R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC:
case R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC:
case R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC:
+ case R_AARCH64_TLSLE_MOVW_TPREL_G0:
+ case R_AARCH64_TLSLE_MOVW_TPREL_G0_NC:
+ case R_AARCH64_TLSLE_MOVW_TPREL_G1:
+ case R_AARCH64_TLSLE_MOVW_TPREL_G1_NC:
+ case R_AARCH64_TLSLE_MOVW_TPREL_G2:
return R_TLS;
case R_AARCH64_CALL26:
case R_AARCH64_CONDBR19:
@@ -101,6 +127,13 @@ RelExpr AArch64::getRelExpr(RelType type, const Symbol &s,
case R_AARCH64_PREL64:
case R_AARCH64_ADR_PREL_LO21:
case R_AARCH64_LD_PREL_LO19:
+ case R_AARCH64_MOVW_PREL_G0:
+ case R_AARCH64_MOVW_PREL_G0_NC:
+ case R_AARCH64_MOVW_PREL_G1:
+ case R_AARCH64_MOVW_PREL_G1_NC:
+ case R_AARCH64_MOVW_PREL_G2:
+ case R_AARCH64_MOVW_PREL_G2_NC:
+ case R_AARCH64_MOVW_PREL_G3:
return R_PC;
case R_AARCH64_ADR_PREL_PG_HI21:
case R_AARCH64_ADR_PREL_PG_HI21_NC:
@@ -114,7 +147,9 @@ RelExpr AArch64::getRelExpr(RelType type, const Symbol &s,
case R_AARCH64_NONE:
return R_NONE;
default:
- return R_ABS;
+ error(getErrorLocation(loc) + "unknown relocation (" + Twine(type) +
+ ") against symbol " + toString(s));
+ return R_NONE;
}
}
@@ -247,6 +282,26 @@ static void or32AArch64Imm(uint8_t *l, uint64_t imm) {
or32le(l, (imm & 0xFFF) << 10);
}
+// Update the immediate field in an AArch64 movk, movn or movz instruction
+// for a signed relocation, and update the opcode of a movn or movz instruction
+// to match the sign of the operand.
+static void writeSMovWImm(uint8_t *loc, uint32_t imm) {
+ uint32_t inst = read32le(loc);
+ // Opcode field is bits 30, 29, with 10 = movz, 00 = movn and 11 = movk.
+ if (!(inst & (1 << 29))) {
+ // movn or movz.
+ if (imm & 0x10000) {
+ // Change opcode to movn, which takes an inverted operand.
+ imm ^= 0xFFFF;
+ inst &= ~(1 << 30);
+ } else {
+ // Change opcode to movz.
+ inst |= 1 << 30;
+ }
+ }
+ write32le(loc, inst | ((imm & 0xFFFF) << 5));
+}
+
void AArch64::relocateOne(uint8_t *loc, RelType type, uint64_t val) const {
switch (type) {
case R_AARCH64_ABS16:
@@ -326,18 +381,56 @@ void AArch64::relocateOne(uint8_t *loc, RelType type, uint64_t val) const {
checkAlignment(loc, val, 16, type);
or32AArch64Imm(loc, getBits(val, 4, 11));
break;
+ case R_AARCH64_MOVW_UABS_G0:
+ checkUInt(loc, val, 16, type);
+ LLVM_FALLTHROUGH;
case R_AARCH64_MOVW_UABS_G0_NC:
or32le(loc, (val & 0xFFFF) << 5);
break;
+ case R_AARCH64_MOVW_UABS_G1:
+ checkUInt(loc, val, 32, type);
+ LLVM_FALLTHROUGH;
case R_AARCH64_MOVW_UABS_G1_NC:
or32le(loc, (val & 0xFFFF0000) >> 11);
break;
+ case R_AARCH64_MOVW_UABS_G2:
+ checkUInt(loc, val, 48, type);
+ LLVM_FALLTHROUGH;
case R_AARCH64_MOVW_UABS_G2_NC:
or32le(loc, (val & 0xFFFF00000000) >> 27);
break;
case R_AARCH64_MOVW_UABS_G3:
or32le(loc, (val & 0xFFFF000000000000) >> 43);
break;
+ case R_AARCH64_MOVW_PREL_G0:
+ case R_AARCH64_MOVW_SABS_G0:
+ case R_AARCH64_TLSLE_MOVW_TPREL_G0:
+ checkInt(loc, val, 17, type);
+ LLVM_FALLTHROUGH;
+ case R_AARCH64_MOVW_PREL_G0_NC:
+ case R_AARCH64_TLSLE_MOVW_TPREL_G0_NC:
+ writeSMovWImm(loc, val);
+ break;
+ case R_AARCH64_MOVW_PREL_G1:
+ case R_AARCH64_MOVW_SABS_G1:
+ case R_AARCH64_TLSLE_MOVW_TPREL_G1:
+ checkInt(loc, val, 33, type);
+ LLVM_FALLTHROUGH;
+ case R_AARCH64_MOVW_PREL_G1_NC:
+ case R_AARCH64_TLSLE_MOVW_TPREL_G1_NC:
+ writeSMovWImm(loc, val >> 16);
+ break;
+ case R_AARCH64_MOVW_PREL_G2:
+ case R_AARCH64_MOVW_SABS_G2:
+ case R_AARCH64_TLSLE_MOVW_TPREL_G2:
+ checkInt(loc, val, 49, type);
+ LLVM_FALLTHROUGH;
+ case R_AARCH64_MOVW_PREL_G2_NC:
+ writeSMovWImm(loc, val >> 32);
+ break;
+ case R_AARCH64_MOVW_PREL_G3:
+ writeSMovWImm(loc, val >> 48);
+ break;
case R_AARCH64_TSTBR14:
checkInt(loc, val, 16, type);
or32le(loc, (val & 0xFFFC) << 3);
@@ -351,7 +444,7 @@ void AArch64::relocateOne(uint8_t *loc, RelType type, uint64_t val) const {
or32AArch64Imm(loc, val);
break;
default:
- error(getErrorLocation(loc) + "unrecognized relocation " + toString(type));
+ llvm_unreachable("unknown relocation");
}
}
@@ -587,4 +680,7 @@ static TargetInfo *getTargetInfo() {
return &t;
}
-TargetInfo *elf::getAArch64TargetInfo() { return getTargetInfo(); }
+TargetInfo *getAArch64TargetInfo() { return getTargetInfo(); }
+
+} // namespace elf
+} // namespace lld