Changeset View
Changeset View
Standalone View
Standalone View
lld/trunk/ELF/Relocations.cpp
Show First 20 Lines • Show All 926 Lines • ▼ Show 20 Lines | template <class ELFT> void elf::scanRelocations(InputSectionBase &S) { | ||||
else | else | ||||
scanRelocs<ELFT>(S, S.rels<ELFT>()); | scanRelocs<ELFT>(S, S.rels<ELFT>()); | ||||
} | } | ||||
// Insert the Thunks for OutputSection OS into their designated place | // Insert the Thunks for OutputSection OS into their designated place | ||||
// in the Sections vector, and recalculate the InputSection output section | // in the Sections vector, and recalculate the InputSection output section | ||||
// offsets. | // offsets. | ||||
// This may invalidate any output section offsets stored outside of InputSection | // This may invalidate any output section offsets stored outside of InputSection | ||||
static void mergeThunks(OutputSection *OS, | template <class ELFT> | ||||
void ThunkCreator<ELFT>::mergeThunks(OutputSection *OS, | |||||
std::vector<ThunkSection *> &Thunks) { | std::vector<ThunkSection *> &Thunks) { | ||||
// Order Thunks in ascending OutSecOff | // Order Thunks in ascending OutSecOff | ||||
auto ThunkCmp = [](const ThunkSection *A, const ThunkSection *B) { | auto ThunkCmp = [](const ThunkSection *A, const ThunkSection *B) { | ||||
return A->OutSecOff < B->OutSecOff; | return A->OutSecOff < B->OutSecOff; | ||||
}; | }; | ||||
std::stable_sort(Thunks.begin(), Thunks.end(), ThunkCmp); | std::stable_sort(Thunks.begin(), Thunks.end(), ThunkCmp); | ||||
// Merge sorted vectors of Thunks and InputSections by OutSecOff | // Merge sorted vectors of Thunks and InputSections by OutSecOff | ||||
std::vector<InputSection *> Tmp; | std::vector<InputSection *> Tmp; | ||||
Show All 11 Lines | auto MergeCmp = [](const InputSection *A, const InputSection *B) { | ||||
return false; | return false; | ||||
}; | }; | ||||
std::merge(OS->Sections.begin(), OS->Sections.end(), Thunks.begin(), | std::merge(OS->Sections.begin(), OS->Sections.end(), Thunks.begin(), | ||||
Thunks.end(), std::back_inserter(Tmp), MergeCmp); | Thunks.end(), std::back_inserter(Tmp), MergeCmp); | ||||
OS->Sections = std::move(Tmp); | OS->Sections = std::move(Tmp); | ||||
OS->assignOffsets(); | OS->assignOffsets(); | ||||
} | } | ||||
// Process all relocations from the InputSections that have been assigned | |||||
// to OutputSections and redirect through Thunks if needed. | |||||
// | |||||
// createThunks must be called after scanRelocs has created the Relocations for | |||||
// each InputSection. It must be called before the static symbol table is | |||||
// finalized. If any Thunks are added to an OutputSection the output section | |||||
// offsets of the InputSections will change. | |||||
// | |||||
// FIXME: All Thunks are assumed to be in range of the relocation. Range | |||||
// extension Thunks are not yet supported. | |||||
template <class ELFT> | template <class ELFT> | ||||
bool elf::createThunks(ArrayRef<OutputSection *> OutputSections) { | ThunkSection *ThunkCreator<ELFT>::getOSThunkSec(ThunkSection *&TS, | ||||
// Track Symbols that already have a Thunk | OutputSection *OS) { | ||||
DenseMap<SymbolBody *, Thunk *> ThunkedSymbols; | |||||
// Track InputSections that have a ThunkSection placed in front | |||||
DenseMap<InputSection *, ThunkSection *> ThunkedSections; | |||||
// Track the ThunksSections that need to be inserted into an OutputSection | |||||
std::map<OutputSection *, std::vector<ThunkSection *>> ThunkSections; | |||||
// Find or create a Thunk for Body for relocation Type | |||||
auto GetThunk = [&](SymbolBody &Body, uint32_t Type) { | |||||
auto res = ThunkedSymbols.insert({&Body, nullptr}); | |||||
if (res.second == true) | |||||
res.first->second = addThunk<ELFT>(Type, Body); | |||||
return std::make_pair(res.first->second, res.second); | |||||
}; | |||||
// Find or create a ThunkSection to be placed immediately before IS | |||||
auto GetISThunkSec = [&](InputSection *IS, OutputSection *OS) { | |||||
ThunkSection *TS = ThunkedSections.lookup(IS); | |||||
if (TS) | |||||
return TS; | |||||
auto *TOS = cast<OutputSection>(IS->OutSec); | |||||
TS = make<ThunkSection>(TOS, IS->OutSecOff); | |||||
ThunkSections[TOS].push_back(TS); | |||||
ThunkedSections[IS] = TS; | |||||
return TS; | |||||
}; | |||||
// Find or create a ThunkSection to be placed as last executable section in | |||||
// OS. | |||||
auto GetOSThunkSec = [&](ThunkSection *&TS, OutputSection *OS) { | |||||
if (TS == nullptr) { | if (TS == nullptr) { | ||||
uint32_t Off = 0; | uint32_t Off = 0; | ||||
for (auto *IS : OS->Sections) { | for (auto *IS : OS->Sections) { | ||||
Off = IS->OutSecOff + IS->getSize(); | Off = IS->OutSecOff + IS->getSize(); | ||||
if ((IS->Flags & SHF_EXECINSTR) == 0) | if ((IS->Flags & SHF_EXECINSTR) == 0) | ||||
break; | break; | ||||
} | } | ||||
TS = make<ThunkSection>(OS, Off); | TS = make<ThunkSection>(OS, Off); | ||||
ThunkSections[OS].push_back(TS); | ThunkSections[OS].push_back(TS); | ||||
} | } | ||||
return TS; | return TS; | ||||
}; | } | ||||
template <class ELFT> | |||||
ThunkSection *ThunkCreator<ELFT>::getISThunkSec(InputSection *IS, | |||||
OutputSection *OS) { | |||||
ThunkSection *TS = ThunkedSections.lookup(IS); | |||||
if (TS) | |||||
return TS; | |||||
auto *TOS = cast<OutputSection>(IS->OutSec); | |||||
TS = make<ThunkSection>(TOS, IS->OutSecOff); | |||||
ThunkSections[TOS].push_back(TS); | |||||
ThunkedSections[IS] = TS; | |||||
return TS; | |||||
} | |||||
template <class ELFT> | |||||
std::pair<Thunk *, bool> ThunkCreator<ELFT>::getThunk(SymbolBody &Body, | |||||
uint32_t Type) { | |||||
auto res = ThunkedSymbols.insert({&Body, nullptr}); | |||||
if (res.second) | |||||
res.first->second = addThunk<ELFT>(Type, Body); | |||||
return std::make_pair(res.first->second, res.second); | |||||
} | |||||
// Process all relocations from the InputSections that have been assigned | |||||
// to OutputSections and redirect through Thunks if needed. | |||||
// | |||||
// createThunks must be called after scanRelocs has created the Relocations for | |||||
// each InputSection. It must be called before the static symbol table is | |||||
// finalized. If any Thunks are added to an OutputSection the output section | |||||
// offsets of the InputSections will change. | |||||
// | |||||
// FIXME: All Thunks are assumed to be in range of the relocation. Range | |||||
// extension Thunks are not yet supported. | |||||
template <class ELFT> | |||||
bool ThunkCreator<ELFT>::createThunks( | |||||
ArrayRef<OutputSection *> OutputSections) { | |||||
// Create all the Thunks and insert them into synthetic ThunkSections. The | // Create all the Thunks and insert them into synthetic ThunkSections. The | ||||
// ThunkSections are later inserted back into the OutputSection. | // ThunkSections are later inserted back into the OutputSection. | ||||
// We separate the creation of ThunkSections from the insertion of the | // We separate the creation of ThunkSections from the insertion of the | ||||
// ThunkSections back into the OutputSection as ThunkSections are not always | // ThunkSections back into the OutputSection as ThunkSections are not always | ||||
// inserted into the same OutputSection as the caller. | // inserted into the same OutputSection as the caller. | ||||
for (OutputSection *OS : OutputSections) { | for (OutputSection *OS : OutputSections) { | ||||
ThunkSection *OSTS = nullptr; | ThunkSection *OSTS = nullptr; | ||||
for (InputSection *IS : OS->Sections) { | for (InputSection *IS : OS->Sections) { | ||||
for (Relocation &Rel : IS->Relocations) { | for (Relocation &Rel : IS->Relocations) { | ||||
SymbolBody &Body = *Rel.Sym; | SymbolBody &Body = *Rel.Sym; | ||||
if (Target->needsThunk(Rel.Expr, Rel.Type, IS->File, Body)) { | if (!Target->needsThunk(Rel.Expr, Rel.Type, IS->File, Body)) | ||||
continue; | |||||
Thunk *T; | Thunk *T; | ||||
bool IsNew; | bool IsNew; | ||||
std::tie(T, IsNew) = GetThunk(Body, Rel.Type); | std::tie(T, IsNew) = getThunk(Body, Rel.Type); | ||||
if (IsNew) { | if (IsNew) { | ||||
// Find or create a ThunkSection for the new Thunk | // Find or create a ThunkSection for the new Thunk | ||||
ThunkSection *TS; | ThunkSection *TS; | ||||
if (auto *TIS = T->getTargetInputSection()) | if (auto *TIS = T->getTargetInputSection()) | ||||
TS = GetISThunkSec(TIS, OS); | TS = getISThunkSec(TIS, OS); | ||||
else | else | ||||
TS = GetOSThunkSec(OSTS, OS); | TS = getOSThunkSec(OSTS, OS); | ||||
TS->addThunk(T); | TS->addThunk(T); | ||||
} | } | ||||
// Redirect relocation to Thunk, we never go via the PLT to a Thunk | // Redirect relocation to Thunk, we never go via the PLT to a Thunk | ||||
Rel.Sym = T->ThunkSym; | Rel.Sym = T->ThunkSym; | ||||
Rel.Expr = fromPlt(Rel.Expr); | Rel.Expr = fromPlt(Rel.Expr); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
} | |||||
// Merge all created synthetic ThunkSections back into OutputSection | // Merge all created synthetic ThunkSections back into OutputSection | ||||
for (auto &KV : ThunkSections) | for (auto &KV : ThunkSections) | ||||
mergeThunks(KV.first, KV.second); | mergeThunks(KV.first, KV.second); | ||||
return !ThunkSections.empty(); | return !ThunkSections.empty(); | ||||
} | } | ||||
template void elf::scanRelocations<ELF32LE>(InputSectionBase &); | template void elf::scanRelocations<ELF32LE>(InputSectionBase &); | ||||
template void elf::scanRelocations<ELF32BE>(InputSectionBase &); | template void elf::scanRelocations<ELF32BE>(InputSectionBase &); | ||||
template void elf::scanRelocations<ELF64LE>(InputSectionBase &); | template void elf::scanRelocations<ELF64LE>(InputSectionBase &); | ||||
template void elf::scanRelocations<ELF64BE>(InputSectionBase &); | template void elf::scanRelocations<ELF64BE>(InputSectionBase &); | ||||
template bool elf::createThunks<ELF32LE>(ArrayRef<OutputSection *>); | template class elf::ThunkCreator<ELF32LE>; | ||||
template bool elf::createThunks<ELF32BE>(ArrayRef<OutputSection *>); | template class elf::ThunkCreator<ELF32BE>; | ||||
template bool elf::createThunks<ELF64LE>(ArrayRef<OutputSection *>); | template class elf::ThunkCreator<ELF64LE>; | ||||
template bool elf::createThunks<ELF64BE>(ArrayRef<OutputSection *>); | template class elf::ThunkCreator<ELF64BE>; |