[ELF] Make ThunkCreator take ownership of thunks

This removes many SpecificAlloc instantiations and makes my lld (x86-64
Release+Assertions) smaller by ~36k.
This commit is contained in:
Fangrui Song 2024-11-19 23:16:35 -08:00
parent a52032448e
commit 37e39667cc
5 changed files with 79 additions and 63 deletions

View File

@ -1907,6 +1907,10 @@ static void forEachInputSectionDescription(
} }
} }
ThunkCreator::ThunkCreator(Ctx &ctx) : ctx(ctx) {}
ThunkCreator::~ThunkCreator() {}
// Thunk Implementation // Thunk Implementation
// //
// Thunks (sometimes called stubs, veneers or branch islands) are small pieces // Thunks (sometimes called stubs, veneers or branch islands) are small pieces
@ -2212,7 +2216,7 @@ static bool isThunkSectionCompatible(InputSection *source,
std::pair<Thunk *, bool> ThunkCreator::getThunk(InputSection *isec, std::pair<Thunk *, bool> ThunkCreator::getThunk(InputSection *isec,
Relocation &rel, uint64_t src) { Relocation &rel, uint64_t src) {
std::vector<Thunk *> *thunkVec = nullptr; SmallVector<std::unique_ptr<Thunk>, 0> *thunkVec = nullptr;
// Arm and Thumb have a PC Bias of 8 and 4 respectively, this is cancelled // Arm and Thumb have a PC Bias of 8 and 4 respectively, this is cancelled
// out in the relocation addend. We compensate for the PC bias so that // out in the relocation addend. We compensate for the PC bias so that
// an Arm and Thumb relocation to the same destination get the same keyAddend, // an Arm and Thumb relocation to the same destination get the same keyAddend,
@ -2233,17 +2237,16 @@ std::pair<Thunk *, bool> ThunkCreator::getThunk(InputSection *isec,
thunkVec = &thunkedSymbols[{rel.sym, keyAddend}]; thunkVec = &thunkedSymbols[{rel.sym, keyAddend}];
// Check existing Thunks for Sym to see if they can be reused // Check existing Thunks for Sym to see if they can be reused
for (Thunk *t : *thunkVec) for (auto &t : *thunkVec)
if (isThunkSectionCompatible(isec, t->getThunkTargetSym()->section) && if (isThunkSectionCompatible(isec, t->getThunkTargetSym()->section) &&
t->isCompatibleWith(*isec, rel) && t->isCompatibleWith(*isec, rel) &&
ctx.target->inBranchRange(rel.type, src, ctx.target->inBranchRange(rel.type, src,
t->getThunkTargetSym()->getVA(ctx, -pcBias))) t->getThunkTargetSym()->getVA(ctx, -pcBias)))
return std::make_pair(t, false); return std::make_pair(t.get(), false);
// No existing compatible Thunk in range, create a new one // No existing compatible Thunk in range, create a new one
Thunk *t = addThunk(ctx, *isec, rel); thunkVec->push_back(addThunk(ctx, *isec, rel));
thunkVec->push_back(t); return std::make_pair(thunkVec->back().get(), true);
return std::make_pair(t, true);
} }
std::pair<Thunk *, bool> ThunkCreator::getSyntheticLandingPad(Defined &d, std::pair<Thunk *, bool> ThunkCreator::getSyntheticLandingPad(Defined &d,
@ -2252,7 +2255,7 @@ std::pair<Thunk *, bool> ThunkCreator::getSyntheticLandingPad(Defined &d,
{{d.section, d.value}, a}, nullptr); {{d.section, d.value}, a}, nullptr);
if (isNew) if (isNew)
it->second = addLandingPadThunk(ctx, d, a); it->second = addLandingPadThunk(ctx, d, a);
return {it->second, isNew}; return {it->second.get(), isNew};
} }
// Return true if the relocation target is an in range Thunk. // Return true if the relocation target is an in range Thunk.

View File

@ -163,7 +163,9 @@ class InputSectionDescription;
class ThunkCreator { class ThunkCreator {
public: public:
ThunkCreator(Ctx &ctx) : ctx(ctx) {} // Thunk may be incomplete. Avoid inline ctor/dtor.
ThunkCreator(Ctx &ctx);
~ThunkCreator();
// Return true if Thunks have been added to OutputSections // Return true if Thunks have been added to OutputSections
bool createThunks(uint32_t pass, ArrayRef<OutputSection *> outputSections); bool createThunks(uint32_t pass, ArrayRef<OutputSection *> outputSections);
@ -199,9 +201,10 @@ private:
// original addend, so we cannot fold offset + addend. A nested pair is used // original addend, so we cannot fold offset + addend. A nested pair is used
// because DenseMapInfo is not specialized for std::tuple. // because DenseMapInfo is not specialized for std::tuple.
llvm::DenseMap<std::pair<std::pair<SectionBase *, uint64_t>, int64_t>, llvm::DenseMap<std::pair<std::pair<SectionBase *, uint64_t>, int64_t>,
std::vector<Thunk *>> SmallVector<std::unique_ptr<Thunk>, 0>>
thunkedSymbolsBySectionAndAddend; thunkedSymbolsBySectionAndAddend;
llvm::DenseMap<std::pair<Symbol *, int64_t>, std::vector<Thunk *>> llvm::DenseMap<std::pair<Symbol *, int64_t>,
SmallVector<std::unique_ptr<Thunk>, 0>>
thunkedSymbols; thunkedSymbols;
// Find a Thunk from the Thunks symbol definition, we can use this to find // Find a Thunk from the Thunks symbol definition, we can use this to find
@ -220,7 +223,7 @@ private:
// to be reached via thunks that use indirect branches. A destination // to be reached via thunks that use indirect branches. A destination
// needs at most one landing pad as that can be reused by all callers. // needs at most one landing pad as that can be reused by all callers.
llvm::DenseMap<std::pair<std::pair<SectionBase *, uint64_t>, int64_t>, llvm::DenseMap<std::pair<std::pair<SectionBase *, uint64_t>, int64_t>,
Thunk *> std::unique_ptr<Thunk>>
landingPadsBySectionAndAddend; landingPadsBySectionAndAddend;
// All the nonLandingPad thunks that have been created, in order of creation. // All the nonLandingPad thunks that have been created, in order of creation.

View File

@ -1372,15 +1372,16 @@ Thunk::Thunk(Ctx &ctx, Symbol &d, int64_t a)
Thunk::~Thunk() = default; Thunk::~Thunk() = default;
static Thunk *addThunkAArch64(Ctx &ctx, RelType type, Symbol &s, int64_t a) { static std::unique_ptr<Thunk> addThunkAArch64(Ctx &ctx, RelType type, Symbol &s,
int64_t a) {
assert(is_contained({R_AARCH64_CALL26, R_AARCH64_JUMP26, R_AARCH64_PLT32}, assert(is_contained({R_AARCH64_CALL26, R_AARCH64_JUMP26, R_AARCH64_PLT32},
type)); type));
bool mayNeedLandingPad = bool mayNeedLandingPad =
(ctx.arg.andFeatures & GNU_PROPERTY_AARCH64_FEATURE_1_BTI) && (ctx.arg.andFeatures & GNU_PROPERTY_AARCH64_FEATURE_1_BTI) &&
!isAArch64BTILandingPad(ctx, s, a); !isAArch64BTILandingPad(ctx, s, a);
if (ctx.arg.picThunk) if (ctx.arg.picThunk)
return make<AArch64ADRPThunk>(ctx, s, a, mayNeedLandingPad); return std::make_unique<AArch64ADRPThunk>(ctx, s, a, mayNeedLandingPad);
return make<AArch64ABSLongThunk>(ctx, s, a, mayNeedLandingPad); return std::make_unique<AArch64ABSLongThunk>(ctx, s, a, mayNeedLandingPad);
} }
// Creates a thunk for long branches or Thumb-ARM interworking. // Creates a thunk for long branches or Thumb-ARM interworking.
@ -1391,7 +1392,8 @@ static Thunk *addThunkAArch64(Ctx &ctx, RelType type, Symbol &s, int64_t a) {
// //
// TODO: use B for short Thumb->Arm thunks instead of LDR (this doesn't work for // TODO: use B for short Thumb->Arm thunks instead of LDR (this doesn't work for
// Arm->Thumb, as in Arm state no BX PC trick; it doesn't switch state). // Arm->Thumb, as in Arm state no BX PC trick; it doesn't switch state).
static Thunk *addThunkArmv4(Ctx &ctx, RelType reloc, Symbol &s, int64_t a) { static std::unique_ptr<Thunk> addThunkArmv4(Ctx &ctx, RelType reloc, Symbol &s,
int64_t a) {
bool thumb_target = s.getVA(ctx, a) & 1; bool thumb_target = s.getVA(ctx, a) & 1;
switch (reloc) { switch (reloc) {
@ -1401,21 +1403,21 @@ static Thunk *addThunkArmv4(Ctx &ctx, RelType reloc, Symbol &s, int64_t a) {
case R_ARM_CALL: case R_ARM_CALL:
if (ctx.arg.picThunk) { if (ctx.arg.picThunk) {
if (thumb_target) if (thumb_target)
return make<ARMV4PILongBXThunk>(ctx, s, a); return std::make_unique<ARMV4PILongBXThunk>(ctx, s, a);
return make<ARMV4PILongThunk>(ctx, s, a); return std::make_unique<ARMV4PILongThunk>(ctx, s, a);
} }
if (thumb_target) if (thumb_target)
return make<ARMV4ABSLongBXThunk>(ctx, s, a); return std::make_unique<ARMV4ABSLongBXThunk>(ctx, s, a);
return make<ARMV5LongLdrPcThunk>(ctx, s, a); return std::make_unique<ARMV5LongLdrPcThunk>(ctx, s, a);
case R_ARM_THM_CALL: case R_ARM_THM_CALL:
if (ctx.arg.picThunk) { if (ctx.arg.picThunk) {
if (thumb_target) if (thumb_target)
return make<ThumbV4PILongThunk>(ctx, s, a); return std::make_unique<ThumbV4PILongThunk>(ctx, s, a);
return make<ThumbV4PILongBXThunk>(ctx, s, a); return std::make_unique<ThumbV4PILongBXThunk>(ctx, s, a);
} }
if (thumb_target) if (thumb_target)
return make<ThumbV4ABSLongThunk>(ctx, s, a); return std::make_unique<ThumbV4ABSLongThunk>(ctx, s, a);
return make<ThumbV4ABSLongBXThunk>(ctx, s, a); return std::make_unique<ThumbV4ABSLongBXThunk>(ctx, s, a);
} }
Fatal(ctx) << "relocation " << reloc << " to " << &s Fatal(ctx) << "relocation " << reloc << " to " << &s
<< " not supported for Armv4 or Armv4T target"; << " not supported for Armv4 or Armv4T target";
@ -1427,7 +1429,8 @@ static Thunk *addThunkArmv4(Ctx &ctx, RelType reloc, Symbol &s, int64_t a) {
// - MOVT and MOVW instructions cannot be used // - MOVT and MOVW instructions cannot be used
// - Only Thumb relocation that can generate a Thunk is a BL, this can always // - Only Thumb relocation that can generate a Thunk is a BL, this can always
// be transformed into a BLX // be transformed into a BLX
static Thunk *addThunkArmv5v6(Ctx &ctx, RelType reloc, Symbol &s, int64_t a) { static std::unique_ptr<Thunk> addThunkArmv5v6(Ctx &ctx, RelType reloc,
Symbol &s, int64_t a) {
switch (reloc) { switch (reloc) {
case R_ARM_PC24: case R_ARM_PC24:
case R_ARM_PLT32: case R_ARM_PLT32:
@ -1435,8 +1438,8 @@ static Thunk *addThunkArmv5v6(Ctx &ctx, RelType reloc, Symbol &s, int64_t a) {
case R_ARM_CALL: case R_ARM_CALL:
case R_ARM_THM_CALL: case R_ARM_THM_CALL:
if (ctx.arg.picThunk) if (ctx.arg.picThunk)
return make<ARMV4PILongBXThunk>(ctx, s, a); return std::make_unique<ARMV4PILongBXThunk>(ctx, s, a);
return make<ARMV5LongLdrPcThunk>(ctx, s, a); return std::make_unique<ARMV5LongLdrPcThunk>(ctx, s, a);
} }
Fatal(ctx) << "relocation " << reloc << " to " << &s Fatal(ctx) << "relocation " << reloc << " to " << &s
<< " not supported for Armv5 or Armv6 targets"; << " not supported for Armv5 or Armv6 targets";
@ -1448,8 +1451,8 @@ static Thunk *addThunkArmv5v6(Ctx &ctx, RelType reloc, Symbol &s, int64_t a) {
// - MOVT and MOVW instructions cannot be used. // - MOVT and MOVW instructions cannot be used.
// - Only a limited number of instructions can access registers r8 and above // - Only a limited number of instructions can access registers r8 and above
// - No interworking support is needed (all Thumb). // - No interworking support is needed (all Thumb).
static Thunk *addThunkV6M(Ctx &ctx, const InputSection &isec, RelType reloc, static std::unique_ptr<Thunk> addThunkV6M(Ctx &ctx, const InputSection &isec,
Symbol &s, int64_t a) { RelType reloc, Symbol &s, int64_t a) {
const bool isPureCode = isec.getParent()->flags & SHF_ARM_PURECODE; const bool isPureCode = isec.getParent()->flags & SHF_ARM_PURECODE;
switch (reloc) { switch (reloc) {
case R_ARM_THM_JUMP19: case R_ARM_THM_JUMP19:
@ -1457,7 +1460,7 @@ static Thunk *addThunkV6M(Ctx &ctx, const InputSection &isec, RelType reloc,
case R_ARM_THM_CALL: case R_ARM_THM_CALL:
if (ctx.arg.isPic) { if (ctx.arg.isPic) {
if (!isPureCode) if (!isPureCode)
return make<ThumbV6MPILongThunk>(ctx, s, a); return std::make_unique<ThumbV6MPILongThunk>(ctx, s, a);
Fatal(ctx) Fatal(ctx)
<< "relocation " << reloc << " to " << &s << "relocation " << reloc << " to " << &s
@ -1466,8 +1469,8 @@ static Thunk *addThunkV6M(Ctx &ctx, const InputSection &isec, RelType reloc,
llvm_unreachable(""); llvm_unreachable("");
} }
if (isPureCode) if (isPureCode)
return make<ThumbV6MABSXOLongThunk>(ctx, s, a); return std::make_unique<ThumbV6MABSXOLongThunk>(ctx, s, a);
return make<ThumbV6MABSLongThunk>(ctx, s, a); return std::make_unique<ThumbV6MABSLongThunk>(ctx, s, a);
} }
Fatal(ctx) << "relocation " << reloc << " to " << &s Fatal(ctx) << "relocation " << reloc << " to " << &s
<< " not supported for Armv6-M targets"; << " not supported for Armv6-M targets";
@ -1475,8 +1478,8 @@ static Thunk *addThunkV6M(Ctx &ctx, const InputSection &isec, RelType reloc,
} }
// Creates a thunk for Thumb-ARM interworking or branch range extension. // Creates a thunk for Thumb-ARM interworking or branch range extension.
static Thunk *addThunkArm(Ctx &ctx, const InputSection &isec, RelType reloc, static std::unique_ptr<Thunk> addThunkArm(Ctx &ctx, const InputSection &isec,
Symbol &s, int64_t a) { RelType reloc, Symbol &s, int64_t a) {
// Decide which Thunk is needed based on: // Decide which Thunk is needed based on:
// Available instruction set // Available instruction set
// - An Arm Thunk can only be used if Arm state is available. // - An Arm Thunk can only be used if Arm state is available.
@ -1508,47 +1511,49 @@ static Thunk *addThunkArm(Ctx &ctx, const InputSection &isec, RelType reloc,
case R_ARM_JUMP24: case R_ARM_JUMP24:
case R_ARM_CALL: case R_ARM_CALL:
if (ctx.arg.picThunk) if (ctx.arg.picThunk)
return make<ARMV7PILongThunk>(ctx, s, a); return std::make_unique<ARMV7PILongThunk>(ctx, s, a);
return make<ARMV7ABSLongThunk>(ctx, s, a); return std::make_unique<ARMV7ABSLongThunk>(ctx, s, a);
case R_ARM_THM_JUMP19: case R_ARM_THM_JUMP19:
case R_ARM_THM_JUMP24: case R_ARM_THM_JUMP24:
case R_ARM_THM_CALL: case R_ARM_THM_CALL:
if (ctx.arg.picThunk) if (ctx.arg.picThunk)
return make<ThumbV7PILongThunk>(ctx, s, a); return std::make_unique<ThumbV7PILongThunk>(ctx, s, a);
return make<ThumbV7ABSLongThunk>(ctx, s, a); return std::make_unique<ThumbV7ABSLongThunk>(ctx, s, a);
} }
llvm_unreachable(""); llvm_unreachable("");
} }
static Thunk *addThunkAVR(Ctx &ctx, RelType type, Symbol &s, int64_t a) { static std::unique_ptr<Thunk> addThunkAVR(Ctx &ctx, RelType type, Symbol &s,
int64_t a) {
switch (type) { switch (type) {
case R_AVR_LO8_LDI_GS: case R_AVR_LO8_LDI_GS:
case R_AVR_HI8_LDI_GS: case R_AVR_HI8_LDI_GS:
return make<AVRThunk>(ctx, s, a); return std::make_unique<AVRThunk>(ctx, s, a);
default: default:
llvm_unreachable(""); llvm_unreachable("");
} }
} }
static Thunk *addThunkMips(Ctx &ctx, RelType type, Symbol &s) { static std::unique_ptr<Thunk> addThunkMips(Ctx &ctx, RelType type, Symbol &s) {
if ((s.stOther & STO_MIPS_MICROMIPS) && isMipsR6(ctx)) if ((s.stOther & STO_MIPS_MICROMIPS) && isMipsR6(ctx))
return make<MicroMipsR6Thunk>(ctx, s); return std::make_unique<MicroMipsR6Thunk>(ctx, s);
if (s.stOther & STO_MIPS_MICROMIPS) if (s.stOther & STO_MIPS_MICROMIPS)
return make<MicroMipsThunk>(ctx, s); return std::make_unique<MicroMipsThunk>(ctx, s);
return make<MipsThunk>(ctx, s); return std::make_unique<MipsThunk>(ctx, s);
} }
static Thunk *addThunkPPC32(Ctx &ctx, const InputSection &isec, static std::unique_ptr<Thunk> addThunkPPC32(Ctx &ctx, const InputSection &isec,
const Relocation &rel, Symbol &s) { const Relocation &rel, Symbol &s) {
assert((rel.type == R_PPC_LOCAL24PC || rel.type == R_PPC_REL24 || assert((rel.type == R_PPC_LOCAL24PC || rel.type == R_PPC_REL24 ||
rel.type == R_PPC_PLTREL24) && rel.type == R_PPC_PLTREL24) &&
"unexpected relocation type for thunk"); "unexpected relocation type for thunk");
if (s.isInPlt(ctx)) if (s.isInPlt(ctx))
return make<PPC32PltCallStub>(ctx, isec, rel, s); return std::make_unique<PPC32PltCallStub>(ctx, isec, rel, s);
return make<PPC32LongThunk>(ctx, s, rel.addend); return std::make_unique<PPC32LongThunk>(ctx, s, rel.addend);
} }
static Thunk *addThunkPPC64(Ctx &ctx, RelType type, Symbol &s, int64_t a) { static std::unique_ptr<Thunk> addThunkPPC64(Ctx &ctx, RelType type, Symbol &s,
int64_t a) {
assert((type == R_PPC64_REL14 || type == R_PPC64_REL24 || assert((type == R_PPC64_REL14 || type == R_PPC64_REL24 ||
type == R_PPC64_REL24_NOTOC) && type == R_PPC64_REL24_NOTOC) &&
"unexpected relocation type for thunk"); "unexpected relocation type for thunk");
@ -1558,27 +1563,30 @@ static Thunk *addThunkPPC64(Ctx &ctx, RelType type, Symbol &s, int64_t a) {
if (type == R_PPC64_REL24_NOTOC) if (type == R_PPC64_REL24_NOTOC)
ctx.target->ppc64DynamicSectionOpt = 0x2; ctx.target->ppc64DynamicSectionOpt = 0x2;
if (s.isInPlt(ctx)) if (s.isInPlt(ctx)) {
return type == R_PPC64_REL24_NOTOC if (type == R_PPC64_REL24_NOTOC)
? (Thunk *)make<PPC64R12SetupStub>(ctx, s, /*gotPlt=*/true) return std::make_unique<PPC64R12SetupStub>(ctx, s,
: (Thunk *)make<PPC64PltCallStub>(ctx, s); /*gotPlt=*/true);
return std::make_unique<PPC64PltCallStub>(ctx, s);
}
// This check looks at the st_other bits of the callee. If the value is 1 // This check looks at the st_other bits of the callee. If the value is 1
// then the callee clobbers the TOC and we need an R2 save stub when RelType // then the callee clobbers the TOC and we need an R2 save stub when RelType
// is R_PPC64_REL14 or R_PPC64_REL24. // is R_PPC64_REL14 or R_PPC64_REL24.
if ((type == R_PPC64_REL14 || type == R_PPC64_REL24) && (s.stOther >> 5) == 1) if ((type == R_PPC64_REL14 || type == R_PPC64_REL24) && (s.stOther >> 5) == 1)
return make<PPC64R2SaveStub>(ctx, s, a); return std::make_unique<PPC64R2SaveStub>(ctx, s, a);
if (type == R_PPC64_REL24_NOTOC) if (type == R_PPC64_REL24_NOTOC)
return make<PPC64R12SetupStub>(ctx, s, /*gotPlt=*/false); return std::make_unique<PPC64R12SetupStub>(ctx, s, /*gotPlt=*/false);
if (ctx.arg.picThunk) if (ctx.arg.picThunk)
return make<PPC64PILongBranchThunk>(ctx, s, a); return std::make_unique<PPC64PILongBranchThunk>(ctx, s, a);
return make<PPC64PDLongBranchThunk>(ctx, s, a); return std::make_unique<PPC64PDLongBranchThunk>(ctx, s, a);
} }
Thunk *elf::addThunk(Ctx &ctx, const InputSection &isec, Relocation &rel) { std::unique_ptr<Thunk> elf::addThunk(Ctx &ctx, const InputSection &isec,
Relocation &rel) {
Symbol &s = *rel.sym; Symbol &s = *rel.sym;
int64_t a = rel.addend; int64_t a = rel.addend;
@ -1600,10 +1608,10 @@ Thunk *elf::addThunk(Ctx &ctx, const InputSection &isec, Relocation &rel) {
} }
} }
Thunk *elf::addLandingPadThunk(Ctx &ctx, Symbol &s, int64_t a) { std::unique_ptr<Thunk> elf::addLandingPadThunk(Ctx &ctx, Symbol &s, int64_t a) {
switch (ctx.arg.emachine) { switch (ctx.arg.emachine) {
case EM_AARCH64: case EM_AARCH64:
return make<AArch64BTILandingPadThunk>(ctx, s, a); return std::make_unique<AArch64BTILandingPadThunk>(ctx, s, a);
default: default:
llvm_unreachable("add landing pad only supported for AArch64"); llvm_unreachable("add landing pad only supported for AArch64");
} }

View File

@ -76,11 +76,12 @@ public:
// For a Relocation to symbol S create a Thunk to be added to a synthetic // For a Relocation to symbol S create a Thunk to be added to a synthetic
// ThunkSection. // ThunkSection.
Thunk *addThunk(Ctx &, const InputSection &isec, Relocation &rel); std::unique_ptr<Thunk> addThunk(Ctx &, const InputSection &isec,
Relocation &rel);
// Create a landing pad Thunk for use when indirect branches from Thunks // Create a landing pad Thunk for use when indirect branches from Thunks
// are restricted. // are restricted.
Thunk *addLandingPadThunk(Ctx &, Symbol &s, int64_t a); std::unique_ptr<Thunk> addLandingPadThunk(Ctx &, Symbol &s, int64_t a);
void writePPC32PltCallStub(Ctx &, uint8_t *buf, uint64_t gotPltVA, void writePPC32PltCallStub(Ctx &, uint8_t *buf, uint64_t gotPltVA,
const InputFile *file, int64_t addend); const InputFile *file, int64_t addend);

View File

@ -49,7 +49,7 @@ template <class ELFT> class Writer {
public: public:
LLVM_ELF_IMPORT_TYPES_ELFT(ELFT) LLVM_ELF_IMPORT_TYPES_ELFT(ELFT)
Writer(Ctx &ctx) : ctx(ctx), buffer(ctx.e.outputBuffer) {} Writer(Ctx &ctx) : ctx(ctx), buffer(ctx.e.outputBuffer), tc(ctx) {}
void run(); void run();
@ -82,6 +82,8 @@ private:
Ctx &ctx; Ctx &ctx;
std::unique_ptr<FileOutputBuffer> &buffer; std::unique_ptr<FileOutputBuffer> &buffer;
// ThunkCreator holds Thunks that are used at writeTo time.
ThunkCreator tc;
void addRelIpltSymbols(); void addRelIpltSymbols();
void addStartEndSymbols(); void addStartEndSymbols();
@ -1448,7 +1450,6 @@ static void finalizeSynthetic(Ctx &ctx, SyntheticSection *sec) {
// in Writer<ELFT>::finalizeSections(). // in Writer<ELFT>::finalizeSections().
template <class ELFT> void Writer<ELFT>::finalizeAddressDependentContent() { template <class ELFT> void Writer<ELFT>::finalizeAddressDependentContent() {
llvm::TimeTraceScope timeScope("Finalize address dependent content"); llvm::TimeTraceScope timeScope("Finalize address dependent content");
ThunkCreator tc(ctx);
AArch64Err843419Patcher a64p(ctx); AArch64Err843419Patcher a64p(ctx);
ARMErr657417Patcher a32p(ctx); ARMErr657417Patcher a32p(ctx);
ctx.script->assignAddresses(); ctx.script->assignAddresses();