Add support for processing .eh_frame.
This adds support for:
* Uniquing CIEs
* Dropping FDEs that point to dropped sections
It drops 657 488 bytes from the .eh_frame of a Release+Asserts clang.
The link time impact is smallish. Linking clang with a Release+Asserts
lld goes from 0.488064805 seconds to 0.504763060 seconds (1.034 X slower).
llvm-svn: 252790
diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index 5b4a560..b60fc7e 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -42,9 +42,10 @@
void copyLocalSymbols();
void createSections();
template <bool isRela>
- void scanRelocs(InputSection<ELFT> &C,
+ void scanRelocs(InputSectionBase<ELFT> &C,
iterator_range<const Elf_Rel_Impl<ELFT, isRela> *> Rels);
void scanRelocs(InputSection<ELFT> &C);
+ void scanRelocs(InputSectionBase<ELFT> &S, const Elf_Shdr &RelSec);
void assignAddresses();
void openFile(StringRef OutputPath);
void writeHeader();
@@ -66,6 +67,7 @@
SpecificBumpPtrAllocator<OutputSection<ELFT>> SecAlloc;
SpecificBumpPtrAllocator<MergeOutputSection<ELFT>> MSecAlloc;
+ SpecificBumpPtrAllocator<EHOutputSection<ELFT>> EHSecAlloc;
BumpPtrAllocator Alloc;
std::vector<OutputSectionBase<ELFT> *> OutputSections;
unsigned getNumSections() const { return OutputSections.size() + 1; }
@@ -181,7 +183,7 @@
template <class ELFT>
template <bool isRela>
void Writer<ELFT>::scanRelocs(
- InputSection<ELFT> &C,
+ InputSectionBase<ELFT> &C,
iterator_range<const Elf_Rel_Impl<ELFT, isRela> *> Rels) {
typedef Elf_Rel_Impl<ELFT, isRela> RelType;
const ObjectFile<ELFT> &File = *C.getFile();
@@ -255,18 +257,21 @@
}
template <class ELFT> void Writer<ELFT>::scanRelocs(InputSection<ELFT> &C) {
- ObjectFile<ELFT> *File = C.getFile();
- ELFFile<ELFT> &EObj = File->getObj();
-
if (!(C.getSectionHdr()->sh_flags & SHF_ALLOC))
return;
- for (const Elf_Shdr *RelSec : C.RelocSections) {
- if (RelSec->sh_type == SHT_RELA)
- scanRelocs(C, EObj.relas(RelSec));
- else
- scanRelocs(C, EObj.rels(RelSec));
- }
+ for (const Elf_Shdr *RelSec : C.RelocSections)
+ scanRelocs(C, *RelSec);
+}
+
+template <class ELFT>
+void Writer<ELFT>::scanRelocs(InputSectionBase<ELFT> &S,
+ const Elf_Shdr &RelSec) {
+ ELFFile<ELFT> &EObj = S.getFile()->getObj();
+ if (RelSec.sh_type == SHT_RELA)
+ scanRelocs(S, EObj.relas(&RelSec));
+ else
+ scanRelocs(S, EObj.rels(&RelSec));
}
template <class ELFT>
@@ -487,8 +492,8 @@
// For SHF_MERGE we create different output sections for each sh_entsize.
// This makes each output section simple and keeps a single level
// mapping from input to output.
- auto *IS = dyn_cast<InputSection<ELFT>>(C);
- uintX_t EntSize = IS ? 0 : H->sh_entsize;
+ typename InputSectionBase<ELFT>::Kind K = C->SectionKind;
+ uintX_t EntSize = K != InputSectionBase<ELFT>::Merge ? 0 : H->sh_entsize;
uint32_t OutType = H->sh_type;
if (OutType == SHT_PROGBITS && C->getSectionName() == ".eh_frame" &&
Config->EMachine == EM_X86_64)
@@ -497,20 +502,37 @@
OutType, OutFlags, EntSize};
OutputSectionBase<ELFT> *&Sec = Map[Key];
if (!Sec) {
- if (IS)
+ switch (K) {
+ case InputSectionBase<ELFT>::Regular:
Sec = new (SecAlloc.Allocate())
OutputSection<ELFT>(Key.Name, Key.Type, Key.Flags);
- else
+ break;
+ case InputSectionBase<ELFT>::EHFrame:
+ Sec = new (EHSecAlloc.Allocate())
+ EHOutputSection<ELFT>(Key.Name, Key.Type, Key.Flags);
+ break;
+ case InputSectionBase<ELFT>::Merge:
Sec = new (MSecAlloc.Allocate())
MergeOutputSection<ELFT>(Key.Name, Key.Type, Key.Flags);
+ break;
+ }
OutputSections.push_back(Sec);
RegularSections.push_back(Sec);
}
- if (IS)
- static_cast<OutputSection<ELFT> *>(Sec)->addSection(IS);
- else
+ switch (K) {
+ case InputSectionBase<ELFT>::Regular:
+ static_cast<OutputSection<ELFT> *>(Sec)
+ ->addSection(cast<InputSection<ELFT>>(C));
+ break;
+ case InputSectionBase<ELFT>::EHFrame:
+ static_cast<EHOutputSection<ELFT> *>(Sec)
+ ->addSection(cast<EHInputSection<ELFT>>(C));
+ break;
+ case InputSectionBase<ELFT>::Merge:
static_cast<MergeOutputSection<ELFT> *>(Sec)
->addSection(cast<MergeInputSection<ELFT>>(C));
+ break;
+ }
}
}
@@ -554,11 +576,17 @@
// Scan relocations. This must be done after every symbol is declared so that
// we can correctly decide if a dynamic relocation is needed.
- for (const std::unique_ptr<ObjectFile<ELFT>> &F : Symtab.getObjectFiles())
- for (InputSectionBase<ELFT> *B : F->getSections())
- if (auto *S = dyn_cast_or_null<InputSection<ELFT>>(B))
+ for (const std::unique_ptr<ObjectFile<ELFT>> &F : Symtab.getObjectFiles()) {
+ for (InputSectionBase<ELFT> *B : F->getSections()) {
+ if (auto *S = dyn_cast_or_null<InputSection<ELFT>>(B)) {
if (S != &InputSection<ELFT>::Discarded && S->isLive())
scanRelocs(*S);
+ } else if (auto *S = dyn_cast_or_null<EHInputSection<ELFT>>(B)) {
+ if (S->RelocSection)
+ scanRelocs(*S, *S->RelocSection);
+ }
+ }
+ }
std::vector<DefinedCommon<ELFT> *> CommonSymbols;
std::vector<SharedSymbol<ELFT> *> SharedCopySymbols;