Index: ELF/InputFiles.h =================================================================== --- ELF/InputFiles.h +++ ELF/InputFiles.h @@ -110,8 +110,8 @@ explicit ObjectFile(MemoryBufferRef M); void parse(llvm::DenseSet &Comdats); - ArrayRef *> getSections() const { return Sections; } - InputSection *getSection(const Elf_Sym &Sym) const; + ArrayRef *> getSections() const { return Sections; } + InputSectionBase *getSection(const Elf_Sym &Sym) const; SymbolBody *getSymbolBody(uint32_t SymbolIndex) const { uint32_t FirstNonLocal = this->Symtab->sh_info; @@ -132,7 +132,7 @@ SymbolBody *createSymbolBody(StringRef StringTable, const Elf_Sym *Sym); // List of all sections defined by this file. - std::vector *> Sections; + std::vector *> Sections; ArrayRef SymtabSHNDX; Index: ELF/InputFiles.cpp =================================================================== --- ELF/InputFiles.cpp +++ ELF/InputFiles.cpp @@ -150,14 +150,21 @@ uint32_t RelocatedSectionIndex = Sec.sh_info; if (RelocatedSectionIndex >= Size) error("Invalid relocated section index"); - InputSection *RelocatedSection = Sections[RelocatedSectionIndex]; + InputSectionBase *RelocatedSection = + Sections[RelocatedSectionIndex]; if (!RelocatedSection) error("Unsupported relocation reference"); - RelocatedSection->RelocSections.push_back(&Sec); + if (auto *S = dyn_cast>(RelocatedSection)) + S->RelocSections.push_back(&Sec); + else + error("bar"); break; } default: - Sections[I] = new (this->Alloc) InputSection(this, &Sec); + if (Sec.sh_flags & SHF_MERGE) + Sections[I] = new (this->Alloc) MergeInputSection(this, &Sec); + else + Sections[I] = new (this->Alloc) InputSection(this, &Sec); break; } } @@ -173,7 +180,7 @@ } template -InputSection * +InputSectionBase * elf2::ObjectFile::getSection(const Elf_Sym &Sym) const { uint32_t Index = Sym.st_shndx; if (Index == ELF::SHN_XINDEX) @@ -209,7 +216,7 @@ case STB_GLOBAL: case STB_WEAK: case STB_GNU_UNIQUE: { - InputSection *Sec = getSection(*Sym); + InputSectionBase *Sec = getSection(*Sym); if (Sec == &InputSection::Discarded) return new (this->Alloc) Undefined(Name, *Sym); return new (this->Alloc) DefinedRegular(Name, *Sym, *Sec); Index: ELF/InputSection.h =================================================================== --- ELF/InputSection.h +++ ELF/InputSection.h @@ -21,26 +21,32 @@ template class OutputSectionBase; // This corresponds to a section of an input file. -template class InputSection { +template class InputSectionBase { +protected: typedef typename llvm::object::ELFFile::Elf_Shdr Elf_Shdr; - typedef typename llvm::object::ELFFile::Elf_Rela Elf_Rela; - typedef typename llvm::object::ELFFile::Elf_Rel Elf_Rel; typedef typename llvm::object::ELFFile::Elf_Sym Elf_Sym; typedef typename llvm::object::ELFFile::uintX_t uintX_t; + const Elf_Shdr *Header; + + // The file this section is from. + ObjectFile *File; public: - InputSection(ObjectFile *F, const Elf_Shdr *Header); + enum Kind { Regular, Merge }; + Kind SectionKind; + + InputSectionBase(ObjectFile *File, const Elf_Shdr *Header, + Kind SectionKind); + OutputSectionBase *OutSec = nullptr; + + const Elf_Shdr *getSectionHdr() const { return Header; } // 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 Discarded; StringRef getSectionName() const; - const Elf_Shdr *getSectionHdr() const { return Header; } - ObjectFile *getFile() const { return File; } // The writer sets and uses the addresses. uintX_t getAlign() { @@ -49,38 +55,70 @@ return std::max(Header->sh_addralign, 1); } + ObjectFile *getFile() const { return File; } + + ArrayRef getSectionData() const; +}; + +template +InputSectionBase + InputSectionBase::Discarded(nullptr, nullptr, + InputSectionBase::Regular); + +// This corresponds to a merge section of an input file. +template class MergeInputSection : public InputSectionBase { + typedef InputSectionBase Base; + typedef typename Base::uintX_t uintX_t; + typedef typename Base::Elf_Sym Elf_Sym; + typedef typename Base::Elf_Shdr Elf_Shdr; + +public: + MergeInputSection(ObjectFile *F, const Elf_Shdr *Header); + static bool classof(const InputSectionBase *S); + unsigned getOffset(const Elf_Sym &Sym) const; +}; + +// This corresponds to a non merge section of an input file. +template class InputSection : public InputSectionBase { + typedef InputSectionBase Base; + typedef typename Base::Elf_Shdr Elf_Shdr; + typedef typename llvm::object::ELFFile::Elf_Rela Elf_Rela; + typedef typename llvm::object::ELFFile::Elf_Rel Elf_Rel; + typedef typename Base::Elf_Sym Elf_Sym; + typedef typename Base::uintX_t uintX_t; + +public: + InputSection(ObjectFile *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 RelocSections; // The offset from beginning of the output sections this section was assigned // to. The writer sets a value. uint64_t OutSecOff = 0; - OutputSectionBase *OutSec = nullptr; - static InputSection Discarded; + static bool classof(const InputSectionBase *S); private: - static void relocateOne(uint8_t *Buf, uint8_t *BufEnd, const Elf_Rel &Rel, - uint32_t Type, uintX_t BaseAddr, uintX_t SymVA); + static void relocateOne(const ObjectFile &File, uint8_t *Buf, + uint8_t *BufEnd, const Elf_Rel &Rel, uint32_t Type, + uintX_t BaseAddr, uintX_t SymVA); - static void relocateOne(uint8_t *Buf, uint8_t *BufEnd, const Elf_Rela &Rel, - uint32_t Type, uintX_t BaseAddr, uintX_t SymVA); + static void relocateOne(const ObjectFile &File, uint8_t *Buf, + uint8_t *BufEnd, const Elf_Rela &Rel, uint32_t Type, + uintX_t BaseAddr, uintX_t SymVA); template void relocate(uint8_t *Buf, uint8_t *BufEnd, llvm::iterator_range< const llvm::object::Elf_Rel_Impl *> Rels, const ObjectFile &File, uintX_t BaseAddr); - - // The file this section is from. - ObjectFile *File; - - const Elf_Shdr *Header; }; -template -InputSection InputSection::Discarded(nullptr, nullptr); - } // namespace elf2 } // namespace lld Index: ELF/InputSection.cpp =================================================================== --- ELF/InputSection.cpp +++ ELF/InputSection.cpp @@ -22,23 +22,71 @@ using namespace lld::elf2; template +InputSectionBase::InputSectionBase(ObjectFile *File, + const Elf_Shdr *Header, + Kind SectionKind) + : Header(Header), File(File), SectionKind(SectionKind) {} + +template StringRef InputSectionBase::getSectionName() const { + ErrorOr Name = File->getObj().getSectionName(this->Header); + error(Name); + return *Name; +} + +template +ArrayRef InputSectionBase::getSectionData() const { + ErrorOr> Ret = + this->File->getObj().getSectionContents(this->Header); + error(Ret); + return *Ret; +} + +template InputSection::InputSection(ObjectFile *F, const Elf_Shdr *Header) - : File(F), Header(Header) {} + : InputSectionBase(F, Header, Base::Regular) {} template -void InputSection::relocateOne(uint8_t *Buf, uint8_t *BufEnd, - const Elf_Rel &Rel, uint32_t Type, - uintX_t BaseAddr, uintX_t SymVA) { +bool InputSection::classof(const InputSectionBase *S) { + return S->SectionKind == Base::Regular; +} + +template +void InputSection::relocateOne(const ObjectFile &File, uint8_t *Buf, + uint8_t *BufEnd, const Elf_Rel &Rel, + uint32_t Type, uintX_t BaseAddr, + uintX_t SymVA) { Target->relocateOne(Buf, BufEnd, reinterpret_cast(&Rel), Type, BaseAddr, SymVA); } template -void InputSection::relocateOne(uint8_t *Buf, uint8_t *BufEnd, - const Elf_Rela &Rel, uint32_t Type, - uintX_t BaseAddr, uintX_t SymVA) { +static typename ELFFile::uintX_t +adjustAddend(const ObjectFile &File, + const typename ELFFile::Elf_Rela &Rel) { + typedef typename ELFFile::Elf_Sym Elf_Sym; + typedef typename ELFFile::uintX_t uintX_t; + + uintX_t Addend = Rel.r_addend; + const Elf_Sym *Sym = + File.getObj().getRelocationSymbol(&Rel, File.getSymbolTable()); + if (!Sym) + return Addend; + if (Sym->getType() != STT_SECTION) + return Addend; + + const InputSectionBase *Section = File.getSection(*Sym); + if (Section && isa>(Section)) + return Addend % Section->getSectionHdr()->sh_entsize; + return Addend; +} + +template +void InputSection::relocateOne(const ObjectFile &File, uint8_t *Buf, + uint8_t *BufEnd, const Elf_Rela &Rel, + uint32_t Type, uintX_t BaseAddr, + uintX_t SymVA) { Target->relocateOne(Buf, BufEnd, reinterpret_cast(&Rel), Type, - BaseAddr, SymVA + Rel.r_addend); + BaseAddr, SymVA + adjustAddend(File, Rel)); } template @@ -58,7 +106,7 @@ const Elf_Shdr *SymTab = File.getSymbolTable(); if (SymIndex < SymTab->sh_info) { uintX_t SymVA = getLocalRelTarget(File, RI); - relocateOne(Buf, BufEnd, RI, Type, BaseAddr, SymVA); + relocateOne(File, Buf, BufEnd, RI, Type, BaseAddr, SymVA); continue; } @@ -76,40 +124,67 @@ } else if (isa>(Body)) { continue; } - relocateOne(Buf, BufEnd, RI, Type, BaseAddr, SymVA); + relocateOne(File, Buf, BufEnd, RI, Type, BaseAddr, SymVA); } } template void InputSection::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 Data = *File->getObj().getSectionContents(Header); + ArrayRef Data = this->getSectionData(); memcpy(Buf + OutSecOff, Data.data(), Data.size()); - ELFFile &EObj = File->getObj(); + ELFFile &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 StringRef InputSection::getSectionName() const { - ErrorOr Name = File->getObj().getSectionName(Header); - error(Name); - return *Name; +template +MergeInputSection::MergeInputSection(ObjectFile *F, + const Elf_Shdr *Header) + : InputSectionBase(F, Header, Base::Merge) {} + +template +bool MergeInputSection::classof(const InputSectionBase *S) { + return S->SectionKind == Base::Merge; +} + +template +unsigned MergeInputSection::getOffset(const Elf_Sym &Sym) const { + uintX_t EntSize = this->Header->sh_entsize; + ArrayRef Data = this->getSectionData(); + uintX_t Value = Sym.st_value; + if (Value + EntSize > Data.size()) + error("zed"); + Data = Data.slice(Value, EntSize); + return static_cast *>(this->OutSec)->getOffset(Data); } namespace lld { namespace elf2 { +template class InputSectionBase; +template class InputSectionBase; +template class InputSectionBase; +template class InputSectionBase; + template class InputSection; template class InputSection; template class InputSection; template class InputSection; + +template class MergeInputSection; +template class MergeInputSection; +template class MergeInputSection; +template class MergeInputSection; } } Index: ELF/OutputSections.h =================================================================== --- ELF/OutputSections.h +++ ELF/OutputSections.h @@ -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 SymbolTableSection; template class StringTableSection; template class InputSection; +template class MergeInputSection; template class OutputSection; template class ObjectFile; template class DefinedRegular; @@ -35,10 +37,10 @@ template typename llvm::object::ELFFile::uintX_t getSymVA(const SymbolBody &S); -template +template typename llvm::object::ELFFile::uintX_t getLocalRelTarget(const ObjectFile &File, - const typename llvm::object::ELFFile::Elf_Rel &Sym); + const llvm::object::Elf_Rel_Impl &Rel); bool canBePreempted(const SymbolBody *Body, bool NeedsGot); template bool includeInSymtab(const SymbolBody &B); @@ -192,6 +194,21 @@ }; template +class MergeOutputSection final : public OutputSectionBase { + typedef typename OutputSectionBase::uintX_t uintX_t; + +public: + MergeOutputSection(StringRef Name, uint32_t sh_type, uintX_t sh_flags); + void addSection(MergeInputSection *S); + void writeTo(uint8_t *Buf) override; + + unsigned getOffset(ArrayRef Val); + +private: + llvm::MapVector Offsets; +}; + +template class InterpSection final : public OutputSectionBase { public: InterpSection(); Index: ELF/OutputSections.cpp =================================================================== --- ELF/OutputSections.cpp +++ ELF/OutputSections.cpp @@ -12,6 +12,9 @@ #include "SymbolTable.h" #include "Target.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/Format.h" + using namespace llvm; using namespace llvm::object; using namespace llvm::support::endian; @@ -395,6 +398,7 @@ template typename ELFFile::uintX_t lld::elf2::getSymVA(const SymbolBody &S) { + typedef typename ELFFile::uintX_t uintX_t; switch (S.kind()) { case SymbolBody::DefinedSyntheticKind: { auto &D = cast>(S); @@ -404,8 +408,13 @@ return cast>(S).Sym.st_value; case SymbolBody::DefinedRegularKind: { const auto &DR = cast>(S); - const InputSection *SC = &DR.Section; - return SC->OutSec->getVA() + SC->OutSecOff + DR.Sym.st_value; + const InputSectionBase *SC = &DR.Section; + uintX_t VA = SC->OutSec->getVA(); + if (auto *S = dyn_cast>(SC)) + VA += DR.Sym.st_value + S->OutSecOff; + else + VA += cast>(SC)->getOffset(DR.Sym); + return VA; } case SymbolBody::DefinedCommonKind: return Out::Bss->getVA() + cast>(S).OffsetInBSS; @@ -419,15 +428,28 @@ llvm_unreachable("Invalid symbol kind"); } +template +static typename ELFFile::uintX_t +getAddend(const typename ELFFile::Elf_Rel &Rel) { + return 0; +} + +template +static typename ELFFile::uintX_t +getAddend(const typename ELFFile::Elf_Rela &Rel) { + return Rel.r_addend; +} + // Returns a VA which a relocatin RI refers to. Used only for local symbols. // For non-local symbols, use getSymVA instead. -template +template typename ELFFile::uintX_t lld::elf2::getLocalRelTarget(const ObjectFile &File, - const typename ELFFile::Elf_Rel &RI) { + const Elf_Rel_Impl &Rel) { typedef typename ELFFile::Elf_Sym Elf_Sym; + typedef typename ELFFile::uintX_t uintX_t; const Elf_Sym *Sym = - File.getObj().getRelocationSymbol(&RI, File.getSymbolTable()); + File.getObj().getRelocationSymbol(&Rel, File.getSymbolTable()); // For certain special relocations, such as R_PPC64_TOC, there's no // corresponding symbol. Just return 0 in that case. @@ -438,11 +460,28 @@ // 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 *Section = File.getSection(*Sym); + InputSectionBase *Section = File.getSection(*Sym); if (Section == &InputSection::Discarded) return 0; - return Section->OutSec->getVA() + Section->OutSecOff + Sym->st_value; + uintX_t VA = Section->OutSec->getVA(); + if (auto *S = dyn_cast>(Section)) + return VA + S->OutSecOff + Sym->st_value; + + uintX_t Offset = Sym->st_value; + if (Sym->getType() == STT_SECTION) + Offset += getAddend(Rel); + uintX_t EntSize = Section->getSectionHdr()->sh_entsize; + Offset -= (Offset % EntSize); + + ArrayRef Data = Section->getSectionData(); + if (Offset + EntSize > Data.size()) + error("zed"); + + Data = Data.slice(Offset, EntSize); + return VA + + static_cast *>(Section->OutSec) + ->getOffset(Data); } // Returns true if a symbol can be replaced at load-time by a symbol @@ -486,6 +525,50 @@ } template +MergeOutputSection::MergeOutputSection(StringRef Name, uint32_t sh_type, + uintX_t sh_flags) + : OutputSectionBase(Name, sh_type, sh_flags) {} + +template void MergeOutputSection::writeTo(uint8_t *Buf) { + for (const std::pair &P : Offsets) { + StringRef Data = P.first; + memcpy(Buf, Data.data(), Data.size()); + Buf += Data.size(); + } +} + +template +void MergeOutputSection::addSection(MergeInputSection *C) { + C->OutSec = this; + uint32_t Align = C->getAlign(); + if (Align > this->Header.sh_addralign) + this->Header.sh_addralign = Align; + + uintX_t Off = this->Header.sh_size; + ArrayRef Data = C->getSectionData(); + uintX_t EntSize = C->getSectionHdr()->sh_entsize; + if (Data.size() % EntSize) + error("bar"); + for (unsigned I = 0, N = Data.size(); I != N; I += EntSize) { + ArrayRef Entry = Data.slice(I, EntSize); + StringRef Hack((char *)Entry.data(), Entry.size()); + auto P = Offsets.insert(std::make_pair(Hack, Off)); + if (P.second) + Off += EntSize; + } + this->Header.sh_size = Off; +} + +template +unsigned MergeOutputSection::getOffset(ArrayRef Val) { + StringRef Hack((char *)Val.data(), Val.size()); + auto I = Offsets.find(Hack); + if (I == Offsets.end()) + error("foo"); + return I->second; +} + +template StringTableSection::StringTableSection(bool Dynamic) : OutputSectionBase(Dynamic ? ".dynstr" : ".strtab", llvm::ELF::SHT_STRTAB, @@ -597,13 +680,19 @@ 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 *Sec = File->getSection(Sym); - ESym->st_shndx = Sec->OutSec->SectionIndex; - VA += Sec->OutSec->getVA() + Sec->OutSecOff; + const InputSectionBase *Section = File->getSection(Sym); + const OutputSectionBase *OutSec = Section->OutSec; + ESym->st_shndx = OutSec->SectionIndex; + VA += OutSec->getVA(); + if (auto *S = dyn_cast>(Section)) + VA += Sym.st_value + S->OutSecOff; + else + VA += cast>(Section)->getOffset(Sym); } ESym->st_value = VA; } @@ -630,7 +719,7 @@ ESym->st_name = StrTabSec.getFileOff(Name); const OutputSectionBase *OutSec = nullptr; - const InputSection *Section = nullptr; + const InputSectionBase *Section = nullptr; switch (Body->kind()) { case SymbolBody::DefinedSyntheticKind: @@ -726,6 +815,11 @@ template class OutputSection; template class OutputSection; +template class MergeOutputSection; +template class MergeOutputSection; +template class MergeOutputSection; +template class MergeOutputSection; + template class StringTableSection; template class StringTableSection; template class StringTableSection; @@ -744,19 +838,29 @@ template ELFFile::uintX_t getLocalRelTarget(const ObjectFile &, const ELFFile::Elf_Rel &); - template ELFFile::uintX_t getLocalRelTarget(const ObjectFile &, const ELFFile::Elf_Rel &); - template ELFFile::uintX_t getLocalRelTarget(const ObjectFile &, const ELFFile::Elf_Rel &); - template ELFFile::uintX_t getLocalRelTarget(const ObjectFile &, const ELFFile::Elf_Rel &); +template ELFFile::uintX_t +getLocalRelTarget(const ObjectFile &, + const ELFFile::Elf_Rela &); +template ELFFile::uintX_t +getLocalRelTarget(const ObjectFile &, + const ELFFile::Elf_Rela &); +template ELFFile::uintX_t +getLocalRelTarget(const ObjectFile &, + const ELFFile::Elf_Rela &); +template ELFFile::uintX_t +getLocalRelTarget(const ObjectFile &, + const ELFFile::Elf_Rela &); + template bool includeInSymtab(const SymbolBody &); template bool includeInSymtab(const SymbolBody &); template bool includeInSymtab(const SymbolBody &); Index: ELF/Symbols.h =================================================================== --- ELF/Symbols.h +++ ELF/Symbols.h @@ -217,14 +217,15 @@ typedef typename Base::Elf_Sym Elf_Sym; public: - DefinedRegular(StringRef N, const Elf_Sym &Sym, InputSection &Section) + DefinedRegular(StringRef N, const Elf_Sym &Sym, + InputSectionBase &Section) : Defined(Base::DefinedRegularKind, N, Sym), Section(Section) {} static bool classof(const SymbolBody *S) { return S->kind() == Base::DefinedRegularKind; } - const InputSection &Section; + const InputSectionBase &Section; }; template class DefinedSynthetic : public Defined { Index: ELF/Writer.cpp =================================================================== --- ELF/Writer.cpp +++ ELF/Writer.cpp @@ -71,6 +71,7 @@ std::unique_ptr Buffer; SpecificBumpPtrAllocator> SecAlloc; + SpecificBumpPtrAllocator> MSecAlloc; BumpPtrAllocator Alloc; std::vector *> OutputSections; unsigned getNumSections() const { return OutputSections.size() + 1; } @@ -135,24 +136,27 @@ StringRef Name; uint32_t Type; uintX_t Flags; + uintX_t EntSize; }; } namespace llvm { template struct DenseMapInfo> { static SectionKey getEmptyKey() { - return SectionKey{DenseMapInfo::getEmptyKey(), 0, 0}; + return SectionKey{DenseMapInfo::getEmptyKey(), 0, 0, + 0}; } static SectionKey getTombstoneKey() { return SectionKey{DenseMapInfo::getTombstoneKey(), 0, - 0}; + 0, 0}; } static unsigned getHashValue(const SectionKey &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 &LHS, const SectionKey &RHS) { return DenseMapInfo::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; } }; } @@ -381,11 +385,11 @@ if (needsInterpSection()) OutputSections.push_back(Out::Interp); - SmallDenseMap, OutputSection *> Map; + SmallDenseMap, OutputSectionBase *> Map; OutputSections.push_back(Out::Bss); Map[{Out::Bss->getName(), Out::Bss->getType(), - Out::Bss->getFlags()}] = Out::Bss; + Out::Bss->getFlags(), 0}] = Out::Bss; // Declare linker generated symbols. // This must be done before the relocation scan to make sure we can correctly @@ -406,34 +410,46 @@ std::vector *> RegularSections; for (const std::unique_ptr> &F : Symtab.getObjectFiles()) { - for (InputSection *C : F->getSections()) { + for (InputSectionBase *C : F->getSections()) { if (!C || C == &InputSection::Discarded) continue; const Elf_Shdr *H = C->getSectionHdr(); uintX_t OutFlags = H->sh_flags & ~SHF_GROUP; + // FIXME: explain + auto *IS = dyn_cast>(C); + uintX_t EntSize = IS ? 0 : H->sh_entsize; SectionKey Key{getOutputName(C->getSectionName()), - H->sh_type, OutFlags}; - OutputSection *&Sec = Map[Key]; + H->sh_type, OutFlags, EntSize}; + OutputSectionBase *&Sec = Map[Key]; if (!Sec) { - Sec = new (SecAlloc.Allocate()) - OutputSection(Key.Name, Key.Type, Key.Flags); + if (IS) + Sec = new (SecAlloc.Allocate()) + OutputSection(Key.Name, Key.Type, Key.Flags); + else + Sec = new (MSecAlloc.Allocate()) + MergeOutputSection(Key.Name, Key.Type, Key.Flags); OutputSections.push_back(Sec); RegularSections.push_back(Sec); } - Sec->addSection(C); - scanRelocs(*C); + if (IS) { + static_cast *>(Sec)->addSection(IS); + scanRelocs(*IS); + } else { + static_cast *>(Sec) + ->addSection(cast>(C)); + } } } for (OutputSectionBase *Sec : RegularSections) addStartStopSymbols(Sec); - Out::Dynamic->PreInitArraySec = - Map.lookup({".preinit_array", SHT_PREINIT_ARRAY, SHF_WRITE | SHF_ALLOC}); + Out::Dynamic->PreInitArraySec = Map.lookup( + {".preinit_array", SHT_PREINIT_ARRAY, SHF_WRITE | SHF_ALLOC, 0}); Out::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::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 *OS) { @@ -507,7 +523,7 @@ // 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::Opd = Map.lookup({".opd", SHT_PROGBITS, SHF_WRITE | SHF_ALLOC}); + Out::Opd = Map.lookup({".opd", SHT_PROGBITS, SHF_WRITE | SHF_ALLOC, 0}); } static bool isAlpha(char C) { Index: test/elf2/Inputs/merge.s =================================================================== --- /dev/null +++ test/elf2/Inputs/merge.s @@ -0,0 +1,6 @@ + .section .mysec,"aM",@progbits,4 + .align 4 + .long 0x42 + + .text + movl .mysec, %eax Index: test/elf2/merge.s =================================================================== --- /dev/null +++ test/elf2/merge.s @@ -0,0 +1,109 @@ +// 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 +// REQUIRES: x86 + + .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