[ELF] Pass Ctx & to Arch/

This commit is contained in:
Fangrui Song 2024-10-06 00:31:51 -07:00
parent 6d03a69034
commit b3e0bd3d28
15 changed files with 52 additions and 47 deletions

View File

@ -372,7 +372,7 @@ static uint64_t scanCortexA53Errata843419(InputSection *isec, uint64_t &off,
class elf::Patch843419Section final : public SyntheticSection {
public:
Patch843419Section(InputSection *p, uint64_t off);
Patch843419Section(Ctx &, InputSection *p, uint64_t off);
void writeTo(Ctx &, uint8_t *buf) override;
@ -392,7 +392,7 @@ public:
Symbol *patchSym;
};
Patch843419Section::Patch843419Section(InputSection *p, uint64_t off)
Patch843419Section::Patch843419Section(Ctx &ctx, InputSection *p, uint64_t off)
: SyntheticSection(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, 4,
".text.patch"),
patchee(p), patcheeOffset(off) {
@ -529,7 +529,7 @@ void AArch64Err843419Patcher::insertPatches(
// instruction that we need to patch at patcheeOffset from the start of
// InputSection isec, create a Patch843419 Section and add it to the
// Patches that we need to insert.
static void implementPatch(uint64_t adrpAddr, uint64_t patcheeOffset,
static void implementPatch(Ctx &ctx, uint64_t adrpAddr, uint64_t patcheeOffset,
InputSection *isec,
std::vector<Patch843419Section *> &patches) {
// There may be a relocation at the same offset that we are patching. There
@ -556,7 +556,7 @@ static void implementPatch(uint64_t adrpAddr, uint64_t patcheeOffset,
log("detected cortex-a53-843419 erratum sequence starting at " +
utohexstr(adrpAddr) + " in unpatched output.");
auto *ps = make<Patch843419Section>(isec, patcheeOffset);
auto *ps = make<Patch843419Section>(ctx, isec, patcheeOffset);
patches.push_back(ps);
auto makeRelToPatch = [](uint64_t offset, Symbol *patchSym) {
@ -599,7 +599,7 @@ AArch64Err843419Patcher::patchInputSectionDescription(
uint64_t startAddr = isec->getVA(off);
if (uint64_t patcheeOffset =
scanCortexA53Errata843419(isec, off, limit))
implementPatch(startAddr, patcheeOffset, isec, patches);
implementPatch(ctx, startAddr, patcheeOffset, isec, patches);
}
if (dataSym == mapSyms.end())
break;

View File

@ -151,7 +151,8 @@ uint64_t Patch657417Section::getBranchAddr() const {
// Given a branch instruction instr at sourceAddr work out its destination
// address. This is only used when the branch instruction has no relocation.
static uint64_t getThumbDestAddr(uint64_t sourceAddr, uint32_t instr) {
static uint64_t getThumbDestAddr(Ctx &ctx, uint64_t sourceAddr,
uint32_t instr) {
uint8_t buf[4];
write16le(buf, instr >> 16);
write16le(buf + 2, instr & 0x0000ffff);
@ -191,7 +192,7 @@ void Patch657417Section::writeTo(Ctx &ctx, uint8_t *buf) {
// Get the destination offset from the addend in the branch instruction.
// We cannot use the instruction in the patchee section as this will have
// been altered to point to us!
uint64_t s = getThumbDestAddr(getBranchAddr(), instr);
uint64_t s = getThumbDestAddr(ctx, getBranchAddr(), instr);
// A BLX changes the state of the branch in the patch to Arm state, which
// has a PC Bias of 8, whereas in all other cases the branch is in Thumb
// state with a PC Bias of 4.
@ -204,8 +205,9 @@ void Patch657417Section::writeTo(Ctx &ctx, uint8_t *buf) {
// Given a branch instruction spanning two 4KiB regions, at offset off from the
// start of isec, return true if the destination of the branch is within the
// first of the two 4Kib regions.
static bool branchDestInFirstRegion(const InputSection *isec, uint64_t off,
uint32_t instr, const Relocation *r) {
static bool branchDestInFirstRegion(Ctx &ctx, const InputSection *isec,
uint64_t off, uint32_t instr,
const Relocation *r) {
uint64_t sourceAddr = isec->getVA(0) + off;
assert((sourceAddr & 0xfff) == 0xffe);
uint64_t destAddr;
@ -219,7 +221,7 @@ static bool branchDestInFirstRegion(const InputSection *isec, uint64_t off,
} else {
// If there is no relocation, we must have an intra-section branch
// We must extract the offset from the addend manually.
destAddr = getThumbDestAddr(sourceAddr, instr);
destAddr = getThumbDestAddr(ctx, sourceAddr, instr);
}
return (destAddr & 0xfffff000) == (sourceAddr & 0xfffff000);
@ -227,7 +229,7 @@ static bool branchDestInFirstRegion(const InputSection *isec, uint64_t off,
// Return true if a branch can reach a patch section placed after isec.
// The Bcc.w instruction has a range of 1 MiB, all others have 16 MiB.
static bool patchInRange(const InputSection *isec, uint64_t off,
static bool patchInRange(Ctx &ctx, const InputSection *isec, uint64_t off,
uint32_t instr) {
// We need the branch at source to reach a patch section placed immediately
@ -289,8 +291,8 @@ static ScanResult scanCortexA8Errata657417(InputSection *isec, uint64_t &off,
});
if (relIt != isec->relocs().end())
scanRes.rel = &(*relIt);
if (branchDestInFirstRegion(isec, branchOff, instr2, scanRes.rel)) {
if (patchInRange(isec, branchOff, instr2)) {
if (branchDestInFirstRegion(ctx, isec, branchOff, instr2, scanRes.rel)) {
if (patchInRange(ctx, isec, branchOff, instr2)) {
scanRes.off = branchOff;
scanRes.instr = instr2;
} else {

View File

@ -14,7 +14,7 @@
#include <vector>
namespace lld::elf {
struct Ctx;
class Defined;
class InputSection;
class InputSectionDescription;
@ -22,6 +22,7 @@ class Patch657417Section;
class ARMErr657417Patcher {
public:
ARMErr657417Patcher(Ctx &ctx) : ctx(ctx) {}
// Return true if Patches have been added to the OutputSections.
bool createFixes();
@ -34,6 +35,7 @@ private:
void init();
Ctx &ctx;
// A cache of the mapping symbols defined by the InputSection sorted in order
// of ascending value with redundant symbols removed. These describe
// the ranges of code and data in an executable InputSection.

View File

@ -230,14 +230,14 @@ static void writePltHeaderLong(Ctx &ctx, uint8_t *buf) {
// True if we should use Thumb PLTs, which currently require Thumb2, and are
// only used if the target does not have the ARM ISA.
static bool useThumbPLTs() {
static bool useThumbPLTs(Ctx &ctx) {
return ctx.arg.armHasThumb2ISA && !ctx.arg.armHasArmISA;
}
// The default PLT header requires the .got.plt to be within 128 Mb of the
// .plt in the positive direction.
void ARM::writePltHeader(uint8_t *buf) const {
if (useThumbPLTs()) {
if (useThumbPLTs(ctx)) {
// The instruction sequence for thumb:
//
// 0: b500 push {lr}
@ -295,7 +295,7 @@ void ARM::writePltHeader(uint8_t *buf) const {
}
void ARM::addPltHeaderSymbols(InputSection &isec) const {
if (useThumbPLTs()) {
if (useThumbPLTs(ctx)) {
addSyntheticLocal("$t", STT_NOTYPE, 0, 0, isec);
addSyntheticLocal("$d", STT_NOTYPE, 12, 0, isec);
} else {
@ -320,8 +320,7 @@ static void writePltLong(uint8_t *buf, uint64_t gotPltEntryAddr,
// .plt in the positive direction.
void ARM::writePlt(uint8_t *buf, const Symbol &sym,
uint64_t pltEntryAddr) const {
if (!useThumbPLTs()) {
if (!useThumbPLTs(ctx)) {
uint64_t offset = sym.getGotPltVA() - pltEntryAddr - 8;
// The PLT entry is similar to the example given in Appendix A of ELF for
@ -373,7 +372,7 @@ void ARM::writePlt(uint8_t *buf, const Symbol &sym,
}
void ARM::addPltSymbols(InputSection &isec, uint64_t off) const {
if (useThumbPLTs()) {
if (useThumbPLTs(ctx)) {
addSyntheticLocal("$t", STT_NOTYPE, off, 0, isec);
} else {
addSyntheticLocal("$a", STT_NOTYPE, off, 0, isec);
@ -399,7 +398,7 @@ bool ARM::needsThunk(RelExpr expr, RelType type, const InputFile *file,
case R_ARM_JUMP24:
// Source is ARM, all PLT entries are ARM so no interworking required.
// Otherwise we need to interwork if STT_FUNC Symbol has bit 0 set (Thumb).
assert(!useThumbPLTs() &&
assert(!useThumbPLTs(ctx) &&
"If the source is ARM, we should not need Thumb PLTs");
if (s.isFunc() && expr == R_PC && (s.getVA() & 1))
return true;
@ -413,7 +412,7 @@ bool ARM::needsThunk(RelExpr expr, RelType type, const InputFile *file,
case R_ARM_THM_JUMP24:
// Source is Thumb, when all PLT entries are ARM interworking is required.
// Otherwise we need to interwork if STT_FUNC Symbol has bit 0 clear (ARM).
if ((expr == R_PLT_PC && !useThumbPLTs()) ||
if ((expr == R_PLT_PC && !useThumbPLTs(ctx)) ||
(s.isFunc() && (s.getVA() & 1) == 0))
return true;
[[fallthrough]];
@ -683,7 +682,7 @@ void ARM::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const {
// PLT entries are always ARM state so we know we need to interwork.
assert(rel.sym); // R_ARM_THM_CALL is always reached via relocate().
bool bit0Thumb = val & 1;
bool useThumb = bit0Thumb || useThumbPLTs();
bool useThumb = bit0Thumb || useThumbPLTs(ctx);
bool isBlx = (read16(loc + 2) & 0x1000) == 0;
// lld 10.0 and before always used bit0Thumb when deciding to write a BLX
// even when type not STT_FUNC.
@ -1330,7 +1329,8 @@ private:
ArmCmseSGSection::ArmCmseSGSection(Ctx &ctx)
: SyntheticSection(llvm::ELF::SHF_ALLOC | llvm::ELF::SHF_EXECINSTR,
llvm::ELF::SHT_PROGBITS,
/*alignment=*/32, ".gnu.sgstubs") {
/*alignment=*/32, ".gnu.sgstubs"),
ctx(ctx) {
entsize = ACLESESYM_SIZE;
// The range of addresses used in the CMSE import library should be fixed.
for (auto &[_, sym] : ctx.symtab->cmseImportLib) {

View File

@ -206,7 +206,7 @@ template <class ELFT> RelType MIPS<ELFT>::getDynRel(RelType type) const {
template <class ELFT>
void MIPS<ELFT>::writeGotPlt(uint8_t *buf, const Symbol &) const {
uint64_t va = ctx.in.plt->getVA();
if (isMicroMips())
if (isMicroMips(ctx))
va |= 1;
write32(buf, va);
}
@ -256,7 +256,7 @@ static void writeMicroRelocation16(uint8_t *loc, uint64_t v, uint8_t bitsSize,
}
template <class ELFT> void MIPS<ELFT>::writePltHeader(uint8_t *buf) const {
if (isMicroMips()) {
if (isMicroMips(ctx)) {
uint64_t gotPlt = ctx.in.gotPlt->getVA();
uint64_t plt = ctx.in.plt->getVA();
// Overwrite trap instructions written by Writer::writeTrapInstr.
@ -320,7 +320,7 @@ template <class ELFT>
void MIPS<ELFT>::writePlt(uint8_t *buf, const Symbol &sym,
uint64_t pltEntryAddr) const {
uint64_t gotPltEntryAddr = sym.getGotPltVA();
if (isMicroMips()) {
if (isMicroMips(ctx)) {
// Overwrite trap instructions written by Writer::writeTrapInstr.
memset(buf, 0, pltEntrySize);

View File

@ -12,6 +12,7 @@
#include "InputFiles.h"
#include "SymbolTable.h"
#include "Target.h"
#include "Writer.h"
#include "lld/Common/ErrorHandler.h"
@ -381,7 +382,7 @@ bool elf::isMipsN32Abi(Ctx &ctx, const InputFile &f) {
}
}
bool elf::isMicroMips() { return ctx.arg.eflags & EF_MIPS_MICROMIPS; }
bool elf::isMicroMips(Ctx &ctx) { return ctx.arg.eflags & EF_MIPS_MICROMIPS; }
bool elf::isMipsR6(Ctx &ctx) {
uint32_t arch = ctx.arg.eflags & EF_MIPS_ARCH;

View File

@ -273,7 +273,7 @@ bool LinkerDriver::tryAddFatLTOFile(MemoryBufferRef mb, StringRef archiveName,
if (errorToBool(fatLTOData.takeError()))
return false;
files.push_back(
make<BitcodeFile>(*fatLTOData, archiveName, offsetInArchive, lazy));
make<BitcodeFile>(ctx, *fatLTOData, archiveName, offsetInArchive, lazy));
return true;
}
@ -300,7 +300,8 @@ void LinkerDriver::addFile(StringRef path, bool withLOption) {
if (inWholeArchive) {
for (const std::pair<MemoryBufferRef, uint64_t> &p : members) {
if (isBitcode(p.first))
files.push_back(make<BitcodeFile>(p.first, path, p.second, false));
files.push_back(
make<BitcodeFile>(ctx, p.first, path, p.second, false));
else if (!tryAddFatLTOFile(p.first, path, p.second, false))
files.push_back(createObjFile(p.first, path));
}
@ -329,7 +330,7 @@ void LinkerDriver::addFile(StringRef path, bool withLOption) {
if (!tryAddFatLTOFile(p.first, path, p.second, true))
files.push_back(createObjFile(p.first, path, true));
} else if (magic == file_magic::bitcode)
files.push_back(make<BitcodeFile>(p.first, path, p.second, true));
files.push_back(make<BitcodeFile>(ctx, p.first, path, p.second, true));
else
warn(path + ": archive member '" + p.first.getBufferIdentifier() +
"' is neither ET_REL nor LLVM bitcode");
@ -357,7 +358,7 @@ void LinkerDriver::addFile(StringRef path, bool withLOption) {
return;
}
case file_magic::bitcode:
files.push_back(make<BitcodeFile>(mbref, "", 0, inLib));
files.push_back(make<BitcodeFile>(ctx, mbref, "", 0, inLib));
break;
case file_magic::elf_relocatable:
if (!tryAddFatLTOFile(mbref, "", 0, inLib))

View File

@ -1698,7 +1698,7 @@ static uint8_t getOsAbi(const Triple &t) {
}
}
BitcodeFile::BitcodeFile(MemoryBufferRef mb, StringRef archiveName,
BitcodeFile::BitcodeFile(Ctx &ctx, MemoryBufferRef mb, StringRef archiveName,
uint64_t offsetInArchive, bool lazy)
: InputFile(BitcodeKind, mb) {
this->archiveName = archiveName;

View File

@ -326,7 +326,7 @@ private:
class BitcodeFile : public InputFile {
public:
BitcodeFile(MemoryBufferRef m, StringRef archiveName,
BitcodeFile(Ctx &, MemoryBufferRef m, StringRef archiveName,
uint64_t offsetInArchive, bool lazy);
static bool classof(const InputFile *f) { return f->kind() == BitcodeKind; }
void parse();

View File

@ -109,7 +109,7 @@ static uint64_t getSymVA(const Symbol &sym, int64_t addend) {
// a symbol value as-is (.dynamic section, `Elf_Ehdr::e_entry`
// field etc) do the same trick as compiler uses to mark microMIPS
// for CPU - set the less-significant bit.
if (ctx.arg.emachine == EM_MIPS && isMicroMips() &&
if (ctx.arg.emachine == EM_MIPS && isMicroMips(ctx) &&
((sym.stOther & STO_MIPS_MICROMIPS) || sym.hasFlag(NEEDS_COPY)))
va |= 1;
@ -177,7 +177,7 @@ uint64_t Symbol::getPltVA() const {
// While linking microMIPS code PLT code are always microMIPS
// code. Set the less-significant bit to track that fact.
// See detailed comment in the `getSymVA` function.
if (ctx.arg.emachine == EM_MIPS && isMicroMips())
if (ctx.arg.emachine == EM_MIPS && isMicroMips(ctx))
outVA |= 1;
return outVA;
}

View File

@ -2302,7 +2302,7 @@ void SymbolTableSection<ELFT>::writeTo(Ctx &ctx, uint8_t *buf) {
Symbol *sym = ent.sym;
if (sym->isInPlt() && sym->hasFlag(NEEDS_COPY))
eSym->st_other |= STO_MIPS_PLT;
if (isMicroMips()) {
if (isMicroMips(ctx)) {
// We already set the less-significant bit for symbols
// marked by the `STO_MIPS_MICROMIPS` flag and for microMIPS PLT
// records. That allows us to distinguish such symbols in

View File

@ -1322,6 +1322,7 @@ public:
uint64_t impLibMaxAddr = 0;
private:
Ctx &ctx;
SmallVector<std::pair<Symbol *, Symbol *>, 0> entries;
SmallVector<ArmCmseSGVeneer *, 0> sgVeneers;
uint64_t newEntries = 0;

View File

@ -210,6 +210,13 @@ static inline std::string getErrorLocation(const uint8_t *loc) {
void processArmCmseSymbols(Ctx &);
template <class ELFT> uint32_t calcMipsEFlags(Ctx &);
uint8_t getMipsFpAbiFlag(uint8_t oldFlag, uint8_t newFlag,
llvm::StringRef fileName);
bool isMipsN32Abi(Ctx &, const InputFile &f);
bool isMicroMips(Ctx &);
bool isMipsR6(Ctx &);
void writePPC32GlinkSection(Ctx &, uint8_t *buf, size_t numEntries);
unsigned getPPCDFormOp(unsigned secondaryOp);

View File

@ -1439,7 +1439,7 @@ template <class ELFT> void Writer<ELFT>::finalizeAddressDependentContent() {
llvm::TimeTraceScope timeScope("Finalize address dependent content");
ThunkCreator tc(ctx);
AArch64Err843419Patcher a64p(ctx);
ARMErr657417Patcher a32p;
ARMErr657417Patcher a32p(ctx);
ctx.script->assignAddresses();
// .ARM.exidx and SHF_LINK_ORDER do not require precise addresses, but they

View File

@ -48,15 +48,6 @@ void addReservedSymbols(Ctx &ctx);
bool includeInSymtab(const Symbol &b);
unsigned getSectionRank(Ctx &, OutputSection &osec);
template <class ELFT> uint32_t calcMipsEFlags(Ctx &);
uint8_t getMipsFpAbiFlag(uint8_t oldFlag, uint8_t newFlag,
llvm::StringRef fileName);
bool isMipsN32Abi(Ctx &, const InputFile &f);
bool isMicroMips();
bool isMipsR6(Ctx &);
} // namespace lld::elf
#endif