[lld] r252790 - Add support for processing .eh_frame.
Rafael Espindola via llvm-commits
llvm-commits at lists.llvm.org
Wed Nov 11 11:54:15 PST 2015
Author: rafael
Date: Wed Nov 11 13:54:14 2015
New Revision: 252790
URL: http://llvm.org/viewvc/llvm-project?rev=252790&view=rev
Log:
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).
Added:
lld/trunk/test/elf2/Inputs/invalid-multiple-eh-relocs.elf
lld/trunk/test/elf2/eh-frame-merge.s
lld/trunk/test/elf2/eh-frame-plt.s
lld/trunk/test/elf2/invalid-cie-length.s
lld/trunk/test/elf2/invalid-cie-length2.s
lld/trunk/test/elf2/invalid-cie-reference.s
lld/trunk/test/elf2/invalid-fde-rel.s
Modified:
lld/trunk/ELF/InputFiles.cpp
lld/trunk/ELF/InputSection.cpp
lld/trunk/ELF/InputSection.h
lld/trunk/ELF/OutputSections.cpp
lld/trunk/ELF/OutputSections.h
lld/trunk/ELF/Writer.cpp
lld/trunk/test/elf2/invalid-elf.test
Modified: lld/trunk/ELF/InputFiles.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputFiles.cpp?rev=252790&r1=252789&r2=252790&view=diff
==============================================================================
--- lld/trunk/ELF/InputFiles.cpp (original)
+++ lld/trunk/ELF/InputFiles.cpp Wed Nov 11 13:54:14 2015
@@ -205,19 +205,29 @@ void elf2::ObjectFile<ELFT>::initializeS
Sections[RelocatedSectionIndex];
if (!RelocatedSection)
error("Unsupported relocation reference");
- if (auto *S = dyn_cast<InputSection<ELFT>>(RelocatedSection))
+ if (auto *S = dyn_cast<InputSection<ELFT>>(RelocatedSection)) {
S->RelocSections.push_back(&Sec);
- else
+ } else if (auto *S = dyn_cast<EHInputSection<ELFT>>(RelocatedSection)) {
+ if (S->RelocSection)
+ error("Multiple relocation sections to .eh_frame are not supported");
+ S->RelocSection = &Sec;
+ } else {
error("Relocations pointing to SHF_MERGE are not supported");
+ }
break;
}
- default:
- if (shouldMerge<ELFT>(Sec))
+ default: {
+ ErrorOr<StringRef> NameOrErr = this->ELFObj.getSectionName(&Sec);
+ error(NameOrErr);
+ if (*NameOrErr == ".eh_frame")
+ Sections[I] = new (this->Alloc) EHInputSection<ELFT>(this, &Sec);
+ else if (shouldMerge<ELFT>(Sec))
Sections[I] = new (this->Alloc) MergeInputSection<ELFT>(this, &Sec);
else
Sections[I] = new (this->Alloc) InputSection<ELFT>(this, &Sec);
break;
}
+ }
}
}
Modified: lld/trunk/ELF/InputSection.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputSection.cpp?rev=252790&r1=252789&r2=252790&view=diff
==============================================================================
--- lld/trunk/ELF/InputSection.cpp (original)
+++ lld/trunk/ELF/InputSection.cpp Wed Nov 11 13:54:14 2015
@@ -47,6 +47,8 @@ InputSectionBase<ELFT>::getOffset(uintX_
switch (SectionKind) {
case Regular:
return cast<InputSection<ELFT>>(this)->OutSecOff + Offset;
+ case EHFrame:
+ return cast<EHInputSection<ELFT>>(this)->getOffset(Offset);
case Merge:
return cast<MergeInputSection<ELFT>>(this)->getOffset(Offset);
}
@@ -93,13 +95,17 @@ template <class ELFT>
template <bool isRela>
void InputSectionBase<ELFT>::relocate(
uint8_t *Buf, uint8_t *BufEnd,
- iterator_range<const Elf_Rel_Impl<ELFT, isRela> *> Rels, uintX_t BaseAddr) {
+ iterator_range<const Elf_Rel_Impl<ELFT, isRela> *> Rels) {
typedef Elf_Rel_Impl<ELFT, isRela> RelType;
for (const RelType &RI : Rels) {
uint32_t SymIndex = RI.getSymbol(Config->Mips64EL);
uint32_t Type = RI.getType(Config->Mips64EL);
- uint8_t *BufLoc = Buf + RI.r_offset;
- uintX_t AddrLoc = BaseAddr + RI.r_offset;
+ uintX_t Offset = getOffset(RI.r_offset);
+ if (Offset == (uintX_t)-1)
+ continue;
+
+ uint8_t *BufLoc = Buf + Offset;
+ uintX_t AddrLoc = OutSec->getVA() + Offset;
if (Type == Target->getTlsLocalDynamicReloc()) {
Target->relocateOne(BufLoc, BufEnd, Type, AddrLoc,
@@ -146,30 +152,59 @@ template <class ELFT> void InputSection<
memcpy(Buf + OutSecOff, Data.data(), Data.size());
ELFFile<ELFT> &EObj = this->File->getObj();
- uint8_t *Base = Buf + OutSecOff;
- uintX_t BaseAddr = this->OutSec->getVA() + OutSecOff;
+ uint8_t *BufEnd = Buf + OutSecOff + Data.size();
// Iterate over all relocation sections that apply to this section.
- for (const Elf_Shdr *RelSec : RelocSections) {
+ for (const Elf_Shdr *RelSec : this->RelocSections) {
if (RelSec->sh_type == SHT_RELA)
- this->relocate(Base, Base + Data.size(), EObj.relas(RelSec), BaseAddr);
+ this->relocate(Buf, BufEnd, EObj.relas(RelSec));
else
- this->relocate(Base, Base + Data.size(), EObj.rels(RelSec), BaseAddr);
+ this->relocate(Buf, BufEnd, EObj.rels(RelSec));
}
}
template <class ELFT>
+SplitInputSection<ELFT>::SplitInputSection(
+ ObjectFile<ELFT> *File, const Elf_Shdr *Header,
+ typename InputSectionBase<ELFT>::Kind SectionKind)
+ : InputSectionBase<ELFT>(File, Header, SectionKind) {}
+
+template <class ELFT>
+EHInputSection<ELFT>::EHInputSection(ObjectFile<ELFT> *F,
+ const Elf_Shdr *Header)
+ : SplitInputSection<ELFT>(F, Header, InputSectionBase<ELFT>::EHFrame) {}
+
+template <class ELFT>
+bool EHInputSection<ELFT>::classof(const InputSectionBase<ELFT> *S) {
+ return S->SectionKind == InputSectionBase<ELFT>::EHFrame;
+}
+
+template <class ELFT>
+typename EHInputSection<ELFT>::uintX_t
+EHInputSection<ELFT>::getOffset(uintX_t Offset) {
+ std::pair<uintX_t, uintX_t> *I = this->getRangeAndSize(Offset).first;
+ uintX_t Base = I->second;
+ if (Base == size_t(-1))
+ return -1; // Not in the output
+
+ uintX_t Addend = Offset - I->first;
+ return Base + Addend;
+}
+
+template <class ELFT>
MergeInputSection<ELFT>::MergeInputSection(ObjectFile<ELFT> *F,
const Elf_Shdr *Header)
- : InputSectionBase<ELFT>(F, Header, Base::Merge) {}
+ : SplitInputSection<ELFT>(F, Header, InputSectionBase<ELFT>::Merge) {}
template <class ELFT>
bool MergeInputSection<ELFT>::classof(const InputSectionBase<ELFT> *S) {
- return S->SectionKind == Base::Merge;
+ return S->SectionKind == InputSectionBase<ELFT>::Merge;
}
template <class ELFT>
-typename MergeInputSection<ELFT>::uintX_t
-MergeInputSection<ELFT>::getOffset(uintX_t Offset) {
+std::pair<std::pair<typename ELFFile<ELFT>::uintX_t,
+ typename ELFFile<ELFT>::uintX_t> *,
+ typename ELFFile<ELFT>::uintX_t>
+SplitInputSection<ELFT>::getRangeAndSize(uintX_t Offset) {
ArrayRef<uint8_t> D = this->getSectionData();
StringRef Data((const char *)D.data(), D.size());
uintX_t Size = Data.size();
@@ -184,6 +219,16 @@ MergeInputSection<ELFT>::getOffset(uintX
});
uintX_t End = I == Offsets.end() ? Data.size() : I->first;
--I;
+ return std::make_pair(&*I, End);
+}
+
+template <class ELFT>
+typename MergeInputSection<ELFT>::uintX_t
+MergeInputSection<ELFT>::getOffset(uintX_t Offset) {
+ std::pair<std::pair<uintX_t, uintX_t> *, size_t> T =
+ this->getRangeAndSize(Offset);
+ std::pair<uintX_t, uintX_t> *I = T.first;
+ uintX_t End = T.second;
uintX_t Start = I->first;
// Compute the Addend and if the Base is cached, return.
@@ -193,6 +238,8 @@ MergeInputSection<ELFT>::getOffset(uintX
return Base + Addend;
// Map the base to the offset in the output section and cashe it.
+ ArrayRef<uint8_t> D = this->getSectionData();
+ StringRef Data((const char *)D.data(), D.size());
StringRef Entry = Data.substr(Start, End - Start);
Base =
static_cast<MergeOutputSection<ELFT> *>(this->OutSec)->getOffset(Entry);
@@ -211,6 +258,11 @@ template class InputSection<object::ELF3
template class InputSection<object::ELF64LE>;
template class InputSection<object::ELF64BE>;
+template class EHInputSection<object::ELF32LE>;
+template class EHInputSection<object::ELF32BE>;
+template class EHInputSection<object::ELF64LE>;
+template class EHInputSection<object::ELF64BE>;
+
template class MergeInputSection<object::ELF32LE>;
template class MergeInputSection<object::ELF32BE>;
template class MergeInputSection<object::ELF64LE>;
Modified: lld/trunk/ELF/InputSection.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputSection.h?rev=252790&r1=252789&r2=252790&view=diff
==============================================================================
--- lld/trunk/ELF/InputSection.h (original)
+++ lld/trunk/ELF/InputSection.h Wed Nov 11 13:54:14 2015
@@ -35,7 +35,7 @@ protected:
ObjectFile<ELFT> *File;
public:
- enum Kind { Regular, Merge };
+ enum Kind { Regular, EHFrame, Merge };
Kind SectionKind;
InputSectionBase(ObjectFile<ELFT> *File, const Elf_Shdr *Header,
@@ -78,8 +78,7 @@ public:
template <bool isRela>
void relocate(uint8_t *Buf, uint8_t *BufEnd,
llvm::iterator_range<
- const llvm::object::Elf_Rel_Impl<ELFT, isRela> *> Rels,
- uintX_t BaseAddr);
+ const llvm::object::Elf_Rel_Impl<ELFT, isRela> *> Rels);
};
template <class ELFT>
@@ -87,15 +86,25 @@ InputSectionBase<ELFT>
InputSectionBase<ELFT>::Discarded(nullptr, nullptr,
InputSectionBase<ELFT>::Regular);
+template <class ELFT> class SplitInputSection : public InputSectionBase<ELFT> {
+ typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr;
+ typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t;
+
+public:
+ SplitInputSection(ObjectFile<ELFT> *File, const Elf_Shdr *Header,
+ typename InputSectionBase<ELFT>::Kind SectionKind);
+ std::vector<std::pair<uintX_t, uintX_t>> Offsets;
+ std::pair<std::pair<uintX_t, uintX_t> *, uintX_t>
+ getRangeAndSize(uintX_t Offset);
+};
+
// This corresponds to a SHF_MERGE section of an input file.
-template <class ELFT> class MergeInputSection : public InputSectionBase<ELFT> {
- typedef InputSectionBase<ELFT> Base;
+template <class ELFT> class MergeInputSection : public SplitInputSection<ELFT> {
typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t;
typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym Elf_Sym;
typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr;
public:
- std::vector<std::pair<uintX_t, uintX_t>> Offsets;
MergeInputSection(ObjectFile<ELFT> *F, const Elf_Shdr *Header);
static bool classof(const InputSectionBase<ELFT> *S);
// Translate an offset in the input section to an offset in the output
@@ -103,6 +112,22 @@ public:
uintX_t getOffset(uintX_t Offset);
};
+// This corresponds to a .eh_frame section of an input file.
+template <class ELFT> class EHInputSection : public SplitInputSection<ELFT> {
+public:
+ typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr;
+ typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t;
+ EHInputSection(ObjectFile<ELFT> *F, const Elf_Shdr *Header);
+ static bool classof(const InputSectionBase<ELFT> *S);
+
+ // Translate an offset in the input section to an offset in the output
+ // section.
+ uintX_t getOffset(uintX_t Offset);
+
+ // Relocation section that refer to this one.
+ const Elf_Shdr *RelocSection = nullptr;
+};
+
// This corresponds to a non SHF_MERGE section of an input file.
template <class ELFT> class InputSection : public InputSectionBase<ELFT> {
typedef InputSectionBase<ELFT> Base;
Modified: lld/trunk/ELF/OutputSections.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/OutputSections.cpp?rev=252790&r1=252789&r2=252790&view=diff
==============================================================================
--- lld/trunk/ELF/OutputSections.cpp (original)
+++ lld/trunk/ELF/OutputSections.cpp Wed Nov 11 13:54:14 2015
@@ -176,7 +176,7 @@ template <class ELFT> void RelocationSec
auto *P = reinterpret_cast<Elf_Rel *>(Buf);
Buf += EntrySize;
- const InputSection<ELFT> &C = Rel.C;
+ InputSectionBase<ELFT> &C = Rel.C;
const Elf_Rel &RI = Rel.RI;
uint32_t SymIndex = RI.getSymbol(Config->Mips64EL);
const ObjectFile<ELFT> &File = *C.getFile();
@@ -223,7 +223,7 @@ template <class ELFT> void RelocationSec
P->r_offset = Out<ELFT>::Bss->getVA() +
dyn_cast<SharedSymbol<ELFT>>(Body)->OffsetInBSS;
} else {
- P->r_offset = RI.r_offset + C.OutSec->getVA() + C.OutSecOff;
+ P->r_offset = C.getOffset(RI.r_offset) + C.OutSec->getVA();
}
uintX_t OrigAddend = 0;
@@ -789,6 +789,150 @@ template <class ELFT> void OutputSection
}
template <class ELFT>
+EHOutputSection<ELFT>::EHOutputSection(StringRef Name, uint32_t sh_type,
+ uintX_t sh_flags)
+ : OutputSectionBase<ELFT>(Name, sh_type, sh_flags) {}
+
+template <class ELFT>
+EHRegion<ELFT>::EHRegion(EHInputSection<ELFT> *S, unsigned Index)
+ : S(S), Index(Index) {}
+
+template <class ELFT> StringRef EHRegion<ELFT>::data() const {
+ ArrayRef<uint8_t> SecData = S->getSectionData();
+ ArrayRef<std::pair<uintX_t, uintX_t>> Offsets = S->Offsets;
+ size_t Start = Offsets[Index].first;
+ size_t End =
+ Index == Offsets.size() - 1 ? SecData.size() : Offsets[Index + 1].first;
+ return StringRef((const char *)SecData.data() + Start, End - Start);
+}
+
+template <class ELFT>
+Cie<ELFT>::Cie(EHInputSection<ELFT> *S, unsigned Index)
+ : EHRegion<ELFT>(S, Index) {}
+
+template <class ELFT>
+template <bool IsRela>
+void EHOutputSection<ELFT>::addSectionAux(
+ EHInputSection<ELFT> *S,
+ iterator_range<const Elf_Rel_Impl<ELFT, IsRela> *> Rels) {
+ const endianness E = ELFT::TargetEndianness;
+
+ S->OutSec = this;
+ uint32_t Align = S->getAlign();
+ if (Align > this->Header.sh_addralign)
+ this->Header.sh_addralign = Align;
+
+ Sections.push_back(S);
+
+ ArrayRef<uint8_t> SecData = S->getSectionData();
+ ArrayRef<uint8_t> D = SecData;
+ uintX_t Offset = 0;
+ auto RelI = Rels.begin();
+ auto RelE = Rels.end();
+
+ DenseMap<unsigned, unsigned> OffsetToIndex;
+ while (!D.empty()) {
+ if (D.size() < 4)
+ error("Truncated CIE/FDE length");
+ uint32_t Length = read32<E>(D.data());
+ Length += 4;
+
+ unsigned Index = S->Offsets.size();
+ S->Offsets.push_back(std::make_pair(Offset, -1));
+
+ if (Length > D.size())
+ error("CIE/FIE ends past the end of the section");
+ StringRef Entry((const char *)D.data(), Length);
+
+ while (RelI != RelE && RelI->r_offset < Offset)
+ ++RelI;
+ uintX_t NextOffset = Offset + Length;
+ bool HasReloc = RelI != RelE && RelI->r_offset < NextOffset;
+
+ uint32_t ID = read32<E>(D.data() + 4);
+ if (ID == 0) {
+ // CIE
+ Cie<ELFT> C(S, Index);
+
+ StringRef Personality;
+ if (HasReloc) {
+ uint32_t SymIndex = RelI->getSymbol(Config->Mips64EL);
+ SymbolBody &Body = *S->getFile()->getSymbolBody(SymIndex)->repl();
+ Personality = Body.getName();
+ }
+
+ std::pair<StringRef, StringRef> CieInfo(Entry, Personality);
+ auto P = CieMap.insert(std::make_pair(CieInfo, Cies.size()));
+ if (P.second) {
+ Cies.push_back(C);
+ this->Header.sh_size += Length;
+ }
+ OffsetToIndex[Offset] = P.first->second;
+ } else {
+ if (!HasReloc)
+ error("FDE doesn't reference another section");
+ InputSectionBase<ELFT> *Target = S->getRelocTarget(*RelI);
+ if (Target != &InputSection<ELFT>::Discarded && Target->isLive()) {
+ uint32_t CieOffset = Offset + 4 - ID;
+ auto I = OffsetToIndex.find(CieOffset);
+ if (I == OffsetToIndex.end())
+ error("Invalid CIE reference");
+ Cies[I->second].Fdes.push_back(EHRegion<ELFT>(S, Index));
+ this->Header.sh_size += Length;
+ }
+ }
+
+ Offset = NextOffset;
+ D = D.slice(Length);
+ }
+}
+
+template <class ELFT>
+void EHOutputSection<ELFT>::addSection(EHInputSection<ELFT> *S) {
+ const Elf_Shdr *RelSec = S->RelocSection;
+ if (!RelSec)
+ return addSectionAux(
+ S, make_range((const Elf_Rela *)nullptr, (const Elf_Rela *)nullptr));
+ ELFFile<ELFT> &Obj = S->getFile()->getObj();
+ if (RelSec->sh_type == SHT_RELA)
+ return addSectionAux(S, Obj.relas(RelSec));
+ return addSectionAux(S, Obj.rels(RelSec));
+}
+
+template <class ELFT> void EHOutputSection<ELFT>::writeTo(uint8_t *Buf) {
+ const endianness E = ELFT::TargetEndianness;
+ size_t Offset = 0;
+ for (const Cie<ELFT> &C : Cies) {
+ size_t CieOffset = Offset;
+
+ StringRef CieData = C.data();
+ memcpy(Buf + Offset, CieData.data(), CieData.size());
+ C.S->Offsets[C.Index].second = Offset;
+ Offset += CieData.size();
+
+ for (const EHRegion<ELFT> &F : C.Fdes) {
+ StringRef FdeData = F.data();
+ memcpy(Buf + Offset, FdeData.data(), 4); // Legnth
+ write32<E>(Buf + Offset + 4, Offset + 4 - CieOffset); // Pointer
+ memcpy(Buf + Offset + 8, FdeData.data() + 8, FdeData.size() - 8);
+ F.S->Offsets[F.Index].second = Offset;
+ Offset += FdeData.size();
+ }
+ }
+
+ for (EHInputSection<ELFT> *S : Sections) {
+ const Elf_Shdr *RelSec = S->RelocSection;
+ if (!RelSec)
+ continue;
+ ELFFile<ELFT> &EObj = S->getFile()->getObj();
+ if (RelSec->sh_type == SHT_RELA)
+ S->relocate(Buf, nullptr, EObj.relas(RelSec));
+ else
+ S->relocate(Buf, nullptr, EObj.relas(RelSec));
+ }
+}
+
+template <class ELFT>
MergeOutputSection<ELFT>::MergeOutputSection(StringRef Name, uint32_t sh_type,
uintX_t sh_flags)
: OutputSectionBase<ELFT>(Name, sh_type, sh_flags) {}
@@ -1141,6 +1285,11 @@ template class OutputSection<ELF32BE>;
template class OutputSection<ELF64LE>;
template class OutputSection<ELF64BE>;
+template class EHOutputSection<ELF32LE>;
+template class EHOutputSection<ELF32BE>;
+template class EHOutputSection<ELF64LE>;
+template class EHOutputSection<ELF64BE>;
+
template class MergeOutputSection<ELF32LE>;
template class MergeOutputSection<ELF32BE>;
template class MergeOutputSection<ELF64LE>;
Modified: lld/trunk/ELF/OutputSections.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/OutputSections.h?rev=252790&r1=252789&r2=252790&view=diff
==============================================================================
--- lld/trunk/ELF/OutputSections.h (original)
+++ lld/trunk/ELF/OutputSections.h Wed Nov 11 13:54:14 2015
@@ -27,7 +27,9 @@ class SymbolBody;
template <class ELFT> class SymbolTable;
template <class ELFT> class SymbolTableSection;
template <class ELFT> class StringTableSection;
+template <class ELFT> class EHInputSection;
template <class ELFT> class InputSection;
+template <class ELFT> class InputSectionBase;
template <class ELFT> class MergeInputSection;
template <class ELFT> class OutputSection;
template <class ELFT> class ObjectFile;
@@ -158,7 +160,7 @@ private:
template <class ELFT> struct DynamicReloc {
typedef typename llvm::object::ELFFile<ELFT>::Elf_Rel Elf_Rel;
- InputSection<ELFT> &C;
+ InputSectionBase<ELFT> &C;
const Elf_Rel &RI;
};
@@ -246,6 +248,46 @@ private:
llvm::StringTableBuilder Builder{llvm::StringTableBuilder::RAW};
};
+// FDE or CIE
+template <class ELFT> struct EHRegion {
+ typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t;
+ EHRegion(EHInputSection<ELFT> *S, unsigned Index);
+ StringRef data() const;
+ EHInputSection<ELFT> *S;
+ unsigned Index;
+};
+
+template <class ELFT> struct Cie : public EHRegion<ELFT> {
+ Cie(EHInputSection<ELFT> *S, unsigned Index);
+ std::vector<EHRegion<ELFT>> Fdes;
+};
+
+template <class ELFT>
+class EHOutputSection final : public OutputSectionBase<ELFT> {
+public:
+ typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t;
+ typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr;
+ typedef typename llvm::object::ELFFile<ELFT>::Elf_Rel Elf_Rel;
+ typedef typename llvm::object::ELFFile<ELFT>::Elf_Rela Elf_Rela;
+ EHOutputSection(StringRef Name, uint32_t sh_type, uintX_t sh_flags);
+ void writeTo(uint8_t *Buf) override;
+
+ template <bool IsRela>
+ void addSectionAux(
+ EHInputSection<ELFT> *S,
+ llvm::iterator_range<const llvm::object::Elf_Rel_Impl<ELFT, IsRela> *>
+ Rels);
+
+ void addSection(EHInputSection<ELFT> *S);
+
+private:
+ std::vector<EHInputSection<ELFT> *> Sections;
+ std::vector<Cie<ELFT>> Cies;
+
+ // Maps CIE content + personality to a index in Cies.
+ llvm::DenseMap<std::pair<StringRef, StringRef>, unsigned> CieMap;
+};
+
template <class ELFT>
class InterpSection final : public OutputSectionBase<ELFT> {
public:
Modified: lld/trunk/ELF/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Writer.cpp?rev=252790&r1=252789&r2=252790&view=diff
==============================================================================
--- lld/trunk/ELF/Writer.cpp (original)
+++ lld/trunk/ELF/Writer.cpp Wed Nov 11 13:54:14 2015
@@ -42,9 +42,10 @@ private:
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 @@ private:
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 <bool Is64Bits> struct DenseMap
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 @@ void Writer<ELFT>::scanRelocs(
}
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 @@ template <class ELFT> void Writer<ELFT>:
// 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 @@ template <class ELFT> void Writer<ELFT>:
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 @@ template <class ELFT> void Writer<ELFT>:
// 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;
Added: lld/trunk/test/elf2/Inputs/invalid-multiple-eh-relocs.elf
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf2/Inputs/invalid-multiple-eh-relocs.elf?rev=252790&view=auto
==============================================================================
Binary files lld/trunk/test/elf2/Inputs/invalid-multiple-eh-relocs.elf (added) and lld/trunk/test/elf2/Inputs/invalid-multiple-eh-relocs.elf Wed Nov 11 13:54:14 2015 differ
Added: lld/trunk/test/elf2/eh-frame-merge.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf2/eh-frame-merge.s?rev=252790&view=auto
==============================================================================
--- lld/trunk/test/elf2/eh-frame-merge.s (added)
+++ lld/trunk/test/elf2/eh-frame-merge.s Wed Nov 11 13:54:14 2015
@@ -0,0 +1,58 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: ld.lld2 %t.o %t.o -o %t -shared
+// RUN: llvm-readobj -s -section-data %t | FileCheck %s
+
+ .section foo,"ax", at progbits
+ .cfi_startproc
+ nop
+ .cfi_endproc
+
+ .section bar,"axG", at progbits,foo,comdat
+ .cfi_startproc
+ nop
+ nop
+ .cfi_endproc
+
+// FIXME: We could really use a .eh_frame parser.
+// The intention is to show that:
+// * There is only one copy of the CIE
+// * There are two copies of the first FDE
+// * There is only one copy of the second FDE
+
+// CHECK: Name: .eh_frame
+// CHECK-NEXT: Type: SHT_X86_64_UNWIND
+// CHECK-NEXT: Flags [
+// CHECK-NEXT: SHF_ALLOC
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address:
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size:
+// CHECK-NEXT: Link: 0
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 8
+// CHECK-NEXT: EntrySize: 0
+// CHECK-NEXT: SectionData (
+// CHECK-NEXT: 0000: 14000000 00000000 017A5200 01781001 |
+// CHECK-NEXT: 0010: 1B0C0708 90010000 10000000 1C000000 |
+// CHECK-NEXT: 0020: 880E0000 01000000 00000000 10000000 |
+// CHECK-NEXT: 0030: 30000000 760E0000 02000000 00000000 |
+// CHECK-NEXT: 0040: 10000000 44000000 610E0000 01000000 |
+// CHECK-NEXT: 0050: 00000000 |
+// CHECK-NEXT: )
+
+// CHECK: Name: foo
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT: SHF_ALLOC
+// CHECK-NEXT: SHF_EXECINSTR
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x1000
+
+// CHECK: Name: bar
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT: SHF_ALLOC
+// CHECK-NEXT: SHF_EXECINSTR
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x1002
Added: lld/trunk/test/elf2/eh-frame-plt.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf2/eh-frame-plt.s?rev=252790&view=auto
==============================================================================
--- lld/trunk/test/elf2/eh-frame-plt.s (added)
+++ lld/trunk/test/elf2/eh-frame-plt.s Wed Nov 11 13:54:14 2015
@@ -0,0 +1,16 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/shared.s -o %t.o
+// RUN: ld.lld2 %t.o -o %t.so -shared
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t2.o
+// RUN: ld.lld2 %t2.o %t.so -o %t
+// RUN: llvm-readobj -r %t | FileCheck %s
+
+ .globl _start
+_start:
+ .cfi_startproc
+ .cfi_personality 3, bar
+ .cfi_endproc
+
+// CHECK: Section ({{.*}}) .rela.plt {
+// CHECK-NEXT: R_X86_64_JUMP_SLOT bar 0x0
+// CHECK-NEXT: }
Added: lld/trunk/test/elf2/invalid-cie-length.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf2/invalid-cie-length.s?rev=252790&view=auto
==============================================================================
--- lld/trunk/test/elf2/invalid-cie-length.s (added)
+++ lld/trunk/test/elf2/invalid-cie-length.s Wed Nov 11 13:54:14 2015
@@ -0,0 +1,9 @@
+// REQUIRES: x86
+
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+// RUN: not ld.lld2 %t -o %t2 2>&1 | FileCheck %s
+
+ .section .eh_frame
+ .byte 0
+
+// CHECK: Truncated CIE/FDE length
Added: lld/trunk/test/elf2/invalid-cie-length2.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf2/invalid-cie-length2.s?rev=252790&view=auto
==============================================================================
--- lld/trunk/test/elf2/invalid-cie-length2.s (added)
+++ lld/trunk/test/elf2/invalid-cie-length2.s Wed Nov 11 13:54:14 2015
@@ -0,0 +1,9 @@
+// REQUIRES: x86
+
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+// RUN: not ld.lld2 %t -o %t2 2>&1 | FileCheck %s
+
+ .section .eh_frame
+ .long 42
+
+// CHECK: CIE/FIE ends past the end of the section
Added: lld/trunk/test/elf2/invalid-cie-reference.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf2/invalid-cie-reference.s?rev=252790&view=auto
==============================================================================
--- lld/trunk/test/elf2/invalid-cie-reference.s (added)
+++ lld/trunk/test/elf2/invalid-cie-reference.s Wed Nov 11 13:54:14 2015
@@ -0,0 +1,32 @@
+// REQUIRES: x86
+
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+// RUN: not ld.lld2 %t -o %t2 2>&1 | FileCheck %s
+
+ .section .eh_frame
+ .long 0x14
+ .long 0x0
+ .byte 0x01
+ .byte 0x7a
+ .byte 0x52
+ .byte 0x00
+ .byte 0x01
+ .byte 0x78
+ .byte 0x10
+ .byte 0x01
+ .byte 0x1b
+ .byte 0x0c
+ .byte 0x07
+ .byte 0x08
+ .byte 0x90
+ .byte 0x01
+ .short 0x0
+
+ .long 0x14
+ .long 0x1b
+ .long .text
+ .long 0x0
+ .long 0x0
+ .long 0x0
+
+// CHECK: Invalid CIE reference
Modified: lld/trunk/test/elf2/invalid-elf.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf2/invalid-elf.test?rev=252790&r1=252789&r2=252790&view=diff
==============================================================================
--- lld/trunk/test/elf2/invalid-elf.test (original)
+++ lld/trunk/test/elf2/invalid-elf.test Wed Nov 11 13:54:14 2015
@@ -27,4 +27,8 @@
# RUN: FileCheck --check-prefix=INVALID-SHENTSIZE-ZERO %s
# INVALID-SHENTSIZE-ZERO: SHF_MERGE section size must be a multiple of sh_entsize
+# RUN: not ld.lld2 %p/Inputs/invalid-multiple-eh-relocs.elf -o %t2 2>&1 | \
+# RUN: FileCheck --check-prefix=INVALID-EH-RELOCS %s
+# INVALID-EH-RELOCS: Multiple relocation sections to .eh_frame are not supported
+
.long foo
Added: lld/trunk/test/elf2/invalid-fde-rel.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf2/invalid-fde-rel.s?rev=252790&view=auto
==============================================================================
--- lld/trunk/test/elf2/invalid-fde-rel.s (added)
+++ lld/trunk/test/elf2/invalid-fde-rel.s Wed Nov 11 13:54:14 2015
@@ -0,0 +1,32 @@
+// REQUIRES: x86
+
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+// RUN: not ld.lld2 %t -o %t2 2>&1 | FileCheck %s
+
+ .section .eh_frame
+ .long 0x14
+ .long 0x0
+ .byte 0x01
+ .byte 0x7a
+ .byte 0x52
+ .byte 0x00
+ .byte 0x01
+ .byte 0x78
+ .byte 0x10
+ .byte 0x01
+ .byte 0x1b
+ .byte 0x0c
+ .byte 0x07
+ .byte 0x08
+ .byte 0x90
+ .byte 0x01
+ .short 0x0
+
+ .long 0x14
+ .long 0x1c
+ .long 0x0
+ .long 0x0
+ .long 0x0
+ .long 0x0
+
+// CHECK: FDE doesn't reference another section
More information about the llvm-commits
mailing list