forked from OSchip/llvm-project
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:
parent
f215dac553
commit
c159c967f6
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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>;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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 &);
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
.section .mysec,"aM",@progbits,4
|
||||
.align 4
|
||||
.long 0x42
|
||||
|
||||
.text
|
||||
movl .mysec, %eax
|
|
@ -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
|
|
@ -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: ]
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
Loading…
Reference in New Issue