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;
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::ObjectFile<ELFT>::initializeSymbols() {
}
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>::createSymbolBody(StringRef StringTable,
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);

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_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;

View File

@ -21,9 +21,42 @@ using namespace llvm::object;
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>;
}
}

View File

@ -21,22 +21,28 @@ template <class ELFT> class OutputSection;
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

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;
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 ObjectFile<ELFT> &File,
// 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
@ -499,6 +510,44 @@ template <class ELFT> void OutputSection<ELFT>::writeTo(uint8_t *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>
StringTableSection<ELFT>::StringTableSection(bool Dynamic)
: OutputSectionBase<ELFT>(Dynamic ? ".dynstr" : ".strtab",
@ -611,13 +660,15 @@ void SymbolTableSection<ELFT>::writeLocalSymbols(uint8_t *&Buf) {
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>::writeGlobalSymbols(uint8_t *Buf) {
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 getSymVA<ELF64BE>(const SymbolBody &);
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 &);

View File

@ -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;
@ -203,6 +205,23 @@ private:
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>
class InterpSection final : public OutputSectionBase<ELFT> {
public:

View File

@ -217,14 +217,15 @@ template <class ELFT> class DefinedRegular : public Defined<ELFT> {
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> {

View File

@ -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 SectionKey {
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>::createSections() {
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>::createSections() {
// 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>::createSections() {
// 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) {

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