Skip to content

Commit c8b5f49

Browse files
committed
Deterministically allocate GOT/PLT slots
Slots are now created during relocation scanning deterministically in input order, matching lld. The scan is now serial. .rela.dyn and .rela.plt are created once alongside .got/.plt rather than per input file. ifunc loops now iterate .plt instead of a DenseMap, which was not deterministic even under a single-threaded link. Signed-off-by: quic-areg <aregmi@qti.qualcomm.com>
1 parent 2d711a5 commit c8b5f49

25 files changed

Lines changed: 254 additions & 136 deletions

File tree

include/eld/Config/LinkerConfig.h

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -60,21 +60,19 @@ class LinkerConfig {
6060
Unset ///< Undetermine code position mode
6161
};
6262

63-
// FIXME: ARM/RISCV/X86 disable multithreading in ScanRelocations and
64-
// ApplyRelocations by default, likely to avoid non-determinism. With
65-
// dynsym order now fixed, revisit those defaults and whether per phase
66-
// granularity is still needed.
63+
// FIXME: ARM/RISCV/X86 disable multithreading in ApplyRelocations by
64+
// default, likely to avoid non-determinism. With dynsym order now fixed,
65+
// revisit those defaults and whether per phase granularity is still needed.
6766
enum EnableThreadsOpt {
6867
NoThreads = 0,
6968
AssignOutputSections = 0x1,
70-
ScanRelocations = 0x2,
7169
SyncRelocations = 0x4,
7270
CheckCrossRefs = 0x8,
7371
CreateOutputSections = 0x10,
7472
ApplyRelocations = 0x20,
7573
LinkerRelaxation = 0x40,
7674
AssignVersionScriptNodes = 0x80,
77-
AllThreads = 0x1 | 0x2 | 0x4 | 0x8 | 0x10 | 0x20 | 0x40 | 0x80,
75+
AllThreads = 0x1 | 0x4 | 0x8 | 0x10 | 0x20 | 0x40 | 0x80,
7876
};
7977

8078
enum SymDefStyle { Default, Provide, UnknownSymDefStyle };
@@ -152,10 +150,6 @@ class LinkerConfig {
152150
return EnableThreads & LinkerConfig::AssignOutputSections;
153151
}
154152

155-
bool isScanRelocationsMultiThreaded() const {
156-
return EnableThreads & LinkerConfig::ScanRelocations;
157-
}
158-
159153
bool isSyncRelocationsMultiThreaded() const {
160154
return EnableThreads & LinkerConfig::SyncRelocations;
161155
}
@@ -184,8 +178,6 @@ class LinkerConfig {
184178
EnableThreads = NoThreads;
185179
if (EnableThreadsOpt & AssignOutputSections)
186180
EnableThreads |= AssignOutputSections;
187-
if (EnableThreadsOpt & ScanRelocations)
188-
EnableThreads |= ScanRelocations;
189181
if (EnableThreadsOpt & SyncRelocations)
190182
EnableThreads |= SyncRelocations;
191183
if (EnableThreadsOpt & CheckCrossRefs)

include/eld/Input/ELFObjectFile.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,6 @@ class ELFObjectFile : public ELFFileBase {
4848
void setDynamicSections(ELFSection &GOT, ELFSection &GOTPLT, ELFSection &PLT,
4949
ELFSection &RelDyn, ELFSection &RelPLT);
5050

51-
void setDynamicRelocSections(ELFSection &RelDyn, ELFSection &RelPLT);
52-
5351
ELFSection *getRelaDyn() const { return RelaDyn; }
5452
ELFSection *getRelaPLT() const { return RelaPLT; }
5553

include/eld/Target/GNULDBackend.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1297,6 +1297,8 @@ class GNULDBackend {
12971297
ELFSection *GOTSection = nullptr;
12981298
ELFSection *GOTPLTSection = nullptr;
12991299
ELFSection *PLTSection = nullptr;
1300+
ELFSection *RelDynSection = nullptr;
1301+
ELFSection *RelPLTSection = nullptr;
13001302
LDSymbol *m_pGOTSymbol = nullptr;
13011303
llvm::DenseMap<const Relocation *, Relocation *> m_RelativeRelocMap;
13021304

lib/Core/Linker.cpp

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -169,13 +169,6 @@ bool Linker::link() {
169169
return false;
170170
}
171171

172-
// Init per-file synthetic dynamic sections.
173-
if (LinkerConfig::Object != ThisConfig->codeGenType()) {
174-
for (auto &Input : ThisModule->getObjectList())
175-
if (ELFObjectFile *ELFObj = llvm::dyn_cast<ELFObjectFile>(Input))
176-
Backend->initDynamicSections(*ELFObj);
177-
}
178-
179172
if (ThisModule->getPrinter()->isVerbose())
180173
ThisConfig->raise(Diag::merging_input_sections);
181174
{

lib/Input/ELFObjectFile.cpp

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,6 @@ void ELFObjectFile::setDynamicSections(ELFSection &PGOT, ELFSection &PGOTPLT,
4444
RelaPLT->setExcludedFromGC();
4545
}
4646

47-
void ELFObjectFile::setDynamicRelocSections(ELFSection &PRelDyn,
48-
ELFSection &PRelPLT) {
49-
RelaDyn = &PRelDyn;
50-
RelaPLT = &PRelPLT;
51-
RelaDyn->setExcludedFromGC();
52-
RelaPLT->setExcludedFromGC();
53-
}
54-
5547
void ELFObjectFile::createDWARFContext(bool Is32) {
5648
if (DebugSections.empty())
5749
return;

lib/Object/ObjectLinker.cpp

Lines changed: 5 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -2229,54 +2229,19 @@ bool ObjectLinker::scanRelocations(bool IsPartialLink) {
22292229

22302230
getTargetBackend().provideSymbols();
22312231

2232+
// Slots are allocated as relocations are scanned in input order.
22322233
std::vector<std::unique_ptr<Relocator::CopyRelocs>> AllCopyRelocs;
2233-
if (ThisConfig.options().numThreads() <= 1 ||
2234-
!ThisConfig.isScanRelocationsMultiThreaded()) {
2235-
if (ThisModule->getPrinter()->traceThreads())
2236-
ThisConfig.raise(Diag::threads_disabled) << "ScanRelocations";
2237-
for (auto &Input : ThisModule->getObjectList()) {
2238-
auto CopyRelocs = std::make_unique<Relocator::CopyRelocs>();
2239-
scanRelocationsHelper(Input, IsPartialLink, PluginVect, *CopyRelocs);
2240-
AllCopyRelocs.push_back(std::move(CopyRelocs));
2241-
}
2242-
} else {
2243-
if (ThisModule->getPrinter()->traceThreads())
2244-
ThisConfig.raise(Diag::threads_enabled)
2245-
<< "ScanRelocations" << ThisConfig.options().numThreads();
2246-
llvm::ThreadPoolInterface *Pool = ThisModule->getThreadPool();
2247-
for (auto &Input : ThisModule->getObjectList()) {
2248-
auto CopyRelocs = std::make_unique<Relocator::CopyRelocs>();
2249-
auto &CopyRelocsRef = *CopyRelocs; // must dereference in the main thread
2250-
Pool->async([&] {
2251-
scanRelocationsHelper(Input, IsPartialLink, PluginVect, CopyRelocsRef);
2252-
});
2253-
AllCopyRelocs.push_back(std::move(CopyRelocs));
2254-
}
2255-
Pool->wait();
2234+
for (auto &Input : ThisModule->getObjectList()) {
2235+
auto CopyRelocs = std::make_unique<Relocator::CopyRelocs>();
2236+
scanRelocationsHelper(Input, IsPartialLink, PluginVect, *CopyRelocs);
2237+
AllCopyRelocs.push_back(std::move(CopyRelocs));
22562238
}
22572239
// assume there is only one copy relocation type per target
22582240
Relocation::Type CopyRelocType = getTargetBackend().getCopyRelType();
22592241
for (const auto &RelocVec : AllCopyRelocs)
22602242
for (auto &Reloc : *RelocVec)
22612243
createCopyRelocation(*Reloc, CopyRelocType);
22622244

2263-
// Merge per-file relocations
2264-
if (!IsPartialLink) {
2265-
ELFObjectFile *RelocInput =
2266-
getTargetBackend().getDynamicSectionHeadersInputFile();
2267-
auto MergeRelocs = [](ELFSection &To, ELFSection &From) {
2268-
To.appendRelocations(From.getRelocations());
2269-
};
2270-
for (auto &Input : ThisModule->getObjectList())
2271-
if (ELFObjectFile *Obj = llvm::dyn_cast<ELFObjectFile>(Input))
2272-
if (Obj != RelocInput) {
2273-
if (const auto &S = Obj->getRelaDyn())
2274-
MergeRelocs(*RelocInput->getRelaDyn(), *S);
2275-
if (const auto &S = Obj->getRelaPLT())
2276-
MergeRelocs(*RelocInput->getRelaPLT(), *S);
2277-
}
2278-
}
2279-
22802245
// If there is a undefined symbol, fail the link. No point fixing the
22812246
// relocations. This is overridden by --noinhibit-exec.
22822247
if (!ThisConfig.getDiagEngine()->diagnose()) {

lib/Target/AArch64/AArch64LDBackend.cpp

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -523,8 +523,15 @@ bool AArch64LDBackend::finalizeScanRelocations() {
523523
if (!Obj)
524524
return true;
525525

526-
for (auto &[symInfo, plt] : m_PLTMap) {
527-
if (!symInfo->isIFunc() || !symInfo->hasIFuncDirectRef() ||
526+
if (!getPLT())
527+
return true;
528+
529+
for (Fragment *F : getPLT()->getFragmentList()) {
530+
auto *plt = llvm::dyn_cast<AArch64PLT>(F);
531+
if (!plt)
532+
continue;
533+
ResolveInfo *symInfo = plt->symInfo();
534+
if (!symInfo || !symInfo->isIFunc() || !symInfo->hasIFuncDirectRef() ||
528535
!symInfo->hasIFuncNeedsGOT())
529536
continue;
530537

@@ -745,7 +752,7 @@ AArch64PLT *AArch64LDBackend::createPLT(ELFObjectFile *Obj, ResolveInfo *R,
745752
*m_Module.getIRBuilder(), createGOT(GOT::GOTPLTN, Obj, R, isIRelative),
746753
getPLT(), R);
747754
// init the corresponding rel entry in .rela.plt
748-
Relocation &rela_entry = *Obj->getRelaPLT()->createOneReloc();
755+
Relocation &rela_entry = *getRelaPLT()->createOneReloc();
749756
rela_entry.setType(isIRelative ? llvm::ELF::R_AARCH64_IRELATIVE
750757
: llvm::ELF::R_AARCH64_JUMP_SLOT);
751758
rela_entry.setTargetRef(make<FragmentRef>(*P->getGOT(), 0));

lib/Target/AArch64/AArch64Relocator.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,9 @@ Relocation *helper_DynRel_init(ELFObjectFile *Obj, Relocation *R,
5656
Relocation *rela_entry = nullptr;
5757

5858
if (pType == R_AARCH64_TLSDESC)
59-
rela_entry = Obj->getRelaPLT()->createOneReloc();
59+
rela_entry = B.getRelaPLT()->createOneReloc();
6060
else
61-
rela_entry = Obj->getRelaDyn()->createOneReloc();
61+
rela_entry = B.getRelaDyn()->createOneReloc();
6262

6363
rela_entry->setType(pType);
6464
rela_entry->setTargetRef(make<FragmentRef>(*F, pOffset));

lib/Target/ARM/ARMLDBackend.cpp

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -637,8 +637,15 @@ bool ARMGNULDBackend::finalizeScanRelocations() {
637637
// holds the address of PLT[ifunc]. GOT references then resolve to this slot
638638
// rather than the GOTPLT slot, so that the GOT-loaded pointer equals the
639639
// direct-reference pointer (pointer equality).
640-
for (auto &[symInfo, plt] : m_PLTMap) {
641-
if (!symInfo->isIFunc() || !symInfo->hasIFuncDirectRef() ||
640+
if (!getPLT())
641+
return true;
642+
643+
for (Fragment *F : getPLT()->getFragmentList()) {
644+
auto *plt = llvm::dyn_cast<ARMPLT>(F);
645+
if (!plt)
646+
continue;
647+
ResolveInfo *symInfo = plt->symInfo();
648+
if (!symInfo || !symInfo->isIFunc() || !symInfo->hasIFuncDirectRef() ||
642649
!symInfo->hasIFuncNeedsGOT())
643650
continue;
644651
ARMGOT *G = createGOT(GOT::Regular, nullptr, symInfo);
@@ -1121,7 +1128,7 @@ ARMPLT *ARMGNULDBackend::createPLT(ELFObjectFile *Obj, ResolveInfo *R,
11211128
*m_Module.getIRBuilder(),
11221129
createGOT(GOT::GOTPLTN, Obj, R, hasNow || isIRelative), getPLT(), R);
11231130
// init the corresponding rel entry in .rel.plt
1124-
Relocation *rel_entry = Obj->getRelaPLT()->createOneReloc();
1131+
Relocation *rel_entry = getRelaPLT()->createOneReloc();
11251132
rel_entry->setType(isIRelative ? llvm::ELF::R_ARM_IRELATIVE
11261133
: llvm::ELF::R_ARM_JUMP_SLOT);
11271134
rel_entry->setTargetRef(make<FragmentRef>(*P->getGOT(), 0));
@@ -1189,7 +1196,6 @@ void ARMGNULDBackend::setDefaultConfigs() {
11891196
if (config().options().threadsEnabled() &&
11901197
!config().isGlobalThreadingEnabled()) {
11911198
config().disableThreadOptions(
1192-
LinkerConfig::EnableThreadsOpt::ScanRelocations |
11931199
LinkerConfig::EnableThreadsOpt::ApplyRelocations |
11941200
LinkerConfig::EnableThreadsOpt::LinkerRelaxation);
11951201
}

lib/Target/ARM/ARMRelocator.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ static Relocation *helper_DynRel_init(ELFObjectFile *Obj, Relocation *R,
8181
ResolveInfo *pSym, Fragment *F,
8282
uint32_t pOffset, Relocator::Type pType,
8383
ARMGNULDBackend &B) {
84-
Relocation *rel_entry = Obj->getRelaDyn()->createOneReloc();
84+
Relocation *rel_entry = B.getRelaDyn()->createOneReloc();
8585
rel_entry->setType(pType);
8686
rel_entry->setTargetRef(make<FragmentRef>(*F, pOffset));
8787
rel_entry->setSymInfo(pSym);

0 commit comments

Comments
 (0)