Add support for merging the contents of SHF_MERGE sections.

For now SHF_STRINGS are not supported.

llvm-svn: 250737
This commit is contained in:
Rafael Espindola 2015-10-19 21:00:02 +00:00
parent f215dac553
commit c159c967f6
15 changed files with 452 additions and 71 deletions

View File

@ -150,16 +150,28 @@ void elf2::ObjectFile<ELFT>::initializeSections(DenseSet<StringRef> &Comdats) {
uint32_t RelocatedSectionIndex = Sec.sh_info; uint32_t RelocatedSectionIndex = Sec.sh_info;
if (RelocatedSectionIndex >= Size) if (RelocatedSectionIndex >= Size)
error("Invalid relocated section index"); error("Invalid relocated section index");
InputSection<ELFT> *RelocatedSection = Sections[RelocatedSectionIndex]; InputSectionBase<ELFT> *RelocatedSection =
Sections[RelocatedSectionIndex];
if (!RelocatedSection) if (!RelocatedSection)
error("Unsupported relocation reference"); 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; break;
} }
default: default: {
Sections[I] = new (this->Alloc) InputSection<ELFT>(this, &Sec); 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; break;
} }
}
} }
} }
@ -173,7 +185,7 @@ template <class ELFT> void elf2::ObjectFile<ELFT>::initializeSymbols() {
} }
template <class ELFT> template <class ELFT>
InputSection<ELFT> * InputSectionBase<ELFT> *
elf2::ObjectFile<ELFT>::getSection(const Elf_Sym &Sym) const { elf2::ObjectFile<ELFT>::getSection(const Elf_Sym &Sym) const {
uint32_t Index = Sym.st_shndx; uint32_t Index = Sym.st_shndx;
if (Index == ELF::SHN_XINDEX) if (Index == ELF::SHN_XINDEX)
@ -209,7 +221,7 @@ SymbolBody *elf2::ObjectFile<ELFT>::createSymbolBody(StringRef StringTable,
case STB_GLOBAL: case STB_GLOBAL:
case STB_WEAK: case STB_WEAK:
case STB_GNU_UNIQUE: { case STB_GNU_UNIQUE: {
InputSection<ELFT> *Sec = getSection(*Sym); InputSectionBase<ELFT> *Sec = getSection(*Sym);
if (Sec == &InputSection<ELFT>::Discarded) if (Sec == &InputSection<ELFT>::Discarded)
return new (this->Alloc) Undefined<ELFT>(Name, *Sym); return new (this->Alloc) Undefined<ELFT>(Name, *Sym);
return new (this->Alloc) DefinedRegular<ELFT>(Name, *Sym, *Sec); return new (this->Alloc) DefinedRegular<ELFT>(Name, *Sym, *Sec);

View File

@ -94,6 +94,7 @@ template <class ELFT> class ObjectFile : public ELFFileBase<ELFT> {
typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr; 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_Sym_Range Elf_Sym_Range;
typedef typename llvm::object::ELFFile<ELFT>::Elf_Word Elf_Word; 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< typedef llvm::support::detail::packed_endian_specific_integral<
uint32_t, ELFT::TargetEndianness, 2> GroupEntryType; uint32_t, ELFT::TargetEndianness, 2> GroupEntryType;
@ -110,8 +111,8 @@ public:
explicit ObjectFile(MemoryBufferRef M); explicit ObjectFile(MemoryBufferRef M);
void parse(llvm::DenseSet<StringRef> &Comdats); void parse(llvm::DenseSet<StringRef> &Comdats);
ArrayRef<InputSection<ELFT> *> getSections() const { return Sections; } ArrayRef<InputSectionBase<ELFT> *> getSections() const { return Sections; }
InputSection<ELFT> *getSection(const Elf_Sym &Sym) const; InputSectionBase<ELFT> *getSection(const Elf_Sym &Sym) const;
SymbolBody *getSymbolBody(uint32_t SymbolIndex) const { SymbolBody *getSymbolBody(uint32_t SymbolIndex) const {
uint32_t FirstNonLocal = this->Symtab->sh_info; uint32_t FirstNonLocal = this->Symtab->sh_info;
@ -132,7 +133,7 @@ private:
SymbolBody *createSymbolBody(StringRef StringTable, const Elf_Sym *Sym); SymbolBody *createSymbolBody(StringRef StringTable, const Elf_Sym *Sym);
// List of all sections defined by this file. // List of all sections defined by this file.
std::vector<InputSection<ELFT> *> Sections; std::vector<InputSectionBase<ELFT> *> Sections;
ArrayRef<Elf_Word> SymtabSHNDX; ArrayRef<Elf_Word> SymtabSHNDX;

View File

@ -21,9 +21,42 @@ using namespace llvm::object;
using namespace lld; using namespace lld;
using namespace lld::elf2; 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> template <class ELFT>
InputSection<ELFT>::InputSection(ObjectFile<ELFT> *F, const Elf_Shdr *Header) 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 <class ELFT>
template <bool isRela> template <bool isRela>
@ -65,35 +98,63 @@ void InputSection<ELFT>::relocate(
} }
template <class ELFT> void InputSection<ELFT>::writeTo(uint8_t *Buf) { template <class ELFT> void InputSection<ELFT>::writeTo(uint8_t *Buf) {
if (Header->sh_type == SHT_NOBITS) if (this->Header->sh_type == SHT_NOBITS)
return; return;
// Copy section contents from source object file to output file. // 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()); memcpy(Buf + OutSecOff, Data.data(), Data.size());
ELFFile<ELFT> &EObj = File->getObj(); ELFFile<ELFT> &EObj = this->File->getObj();
uint8_t *Base = Buf + OutSecOff; 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. // Iterate over all relocation sections that apply to this section.
for (const Elf_Shdr *RelSec : RelocSections) { for (const Elf_Shdr *RelSec : RelocSections) {
if (RelSec->sh_type == SHT_RELA) 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 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 { template <class ELFT>
ErrorOr<StringRef> Name = File->getObj().getSectionName(Header); MergeInputSection<ELFT>::MergeInputSection(ObjectFile<ELFT> *F,
error(Name); const Elf_Shdr *Header)
return *Name; : 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 lld {
namespace elf2 { 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::ELF32LE>;
template class InputSection<object::ELF32BE>; template class InputSection<object::ELF32BE>;
template class InputSection<object::ELF64LE>; template class InputSection<object::ELF64LE>;
template class InputSection<object::ELF64BE>; 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>;
} }
} }

View File

@ -21,22 +21,28 @@ template <class ELFT> class OutputSection;
template <class ELFT> class OutputSectionBase; template <class ELFT> class OutputSectionBase;
// This corresponds to a section of an input file. // 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_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>::Elf_Sym Elf_Sym;
typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t; typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t;
const Elf_Shdr *Header;
// The file this section is from.
ObjectFile<ELFT> *File;
public: 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.) // Returns the size of this section (even if this is a common or BSS.)
size_t getSize() const { return Header->sh_size; } size_t getSize() const { return Header->sh_size; }
// Write this section to a mmap'ed file, assuming Buf is pointing to static InputSectionBase<ELFT> Discarded;
// beginning of the output section.
void writeTo(uint8_t *Buf);
StringRef getSectionName() const; StringRef getSectionName() const;
const Elf_Shdr *getSectionHdr() const { return Header; } const Elf_Shdr *getSectionHdr() const { return Header; }
@ -49,15 +55,52 @@ public:
return std::max<uintX_t>(Header->sh_addralign, 1); 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. // Relocation sections that refer to this one.
SmallVector<const Elf_Shdr *, 1> RelocSections; SmallVector<const Elf_Shdr *, 1> RelocSections;
// The offset from beginning of the output sections this section was assigned // The offset from beginning of the output sections this section was assigned
// to. The writer sets a value. // to. The writer sets a value.
uint64_t OutSecOff = 0; uint64_t OutSecOff = 0;
OutputSectionBase<ELFT> *OutSec = nullptr;
static InputSection<ELFT> Discarded; static bool classof(const InputSectionBase<ELFT> *S);
private: private:
template <bool isRela> template <bool isRela>
@ -65,16 +108,8 @@ private:
llvm::iterator_range< llvm::iterator_range<
const llvm::object::Elf_Rel_Impl<ELFT, isRela> *> Rels, const llvm::object::Elf_Rel_Impl<ELFT, isRela> *> Rels,
const ObjectFile<ELFT> &File, uintX_t BaseAddr); 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 elf2
} // namespace lld } // namespace lld

View File

@ -408,8 +408,8 @@ typename ELFFile<ELFT>::uintX_t lld::elf2::getSymVA(const SymbolBody &S) {
return cast<DefinedAbsolute<ELFT>>(S).Sym.st_value; return cast<DefinedAbsolute<ELFT>>(S).Sym.st_value;
case SymbolBody::DefinedRegularKind: { case SymbolBody::DefinedRegularKind: {
const auto &DR = cast<DefinedRegular<ELFT>>(S); const auto &DR = cast<DefinedRegular<ELFT>>(S);
const InputSection<ELFT> &SC = DR.Section; const InputSectionBase<ELFT> &SC = DR.Section;
return SC.OutSec->getVA() + SC.OutSecOff + DR.Sym.st_value; return SC.OutSec->getVA() + SC.getOffset(DR.Sym);
} }
case SymbolBody::DefinedCommonKind: case SymbolBody::DefinedCommonKind:
return Out<ELFT>::Bss->getVA() + cast<DefinedCommon<ELFT>>(S).OffsetInBSS; return Out<ELFT>::Bss->getVA() + cast<DefinedCommon<ELFT>>(S).OffsetInBSS;
@ -449,11 +449,22 @@ lld::elf2::getLocalRelTarget(const ObjectFile<ELFT> &File,
// the group are not allowed. Unfortunately .eh_frame breaks that rule // the group are not allowed. Unfortunately .eh_frame breaks that rule
// and must be treated specially. For now we just replace the symbol with // and must be treated specially. For now we just replace the symbol with
// 0. // 0.
InputSection<ELFT> *Section = File.getSection(*Sym); InputSectionBase<ELFT> *Section = File.getSection(*Sym);
if (Section == &InputSection<ELFT>::Discarded) if (Section == &InputSection<ELFT>::Discarded)
return Addend; 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 // Returns true if a symbol can be replaced at load-time by a symbol
@ -499,6 +510,44 @@ template <class ELFT> void OutputSection<ELFT>::writeTo(uint8_t *Buf) {
C->writeTo(Buf); C->writeTo(Buf);
} }
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> template <class ELFT>
StringTableSection<ELFT>::StringTableSection(bool Dynamic) StringTableSection<ELFT>::StringTableSection(bool Dynamic)
: OutputSectionBase<ELFT>(Dynamic ? ".dynstr" : ".strtab", : OutputSectionBase<ELFT>(Dynamic ? ".dynstr" : ".strtab",
@ -611,13 +660,15 @@ void SymbolTableSection<ELFT>::writeLocalSymbols(uint8_t *&Buf) {
ESym->st_name = StrTabSec.getFileOff(SymName); ESym->st_name = StrTabSec.getFileOff(SymName);
ESym->st_size = Sym.st_size; ESym->st_size = Sym.st_size;
ESym->setBindingAndType(Sym.getBinding(), Sym.getType()); ESym->setBindingAndType(Sym.getBinding(), Sym.getType());
uintX_t VA = Sym.st_value; uintX_t VA = 0;
if (Sym.st_shndx == SHN_ABS) { if (Sym.st_shndx == SHN_ABS) {
ESym->st_shndx = SHN_ABS; ESym->st_shndx = SHN_ABS;
VA = Sym.st_value;
} else { } else {
const InputSection<ELFT> *Sec = File->getSection(Sym); const InputSectionBase<ELFT> *Section = File->getSection(Sym);
ESym->st_shndx = Sec->OutSec->SectionIndex; const OutputSectionBase<ELFT> *OutSec = Section->OutSec;
VA += Sec->OutSec->getVA() + Sec->OutSecOff; ESym->st_shndx = OutSec->SectionIndex;
VA += OutSec->getVA() + Section->getOffset(Sym);
} }
ESym->st_value = VA; ESym->st_value = VA;
} }
@ -644,7 +695,7 @@ void SymbolTableSection<ELFT>::writeGlobalSymbols(uint8_t *Buf) {
ESym->st_name = StrTabSec.getFileOff(Name); ESym->st_name = StrTabSec.getFileOff(Name);
const OutputSectionBase<ELFT> *OutSec = nullptr; const OutputSectionBase<ELFT> *OutSec = nullptr;
const InputSection<ELFT> *Section = nullptr; const InputSectionBase<ELFT> *Section = nullptr;
switch (Body->kind()) { switch (Body->kind()) {
case SymbolBody::DefinedSyntheticKind: case SymbolBody::DefinedSyntheticKind:
@ -740,6 +791,11 @@ template class OutputSection<ELF32BE>;
template class OutputSection<ELF64LE>; template class OutputSection<ELF64LE>;
template class OutputSection<ELF64BE>; 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<ELF32LE>;
template class StringTableSection<ELF32BE>; template class StringTableSection<ELF32BE>;
template class StringTableSection<ELF64LE>; template class StringTableSection<ELF64LE>;
@ -758,19 +814,29 @@ template ELFFile<ELF64BE>::uintX_t getSymVA<ELF64BE>(const SymbolBody &);
template ELFFile<ELF32LE>::uintX_t template ELFFile<ELF32LE>::uintX_t
getLocalRelTarget(const ObjectFile<ELF32LE> &, getLocalRelTarget(const ObjectFile<ELF32LE> &,
const ELFFile<ELF32LE>::Elf_Rel &); const ELFFile<ELF32LE>::Elf_Rel &);
template ELFFile<ELF32BE>::uintX_t template ELFFile<ELF32BE>::uintX_t
getLocalRelTarget(const ObjectFile<ELF32BE> &, getLocalRelTarget(const ObjectFile<ELF32BE> &,
const ELFFile<ELF32BE>::Elf_Rel &); const ELFFile<ELF32BE>::Elf_Rel &);
template ELFFile<ELF64LE>::uintX_t template ELFFile<ELF64LE>::uintX_t
getLocalRelTarget(const ObjectFile<ELF64LE> &, getLocalRelTarget(const ObjectFile<ELF64LE> &,
const ELFFile<ELF64LE>::Elf_Rel &); const ELFFile<ELF64LE>::Elf_Rel &);
template ELFFile<ELF64BE>::uintX_t template ELFFile<ELF64BE>::uintX_t
getLocalRelTarget(const ObjectFile<ELF64BE> &, getLocalRelTarget(const ObjectFile<ELF64BE> &,
const ELFFile<ELF64BE>::Elf_Rel &); 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<ELF32LE>(const SymbolBody &);
template bool includeInSymtab<ELF32BE>(const SymbolBody &); template bool includeInSymtab<ELF32BE>(const SymbolBody &);
template bool includeInSymtab<ELF64LE>(const SymbolBody &); template bool includeInSymtab<ELF64LE>(const SymbolBody &);

View File

@ -12,6 +12,7 @@
#include "lld/Core/LLVM.h" #include "lld/Core/LLVM.h"
#include "llvm/ADT/MapVector.h"
#include "llvm/MC/StringTableBuilder.h" #include "llvm/MC/StringTableBuilder.h"
#include "llvm/Object/ELF.h" #include "llvm/Object/ELF.h"
@ -27,6 +28,7 @@ template <class ELFT> class SymbolTable;
template <class ELFT> class SymbolTableSection; template <class ELFT> class SymbolTableSection;
template <class ELFT> class StringTableSection; template <class ELFT> class StringTableSection;
template <class ELFT> class InputSection; template <class ELFT> class InputSection;
template <class ELFT> class MergeInputSection;
template <class ELFT> class OutputSection; template <class ELFT> class OutputSection;
template <class ELFT> class ObjectFile; template <class ELFT> class ObjectFile;
template <class ELFT> class DefinedRegular; template <class ELFT> class DefinedRegular;
@ -203,6 +205,23 @@ private:
std::vector<InputSection<ELFT> *> Sections; std::vector<InputSection<ELFT> *> Sections;
}; };
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> template <class ELFT>
class InterpSection final : public OutputSectionBase<ELFT> { class InterpSection final : public OutputSectionBase<ELFT> {
public: public:

View File

@ -217,14 +217,15 @@ template <class ELFT> class DefinedRegular : public Defined<ELFT> {
typedef typename Base::Elf_Sym Elf_Sym; typedef typename Base::Elf_Sym Elf_Sym;
public: 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) {} : Defined<ELFT>(Base::DefinedRegularKind, N, Sym), Section(Section) {}
static bool classof(const SymbolBody *S) { static bool classof(const SymbolBody *S) {
return S->kind() == Base::DefinedRegularKind; return S->kind() == Base::DefinedRegularKind;
} }
const InputSection<ELFT> &Section; const InputSectionBase<ELFT> &Section;
}; };
template <class ELFT> class DefinedSynthetic : public Defined<ELFT> { template <class ELFT> class DefinedSynthetic : public Defined<ELFT> {

View File

@ -71,6 +71,7 @@ private:
std::unique_ptr<llvm::FileOutputBuffer> Buffer; std::unique_ptr<llvm::FileOutputBuffer> Buffer;
SpecificBumpPtrAllocator<OutputSection<ELFT>> SecAlloc; SpecificBumpPtrAllocator<OutputSection<ELFT>> SecAlloc;
SpecificBumpPtrAllocator<MergeOutputSection<ELFT>> MSecAlloc;
BumpPtrAllocator Alloc; BumpPtrAllocator Alloc;
std::vector<OutputSectionBase<ELFT> *> OutputSections; std::vector<OutputSectionBase<ELFT> *> OutputSections;
unsigned getNumSections() const { return OutputSections.size() + 1; } unsigned getNumSections() const { return OutputSections.size() + 1; }
@ -135,24 +136,27 @@ template <bool Is64Bits> struct SectionKey {
StringRef Name; StringRef Name;
uint32_t Type; uint32_t Type;
uintX_t Flags; uintX_t Flags;
uintX_t EntSize;
}; };
} }
namespace llvm { namespace llvm {
template <bool Is64Bits> struct DenseMapInfo<SectionKey<Is64Bits>> { template <bool Is64Bits> struct DenseMapInfo<SectionKey<Is64Bits>> {
static SectionKey<Is64Bits> getEmptyKey() { 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() { static SectionKey<Is64Bits> getTombstoneKey() {
return SectionKey<Is64Bits>{DenseMapInfo<StringRef>::getTombstoneKey(), 0, return SectionKey<Is64Bits>{DenseMapInfo<StringRef>::getTombstoneKey(), 0,
0}; 0, 0};
} }
static unsigned getHashValue(const SectionKey<Is64Bits> &Val) { 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, static bool isEqual(const SectionKey<Is64Bits> &LHS,
const SectionKey<Is64Bits> &RHS) { const SectionKey<Is64Bits> &RHS) {
return DenseMapInfo<StringRef>::isEqual(LHS.Name, RHS.Name) && 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>::createSections() {
if (needsInterpSection()) if (needsInterpSection())
OutputSections.push_back(Out<ELFT>::Interp); 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); OutputSections.push_back(Out<ELFT>::Bss);
Map[{Out<ELFT>::Bss->getName(), Out<ELFT>::Bss->getType(), 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; std::vector<OutputSectionBase<ELFT> *> RegularSections;
for (const std::unique_ptr<ObjectFile<ELFT>> &F : Symtab.getObjectFiles()) { 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) if (!C || C == &InputSection<ELFT>::Discarded)
continue; continue;
const Elf_Shdr *H = C->getSectionHdr(); const Elf_Shdr *H = C->getSectionHdr();
uintX_t OutFlags = H->sh_flags & ~SHF_GROUP; 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()), SectionKey<ELFT::Is64Bits> Key{getOutputName(C->getSectionName()),
H->sh_type, OutFlags}; H->sh_type, OutFlags, EntSize};
OutputSection<ELFT> *&Sec = Map[Key]; OutputSectionBase<ELFT> *&Sec = Map[Key];
if (!Sec) { if (!Sec) {
Sec = new (SecAlloc.Allocate()) if (IS)
OutputSection<ELFT>(Key.Name, Key.Type, Key.Flags); 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); OutputSections.push_back(Sec);
RegularSections.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 = Out<ELFT>::Dynamic->PreInitArraySec = Map.lookup(
Map.lookup({".preinit_array", SHT_PREINIT_ARRAY, SHF_WRITE | SHF_ALLOC}); {".preinit_array", SHT_PREINIT_ARRAY, SHF_WRITE | SHF_ALLOC, 0});
Out<ELFT>::Dynamic->InitArraySec = 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 = 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, auto AddStartEnd = [&](StringRef Start, StringRef End,
OutputSectionBase<ELFT> *OS) { OutputSectionBase<ELFT> *OS) {
@ -455,9 +472,10 @@ template <class ELFT> void Writer<ELFT>::createSections() {
// Scan relocations. This must be done after every symbol is declared so that // Scan relocations. This must be done after every symbol is declared so that
// we can correctly decide if a dynamic relocation is needed. // we can correctly decide if a dynamic relocation is needed.
for (const std::unique_ptr<ObjectFile<ELFT>> &F : Symtab.getObjectFiles()) for (const std::unique_ptr<ObjectFile<ELFT>> &F : Symtab.getObjectFiles())
for (InputSection<ELFT> *S : F->getSections()) for (InputSectionBase<ELFT> *B : F->getSections())
if (S && S != &InputSection<ELFT>::Discarded) if (auto *S = dyn_cast_or_null<InputSection<ELFT>>(B))
scanRelocs(*S); if (S != &InputSection<ELFT>::Discarded)
scanRelocs(*S);
// FIXME: Try to avoid the extra walk over all global symbols. // FIXME: Try to avoid the extra walk over all global symbols.
std::vector<DefinedCommon<ELFT> *> CommonSymbols; std::vector<DefinedCommon<ELFT> *> CommonSymbols;
@ -516,7 +534,7 @@ template <class ELFT> void Writer<ELFT>::createSections() {
// If we have a .opd section (used under PPC64 for function descriptors), // 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 // store a pointer to it here so that we can use it later when processing
// relocations. // 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) { static bool isAlpha(char C) {

View File

@ -0,0 +1,6 @@
.section .mysec,"aM",@progbits,4
.align 4
.long 0x42
.text
movl .mysec, %eax

View File

@ -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",@progbits,4
.short 42

View File

@ -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",@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: ]

109
lld/test/elf2/merge.s Normal file
View File

@ -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",@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

View File

@ -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",@progbits,4
.long bar

View File

@ -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",@progbits,4

View File

@ -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",@progbits,4