[lld] r250737 - Add support for merging the contents of SHF_MERGE sections.
Rafael Espindola via llvm-commits
llvm-commits at lists.llvm.org
Mon Oct 19 14:00:02 PDT 2015
Author: rafael
Date: Mon Oct 19 16:00:02 2015
New Revision: 250737
URL: http://llvm.org/viewvc/llvm-project?rev=250737&view=rev
Log:
Add support for merging the contents of SHF_MERGE sections.
For now SHF_STRINGS are not supported.
Added:
lld/trunk/test/elf2/Inputs/merge.s
lld/trunk/test/elf2/merge-invalid-size.s
lld/trunk/test/elf2/merge-shared.s
lld/trunk/test/elf2/merge.s
lld/trunk/test/elf2/relocation-in-merge.s
lld/trunk/test/elf2/relocation-past-merge-end.s
lld/trunk/test/elf2/writable-merge.s
Modified:
lld/trunk/ELF/InputFiles.cpp
lld/trunk/ELF/InputFiles.h
lld/trunk/ELF/InputSection.cpp
lld/trunk/ELF/InputSection.h
lld/trunk/ELF/OutputSections.cpp
lld/trunk/ELF/OutputSections.h
lld/trunk/ELF/Symbols.h
lld/trunk/ELF/Writer.cpp
Modified: lld/trunk/ELF/InputFiles.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputFiles.cpp?rev=250737&r1=250736&r2=250737&view=diff
==============================================================================
--- lld/trunk/ELF/InputFiles.cpp (original)
+++ lld/trunk/ELF/InputFiles.cpp Mon Oct 19 16:00:02 2015
@@ -150,16 +150,28 @@ void elf2::ObjectFile<ELFT>::initializeS
uint32_t RelocatedSectionIndex = Sec.sh_info;
if (RelocatedSectionIndex >= Size)
error("Invalid relocated section index");
- InputSection<ELFT> *RelocatedSection = Sections[RelocatedSectionIndex];
+ InputSectionBase<ELFT> *RelocatedSection =
+ Sections[RelocatedSectionIndex];
if (!RelocatedSection)
error("Unsupported relocation reference");
- RelocatedSection->RelocSections.push_back(&Sec);
+ if (auto *S = dyn_cast<InputSection<ELFT>>(RelocatedSection))
+ S->RelocSections.push_back(&Sec);
+ else
+ error("Relocations pointing to SHF_MERGE are not supported");
break;
}
- default:
- Sections[I] = new (this->Alloc) InputSection<ELFT>(this, &Sec);
+ default: {
+ uintX_t Flags = Sec.sh_flags;
+ if (Flags & SHF_MERGE && !(Flags & SHF_STRINGS)) {
+ if (Flags & SHF_WRITE)
+ error("Writable SHF_MERGE sections are not supported");
+ Sections[I] = new (this->Alloc) MergeInputSection<ELFT>(this, &Sec);
+ } else {
+ Sections[I] = new (this->Alloc) InputSection<ELFT>(this, &Sec);
+ }
break;
}
+ }
}
}
@@ -173,7 +185,7 @@ template <class ELFT> void elf2::ObjectF
}
template <class ELFT>
-InputSection<ELFT> *
+InputSectionBase<ELFT> *
elf2::ObjectFile<ELFT>::getSection(const Elf_Sym &Sym) const {
uint32_t Index = Sym.st_shndx;
if (Index == ELF::SHN_XINDEX)
@@ -209,7 +221,7 @@ SymbolBody *elf2::ObjectFile<ELFT>::crea
case STB_GLOBAL:
case STB_WEAK:
case STB_GNU_UNIQUE: {
- InputSection<ELFT> *Sec = getSection(*Sym);
+ InputSectionBase<ELFT> *Sec = getSection(*Sym);
if (Sec == &InputSection<ELFT>::Discarded)
return new (this->Alloc) Undefined<ELFT>(Name, *Sym);
return new (this->Alloc) DefinedRegular<ELFT>(Name, *Sym, *Sec);
Modified: lld/trunk/ELF/InputFiles.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputFiles.h?rev=250737&r1=250736&r2=250737&view=diff
==============================================================================
--- lld/trunk/ELF/InputFiles.h (original)
+++ lld/trunk/ELF/InputFiles.h Mon Oct 19 16:00:02 2015
@@ -94,6 +94,7 @@ template <class ELFT> class ObjectFile :
typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr;
typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym_Range Elf_Sym_Range;
typedef typename llvm::object::ELFFile<ELFT>::Elf_Word Elf_Word;
+ typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t;
typedef llvm::support::detail::packed_endian_specific_integral<
uint32_t, ELFT::TargetEndianness, 2> GroupEntryType;
@@ -110,8 +111,8 @@ public:
explicit ObjectFile(MemoryBufferRef M);
void parse(llvm::DenseSet<StringRef> &Comdats);
- ArrayRef<InputSection<ELFT> *> getSections() const { return Sections; }
- InputSection<ELFT> *getSection(const Elf_Sym &Sym) const;
+ ArrayRef<InputSectionBase<ELFT> *> getSections() const { return Sections; }
+ InputSectionBase<ELFT> *getSection(const Elf_Sym &Sym) const;
SymbolBody *getSymbolBody(uint32_t SymbolIndex) const {
uint32_t FirstNonLocal = this->Symtab->sh_info;
@@ -132,7 +133,7 @@ private:
SymbolBody *createSymbolBody(StringRef StringTable, const Elf_Sym *Sym);
// List of all sections defined by this file.
- std::vector<InputSection<ELFT> *> Sections;
+ std::vector<InputSectionBase<ELFT> *> Sections;
ArrayRef<Elf_Word> SymtabSHNDX;
Modified: lld/trunk/ELF/InputSection.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputSection.cpp?rev=250737&r1=250736&r2=250737&view=diff
==============================================================================
--- lld/trunk/ELF/InputSection.cpp (original)
+++ lld/trunk/ELF/InputSection.cpp Mon Oct 19 16:00:02 2015
@@ -22,8 +22,41 @@ using namespace lld;
using namespace lld::elf2;
template <class ELFT>
+InputSectionBase<ELFT>::InputSectionBase(ObjectFile<ELFT> *File,
+ const Elf_Shdr *Header,
+ Kind SectionKind)
+ : Header(Header), File(File), SectionKind(SectionKind) {}
+
+template <class ELFT> StringRef InputSectionBase<ELFT>::getSectionName() const {
+ ErrorOr<StringRef> Name = File->getObj().getSectionName(this->Header);
+ error(Name);
+ return *Name;
+}
+
+template <class ELFT>
+ArrayRef<uint8_t> InputSectionBase<ELFT>::getSectionData() const {
+ ErrorOr<ArrayRef<uint8_t>> Ret =
+ this->File->getObj().getSectionContents(this->Header);
+ error(Ret);
+ return *Ret;
+}
+
+template <class ELFT>
+typename ELFFile<ELFT>::uintX_t
+InputSectionBase<ELFT>::getOffset(const Elf_Sym &Sym) const {
+ if (auto *S = dyn_cast<InputSection<ELFT>>(this))
+ return S->OutSecOff + Sym.st_value;
+ return cast<MergeInputSection<ELFT>>(this)->getOffset(Sym.st_value);
+}
+
+template <class ELFT>
InputSection<ELFT>::InputSection(ObjectFile<ELFT> *F, const Elf_Shdr *Header)
- : File(F), Header(Header) {}
+ : InputSectionBase<ELFT>(F, Header, Base::Regular) {}
+
+template <class ELFT>
+bool InputSection<ELFT>::classof(const InputSectionBase<ELFT> *S) {
+ return S->SectionKind == Base::Regular;
+}
template <class ELFT>
template <bool isRela>
@@ -65,35 +98,63 @@ void InputSection<ELFT>::relocate(
}
template <class ELFT> void InputSection<ELFT>::writeTo(uint8_t *Buf) {
- if (Header->sh_type == SHT_NOBITS)
+ if (this->Header->sh_type == SHT_NOBITS)
return;
// Copy section contents from source object file to output file.
- ArrayRef<uint8_t> Data = *File->getObj().getSectionContents(Header);
+ ArrayRef<uint8_t> Data = this->getSectionData();
memcpy(Buf + OutSecOff, Data.data(), Data.size());
- ELFFile<ELFT> &EObj = File->getObj();
+ ELFFile<ELFT> &EObj = this->File->getObj();
uint8_t *Base = Buf + OutSecOff;
- uintX_t BaseAddr = OutSec->getVA() + OutSecOff;
+ uintX_t BaseAddr = this->OutSec->getVA() + OutSecOff;
// Iterate over all relocation sections that apply to this section.
for (const Elf_Shdr *RelSec : RelocSections) {
if (RelSec->sh_type == SHT_RELA)
- relocate(Base, Base + Data.size(), EObj.relas(RelSec), *File, BaseAddr);
+ relocate(Base, Base + Data.size(), EObj.relas(RelSec), *this->File,
+ BaseAddr);
else
- relocate(Base, Base + Data.size(), EObj.rels(RelSec), *File, BaseAddr);
+ relocate(Base, Base + Data.size(), EObj.rels(RelSec), *this->File,
+ BaseAddr);
}
}
-template <class ELFT> StringRef InputSection<ELFT>::getSectionName() const {
- ErrorOr<StringRef> Name = File->getObj().getSectionName(Header);
- error(Name);
- return *Name;
+template <class ELFT>
+MergeInputSection<ELFT>::MergeInputSection(ObjectFile<ELFT> *F,
+ const Elf_Shdr *Header)
+ : InputSectionBase<ELFT>(F, Header, Base::Merge) {}
+
+template <class ELFT>
+bool MergeInputSection<ELFT>::classof(const InputSectionBase<ELFT> *S) {
+ return S->SectionKind == Base::Merge;
+}
+
+// FIXME: Optimize this by keeping an offset for each element.
+template <class ELFT>
+typename MergeInputSection<ELFT>::uintX_t
+MergeInputSection<ELFT>::getOffset(uintX_t Offset) const {
+ ArrayRef<uint8_t> Data = this->getSectionData();
+ uintX_t EntSize = this->Header->sh_entsize;
+ if (Offset + EntSize > Data.size())
+ error("Entry is past the end of the section");
+ Data = Data.slice(Offset, EntSize);
+ return static_cast<MergeOutputSection<ELFT> *>(this->OutSec)->getOffset(Data);
}
namespace lld {
namespace elf2 {
+template class InputSectionBase<object::ELF32LE>;
+template class InputSectionBase<object::ELF32BE>;
+template class InputSectionBase<object::ELF64LE>;
+template class InputSectionBase<object::ELF64BE>;
+
template class InputSection<object::ELF32LE>;
template class InputSection<object::ELF32BE>;
template class InputSection<object::ELF64LE>;
template class InputSection<object::ELF64BE>;
+
+template class MergeInputSection<object::ELF32LE>;
+template class MergeInputSection<object::ELF32BE>;
+template class MergeInputSection<object::ELF64LE>;
+template class MergeInputSection<object::ELF64BE>;
}
}
Modified: lld/trunk/ELF/InputSection.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputSection.h?rev=250737&r1=250736&r2=250737&view=diff
==============================================================================
--- lld/trunk/ELF/InputSection.h (original)
+++ lld/trunk/ELF/InputSection.h Mon Oct 19 16:00:02 2015
@@ -21,22 +21,28 @@ template <class ELFT> class OutputSectio
template <class ELFT> class OutputSectionBase;
// This corresponds to a section of an input file.
-template <class ELFT> class InputSection {
+template <class ELFT> class InputSectionBase {
+protected:
typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr;
- typedef typename llvm::object::ELFFile<ELFT>::Elf_Rela Elf_Rela;
- typedef typename llvm::object::ELFFile<ELFT>::Elf_Rel Elf_Rel;
typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym Elf_Sym;
typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t;
+ const Elf_Shdr *Header;
+
+ // The file this section is from.
+ ObjectFile<ELFT> *File;
public:
- InputSection(ObjectFile<ELFT> *F, const Elf_Shdr *Header);
+ enum Kind { Regular, Merge };
+ Kind SectionKind;
+
+ InputSectionBase(ObjectFile<ELFT> *File, const Elf_Shdr *Header,
+ Kind SectionKind);
+ OutputSectionBase<ELFT> *OutSec = nullptr;
// Returns the size of this section (even if this is a common or BSS.)
size_t getSize() const { return Header->sh_size; }
- // Write this section to a mmap'ed file, assuming Buf is pointing to
- // beginning of the output section.
- void writeTo(uint8_t *Buf);
+ static InputSectionBase<ELFT> Discarded;
StringRef getSectionName() const;
const Elf_Shdr *getSectionHdr() const { return Header; }
@@ -49,15 +55,52 @@ public:
return std::max<uintX_t>(Header->sh_addralign, 1);
}
+ uintX_t getOffset(const Elf_Sym &Sym) const;
+ ArrayRef<uint8_t> getSectionData() const;
+};
+
+template <class ELFT>
+InputSectionBase<ELFT>
+ InputSectionBase<ELFT>::Discarded(nullptr, nullptr,
+ InputSectionBase<ELFT>::Regular);
+
+// This corresponds to a SHF_MERGE section of an input file.
+template <class ELFT> class MergeInputSection : public InputSectionBase<ELFT> {
+ typedef InputSectionBase<ELFT> Base;
+ 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:
+ MergeInputSection(ObjectFile<ELFT> *F, const Elf_Shdr *Header);
+ static bool classof(const InputSectionBase<ELFT> *S);
+ uintX_t getOffset(uintX_t Offset) const;
+};
+
+// This corresponds to a non SHF_MERGE section of an input file.
+template <class ELFT> class InputSection : public InputSectionBase<ELFT> {
+ typedef InputSectionBase<ELFT> Base;
+ typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr;
+ typedef typename llvm::object::ELFFile<ELFT>::Elf_Rela Elf_Rela;
+ typedef typename llvm::object::ELFFile<ELFT>::Elf_Rel Elf_Rel;
+ typedef typename llvm::object::ELFFile<ELFT>::Elf_Sym Elf_Sym;
+ typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t;
+
+public:
+ InputSection(ObjectFile<ELFT> *F, const Elf_Shdr *Header);
+
+ // Write this section to a mmap'ed file, assuming Buf is pointing to
+ // beginning of the output section.
+ void writeTo(uint8_t *Buf);
+
// Relocation sections that refer to this one.
SmallVector<const Elf_Shdr *, 1> RelocSections;
// The offset from beginning of the output sections this section was assigned
// to. The writer sets a value.
uint64_t OutSecOff = 0;
- OutputSectionBase<ELFT> *OutSec = nullptr;
- static InputSection<ELFT> Discarded;
+ static bool classof(const InputSectionBase<ELFT> *S);
private:
template <bool isRela>
@@ -65,16 +108,8 @@ private:
llvm::iterator_range<
const llvm::object::Elf_Rel_Impl<ELFT, isRela> *> Rels,
const ObjectFile<ELFT> &File, uintX_t BaseAddr);
-
- // The file this section is from.
- ObjectFile<ELFT> *File;
-
- const Elf_Shdr *Header;
};
-template <class ELFT>
-InputSection<ELFT> InputSection<ELFT>::Discarded(nullptr, nullptr);
-
} // namespace elf2
} // namespace lld
Modified: lld/trunk/ELF/OutputSections.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/OutputSections.cpp?rev=250737&r1=250736&r2=250737&view=diff
==============================================================================
--- lld/trunk/ELF/OutputSections.cpp (original)
+++ lld/trunk/ELF/OutputSections.cpp Mon Oct 19 16:00:02 2015
@@ -408,8 +408,8 @@ typename ELFFile<ELFT>::uintX_t lld::elf
return cast<DefinedAbsolute<ELFT>>(S).Sym.st_value;
case SymbolBody::DefinedRegularKind: {
const auto &DR = cast<DefinedRegular<ELFT>>(S);
- const InputSection<ELFT> &SC = DR.Section;
- return SC.OutSec->getVA() + SC.OutSecOff + DR.Sym.st_value;
+ const InputSectionBase<ELFT> &SC = DR.Section;
+ return SC.OutSec->getVA() + SC.getOffset(DR.Sym);
}
case SymbolBody::DefinedCommonKind:
return Out<ELFT>::Bss->getVA() + cast<DefinedCommon<ELFT>>(S).OffsetInBSS;
@@ -449,11 +449,22 @@ lld::elf2::getLocalRelTarget(const Objec
// the group are not allowed. Unfortunately .eh_frame breaks that rule
// and must be treated specially. For now we just replace the symbol with
// 0.
- InputSection<ELFT> *Section = File.getSection(*Sym);
+ InputSectionBase<ELFT> *Section = File.getSection(*Sym);
if (Section == &InputSection<ELFT>::Discarded)
return Addend;
- return Section->OutSec->getVA() + Section->OutSecOff + Sym->st_value + Addend;
+ uintX_t VA = Section->OutSec->getVA();
+ if (isa<InputSection<ELFT>>(Section))
+ return VA + Section->getOffset(*Sym) + Addend;
+
+ uintX_t Offset = Sym->st_value;
+ if (Sym->getType() == STT_SECTION) {
+ Offset += Addend;
+ Addend = Offset % Section->getSectionHdr()->sh_entsize;
+ Offset -= Addend;
+ }
+ return VA + cast<MergeInputSection<ELFT>>(Section)->getOffset(Offset) +
+ Addend;
}
// Returns true if a symbol can be replaced at load-time by a symbol
@@ -500,6 +511,44 @@ template <class ELFT> void OutputSection
}
template <class ELFT>
+MergeOutputSection<ELFT>::MergeOutputSection(StringRef Name, uint32_t sh_type,
+ uintX_t sh_flags)
+ : OutputSectionBase<ELFT>(Name, sh_type, sh_flags) {}
+
+template <class ELFT> void MergeOutputSection<ELFT>::writeTo(uint8_t *Buf) {
+ for (const std::pair<ArrayRef<uint8_t>, uintX_t> &P : Offsets) {
+ ArrayRef<uint8_t> Data = P.first;
+ memcpy(Buf, Data.data(), Data.size());
+ Buf += Data.size();
+ }
+}
+
+template <class ELFT>
+void MergeOutputSection<ELFT>::addSection(MergeInputSection<ELFT> *S) {
+ S->OutSec = this;
+ uint32_t Align = S->getAlign();
+ if (Align > this->Header.sh_addralign)
+ this->Header.sh_addralign = Align;
+
+ uintX_t Off = this->Header.sh_size;
+ ArrayRef<uint8_t> Data = S->getSectionData();
+ uintX_t EntSize = S->getSectionHdr()->sh_entsize;
+ if (Data.size() % EntSize)
+ error("SHF_MERGE section size must be a multiple of sh_entsize");
+ for (unsigned I = 0, N = Data.size(); I != N; I += EntSize) {
+ auto P = Offsets.insert(std::make_pair(Data.slice(I, EntSize), Off));
+ if (P.second)
+ Off += EntSize;
+ }
+ this->Header.sh_size = Off;
+}
+
+template <class ELFT>
+unsigned MergeOutputSection<ELFT>::getOffset(ArrayRef<uint8_t> Val) {
+ return Offsets.find(Val)->second;
+}
+
+template <class ELFT>
StringTableSection<ELFT>::StringTableSection(bool Dynamic)
: OutputSectionBase<ELFT>(Dynamic ? ".dynstr" : ".strtab",
llvm::ELF::SHT_STRTAB,
@@ -611,13 +660,15 @@ void SymbolTableSection<ELFT>::writeLoca
ESym->st_name = StrTabSec.getFileOff(SymName);
ESym->st_size = Sym.st_size;
ESym->setBindingAndType(Sym.getBinding(), Sym.getType());
- uintX_t VA = Sym.st_value;
+ uintX_t VA = 0;
if (Sym.st_shndx == SHN_ABS) {
ESym->st_shndx = SHN_ABS;
+ VA = Sym.st_value;
} else {
- const InputSection<ELFT> *Sec = File->getSection(Sym);
- ESym->st_shndx = Sec->OutSec->SectionIndex;
- VA += Sec->OutSec->getVA() + Sec->OutSecOff;
+ const InputSectionBase<ELFT> *Section = File->getSection(Sym);
+ const OutputSectionBase<ELFT> *OutSec = Section->OutSec;
+ ESym->st_shndx = OutSec->SectionIndex;
+ VA += OutSec->getVA() + Section->getOffset(Sym);
}
ESym->st_value = VA;
}
@@ -644,7 +695,7 @@ void SymbolTableSection<ELFT>::writeGlob
ESym->st_name = StrTabSec.getFileOff(Name);
const OutputSectionBase<ELFT> *OutSec = nullptr;
- const InputSection<ELFT> *Section = nullptr;
+ const InputSectionBase<ELFT> *Section = nullptr;
switch (Body->kind()) {
case SymbolBody::DefinedSyntheticKind:
@@ -740,6 +791,11 @@ template class OutputSection<ELF32BE>;
template class OutputSection<ELF64LE>;
template class OutputSection<ELF64BE>;
+template class MergeOutputSection<ELF32LE>;
+template class MergeOutputSection<ELF32BE>;
+template class MergeOutputSection<ELF64LE>;
+template class MergeOutputSection<ELF64BE>;
+
template class StringTableSection<ELF32LE>;
template class StringTableSection<ELF32BE>;
template class StringTableSection<ELF64LE>;
@@ -758,19 +814,29 @@ template ELFFile<ELF64BE>::uintX_t getSy
template ELFFile<ELF32LE>::uintX_t
getLocalRelTarget(const ObjectFile<ELF32LE> &,
const ELFFile<ELF32LE>::Elf_Rel &);
-
template ELFFile<ELF32BE>::uintX_t
getLocalRelTarget(const ObjectFile<ELF32BE> &,
const ELFFile<ELF32BE>::Elf_Rel &);
-
template ELFFile<ELF64LE>::uintX_t
getLocalRelTarget(const ObjectFile<ELF64LE> &,
const ELFFile<ELF64LE>::Elf_Rel &);
-
template ELFFile<ELF64BE>::uintX_t
getLocalRelTarget(const ObjectFile<ELF64BE> &,
const ELFFile<ELF64BE>::Elf_Rel &);
+template ELFFile<ELF32LE>::uintX_t
+getLocalRelTarget(const ObjectFile<ELF32LE> &,
+ const ELFFile<ELF32LE>::Elf_Rela &);
+template ELFFile<ELF32BE>::uintX_t
+getLocalRelTarget(const ObjectFile<ELF32BE> &,
+ const ELFFile<ELF32BE>::Elf_Rela &);
+template ELFFile<ELF64LE>::uintX_t
+getLocalRelTarget(const ObjectFile<ELF64LE> &,
+ const ELFFile<ELF64LE>::Elf_Rela &);
+template ELFFile<ELF64BE>::uintX_t
+getLocalRelTarget(const ObjectFile<ELF64BE> &,
+ const ELFFile<ELF64BE>::Elf_Rela &);
+
template bool includeInSymtab<ELF32LE>(const SymbolBody &);
template bool includeInSymtab<ELF32BE>(const SymbolBody &);
template bool includeInSymtab<ELF64LE>(const SymbolBody &);
Modified: lld/trunk/ELF/OutputSections.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/OutputSections.h?rev=250737&r1=250736&r2=250737&view=diff
==============================================================================
--- lld/trunk/ELF/OutputSections.h (original)
+++ lld/trunk/ELF/OutputSections.h Mon Oct 19 16:00:02 2015
@@ -12,6 +12,7 @@
#include "lld/Core/LLVM.h"
+#include "llvm/ADT/MapVector.h"
#include "llvm/MC/StringTableBuilder.h"
#include "llvm/Object/ELF.h"
@@ -27,6 +28,7 @@ template <class ELFT> class SymbolTable;
template <class ELFT> class SymbolTableSection;
template <class ELFT> class StringTableSection;
template <class ELFT> class InputSection;
+template <class ELFT> class MergeInputSection;
template <class ELFT> class OutputSection;
template <class ELFT> class ObjectFile;
template <class ELFT> class DefinedRegular;
@@ -204,6 +206,23 @@ private:
};
template <class ELFT>
+class MergeOutputSection final : public OutputSectionBase<ELFT> {
+ typedef typename OutputSectionBase<ELFT>::uintX_t uintX_t;
+
+public:
+ MergeOutputSection(StringRef Name, uint32_t sh_type, uintX_t sh_flags);
+ void addSection(MergeInputSection<ELFT> *S);
+ void writeTo(uint8_t *Buf) override;
+
+ unsigned getOffset(ArrayRef<uint8_t> Val);
+
+private:
+ // This map is used to find if we already have an entry for a given value and,
+ // if so, at what offset it is.
+ llvm::MapVector<ArrayRef<uint8_t>, uintX_t> Offsets;
+};
+
+template <class ELFT>
class InterpSection final : public OutputSectionBase<ELFT> {
public:
InterpSection();
Modified: lld/trunk/ELF/Symbols.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Symbols.h?rev=250737&r1=250736&r2=250737&view=diff
==============================================================================
--- lld/trunk/ELF/Symbols.h (original)
+++ lld/trunk/ELF/Symbols.h Mon Oct 19 16:00:02 2015
@@ -217,14 +217,15 @@ template <class ELFT> class DefinedRegul
typedef typename Base::Elf_Sym Elf_Sym;
public:
- DefinedRegular(StringRef N, const Elf_Sym &Sym, InputSection<ELFT> &Section)
+ DefinedRegular(StringRef N, const Elf_Sym &Sym,
+ InputSectionBase<ELFT> &Section)
: Defined<ELFT>(Base::DefinedRegularKind, N, Sym), Section(Section) {}
static bool classof(const SymbolBody *S) {
return S->kind() == Base::DefinedRegularKind;
}
- const InputSection<ELFT> &Section;
+ const InputSectionBase<ELFT> &Section;
};
template <class ELFT> class DefinedSynthetic : public Defined<ELFT> {
Modified: lld/trunk/ELF/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Writer.cpp?rev=250737&r1=250736&r2=250737&view=diff
==============================================================================
--- lld/trunk/ELF/Writer.cpp (original)
+++ lld/trunk/ELF/Writer.cpp Mon Oct 19 16:00:02 2015
@@ -71,6 +71,7 @@ private:
std::unique_ptr<llvm::FileOutputBuffer> Buffer;
SpecificBumpPtrAllocator<OutputSection<ELFT>> SecAlloc;
+ SpecificBumpPtrAllocator<MergeOutputSection<ELFT>> MSecAlloc;
BumpPtrAllocator Alloc;
std::vector<OutputSectionBase<ELFT> *> OutputSections;
unsigned getNumSections() const { return OutputSections.size() + 1; }
@@ -135,24 +136,27 @@ template <bool Is64Bits> struct SectionK
StringRef Name;
uint32_t Type;
uintX_t Flags;
+ uintX_t EntSize;
};
}
namespace llvm {
template <bool Is64Bits> struct DenseMapInfo<SectionKey<Is64Bits>> {
static SectionKey<Is64Bits> getEmptyKey() {
- return SectionKey<Is64Bits>{DenseMapInfo<StringRef>::getEmptyKey(), 0, 0};
+ return SectionKey<Is64Bits>{DenseMapInfo<StringRef>::getEmptyKey(), 0, 0,
+ 0};
}
static SectionKey<Is64Bits> getTombstoneKey() {
return SectionKey<Is64Bits>{DenseMapInfo<StringRef>::getTombstoneKey(), 0,
- 0};
+ 0, 0};
}
static unsigned getHashValue(const SectionKey<Is64Bits> &Val) {
- return hash_combine(Val.Name, Val.Type, Val.Flags);
+ return hash_combine(Val.Name, Val.Type, Val.Flags, Val.EntSize);
}
static bool isEqual(const SectionKey<Is64Bits> &LHS,
const SectionKey<Is64Bits> &RHS) {
return DenseMapInfo<StringRef>::isEqual(LHS.Name, RHS.Name) &&
- LHS.Type == RHS.Type && LHS.Flags == RHS.Flags;
+ LHS.Type == RHS.Type && LHS.Flags == RHS.Flags &&
+ LHS.EntSize == RHS.EntSize;
}
};
}
@@ -390,39 +394,52 @@ template <class ELFT> void Writer<ELFT>:
if (needsInterpSection())
OutputSections.push_back(Out<ELFT>::Interp);
- SmallDenseMap<SectionKey<ELFT::Is64Bits>, OutputSection<ELFT> *> Map;
+ SmallDenseMap<SectionKey<ELFT::Is64Bits>, OutputSectionBase<ELFT> *> Map;
OutputSections.push_back(Out<ELFT>::Bss);
Map[{Out<ELFT>::Bss->getName(), Out<ELFT>::Bss->getType(),
- Out<ELFT>::Bss->getFlags()}] = Out<ELFT>::Bss;
+ Out<ELFT>::Bss->getFlags(), 0}] = Out<ELFT>::Bss;
std::vector<OutputSectionBase<ELFT> *> RegularSections;
for (const std::unique_ptr<ObjectFile<ELFT>> &F : Symtab.getObjectFiles()) {
- for (InputSection<ELFT> *C : F->getSections()) {
+ for (InputSectionBase<ELFT> *C : F->getSections()) {
if (!C || C == &InputSection<ELFT>::Discarded)
continue;
const Elf_Shdr *H = C->getSectionHdr();
uintX_t OutFlags = H->sh_flags & ~SHF_GROUP;
+ // 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;
SectionKey<ELFT::Is64Bits> Key{getOutputName(C->getSectionName()),
- H->sh_type, OutFlags};
- OutputSection<ELFT> *&Sec = Map[Key];
+ H->sh_type, OutFlags, EntSize};
+ OutputSectionBase<ELFT> *&Sec = Map[Key];
if (!Sec) {
- Sec = new (SecAlloc.Allocate())
- OutputSection<ELFT>(Key.Name, Key.Type, Key.Flags);
+ if (IS)
+ Sec = new (SecAlloc.Allocate())
+ OutputSection<ELFT>(Key.Name, Key.Type, Key.Flags);
+ else
+ Sec = new (MSecAlloc.Allocate())
+ MergeOutputSection<ELFT>(Key.Name, Key.Type, Key.Flags);
OutputSections.push_back(Sec);
RegularSections.push_back(Sec);
}
- Sec->addSection(C);
+ if (IS)
+ static_cast<OutputSection<ELFT> *>(Sec)->addSection(IS);
+ else
+ static_cast<MergeOutputSection<ELFT> *>(Sec)
+ ->addSection(cast<MergeInputSection<ELFT>>(C));
}
}
- Out<ELFT>::Dynamic->PreInitArraySec =
- Map.lookup({".preinit_array", SHT_PREINIT_ARRAY, SHF_WRITE | SHF_ALLOC});
+ Out<ELFT>::Dynamic->PreInitArraySec = Map.lookup(
+ {".preinit_array", SHT_PREINIT_ARRAY, SHF_WRITE | SHF_ALLOC, 0});
Out<ELFT>::Dynamic->InitArraySec =
- Map.lookup({".init_array", SHT_INIT_ARRAY, SHF_WRITE | SHF_ALLOC});
+ Map.lookup({".init_array", SHT_INIT_ARRAY, SHF_WRITE | SHF_ALLOC, 0});
Out<ELFT>::Dynamic->FiniArraySec =
- Map.lookup({".fini_array", SHT_FINI_ARRAY, SHF_WRITE | SHF_ALLOC});
+ Map.lookup({".fini_array", SHT_FINI_ARRAY, SHF_WRITE | SHF_ALLOC, 0});
auto AddStartEnd = [&](StringRef Start, StringRef End,
OutputSectionBase<ELFT> *OS) {
@@ -455,9 +472,10 @@ 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 (InputSection<ELFT> *S : F->getSections())
- if (S && S != &InputSection<ELFT>::Discarded)
- scanRelocs(*S);
+ for (InputSectionBase<ELFT> *B : F->getSections())
+ if (auto *S = dyn_cast_or_null<InputSection<ELFT>>(B))
+ if (S != &InputSection<ELFT>::Discarded)
+ scanRelocs(*S);
// FIXME: Try to avoid the extra walk over all global symbols.
std::vector<DefinedCommon<ELFT> *> CommonSymbols;
@@ -516,7 +534,7 @@ template <class ELFT> void Writer<ELFT>:
// If we have a .opd section (used under PPC64 for function descriptors),
// store a pointer to it here so that we can use it later when processing
// relocations.
- Out<ELFT>::Opd = Map.lookup({".opd", SHT_PROGBITS, SHF_WRITE | SHF_ALLOC});
+ Out<ELFT>::Opd = Map.lookup({".opd", SHT_PROGBITS, SHF_WRITE | SHF_ALLOC, 0});
}
static bool isAlpha(char C) {
Added: lld/trunk/test/elf2/Inputs/merge.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf2/Inputs/merge.s?rev=250737&view=auto
==============================================================================
--- lld/trunk/test/elf2/Inputs/merge.s (added)
+++ lld/trunk/test/elf2/Inputs/merge.s Mon Oct 19 16:00:02 2015
@@ -0,0 +1,6 @@
+ .section .mysec,"aM", at progbits,4
+ .align 4
+ .long 0x42
+
+ .text
+ movl .mysec, %eax
Added: lld/trunk/test/elf2/merge-invalid-size.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf2/merge-invalid-size.s?rev=250737&view=auto
==============================================================================
--- lld/trunk/test/elf2/merge-invalid-size.s (added)
+++ lld/trunk/test/elf2/merge-invalid-size.s Mon Oct 19 16:00:02 2015
@@ -0,0 +1,7 @@
+// REQUIRES: x86
+// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux
+// RUN: not ld.lld2 %t.o -o %t.so 2>&1 | FileCheck %s
+// CHECK: SHF_MERGE section size must be a multiple of sh_entsize
+
+ .section .foo,"aM", at progbits,4
+ .short 42
Added: lld/trunk/test/elf2/merge-shared.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf2/merge-shared.s?rev=250737&view=auto
==============================================================================
--- lld/trunk/test/elf2/merge-shared.s (added)
+++ lld/trunk/test/elf2/merge-shared.s Mon Oct 19 16:00:02 2015
@@ -0,0 +1,26 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: ld.lld2 %t.o -o %t.so -shared
+// RUN: llvm-readobj -r -s %t.so | FileCheck %s
+
+ .section foo,"aM", at progbits,4
+ .long 42
+ .long 42
+
+ .text
+ .quad foo + 6
+
+
+// CHECK: Name: foo (20)
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT: SHF_ALLOC
+// CHECK-NEXT: SHF_MERGE
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x158
+
+// CHECK: Relocations [
+// CHECK-NEXT: Section ({{.*}}) .rela.dyn {
+// CHECK-NEXT: 0x{{.*}} R_X86_64_RELATIVE - 0x15A
+// CHECK-NEXT: }
+// CHECK-NEXT: ]
Added: lld/trunk/test/elf2/merge.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf2/merge.s?rev=250737&view=auto
==============================================================================
--- lld/trunk/test/elf2/merge.s (added)
+++ lld/trunk/test/elf2/merge.s Mon Oct 19 16:00:02 2015
@@ -0,0 +1,109 @@
+// REQUIRES: x86
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/merge.s -o %t2.o
+// RUN: ld.lld2 %t.o %t2.o -o %t
+// RUN: llvm-readobj -s -section-data -t %t | FileCheck %s
+// RUN: llvm-objdump -d %t | FileCheck --check-prefix=DISASM %s
+
+ .section .mysec,"aM", at progbits,4
+ .align 4
+ .global foo
+ .hidden foo
+ .long 0x10
+foo:
+ .long 0x42
+bar:
+ .long 0x42
+zed:
+ .long 0x42
+
+// CHECK: Name: .mysec
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT: SHF_ALLOC
+// CHECK-NEXT: SHF_MERGE
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x100E8
+// CHECK-NEXT: Offset: 0xE8
+// CHECK-NEXT: Size: 8
+// CHECK-NEXT: Link: 0
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 4
+// CHECK-NEXT: EntrySize: 0
+// CHECK-NEXT: SectionData (
+// CHECK-NEXT: 0000: 10000000 42000000
+// CHECK-NEXT: )
+
+
+// Address of the constant 0x10 = 0x100E8 = 65768
+// Address of the constant 0x42 = 0x100EC = 65772
+
+// CHECK: Symbols [
+
+// CHECK: Name: bar
+// CHECK-NEXT: Value: 0x100EC
+// CHECK-NEXT: Size: 0
+// CHECK-NEXT: Binding: Loca
+// CHECK-NEXT: Type: None
+// CHECK-NEXT: Other: 0
+// CHECK-NEXT: Section: .mysec
+
+// CHECK: Name: zed
+// CHECK-NEXT: Value: 0x100EC
+// CHECK-NEXT: Size: 0
+// CHECK-NEXT: Binding: Local
+// CHECK-NEXT: Type: None
+// CHECK-NEXT: Other: 0
+// CHECK-NEXT: Section: .mysec
+
+// CHECK: Name: foo
+// CHECK-NEXT: Value: 0x100EC
+// CHECK-NEXT: Size: 0
+// CHECK-NEXT: Binding: Local
+// CHECK-NEXT: Type: None
+// CHECK-NEXT: Other: 2
+// CHECK-NEXT: Section: .mysec
+
+ // CHECK: ]
+
+ .text
+ .globl _start
+_start:
+// DISASM: Disassembly of section .text:
+// DISASM-NEXT: _start:
+
+ movl .mysec, %eax
+// addr(0x10) = 65768
+// DISASM-NEXT: movl 65768, %eax
+
+ movl .mysec+7, %eax
+// addr(0x42) + 3 = 65772 + 3 = 65775
+// DISASM-NEXT: movl 65775, %eax
+
+ movl .mysec+8, %eax
+// addr(0x42) = 65772
+// DISASM-NEXT: movl 65772, %eax
+
+ movl bar+7, %eax
+// addr(0x42) + 7 = 65772 + 7 = 65779
+// DISASM-NEXT: movl 65779, %eax
+
+ movl bar+8, %eax
+// addr(0x42) + 8 = 65772 + 8 = 65780
+// DISASM-NEXT: movl 65780, %eax
+
+ movl foo, %eax
+// addr(0x42) = 65772
+// DISASM-NEXT: movl 65772, %eax
+
+ movl foo+7, %eax
+// addr(0x42) + 7 = = 65772 + 7 = 65779
+// DISASM-NEXT: movl 65779, %eax
+
+ movl foo+8, %eax
+// addr(0x42) + 8 = = 65772 + 8 = 65780
+// DISASM-NEXT: movl 65780, %eax
+
+// From the other file: movl .mysec, %eax
+// addr(0x42) = 65772
+// DISASM-NEXT: movl 65772, %eax
Added: lld/trunk/test/elf2/relocation-in-merge.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf2/relocation-in-merge.s?rev=250737&view=auto
==============================================================================
--- lld/trunk/test/elf2/relocation-in-merge.s (added)
+++ lld/trunk/test/elf2/relocation-in-merge.s Mon Oct 19 16:00:02 2015
@@ -0,0 +1,7 @@
+// REQUIRES: x86
+// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux
+// RUN: not ld.lld2 %t.o -o %t 2>&1 | FileCheck %s
+// CHECK: Relocations pointing to SHF_MERGE are not supported
+
+ .section .foo,"aM", at progbits,4
+ .long bar
Added: lld/trunk/test/elf2/relocation-past-merge-end.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf2/relocation-past-merge-end.s?rev=250737&view=auto
==============================================================================
--- lld/trunk/test/elf2/relocation-past-merge-end.s (added)
+++ lld/trunk/test/elf2/relocation-past-merge-end.s Mon Oct 19 16:00:02 2015
@@ -0,0 +1,7 @@
+// REQUIRES: x86
+// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux
+// RUN: not ld.lld2 %t.o -o %t.so -shared 2>&1 | FileCheck %s
+// CHECK: Entry is past the end of the section
+
+ .long .foo + 1
+ .section .foo,"aM", at progbits,4
Added: lld/trunk/test/elf2/writable-merge.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf2/writable-merge.s?rev=250737&view=auto
==============================================================================
--- lld/trunk/test/elf2/writable-merge.s (added)
+++ lld/trunk/test/elf2/writable-merge.s Mon Oct 19 16:00:02 2015
@@ -0,0 +1,6 @@
+// REQUIRES: x86
+// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux
+// RUN: not ld.lld2 %t.o -o %t 2>&1 | FileCheck %s
+// CHECK: Writable SHF_MERGE sections are not supported
+
+ .section .foo,"awM", at progbits,4
More information about the llvm-commits
mailing list