diff options
Diffstat (limited to 'ELF/Arch/AArch64.cpp')
-rw-r--r-- | ELF/Arch/AArch64.cpp | 108 |
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 |