Skip to content

Commit

Permalink
[ELF] Rename relocateOne() to relocate() and pass Relocation to it
Browse files Browse the repository at this point in the history
Symbol information can be used to improve out-of-range/misalignment diagnostics.
It also helps R_ARM_CALL/R_ARM_THM_CALL which has different behaviors with different symbol types.

There are many (67) relocateOne() call sites used in thunks, {Arm,AArch64}errata, PLT, etc.
Rename them to `relocateNoSym()` to be clearer that there is no symbol information.

Reviewed By: grimar, peter.smith

Differential Revision: https://reviews.llvm.org/D73254
  • Loading branch information
MaskRay committed Jan 25, 2020
1 parent 481b796 commit deb5819
Show file tree
Hide file tree
Showing 20 changed files with 266 additions and 243 deletions.
2 changes: 1 addition & 1 deletion lld/ELF/AArch64ErrataFix.cpp
Expand Up @@ -421,7 +421,7 @@ void Patch843419Section::writeTo(uint8_t *buf) {
// Return address is the next instruction after the one we have just copied.
uint64_t s = getLDSTAddr() + 4;
uint64_t p = patchSym->getVA() + 4;
target->relocateOne(buf + 4, R_AARCH64_JUMP26, s - p);
target->relocateNoSym(buf + 4, R_AARCH64_JUMP26, s - p);
}

void AArch64Err843419Patcher::init() {
Expand Down
2 changes: 1 addition & 1 deletion lld/ELF/ARMErrataFix.cpp
Expand Up @@ -189,7 +189,7 @@ void Patch657417Section::writeTo(uint8_t *buf) {
// been altered to point to us!
uint64_t s = getThumbDestAddr(getBranchAddr(), instr);
uint64_t p = getVA(4);
target->relocateOne(buf, isARM ? R_ARM_JUMP24 : R_ARM_THM_JUMP24, s - p);
target->relocateNoSym(buf, isARM ? R_ARM_JUMP24 : R_ARM_THM_JUMP24, s - p);
}

// Given a branch instruction spanning two 4KiB regions, at offset off from the
Expand Down
87 changes: 44 additions & 43 deletions lld/ELF/Arch/AArch64.cpp
Expand Up @@ -45,7 +45,8 @@ class AArch64 : public TargetInfo {
uint32_t getThunkSectionSpacing() const override;
bool inBranchRange(RelType type, uint64_t src, uint64_t dst) const override;
bool usesOnlyLowPageBits(RelType type) const override;
void relocateOne(uint8_t *loc, RelType type, uint64_t val) const override;
void relocate(uint8_t *loc, const Relocation &rel,
uint64_t val) const override;
RelExpr adjustRelaxExpr(RelType type, const uint8_t *data,
RelExpr expr) const override;
void relaxTlsGdToLe(uint8_t *loc, const Relocation &rel,
Expand Down Expand Up @@ -211,10 +212,10 @@ void AArch64::writePltHeader(uint8_t *buf) const {

uint64_t got = in.gotPlt->getVA();
uint64_t plt = in.plt->getVA();
relocateOne(buf + 4, R_AARCH64_ADR_PREL_PG_HI21,
getAArch64Page(got + 16) - getAArch64Page(plt + 4));
relocateOne(buf + 8, R_AARCH64_LDST64_ABS_LO12_NC, got + 16);
relocateOne(buf + 12, R_AARCH64_ADD_ABS_LO12_NC, got + 16);
relocateNoSym(buf + 4, R_AARCH64_ADR_PREL_PG_HI21,
getAArch64Page(got + 16) - getAArch64Page(plt + 4));
relocateNoSym(buf + 8, R_AARCH64_LDST64_ABS_LO12_NC, got + 16);
relocateNoSym(buf + 12, R_AARCH64_ADD_ABS_LO12_NC, got + 16);
}

void AArch64::writePlt(uint8_t *buf, const Symbol &sym,
Expand All @@ -228,10 +229,10 @@ void AArch64::writePlt(uint8_t *buf, const Symbol &sym,
memcpy(buf, inst, sizeof(inst));

uint64_t gotPltEntryAddr = sym.getGotPltVA();
relocateOne(buf, R_AARCH64_ADR_PREL_PG_HI21,
getAArch64Page(gotPltEntryAddr) - getAArch64Page(pltEntryAddr));
relocateOne(buf + 4, R_AARCH64_LDST64_ABS_LO12_NC, gotPltEntryAddr);
relocateOne(buf + 8, R_AARCH64_ADD_ABS_LO12_NC, gotPltEntryAddr);
relocateNoSym(buf, R_AARCH64_ADR_PREL_PG_HI21,
getAArch64Page(gotPltEntryAddr) - getAArch64Page(pltEntryAddr));
relocateNoSym(buf + 4, R_AARCH64_LDST64_ABS_LO12_NC, gotPltEntryAddr);
relocateNoSym(buf + 8, R_AARCH64_ADD_ABS_LO12_NC, gotPltEntryAddr);
}

bool AArch64::needsThunk(RelExpr expr, RelType type, const InputFile *file,
Expand Down Expand Up @@ -312,16 +313,17 @@ static void writeSMovWImm(uint8_t *loc, uint32_t imm) {
write32le(loc, inst | ((imm & 0xFFFF) << 5));
}

void AArch64::relocateOne(uint8_t *loc, RelType type, uint64_t val) const {
switch (type) {
void AArch64::relocate(uint8_t *loc, const Relocation &rel,
uint64_t val) const {
switch (rel.type) {
case R_AARCH64_ABS16:
case R_AARCH64_PREL16:
checkIntUInt(loc, val, 16, type);
checkIntUInt(loc, val, 16, rel);
write16le(loc, val);
break;
case R_AARCH64_ABS32:
case R_AARCH64_PREL32:
checkIntUInt(loc, val, 32, type);
checkIntUInt(loc, val, 32, rel);
write32le(loc, val);
break;
case R_AARCH64_ABS64:
Expand All @@ -335,13 +337,13 @@ void AArch64::relocateOne(uint8_t *loc, RelType type, uint64_t val) const {
case R_AARCH64_ADR_PREL_PG_HI21:
case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
case R_AARCH64_TLSDESC_ADR_PAGE21:
checkInt(loc, val, 33, type);
checkInt(loc, val, 33, rel);
LLVM_FALLTHROUGH;
case R_AARCH64_ADR_PREL_PG_HI21_NC:
write32AArch64Addr(loc, val >> 12);
break;
case R_AARCH64_ADR_PREL_LO21:
checkInt(loc, val, 21, type);
checkInt(loc, val, 21, rel);
write32AArch64Addr(loc, val);
break;
case R_AARCH64_JUMP26:
Expand All @@ -355,13 +357,13 @@ void AArch64::relocateOne(uint8_t *loc, RelType type, uint64_t val) const {
write32le(loc, 0x14000000);
LLVM_FALLTHROUGH;
case R_AARCH64_CALL26:
checkInt(loc, val, 28, type);
checkInt(loc, val, 28, rel);
or32le(loc, (val & 0x0FFFFFFC) >> 2);
break;
case R_AARCH64_CONDBR19:
case R_AARCH64_LD_PREL_LO19:
checkAlignment(loc, val, 4, type);
checkInt(loc, val, 21, type);
checkAlignment(loc, val, 4, rel);
checkInt(loc, val, 21, rel);
or32le(loc, (val & 0x1FFFFC) << 3);
break;
case R_AARCH64_LDST8_ABS_LO12_NC:
Expand All @@ -370,41 +372,41 @@ void AArch64::relocateOne(uint8_t *loc, RelType type, uint64_t val) const {
break;
case R_AARCH64_LDST16_ABS_LO12_NC:
case R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC:
checkAlignment(loc, val, 2, type);
checkAlignment(loc, val, 2, rel);
or32AArch64Imm(loc, getBits(val, 1, 11));
break;
case R_AARCH64_LDST32_ABS_LO12_NC:
case R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC:
checkAlignment(loc, val, 4, type);
checkAlignment(loc, val, 4, rel);
or32AArch64Imm(loc, getBits(val, 2, 11));
break;
case R_AARCH64_LDST64_ABS_LO12_NC:
case R_AARCH64_LD64_GOT_LO12_NC:
case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
case R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC:
case R_AARCH64_TLSDESC_LD64_LO12:
checkAlignment(loc, val, 8, type);
checkAlignment(loc, val, 8, rel);
or32AArch64Imm(loc, getBits(val, 3, 11));
break;
case R_AARCH64_LDST128_ABS_LO12_NC:
case R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC:
checkAlignment(loc, val, 16, type);
checkAlignment(loc, val, 16, rel);
or32AArch64Imm(loc, getBits(val, 4, 11));
break;
case R_AARCH64_MOVW_UABS_G0:
checkUInt(loc, val, 16, type);
checkUInt(loc, val, 16, rel);
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);
checkUInt(loc, val, 32, rel);
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);
checkUInt(loc, val, 48, rel);
LLVM_FALLTHROUGH;
case R_AARCH64_MOVW_UABS_G2_NC:
or32le(loc, (val & 0xFFFF00000000) >> 27);
Expand All @@ -415,7 +417,7 @@ void AArch64::relocateOne(uint8_t *loc, RelType type, uint64_t val) const {
case R_AARCH64_MOVW_PREL_G0:
case R_AARCH64_MOVW_SABS_G0:
case R_AARCH64_TLSLE_MOVW_TPREL_G0:
checkInt(loc, val, 17, type);
checkInt(loc, val, 17, rel);
LLVM_FALLTHROUGH;
case R_AARCH64_MOVW_PREL_G0_NC:
case R_AARCH64_TLSLE_MOVW_TPREL_G0_NC:
Expand All @@ -424,7 +426,7 @@ void AArch64::relocateOne(uint8_t *loc, RelType type, uint64_t val) const {
case R_AARCH64_MOVW_PREL_G1:
case R_AARCH64_MOVW_SABS_G1:
case R_AARCH64_TLSLE_MOVW_TPREL_G1:
checkInt(loc, val, 33, type);
checkInt(loc, val, 33, rel);
LLVM_FALLTHROUGH;
case R_AARCH64_MOVW_PREL_G1_NC:
case R_AARCH64_TLSLE_MOVW_TPREL_G1_NC:
Expand All @@ -433,7 +435,7 @@ void AArch64::relocateOne(uint8_t *loc, RelType type, uint64_t val) const {
case R_AARCH64_MOVW_PREL_G2:
case R_AARCH64_MOVW_SABS_G2:
case R_AARCH64_TLSLE_MOVW_TPREL_G2:
checkInt(loc, val, 49, type);
checkInt(loc, val, 49, rel);
LLVM_FALLTHROUGH;
case R_AARCH64_MOVW_PREL_G2_NC:
writeSMovWImm(loc, val >> 32);
Expand All @@ -442,11 +444,11 @@ void AArch64::relocateOne(uint8_t *loc, RelType type, uint64_t val) const {
writeSMovWImm(loc, val >> 48);
break;
case R_AARCH64_TSTBR14:
checkInt(loc, val, 16, type);
checkInt(loc, val, 16, rel);
or32le(loc, (val & 0xFFFC) << 3);
break;
case R_AARCH64_TLSLE_ADD_TPREL_HI12:
checkUInt(loc, val, 24, type);
checkUInt(loc, val, 24, rel);
or32AArch64Imm(loc, val >> 12);
break;
case R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
Expand All @@ -471,7 +473,7 @@ void AArch64::relaxTlsGdToLe(uint8_t *loc, const Relocation &rel,
// movk x0, #0x10
// nop
// nop
checkUInt(loc, val, 32, rel.type);
checkUInt(loc, val, 32, rel);

switch (rel.type) {
case R_AARCH64_TLSDESC_ADD_LO12:
Expand Down Expand Up @@ -510,11 +512,11 @@ void AArch64::relaxTlsGdToIe(uint8_t *loc, const Relocation &rel,
break;
case R_AARCH64_TLSDESC_ADR_PAGE21:
write32le(loc, 0x90000000); // adrp
relocateOne(loc, R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21, val);
relocateNoSym(loc, R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21, val);
break;
case R_AARCH64_TLSDESC_LD64_LO12:
write32le(loc, 0xf9400000); // ldr
relocateOne(loc, R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC, val);
relocateNoSym(loc, R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC, val);
break;
default:
llvm_unreachable("unsupported relocation for TLS GD to LE relaxation");
Expand All @@ -523,7 +525,7 @@ void AArch64::relaxTlsGdToIe(uint8_t *loc, const Relocation &rel,

void AArch64::relaxTlsIeToLe(uint8_t *loc, const Relocation &rel,
uint64_t val) const {
checkUInt(loc, val, 32, rel.type);
checkUInt(loc, val, 32, rel);

if (rel.type == R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21) {
// Generate MOVZ.
Expand Down Expand Up @@ -633,10 +635,10 @@ void AArch64BtiPac::writePltHeader(uint8_t *buf) const {
}
memcpy(buf, pltData, sizeof(pltData));

relocateOne(buf + 4, R_AARCH64_ADR_PREL_PG_HI21,
getAArch64Page(got + 16) - getAArch64Page(plt + 8));
relocateOne(buf + 8, R_AARCH64_LDST64_ABS_LO12_NC, got + 16);
relocateOne(buf + 12, R_AARCH64_ADD_ABS_LO12_NC, got + 16);
relocateNoSym(buf + 4, R_AARCH64_ADR_PREL_PG_HI21,
getAArch64Page(got + 16) - getAArch64Page(plt + 8));
relocateNoSym(buf + 8, R_AARCH64_LDST64_ABS_LO12_NC, got + 16);
relocateNoSym(buf + 12, R_AARCH64_ADD_ABS_LO12_NC, got + 16);
if (!btiHeader)
// We didn't add the BTI c instruction so round out size with NOP.
memcpy(buf + sizeof(pltData), nopData, sizeof(nopData));
Expand Down Expand Up @@ -670,11 +672,10 @@ void AArch64BtiPac::writePlt(uint8_t *buf, const Symbol &sym,

uint64_t gotPltEntryAddr = sym.getGotPltVA();
memcpy(buf, addrInst, sizeof(addrInst));
relocateOne(buf, R_AARCH64_ADR_PREL_PG_HI21,
getAArch64Page(gotPltEntryAddr) -
getAArch64Page(pltEntryAddr));
relocateOne(buf + 4, R_AARCH64_LDST64_ABS_LO12_NC, gotPltEntryAddr);
relocateOne(buf + 8, R_AARCH64_ADD_ABS_LO12_NC, gotPltEntryAddr);
relocateNoSym(buf, R_AARCH64_ADR_PREL_PG_HI21,
getAArch64Page(gotPltEntryAddr) - getAArch64Page(pltEntryAddr));
relocateNoSym(buf + 4, R_AARCH64_LDST64_ABS_LO12_NC, gotPltEntryAddr);
relocateNoSym(buf + 8, R_AARCH64_ADD_ABS_LO12_NC, gotPltEntryAddr);

if (pacEntry)
memcpy(buf + sizeof(addrInst), pacBr, sizeof(pacBr));
Expand Down
7 changes: 4 additions & 3 deletions lld/ELF/Arch/AMDGPU.cpp
Expand Up @@ -26,7 +26,8 @@ class AMDGPU final : public TargetInfo {
public:
AMDGPU();
uint32_t calcEFlags() const override;
void relocateOne(uint8_t *loc, RelType type, uint64_t val) const override;
void relocate(uint8_t *loc, const Relocation &rel,
uint64_t val) const override;
RelExpr getRelExpr(RelType type, const Symbol &s,
const uint8_t *loc) const override;
RelType getDynRel(RelType type) const override;
Expand Down Expand Up @@ -58,8 +59,8 @@ uint32_t AMDGPU::calcEFlags() const {
return ret;
}

void AMDGPU::relocateOne(uint8_t *loc, RelType type, uint64_t val) const {
switch (type) {
void AMDGPU::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const {
switch (rel.type) {
case R_AMDGPU_ABS32:
case R_AMDGPU_GOTPCREL:
case R_AMDGPU_GOTPCREL32_LO:
Expand Down
24 changes: 13 additions & 11 deletions lld/ELF/Arch/ARM.cpp
Expand Up @@ -43,7 +43,8 @@ class ARM final : public TargetInfo {
int64_t a) const override;
uint32_t getThunkSectionSpacing() const override;
bool inBranchRange(RelType type, uint64_t src, uint64_t dst) const override;
void relocateOne(uint8_t *loc, RelType type, uint64_t val) const override;
void relocate(uint8_t *loc, const Relocation &rel,
uint64_t val) const override;
};
} // namespace

Expand Down Expand Up @@ -375,8 +376,8 @@ bool ARM::inBranchRange(RelType type, uint64_t src, uint64_t dst) const {
return distance <= range;
}

void ARM::relocateOne(uint8_t *loc, RelType type, uint64_t val) const {
switch (type) {
void ARM::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const {
switch (rel.type) {
case R_ARM_ABS32:
case R_ARM_BASE_PREL:
case R_ARM_GOTOFF32:
Expand All @@ -397,7 +398,7 @@ void ARM::relocateOne(uint8_t *loc, RelType type, uint64_t val) const {
write32le(loc, val);
break;
case R_ARM_PREL31:
checkInt(loc, val, 31, type);
checkInt(loc, val, 31, rel);
write32le(loc, (read32le(loc) & 0x80000000) | (val & ~0x80000000));
break;
case R_ARM_CALL:
Expand All @@ -406,7 +407,7 @@ void ARM::relocateOne(uint8_t *loc, RelType type, uint64_t val) const {
if (val & 1) {
// If bit 0 of Val is 1 the target is Thumb, we must select a BLX.
// The BLX encoding is 0xfa:H:imm24 where Val = imm24:H:'1'
checkInt(loc, val, 26, type);
checkInt(loc, val, 26, rel);
write32le(loc, 0xfa000000 | // opcode
((val & 2) << 23) | // H
((val >> 2) & 0x00ffffff)); // imm24
Expand All @@ -421,16 +422,16 @@ void ARM::relocateOne(uint8_t *loc, RelType type, uint64_t val) const {
case R_ARM_JUMP24:
case R_ARM_PC24:
case R_ARM_PLT32:
checkInt(loc, val, 26, type);
checkInt(loc, val, 26, rel);
write32le(loc, (read32le(loc) & ~0x00ffffff) | ((val >> 2) & 0x00ffffff));
break;
case R_ARM_THM_JUMP11:
checkInt(loc, val, 12, type);
checkInt(loc, val, 12, rel);
write16le(loc, (read32le(loc) & 0xf800) | ((val >> 1) & 0x07ff));
break;
case R_ARM_THM_JUMP19:
// Encoding T3: Val = S:J2:J1:imm6:imm11:0
checkInt(loc, val, 21, type);
checkInt(loc, val, 21, rel);
write16le(loc,
(read16le(loc) & 0xfbc0) | // opcode cond
((val >> 10) & 0x0400) | // S
Expand All @@ -454,7 +455,7 @@ void ARM::relocateOne(uint8_t *loc, RelType type, uint64_t val) const {
if (!config->armJ1J2BranchEncoding) {
// Older Arm architectures do not support R_ARM_THM_JUMP24 and have
// different encoding rules and range due to J1 and J2 always being 1.
checkInt(loc, val, 23, type);
checkInt(loc, val, 23, rel);
write16le(loc,
0xf000 | // opcode
((val >> 12) & 0x07ff)); // imm11
Expand All @@ -468,7 +469,7 @@ void ARM::relocateOne(uint8_t *loc, RelType type, uint64_t val) const {
LLVM_FALLTHROUGH;
case R_ARM_THM_JUMP24:
// Encoding B T4, BL T1, BLX T2: Val = S:I1:I2:imm10:imm11:0
checkInt(loc, val, 25, type);
checkInt(loc, val, 25, rel);
write16le(loc,
0xf000 | // opcode
((val >> 14) & 0x0400) | // S
Expand Down Expand Up @@ -514,7 +515,8 @@ void ARM::relocateOne(uint8_t *loc, RelType type, uint64_t val) const {
(val & 0x00ff)); // imm8
break;
default:
error(getErrorLocation(loc) + "unrecognized relocation " + toString(type));
error(getErrorLocation(loc) + "unrecognized relocation " +
toString(rel.type));
}
}

Expand Down

0 comments on commit deb5819

Please sign in to comment.