[ELF] Add target-specific relocation scanning for AArch64 (#181099)
Implement AArch64::scanSectionImpl, following the pattern established for x86 (#178846), PPC64 (#181496), and SystemZ (#181563). This merges the getRelExpr and TLS handling for SHF_ALLOC sections into the target-specific scanner, enabling devirtualization and eliminating abstraction overhead. - Inline relocation classification into scanSectionImpl with a switch on relocation type, replacing the generic rs.scan() path. - Use processR_PC/processR_PLT_PC for common PC-relative and PLT relocations, and handleTlsIe/handleTlsDesc for TLS IE/TLSDESC. - Remove some AArch64-specific RelExpr members (RE_AARCH64_AUTH_GOT, RE_AARCH64_AUTH_GOT_PC, RE_AARCH64_AUTH_GOT_PAGE_PC, RE_AARCH64_AUTH_TLSDESC_PAGE, RE_AARCH64_AUTH_TLSDESC, RE_AARCH64_RELAX_TLS_GD_TO_IE_PAGE_PC) by using regular RelExpr members with flag-based dispatch (NEEDS_GOT_AUTH, NEEDS_TLSDESC_AUTH). AUTH GOT relocations now call `sym.setFlags(NEEDS_GOT | NEEDS_GOT_AUTH)` and `rs.processAux` directly. - Remove adjustTlsExpr and handleAArch64PAuthTlsRelocation by inlining their logic into scanSectionImpl and relocateAlloc. - Simplify getRelExpr to only handle relocations needed by relocateNonAlloc and EhInputSection::preprocessRelocs.
This commit is contained in:
parent
c5ac41dba8
commit
371e0e2082
@ -539,9 +539,9 @@ static void implementPatch(Ctx &ctx, uint64_t adrpAddr, uint64_t patcheeOffset,
|
||||
// Case 1: R_AARCH64_JUMP26 branch relocation. We have already patched this
|
||||
// instance of the erratum on a previous patch and altered the relocation. We
|
||||
// have nothing more to do.
|
||||
// Case 2: A TLS Relaxation R_RELAX_TLS_IE_TO_LE. In this case the ADRP that
|
||||
// we read will be transformed into a MOVZ later so we actually don't match
|
||||
// the sequence and have nothing more to do.
|
||||
// Case 2: A TLS IE to LE optimization. In this case the ADRP that we read
|
||||
// will be transformed into a MOVZ later so we actually don't match the
|
||||
// sequence and have nothing more to do.
|
||||
// Case 3: A load/store register (unsigned immediate) class relocation. There
|
||||
// are two of these R_AARCH_LD64_ABS_LO12_NC and R_AARCH_LD64_GOT_LO12_NC and
|
||||
// they are both absolute. We need to add the same relocation to the patch,
|
||||
@ -551,8 +551,12 @@ static void implementPatch(Ctx &ctx, uint64_t adrpAddr, uint64_t patcheeOffset,
|
||||
auto relIt = llvm::find_if(isec->relocs(), [=](const Relocation &r) {
|
||||
return r.offset == patcheeOffset;
|
||||
});
|
||||
// Detect and skip Case 1 and Case 2 above.
|
||||
if (relIt != isec->relocs().end() &&
|
||||
(relIt->type == R_AARCH64_JUMP26 || relIt->expr == R_RELAX_TLS_IE_TO_LE))
|
||||
(relIt->type == R_AARCH64_JUMP26 ||
|
||||
((relIt->type == R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 ||
|
||||
relIt->type == R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC) &&
|
||||
relIt->expr == R_TPREL)))
|
||||
return;
|
||||
|
||||
Log(ctx) << "detected cortex-a53-843419 erratum sequence starting at " <<
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
|
||||
#include "InputFiles.h"
|
||||
#include "OutputSections.h"
|
||||
#include "RelocScan.h"
|
||||
#include "Symbols.h"
|
||||
#include "SyntheticSections.h"
|
||||
#include "Target.h"
|
||||
@ -78,6 +79,14 @@ public:
|
||||
void writePltHeader(uint8_t *buf) const override;
|
||||
void writePlt(uint8_t *buf, const Symbol &sym,
|
||||
uint64_t pltEntryAddr) const override;
|
||||
template <class ELFT, class RelTy>
|
||||
void scanSectionImpl(InputSectionBase &sec, Relocs<RelTy> rels);
|
||||
void scanSection(InputSectionBase &sec) override {
|
||||
if (ctx.arg.ekind == ELF64BEKind)
|
||||
elf::scanSection1<AArch64, ELF64BE>(*this, sec);
|
||||
else
|
||||
elf::scanSection1<AArch64, ELF64LE>(*this, sec);
|
||||
}
|
||||
bool needsThunk(RelExpr expr, RelType type, const InputFile *file,
|
||||
uint64_t branchAddr, const Symbol &s,
|
||||
int64_t a) const override;
|
||||
@ -86,7 +95,6 @@ public:
|
||||
bool usesOnlyLowPageBits(RelType type) const override;
|
||||
void relocate(uint8_t *loc, const Relocation &rel,
|
||||
uint64_t val) const override;
|
||||
RelExpr adjustTlsExpr(RelType type, RelExpr expr) const override;
|
||||
void relocateAlloc(InputSection &sec, uint8_t *buf) const override;
|
||||
void applyBranchToBranchOpt() const override;
|
||||
|
||||
@ -137,106 +145,17 @@ AArch64::AArch64(Ctx &ctx) : TargetInfo(ctx) {
|
||||
needsThunks = true;
|
||||
}
|
||||
|
||||
// Only needed to support relocations used by relocateNonAlloc and
|
||||
// preprocessRelocs.
|
||||
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_FUNCINIT64:
|
||||
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_PATCHINST:
|
||||
if (!isAbsolute(s))
|
||||
Err(ctx) << getErrorLoc(ctx, loc)
|
||||
<< "R_AARCH64_PATCHINST relocation against non-absolute symbol "
|
||||
<< &s;
|
||||
return R_ABS;
|
||||
case R_AARCH64_AUTH_ABS64:
|
||||
return RE_AARCH64_AUTH;
|
||||
case R_AARCH64_TLSDESC_ADR_PAGE21:
|
||||
return RE_AARCH64_TLSDESC_PAGE;
|
||||
case R_AARCH64_AUTH_TLSDESC_ADR_PAGE21:
|
||||
return RE_AARCH64_AUTH_TLSDESC_PAGE;
|
||||
case R_AARCH64_TLSDESC_LD64_LO12:
|
||||
case R_AARCH64_TLSDESC_ADD_LO12:
|
||||
return R_TLSDESC;
|
||||
case R_AARCH64_AUTH_TLSDESC_LD64_LO12:
|
||||
case R_AARCH64_AUTH_TLSDESC_ADD_LO12:
|
||||
return RE_AARCH64_AUTH_TLSDESC;
|
||||
case R_AARCH64_TLSDESC_CALL:
|
||||
return R_TLSDESC_CALL;
|
||||
case R_AARCH64_TLSLE_ADD_TPREL_HI12:
|
||||
case R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
|
||||
case R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC:
|
||||
case R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC:
|
||||
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_TPREL;
|
||||
case R_AARCH64_CALL26:
|
||||
case R_AARCH64_CONDBR19:
|
||||
case R_AARCH64_JUMP26:
|
||||
case R_AARCH64_TSTBR14:
|
||||
return R_PLT_PC;
|
||||
case R_AARCH64_PLT32:
|
||||
const_cast<Symbol &>(s).thunkAccessed = true;
|
||||
return R_PLT_PC;
|
||||
case R_AARCH64_PREL16:
|
||||
case R_AARCH64_PREL32:
|
||||
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:
|
||||
return RE_AARCH64_PAGE_PC;
|
||||
case R_AARCH64_LD64_GOT_LO12_NC:
|
||||
case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
|
||||
return R_GOT;
|
||||
case R_AARCH64_AUTH_LD64_GOT_LO12_NC:
|
||||
case R_AARCH64_AUTH_GOT_ADD_LO12_NC:
|
||||
return RE_AARCH64_AUTH_GOT;
|
||||
case R_AARCH64_AUTH_GOT_LD_PREL19:
|
||||
case R_AARCH64_AUTH_GOT_ADR_PREL_LO21:
|
||||
return RE_AARCH64_AUTH_GOT_PC;
|
||||
case R_AARCH64_LD64_GOTPAGE_LO15:
|
||||
return RE_AARCH64_GOT_PAGE;
|
||||
case R_AARCH64_ADR_GOT_PAGE:
|
||||
case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
|
||||
return RE_AARCH64_GOT_PAGE_PC;
|
||||
case R_AARCH64_AUTH_ADR_GOT_PAGE:
|
||||
return RE_AARCH64_AUTH_GOT_PAGE_PC;
|
||||
case R_AARCH64_GOTPCREL32:
|
||||
case R_AARCH64_GOT_LD_PREL19:
|
||||
return R_GOT_PC;
|
||||
case R_AARCH64_NONE:
|
||||
return R_NONE;
|
||||
default:
|
||||
@ -246,21 +165,14 @@ RelExpr AArch64::getRelExpr(RelType type, const Symbol &s,
|
||||
}
|
||||
}
|
||||
|
||||
RelExpr AArch64::adjustTlsExpr(RelType type, RelExpr expr) const {
|
||||
if (expr == R_RELAX_TLS_GD_TO_IE) {
|
||||
if (type == R_AARCH64_TLSDESC_ADR_PAGE21)
|
||||
return RE_AARCH64_RELAX_TLS_GD_TO_IE_PAGE_PC;
|
||||
return R_RELAX_TLS_GD_TO_IE_ABS;
|
||||
}
|
||||
return expr;
|
||||
}
|
||||
|
||||
bool AArch64::usesOnlyLowPageBits(RelType type) const {
|
||||
switch (type) {
|
||||
default:
|
||||
return false;
|
||||
case R_AARCH64_ADD_ABS_LO12_NC:
|
||||
case R_AARCH64_LD64_GOT_LO12_NC:
|
||||
case R_AARCH64_AUTH_LD64_GOT_LO12_NC:
|
||||
case R_AARCH64_AUTH_GOT_ADD_LO12_NC:
|
||||
case R_AARCH64_LDST128_ABS_LO12_NC:
|
||||
case R_AARCH64_LDST16_ABS_LO12_NC:
|
||||
case R_AARCH64_LDST32_ABS_LO12_NC:
|
||||
@ -273,6 +185,199 @@ bool AArch64::usesOnlyLowPageBits(RelType type) const {
|
||||
}
|
||||
}
|
||||
|
||||
template <class ELFT, class RelTy>
|
||||
void AArch64::scanSectionImpl(InputSectionBase &sec, Relocs<RelTy> rels) {
|
||||
RelocScan rs(ctx, &sec);
|
||||
sec.relocations.reserve(rels.size());
|
||||
|
||||
for (auto it = rels.begin(); it != rels.end(); ++it) {
|
||||
const RelTy &rel = *it;
|
||||
uint32_t symIdx = rel.getSymbol(false);
|
||||
Symbol &sym = sec.getFile<ELFT>()->getSymbol(symIdx);
|
||||
uint64_t offset = rel.r_offset;
|
||||
RelType type = rel.getType(false);
|
||||
if (sym.isUndefined() && symIdx != 0 &&
|
||||
rs.maybeReportUndefined(cast<Undefined>(sym), offset))
|
||||
continue;
|
||||
int64_t addend = rs.getAddend<ELFT>(rel, type);
|
||||
RelExpr expr;
|
||||
// Relocation types that only need a RelExpr set `expr` and break out of
|
||||
// the switch to reach rs.process(). Types that need special handling
|
||||
// (fast-path helpers, TLS) call a handler and use `continue`.
|
||||
switch (type) {
|
||||
case R_AARCH64_NONE:
|
||||
continue;
|
||||
|
||||
// Absolute relocations:
|
||||
case R_AARCH64_ABS16:
|
||||
case R_AARCH64_ABS32:
|
||||
case R_AARCH64_ABS64:
|
||||
case R_AARCH64_FUNCINIT64:
|
||||
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:
|
||||
expr = R_ABS;
|
||||
break;
|
||||
|
||||
case R_AARCH64_AUTH_ABS64:
|
||||
expr = RE_AARCH64_AUTH;
|
||||
break;
|
||||
|
||||
case R_AARCH64_PATCHINST:
|
||||
if (!isAbsolute(sym))
|
||||
Err(ctx) << getErrorLoc(ctx, sec.content().data() + offset)
|
||||
<< "R_AARCH64_PATCHINST relocation against non-absolute "
|
||||
"symbol "
|
||||
<< &sym;
|
||||
expr = R_ABS;
|
||||
break;
|
||||
|
||||
// PC-relative relocations:
|
||||
case R_AARCH64_PREL16:
|
||||
case R_AARCH64_PREL32:
|
||||
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:
|
||||
rs.processR_PC(type, offset, addend, sym);
|
||||
continue;
|
||||
|
||||
// Page-PC relocations:
|
||||
case R_AARCH64_ADR_PREL_PG_HI21:
|
||||
case R_AARCH64_ADR_PREL_PG_HI21_NC:
|
||||
expr = RE_AARCH64_PAGE_PC;
|
||||
break;
|
||||
|
||||
// PLT-generating relocations:
|
||||
case R_AARCH64_PLT32:
|
||||
sym.thunkAccessed = true;
|
||||
[[fallthrough]];
|
||||
case R_AARCH64_CALL26:
|
||||
case R_AARCH64_CONDBR19:
|
||||
case R_AARCH64_JUMP26:
|
||||
case R_AARCH64_TSTBR14:
|
||||
rs.processR_PLT_PC(type, offset, addend, sym);
|
||||
continue;
|
||||
|
||||
// GOT relocations:
|
||||
case R_AARCH64_ADR_GOT_PAGE:
|
||||
expr = RE_AARCH64_GOT_PAGE_PC;
|
||||
break;
|
||||
case R_AARCH64_LD64_GOT_LO12_NC:
|
||||
expr = R_GOT;
|
||||
break;
|
||||
case R_AARCH64_LD64_GOTPAGE_LO15:
|
||||
expr = RE_AARCH64_GOT_PAGE;
|
||||
break;
|
||||
case R_AARCH64_GOTPCREL32:
|
||||
case R_AARCH64_GOT_LD_PREL19:
|
||||
expr = R_GOT_PC;
|
||||
break;
|
||||
|
||||
// AUTH GOT relocations. Set NEEDS_GOT_AUTH to detect incompatibility with
|
||||
// NEEDS_GOT_NONAUTH. rs.process does not set the flag.
|
||||
case R_AARCH64_AUTH_LD64_GOT_LO12_NC:
|
||||
case R_AARCH64_AUTH_GOT_ADD_LO12_NC:
|
||||
sym.setFlags(NEEDS_GOT | NEEDS_GOT_AUTH);
|
||||
rs.processAux(R_GOT, type, offset, sym, addend);
|
||||
continue;
|
||||
case R_AARCH64_AUTH_GOT_LD_PREL19:
|
||||
case R_AARCH64_AUTH_GOT_ADR_PREL_LO21:
|
||||
sym.setFlags(NEEDS_GOT | NEEDS_GOT_AUTH);
|
||||
rs.processAux(R_GOT_PC, type, offset, sym, addend);
|
||||
continue;
|
||||
case R_AARCH64_AUTH_ADR_GOT_PAGE:
|
||||
sym.setFlags(NEEDS_GOT | NEEDS_GOT_AUTH);
|
||||
rs.processAux(RE_AARCH64_GOT_PAGE_PC, type, offset, sym, addend);
|
||||
continue;
|
||||
|
||||
// TLS LE relocations:
|
||||
case R_AARCH64_TLSLE_ADD_TPREL_HI12:
|
||||
case R_AARCH64_TLSLE_ADD_TPREL_LO12_NC:
|
||||
case R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC:
|
||||
case R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC:
|
||||
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:
|
||||
if (rs.checkTlsLe(offset, sym, type))
|
||||
continue;
|
||||
expr = R_TPREL;
|
||||
break;
|
||||
|
||||
// TLS IE relocations:
|
||||
case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
|
||||
rs.handleTlsIe(RE_AARCH64_GOT_PAGE_PC, type, offset, addend, sym);
|
||||
continue;
|
||||
case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
|
||||
rs.handleTlsIe(R_GOT, type, offset, addend, sym);
|
||||
continue;
|
||||
|
||||
// TLSDESC relocations:
|
||||
case R_AARCH64_TLSDESC_ADR_PAGE21:
|
||||
rs.handleTlsDesc(RE_AARCH64_TLSDESC_PAGE, RE_AARCH64_GOT_PAGE_PC, type,
|
||||
offset, addend, sym);
|
||||
continue;
|
||||
case R_AARCH64_TLSDESC_LD64_LO12:
|
||||
case R_AARCH64_TLSDESC_ADD_LO12:
|
||||
rs.handleTlsDesc(R_TLSDESC, R_GOT, type, offset, addend, sym);
|
||||
continue;
|
||||
case R_AARCH64_TLSDESC_CALL:
|
||||
sym.setFlags(NEEDS_TLSDESC_NONAUTH);
|
||||
if (!ctx.arg.shared)
|
||||
sec.addReloc({R_TPREL, type, offset, addend, &sym});
|
||||
continue;
|
||||
|
||||
// AUTH TLSDESC relocations. Do not optimize to LE/IE because PAUTHELF64
|
||||
// only supports the descriptor based TLS (TLSDESC).
|
||||
// https://github.com/ARM-software/abi-aa/blob/main/pauthabielf64/pauthabielf64.rst#general-restrictions
|
||||
case R_AARCH64_AUTH_TLSDESC_ADR_PAGE21:
|
||||
sym.setFlags(NEEDS_TLSDESC | NEEDS_TLSDESC_AUTH);
|
||||
sec.addReloc({RE_AARCH64_TLSDESC_PAGE, type, offset, addend, &sym});
|
||||
continue;
|
||||
case R_AARCH64_AUTH_TLSDESC_LD64_LO12:
|
||||
case R_AARCH64_AUTH_TLSDESC_ADD_LO12:
|
||||
sym.setFlags(NEEDS_TLSDESC | NEEDS_TLSDESC_AUTH);
|
||||
sec.addReloc({R_TLSDESC, type, offset, addend, &sym});
|
||||
continue;
|
||||
|
||||
default:
|
||||
Err(ctx) << getErrorLoc(ctx, sec.content().data() + offset)
|
||||
<< "unknown relocation (" << type.v << ") against symbol "
|
||||
<< &sym;
|
||||
continue;
|
||||
}
|
||||
rs.process(expr, type, offset, sym, addend);
|
||||
}
|
||||
|
||||
if (ctx.arg.branchToBranch)
|
||||
llvm::stable_sort(sec.relocs(),
|
||||
[](auto &l, auto &r) { return l.offset < r.offset; });
|
||||
}
|
||||
|
||||
RelType AArch64::getDynRel(RelType type) const {
|
||||
if (type == R_AARCH64_ABS64 || type == R_AARCH64_AUTH_ABS64 ||
|
||||
type == R_AARCH64_FUNCINIT64)
|
||||
@ -807,8 +912,7 @@ bool AArch64Relaxer::tryRelaxAdrpAdd(const Relocation &adrpRel,
|
||||
// to
|
||||
// NOP
|
||||
// ADR xn, sym
|
||||
if (!ctx.arg.relax || adrpRel.type != R_AARCH64_ADR_PREL_PG_HI21 ||
|
||||
addRel.type != R_AARCH64_ADD_ABS_LO12_NC)
|
||||
if (!ctx.arg.relax || addRel.type != R_AARCH64_ADD_ABS_LO12_NC)
|
||||
return false;
|
||||
// Check if the relocations apply to consecutive instructions.
|
||||
if (adrpRel.offset + 4 != addRel.offset)
|
||||
@ -945,34 +1049,44 @@ void AArch64::relocateAlloc(InputSection &sec, uint8_t *buf) const {
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (rel.expr) {
|
||||
case RE_AARCH64_GOT_PAGE_PC:
|
||||
switch (rel.type) {
|
||||
case R_AARCH64_ADR_GOT_PAGE:
|
||||
if (i + 1 < size &&
|
||||
relaxer.tryRelaxAdrpLdr(rel, relocs[i + 1], secAddr, buf)) {
|
||||
++i;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case RE_AARCH64_PAGE_PC:
|
||||
case R_AARCH64_ADR_PREL_PG_HI21:
|
||||
if (i + 1 < size &&
|
||||
relaxer.tryRelaxAdrpAdd(rel, relocs[i + 1], secAddr, buf)) {
|
||||
++i;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case RE_AARCH64_RELAX_TLS_GD_TO_IE_PAGE_PC:
|
||||
case R_RELAX_TLS_GD_TO_IE_ABS:
|
||||
relaxTlsGdToIe(loc, rel, val);
|
||||
|
||||
case R_AARCH64_TLSDESC_ADR_PAGE21:
|
||||
case R_AARCH64_TLSDESC_LD64_LO12:
|
||||
case R_AARCH64_TLSDESC_ADD_LO12:
|
||||
case R_AARCH64_TLSDESC_CALL:
|
||||
if (rel.expr == R_TPREL)
|
||||
relaxTlsGdToLe(loc, rel, val);
|
||||
else if (rel.expr == RE_AARCH64_GOT_PAGE_PC || rel.expr == R_GOT)
|
||||
relaxTlsGdToIe(loc, rel, val);
|
||||
else
|
||||
relocate(loc, rel, val);
|
||||
continue;
|
||||
case R_RELAX_TLS_GD_TO_LE:
|
||||
relaxTlsGdToLe(loc, rel, val);
|
||||
continue;
|
||||
case R_RELAX_TLS_IE_TO_LE:
|
||||
relaxTlsIeToLe(loc, rel, val);
|
||||
case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21:
|
||||
case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC:
|
||||
if (rel.expr == R_TPREL)
|
||||
relaxTlsIeToLe(loc, rel, val);
|
||||
else
|
||||
relocate(loc, rel, val);
|
||||
continue;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
relocate(loc, rel, val);
|
||||
}
|
||||
}
|
||||
|
||||
@ -820,7 +820,6 @@ uint64_t InputSectionBase::getRelocTargetVA(Ctx &ctx, const Relocation &r,
|
||||
case RE_ARM_SBREL:
|
||||
return r.sym->getVA(ctx, a) - getARMStaticBase(*r.sym);
|
||||
case R_GOT:
|
||||
case RE_AARCH64_AUTH_GOT:
|
||||
case R_RELAX_TLS_GD_TO_IE_ABS:
|
||||
return r.sym->getGotVA(ctx) + a;
|
||||
case RE_LOONGARCH_GOT:
|
||||
@ -847,13 +846,10 @@ uint64_t InputSectionBase::getRelocTargetVA(Ctx &ctx, const Relocation &r,
|
||||
case R_RELAX_TLS_GD_TO_IE_GOT_OFF:
|
||||
return r.sym->getGotOffset(ctx) + a;
|
||||
case RE_AARCH64_GOT_PAGE_PC:
|
||||
case RE_AARCH64_AUTH_GOT_PAGE_PC:
|
||||
case RE_AARCH64_RELAX_TLS_GD_TO_IE_PAGE_PC:
|
||||
return getAArch64Page(r.sym->getGotVA(ctx) + a) - getAArch64Page(p);
|
||||
case RE_AARCH64_GOT_PAGE:
|
||||
return r.sym->getGotVA(ctx) + a - getAArch64Page(ctx.in.got->getVA());
|
||||
case R_GOT_PC:
|
||||
case RE_AARCH64_AUTH_GOT_PC:
|
||||
case R_RELAX_TLS_GD_TO_IE:
|
||||
return r.sym->getGotVA(ctx) + a - p;
|
||||
case R_GOTPLT_GOTREL:
|
||||
@ -1012,14 +1008,12 @@ uint64_t InputSectionBase::getRelocTargetVA(Ctx &ctx, const Relocation &r,
|
||||
case R_SIZE:
|
||||
return r.sym->getSize() + a;
|
||||
case R_TLSDESC:
|
||||
case RE_AARCH64_AUTH_TLSDESC:
|
||||
return ctx.in.got->getTlsDescAddr(*r.sym) + a;
|
||||
case R_TLSDESC_PC:
|
||||
return ctx.in.got->getTlsDescAddr(*r.sym) + a - p;
|
||||
case R_TLSDESC_GOTPLT:
|
||||
return ctx.in.got->getTlsDescAddr(*r.sym) + a - ctx.in.gotPlt->getVA();
|
||||
case RE_AARCH64_TLSDESC_PAGE:
|
||||
case RE_AARCH64_AUTH_TLSDESC_PAGE:
|
||||
return getAArch64Page(ctx.in.got->getTlsDescAddr(*r.sym) + a) -
|
||||
getAArch64Page(p);
|
||||
case RE_LOONGARCH_TLSDESC_PAGE_PC:
|
||||
|
||||
@ -112,8 +112,9 @@ public:
|
||||
} else {
|
||||
sym.setFlags(NEEDS_TLSIE);
|
||||
// R_GOT (absolute GOT address) needs a RELATIVE dynamic relocation in
|
||||
// PIC. This is used by R_386_TLS_IE.
|
||||
if (ieExpr == R_GOT && ctx.arg.isPic)
|
||||
// PIC when the relocation uses the full address (not just low page bits).
|
||||
if (ieExpr == R_GOT && ctx.arg.isPic &&
|
||||
!ctx.target->usesOnlyLowPageBits(type))
|
||||
sec->getPartition(ctx).relaDyn->addRelativeReloc(
|
||||
ctx.target->relativeRel, *sec, offset, sym, addend, type, ieExpr);
|
||||
else
|
||||
@ -159,7 +160,9 @@ public:
|
||||
void handleTlsDesc(RelExpr sharedExpr, RelExpr ieExpr, RelType type,
|
||||
uint64_t offset, int64_t addend, Symbol &sym) {
|
||||
if (ctx.arg.shared) {
|
||||
sym.setFlags(NEEDS_TLSDESC);
|
||||
// NEEDS_TLSDESC_NONAUTH is a no-op for non-AArch64 targets and detects
|
||||
// incompatibility with NEEDS_TLSDESC_AUTH.
|
||||
sym.setFlags(NEEDS_TLSDESC | NEEDS_TLSDESC_NONAUTH);
|
||||
sec->addReloc({sharedExpr, type, offset, addend, &sym});
|
||||
} else if (sym.isPreemptible) {
|
||||
// Optimize to Initial Exec.
|
||||
|
||||
@ -134,10 +134,8 @@ static bool needsPlt(RelExpr expr) {
|
||||
}
|
||||
|
||||
bool lld::elf::needsGot(RelExpr expr) {
|
||||
return oneof<R_GOT, RE_AARCH64_AUTH_GOT, RE_AARCH64_AUTH_GOT_PC, R_GOT_OFF,
|
||||
RE_MIPS_GOT_LOCAL_PAGE, RE_MIPS_GOT_OFF, RE_MIPS_GOT_OFF32,
|
||||
RE_AARCH64_GOT_PAGE_PC, RE_AARCH64_AUTH_GOT_PAGE_PC,
|
||||
RE_AARCH64_AUTH_GOT_PAGE_PC, R_GOT_PC, R_GOTPLT,
|
||||
return oneof<R_GOT, R_GOT_OFF, RE_MIPS_GOT_LOCAL_PAGE, RE_MIPS_GOT_OFF,
|
||||
RE_MIPS_GOT_OFF32, RE_AARCH64_GOT_PAGE_PC, R_GOT_PC, R_GOTPLT,
|
||||
RE_AARCH64_GOT_PAGE, RE_LOONGARCH_GOT, RE_LOONGARCH_GOT_PAGE_PC>(
|
||||
expr);
|
||||
}
|
||||
@ -843,13 +841,11 @@ bool RelocScan::isStaticLinkTimeConstant(RelExpr e, RelType type,
|
||||
// These expressions always compute a constant
|
||||
if (oneof<R_GOTPLT, R_GOT_OFF, R_RELAX_HINT, RE_MIPS_GOT_LOCAL_PAGE,
|
||||
RE_MIPS_GOTREL, RE_MIPS_GOT_OFF, RE_MIPS_GOT_OFF32,
|
||||
RE_MIPS_GOT_GP_PC, RE_AARCH64_GOT_PAGE_PC,
|
||||
RE_AARCH64_AUTH_GOT_PAGE_PC, R_GOT_PC, R_GOTONLY_PC,
|
||||
RE_MIPS_GOT_GP_PC, RE_AARCH64_GOT_PAGE_PC, R_GOT_PC, R_GOTONLY_PC,
|
||||
R_GOTPLTONLY_PC, R_PLT_PC, R_PLT_GOTREL, R_PLT_GOTPLT,
|
||||
R_GOTPLT_GOTREL, R_GOTPLT_PC, RE_PPC32_PLTREL, RE_PPC64_CALL_PLT,
|
||||
RE_RISCV_ADD, RE_AARCH64_GOT_PAGE, RE_AARCH64_AUTH_GOT,
|
||||
RE_AARCH64_AUTH_GOT_PC, RE_LOONGARCH_PLT_PAGE_PC, RE_LOONGARCH_GOT,
|
||||
RE_LOONGARCH_GOT_PAGE_PC>(e))
|
||||
RE_RISCV_ADD, RE_AARCH64_GOT_PAGE, RE_LOONGARCH_PLT_PAGE_PC,
|
||||
RE_LOONGARCH_GOT, RE_LOONGARCH_GOT_PAGE_PC>(e))
|
||||
return true;
|
||||
|
||||
// These never do, except if the entire file is position dependent or if
|
||||
@ -960,11 +956,7 @@ void RelocScan::process(RelExpr expr, RelType type, uint64_t offset,
|
||||
} else if (!sym.isTls() || ctx.arg.emachine != EM_LOONGARCH) {
|
||||
// Many LoongArch TLS relocs reuse the RE_LOONGARCH_GOT type, in which
|
||||
// case the NEEDS_GOT flag shouldn't get set.
|
||||
if (expr == RE_AARCH64_AUTH_GOT || expr == RE_AARCH64_AUTH_GOT_PAGE_PC ||
|
||||
expr == RE_AARCH64_AUTH_GOT_PC)
|
||||
sym.setFlags(NEEDS_GOT | NEEDS_GOT_AUTH);
|
||||
else
|
||||
sym.setFlags(NEEDS_GOT | NEEDS_GOT_NONAUTH);
|
||||
sym.setFlags(NEEDS_GOT | NEEDS_GOT_NONAUTH);
|
||||
}
|
||||
} else if (needsPlt(expr)) {
|
||||
sym.setFlags(NEEDS_PLT);
|
||||
@ -1131,27 +1123,6 @@ void RelocScan::processAux(RelExpr expr, RelType type, uint64_t offset,
|
||||
printLocation(diag, *sec, sym, offset);
|
||||
}
|
||||
|
||||
static unsigned handleAArch64PAuthTlsRelocation(InputSectionBase *sec,
|
||||
RelExpr expr, RelType type,
|
||||
uint64_t offset, Symbol &sym,
|
||||
int64_t addend) {
|
||||
// Do not optimize signed TLSDESC to LE/IE (as described in pauthabielf64).
|
||||
// https://github.com/ARM-software/abi-aa/blob/main/pauthabielf64/pauthabielf64.rst#general-restrictions
|
||||
// > PAUTHELF64 only supports the descriptor based TLS (TLSDESC).
|
||||
if (oneof<RE_AARCH64_AUTH_TLSDESC_PAGE, RE_AARCH64_AUTH_TLSDESC>(expr)) {
|
||||
sym.setFlags(NEEDS_TLSDESC | NEEDS_TLSDESC_AUTH);
|
||||
sec->addReloc({expr, type, offset, addend, &sym});
|
||||
return 1;
|
||||
}
|
||||
|
||||
// TLSDESC_CALL hint relocation should not be emitted by compiler with signed
|
||||
// TLSDESC enabled.
|
||||
if (expr == R_TLSDESC_CALL)
|
||||
sym.setFlags(NEEDS_TLSDESC_NONAUTH);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Notes about General Dynamic and Local Dynamic TLS models below. They may
|
||||
// require the generation of a pair of GOT entries that have associated dynamic
|
||||
// relocations. The pair of GOT entries created are of the form GOT[e0] Module
|
||||
@ -1162,27 +1133,18 @@ static unsigned handleAArch64PAuthTlsRelocation(InputSectionBase *sec,
|
||||
unsigned RelocScan::handleTlsRelocation(RelExpr expr, RelType type,
|
||||
uint64_t offset, Symbol &sym,
|
||||
int64_t addend) {
|
||||
bool isAArch64 = ctx.arg.emachine == EM_AARCH64;
|
||||
|
||||
if (isAArch64)
|
||||
if (unsigned processed = handleAArch64PAuthTlsRelocation(
|
||||
sec, expr, type, offset, sym, addend))
|
||||
return processed;
|
||||
|
||||
if (expr == R_TPREL || expr == R_TPREL_NEG)
|
||||
return checkTlsLe(offset, sym, type) ? 1 : 0;
|
||||
|
||||
bool isRISCV = ctx.arg.emachine == EM_RISCV;
|
||||
|
||||
if (oneof<RE_AARCH64_TLSDESC_PAGE, R_TLSDESC, R_TLSDESC_CALL, R_TLSDESC_PC,
|
||||
R_TLSDESC_GOTPLT, RE_LOONGARCH_TLSDESC_PAGE_PC>(expr) &&
|
||||
if (oneof<R_TLSDESC, R_TLSDESC_CALL, R_TLSDESC_PC, R_TLSDESC_GOTPLT,
|
||||
RE_LOONGARCH_TLSDESC_PAGE_PC>(expr) &&
|
||||
ctx.arg.shared) {
|
||||
// R_RISCV_TLSDESC_{LOAD_LO12,ADD_LO12_I,CALL} reference a label. Do not
|
||||
// set NEEDS_TLSDESC on the label.
|
||||
if (expr != R_TLSDESC_CALL) {
|
||||
if (isAArch64)
|
||||
sym.setFlags(NEEDS_TLSDESC | NEEDS_TLSDESC_NONAUTH);
|
||||
else if (!isRISCV || type == R_RISCV_TLSDESC_HI20)
|
||||
if (!isRISCV || type == R_RISCV_TLSDESC_HI20)
|
||||
sym.setFlags(NEEDS_TLSDESC);
|
||||
sec->addReloc({expr, type, offset, addend, &sym});
|
||||
}
|
||||
@ -1256,9 +1218,9 @@ unsigned RelocScan::handleTlsRelocation(RelExpr expr, RelType type,
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (oneof<RE_AARCH64_TLSDESC_PAGE, R_TLSDESC, R_TLSDESC_CALL, R_TLSDESC_PC,
|
||||
R_TLSDESC_GOTPLT, R_TLSGD_GOT, R_TLSGD_GOTPLT, R_TLSGD_PC,
|
||||
RE_LOONGARCH_TLSGD_PAGE_PC, RE_LOONGARCH_TLSDESC_PAGE_PC>(expr)) {
|
||||
if (oneof<R_TLSDESC, R_TLSDESC_CALL, R_TLSDESC_PC, R_TLSDESC_GOTPLT,
|
||||
R_TLSGD_GOT, R_TLSGD_GOTPLT, R_TLSGD_PC, RE_LOONGARCH_TLSGD_PAGE_PC,
|
||||
RE_LOONGARCH_TLSDESC_PAGE_PC>(expr)) {
|
||||
if (!execOptimize) {
|
||||
sym.setFlags(NEEDS_TLSGD);
|
||||
sec->addReloc({expr, type, offset, addend, &sym});
|
||||
@ -1282,8 +1244,8 @@ unsigned RelocScan::handleTlsRelocation(RelExpr expr, RelType type,
|
||||
return ctx.target->getTlsGdRelaxSkip(type);
|
||||
}
|
||||
|
||||
if (oneof<R_GOT, R_GOTPLT, R_GOT_PC, RE_AARCH64_GOT_PAGE_PC,
|
||||
RE_LOONGARCH_GOT_PAGE_PC, R_GOT_OFF, R_TLSIE_HINT>(expr)) {
|
||||
if (oneof<R_GOT, R_GOTPLT, R_GOT_PC, RE_LOONGARCH_GOT_PAGE_PC, R_GOT_OFF,
|
||||
R_TLSIE_HINT>(expr)) {
|
||||
// Initial-Exec relocs can be optimized to Local-Exec if the symbol is
|
||||
// locally defined.
|
||||
if (execOptimize && isLocalInExecutable) {
|
||||
|
||||
@ -94,15 +94,9 @@ enum RelExpr {
|
||||
// of a relocation type, there are some relocations whose semantics are
|
||||
// unique to a target. Such relocation are marked with RE_<TARGET_NAME>.
|
||||
RE_AARCH64_GOT_PAGE_PC,
|
||||
RE_AARCH64_AUTH_GOT_PAGE_PC,
|
||||
RE_AARCH64_GOT_PAGE,
|
||||
RE_AARCH64_AUTH_GOT,
|
||||
RE_AARCH64_AUTH_GOT_PC,
|
||||
RE_AARCH64_PAGE_PC,
|
||||
RE_AARCH64_RELAX_TLS_GD_TO_IE_PAGE_PC,
|
||||
RE_AARCH64_TLSDESC_PAGE,
|
||||
RE_AARCH64_AUTH_TLSDESC_PAGE,
|
||||
RE_AARCH64_AUTH_TLSDESC,
|
||||
RE_AARCH64_AUTH,
|
||||
RE_ARM_PCA,
|
||||
RE_ARM_SBREL,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user