diff options
author | Alexander Shaposhnikov <shal1t712@gmail.com> | 2018-03-21 19:53:44 +0000 |
---|---|---|
committer | Alexander Shaposhnikov <shal1t712@gmail.com> | 2018-03-21 19:53:44 +0000 |
commit | 36cdb40ffa9ffe8b1166dd784c5ab4e21fa4d70d (patch) | |
tree | 67f1e8bc9bc3650cca23c202389a3ebd535847f4 /tools/llvm-objcopy | |
parent | 6790638696e8730c36392104f96c4fbfad5120e0 (diff) |
[llvm-objcopy] Implement support for section groups
This diff adds support for SHT_GROUP sections to llvm-objcopy.
Some sections are interrelated and comprise a group.
For example, a definition of an inline function might require,
in addition to the section containing its instructions,
a read-only data section containing literals referenced inside the function.
A section of the type SHT_GROUP contains the indices of the group members,
therefore, it needs to be updated whenever the indices change.
Similarly, the fields sh_link, sh_info should be recalculated as well.
[Resubmit r328012 with the proper handling of endianness]
Test plan: make check-all
Differential revision: https://reviews.llvm.org/D43996
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@328143 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'tools/llvm-objcopy')
-rw-r--r-- | tools/llvm-objcopy/Object.cpp | 109 | ||||
-rw-r--r-- | tools/llvm-objcopy/Object.h | 73 |
2 files changed, 137 insertions, 45 deletions
diff --git a/tools/llvm-objcopy/Object.cpp b/tools/llvm-objcopy/Object.cpp index b3ad7329bb6..e4c268d115c 100644 --- a/tools/llvm-objcopy/Object.cpp +++ b/tools/llvm-objcopy/Object.cpp @@ -77,7 +77,11 @@ void BinarySectionWriter::visit(const RelocationSection &Sec) { } void BinarySectionWriter::visit(const GnuDebugLinkSection &Sec) { - error("Cannot write '.gnu_debuglink' out to binary"); + error("Cannot write '" + Sec.Name + "' out to binary"); +} + +void BinarySectionWriter::visit(const GroupSection &Sec) { + error("Cannot write '" + Sec.Name + "' out to binary"); } void SectionWriter::visit(const Section &Sec) { @@ -155,6 +159,12 @@ uint16_t Symbol::getShndx() const { llvm_unreachable("Symbol with invalid ShndxType encountered"); } +void SymbolTableSection::assignIndices() { + uint32_t Index = 0; + for (auto &Sym : Symbols) + Sym->Index = Index++; +} + void SymbolTableSection::addSymbol(StringRef Name, uint8_t Bind, uint8_t Type, SectionBase *DefinedIn, uint64_t Value, uint8_t Visibility, uint16_t Shndx, @@ -189,6 +199,7 @@ void SymbolTableSection::removeSectionReferences(const SectionBase *Sec) { [=](const SymPtr &Sym) { return Sym->DefinedIn == Sec; }); Size -= (std::end(Symbols) - Iter) * this->EntrySize; Symbols.erase(Iter, std::end(Symbols)); + assignIndices(); } void SymbolTableSection::localize( @@ -203,11 +214,7 @@ void SymbolTableSection::localize( std::stable_partition( std::begin(Symbols), std::end(Symbols), [](const SymPtr &Sym) { return Sym->Binding == STB_LOCAL; }); - - // Lastly we fix the symbol indexes. - uint32_t Index = 0; - for (auto &Sym : Symbols) - Sym->Index = Index++; + assignIndices(); } void SymbolTableSection::initialize(SectionTableRef SecTable) { @@ -274,9 +281,10 @@ template <class SymTabType> void RelocSectionWithSymtabBase<SymTabType>::removeSectionReferences( const SectionBase *Sec) { if (Symbols == Sec) { - error("Symbol table " + Symbols->Name + " cannot be removed because it is " - "referenced by the relocation " - "section " + + error("Symbol table " + Symbols->Name + + " cannot be removed because it is " + "referenced by the relocation " + "section " + this->Name); } } @@ -291,9 +299,9 @@ void RelocSectionWithSymtabBase<SymTabType>::initialize( " is not a symbol table")); if (Info != SHN_UNDEF) - setSection(SecTable.getSection(Info, - "Info field value " + Twine(Info) + - " in section " + Name + " is invalid")); + setSection(SecTable.getSection(Info, "Info field value " + Twine(Info) + + " in section " + Name + + " is invalid")); else setSection(nullptr); } @@ -347,20 +355,26 @@ void DynamicRelocationSection::accept(SectionVisitor &Visitor) const { void SectionWithStrTab::removeSectionReferences(const SectionBase *Sec) { if (StrTab == Sec) { - error("String table " + StrTab->Name + " cannot be removed because it is " - "referenced by the section " + + error("String table " + StrTab->Name + + " cannot be removed because it is " + "referenced by the section " + this->Name); } } +void GroupSection::finalize() { + this->Info = Sym->Index; + this->Link = SymTab->Index; +} + bool SectionWithStrTab::classof(const SectionBase *S) { return isa<DynamicSymbolTableSection>(S) || isa<DynamicSection>(S); } void SectionWithStrTab::initialize(SectionTableRef SecTable) { - auto StrTab = SecTable.getSection(Link, - "Link field value " + Twine(Link) + - " in section " + Name + " is invalid"); + auto StrTab = + SecTable.getSection(Link, "Link field value " + Twine(Link) + + " in section " + Name + " is invalid"); if (StrTab->Type != SHT_STRTAB) { error("Link field value " + Twine(Link) + " in section " + Name + " is not a string table"); @@ -416,6 +430,19 @@ void GnuDebugLinkSection::accept(SectionVisitor &Visitor) const { Visitor.visit(*this); } +template <class ELFT> +void ELFSectionWriter<ELFT>::visit(const GroupSection &Sec) { + ELF::Elf32_Word *Buf = + reinterpret_cast<ELF::Elf32_Word *>(Out.getBufferStart() + Sec.Offset); + *Buf++ = Sec.FlagWord; + for (const auto *S : Sec.GroupMembers) + support::endian::write32<ELFT::TargetEndianness>(Buf++, S->Index); +} + +void GroupSection::accept(SectionVisitor &Visitor) const { + Visitor.visit(*this); +} + // Returns true IFF a section is wholly inside the range of a segment static bool sectionWithinSegment(const SectionBase &Section, const Segment &Segment) { @@ -455,8 +482,7 @@ static bool compareSegmentsByPAddr(const Segment *A, const Segment *B) { return A->Index < B->Index; } -template <class ELFT> -void ELFBuilder<ELFT>::setParentSegment(Segment &Child) { +template <class ELFT> void ELFBuilder<ELFT>::setParentSegment(Segment &Child) { for (auto &Parent : Obj.segments()) { // Every segment will overlap with itself but we don't want a segment to // be it's own parent so we avoid that situation. @@ -522,7 +548,7 @@ template <class ELFT> void ELFBuilder<ELFT>::readProgramHeaders() { PrHdr.OriginalOffset = PrHdr.Offset = PrHdr.VAddr = Ehdr.e_phoff; PrHdr.PAddr = 0; PrHdr.FileSize = PrHdr.MemSize = Ehdr.e_phentsize * Ehdr.e_phnum; - // The spec requires us to naturally align all the fields. + // The spec requires us to naturally align all the fields. PrHdr.Align = sizeof(Elf_Addr); PrHdr.Index = Index++; @@ -535,6 +561,37 @@ template <class ELFT> void ELFBuilder<ELFT>::readProgramHeaders() { } template <class ELFT> +void ELFBuilder<ELFT>::initGroupSection(GroupSection *GroupSec) { + auto SecTable = Obj.sections(); + auto SymTab = SecTable.template getSectionOfType<SymbolTableSection>( + GroupSec->Link, + "Link field value " + Twine(GroupSec->Link) + " in section " + + GroupSec->Name + " is invalid", + "Link field value " + Twine(GroupSec->Link) + " in section " + + GroupSec->Name + " is not a symbol table"); + auto Sym = SymTab->getSymbolByIndex(GroupSec->Info); + if (!Sym) + error("Info field value " + Twine(GroupSec->Info) + " in section " + + GroupSec->Name + " is not a valid symbol index"); + GroupSec->setSymTab(SymTab); + GroupSec->setSymbol(Sym); + if (GroupSec->Contents.size() % sizeof(ELF::Elf32_Word) || + GroupSec->Contents.empty()) + error("The content of the section " + GroupSec->Name + " is malformed"); + const ELF::Elf32_Word *Word = + reinterpret_cast<const ELF::Elf32_Word *>(GroupSec->Contents.data()); + const ELF::Elf32_Word *End = + Word + GroupSec->Contents.size() / sizeof(ELF::Elf32_Word); + GroupSec->setFlagWord(*Word++); + for (; Word != End; ++Word) { + uint32_t Index = support::endian::read32<ELFT::TargetEndianness>(Word); + GroupSec->addMember(SecTable.getSection( + Index, "Group member index " + Twine(Index) + " in section " + + GroupSec->Name + " is invalid")); + } +} + +template <class ELFT> void ELFBuilder<ELFT>::initSymbolTable(SymbolTableSection *SymTab) { const Elf_Shdr &Shdr = *unwrapOrError(ElfFile.getSection(SymTab->Index)); StringRef StrTabData = unwrapOrError(ElfFile.getStringTableForSymtab(Shdr)); @@ -552,9 +609,9 @@ void ELFBuilder<ELFT>::initSymbolTable(SymbolTableSection *SymTab) { } } else if (Sym.st_shndx != SHN_UNDEF) { DefSection = Obj.sections().getSection( - Sym.st_shndx, - "Symbol '" + Name + "' is defined in invalid section with index " + - Twine(Sym.st_shndx)); + Sym.st_shndx, "Symbol '" + Name + + "' is defined in invalid section with index " + + Twine(Sym.st_shndx)); } SymTab->addSymbol(Name, Sym.getBinding(), Sym.getType(), DefSection, @@ -623,6 +680,9 @@ SectionBase &ELFBuilder<ELFT>::makeSection(const Elf_Shdr &Shdr) { // Because of this we don't need to mess with the hash tables either. Data = unwrapOrError(ElfFile.getSectionContents(&Shdr)); return Obj.addSection<Section>(Data); + case SHT_GROUP: + Data = unwrapOrError(ElfFile.getSectionContents(&Shdr)); + return Obj.addSection<GroupSection>(Data); case SHT_DYNSYM: Data = unwrapOrError(ElfFile.getSectionContents(&Shdr)); return Obj.addSection<DynamicSymbolTableSection>(Data); @@ -687,6 +747,8 @@ template <class ELFT> void ELFBuilder<ELFT>::readSectionHeaders() { else initRelocations(RelSec, Obj.SymbolTable, unwrapOrError(ElfFile.relas(Shdr))); + } else if (auto GroupSec = dyn_cast<GroupSection>(&Section)) { + initGroupSection(GroupSec); } } } @@ -1131,5 +1193,4 @@ template class ELFWriter<ELF64LE>; template class ELFWriter<ELF64BE>; template class ELFWriter<ELF32LE>; template class ELFWriter<ELF32BE>; - } // end namespace llvm diff --git a/tools/llvm-objcopy/Object.h b/tools/llvm-objcopy/Object.h index 27beafc0ce6..bf8b52244d8 100644 --- a/tools/llvm-objcopy/Object.h +++ b/tools/llvm-objcopy/Object.h @@ -35,17 +35,17 @@ class SymbolTableSection; class RelocationSection; class DynamicRelocationSection; class GnuDebugLinkSection; +class GroupSection; class Segment; class Object; class SectionTableRef { -private: MutableArrayRef<std::unique_ptr<SectionBase>> Sections; public: using iterator = pointee_iterator<std::unique_ptr<SectionBase> *>; - SectionTableRef(MutableArrayRef<std::unique_ptr<SectionBase>> Secs) + explicit SectionTableRef(MutableArrayRef<std::unique_ptr<SectionBase>> Secs) : Sections(Secs) {} SectionTableRef(const SectionTableRef &) = default; @@ -71,6 +71,7 @@ public: virtual void visit(const RelocationSection &Sec) = 0; virtual void visit(const DynamicRelocationSection &Sec) = 0; virtual void visit(const GnuDebugLinkSection &Sec) = 0; + virtual void visit(const GroupSection &Sec) = 0; }; class SectionWriter : public SectionVisitor { @@ -87,6 +88,7 @@ public: virtual void visit(const SymbolTableSection &Sec) override = 0; virtual void visit(const RelocationSection &Sec) override = 0; virtual void visit(const GnuDebugLinkSection &Sec) override = 0; + virtual void visit(const GroupSection &Sec) override = 0; SectionWriter(FileOutputBuffer &Buf) : Out(Buf) {} }; @@ -102,6 +104,7 @@ public: void visit(const SymbolTableSection &Sec) override; void visit(const RelocationSection &Sec) override; void visit(const GnuDebugLinkSection &Sec) override; + void visit(const GroupSection &Sec) override; ELFSectionWriter(FileOutputBuffer &Buf) : SectionWriter(Buf) {} }; @@ -117,6 +120,8 @@ public: void visit(const SymbolTableSection &Sec) override; void visit(const RelocationSection &Sec) override; void visit(const GnuDebugLinkSection &Sec) override; + void visit(const GroupSection &Sec) override; + BinarySectionWriter(FileOutputBuffer &Buf) : SectionWriter(Buf) {} }; @@ -237,7 +242,7 @@ public: uint64_t OriginalOffset; Segment *ParentSegment = nullptr; - Segment(ArrayRef<uint8_t> Data) : Contents(Data) {} + explicit Segment(ArrayRef<uint8_t> Data) : Contents(Data) {} Segment() {} const SectionBase *firstSection() const { @@ -253,11 +258,10 @@ public: class Section : public SectionBase { MAKE_SEC_WRITER_FRIEND -private: ArrayRef<uint8_t> Contents; public: - Section(ArrayRef<uint8_t> Data) : Contents(Data) {} + explicit Section(ArrayRef<uint8_t> Data) : Contents(Data) {} void accept(SectionVisitor &Visitor) const override; }; @@ -265,7 +269,6 @@ public: class OwnedDataSection : public SectionBase { MAKE_SEC_WRITER_FRIEND -private: std::vector<uint8_t> Data; public: @@ -291,7 +294,6 @@ public: class StringTableSection : public SectionBase { MAKE_SEC_WRITER_FRIEND -private: StringTableBuilder StrTabBuilder; public: @@ -344,6 +346,7 @@ class SymbolTableSection : public SectionBase { MAKE_SEC_WRITER_FRIEND void setStrTab(StringTableSection *StrTab) { SymbolNames = StrTab; } + void assignIndices(); protected: std::vector<std::unique_ptr<Symbol>> Symbols; @@ -402,7 +405,6 @@ public: // that code between the two symbol table types. template <class SymTabType> class RelocSectionWithSymtabBase : public RelocationSectionBase { -private: SymTabType *Symbols = nullptr; void setSymTab(SymTabType *SymTab) { Symbols = SymTab; } @@ -419,7 +421,6 @@ class RelocationSection : public RelocSectionWithSymtabBase<SymbolTableSection> { MAKE_SEC_WRITER_FRIEND -private: std::vector<Relocation> Relocations; public: @@ -433,14 +434,43 @@ public: } }; -class SectionWithStrTab : public Section { -private: - const SectionBase *StrTab = nullptr; +// TODO: The way stripping and groups interact is complicated +// and still needs to be worked on. + +class GroupSection : public SectionBase { + MAKE_SEC_WRITER_FRIEND + const SymbolTableSection *SymTab = nullptr; + const Symbol *Sym = nullptr; + ELF::Elf32_Word FlagWord; + SmallVector<SectionBase *, 3> GroupMembers; public: - SectionWithStrTab(ArrayRef<uint8_t> Data) : Section(Data) {} + // TODO: Contents is present in several classes of the hierarchy. + // This needs to be refactored to avoid duplication. + ArrayRef<uint8_t> Contents; + + explicit GroupSection(ArrayRef<uint8_t> Data) : Contents(Data) {} + + void setSymTab(const SymbolTableSection *SymTabSec) { SymTab = SymTabSec; } + void setSymbol(const Symbol *S) { Sym = S; } + void setFlagWord(ELF::Elf32_Word W) { FlagWord = W; } + void addMember(SectionBase *Sec) { GroupMembers.push_back(Sec); } + void initialize(SectionTableRef SecTable) override {}; + void accept(SectionVisitor &) const override; + void finalize() override; + + static bool classof(const SectionBase *S) { + return S->Type == ELF::SHT_GROUP; + } +}; + +class SectionWithStrTab : public Section { + const SectionBase *StrTab = nullptr; void setStrTab(const SectionBase *StringTable) { StrTab = StringTable; } + +public: + explicit SectionWithStrTab(ArrayRef<uint8_t> Data) : Section(Data) {} void removeSectionReferences(const SectionBase *Sec) override; void initialize(SectionTableRef SecTable) override; void finalize() override; @@ -449,7 +479,8 @@ public: class DynamicSymbolTableSection : public SectionWithStrTab { public: - DynamicSymbolTableSection(ArrayRef<uint8_t> Data) : SectionWithStrTab(Data) {} + explicit DynamicSymbolTableSection(ArrayRef<uint8_t> Data) + : SectionWithStrTab(Data) {} static bool classof(const SectionBase *S) { return S->Type == ELF::SHT_DYNSYM; @@ -458,7 +489,7 @@ public: class DynamicSection : public SectionWithStrTab { public: - DynamicSection(ArrayRef<uint8_t> Data) : SectionWithStrTab(Data) {} + explicit DynamicSection(ArrayRef<uint8_t> Data) : SectionWithStrTab(Data) {} static bool classof(const SectionBase *S) { return S->Type == ELF::SHT_DYNAMIC; @@ -473,7 +504,7 @@ private: ArrayRef<uint8_t> Contents; public: - DynamicRelocationSection(ArrayRef<uint8_t> Data) : Contents(Data) {} + explicit DynamicRelocationSection(ArrayRef<uint8_t> Data) : Contents(Data) {} void accept(SectionVisitor &) const override; @@ -488,7 +519,6 @@ class GnuDebugLinkSection : public SectionBase { MAKE_SEC_WRITER_FRIEND private: - StringRef FileName; uint32_t CRC32; @@ -496,7 +526,7 @@ private: public: // If we add this section from an external source we can use this ctor. - GnuDebugLinkSection(StringRef File); + explicit GnuDebugLinkSection(StringRef File); void accept(SectionVisitor &Visitor) const override; }; @@ -506,10 +536,10 @@ public: virtual std::unique_ptr<Object> create() const = 0; }; -using object::OwningBinary; using object::Binary; using object::ELFFile; using object::ELFObjectFile; +using object::OwningBinary; template <class ELFT> class ELFBuilder { private: @@ -522,6 +552,7 @@ private: void setParentSegment(Segment &Child); void readProgramHeaders(); + void initGroupSection(GroupSection *GroupSec); void initSymbolTable(SymbolTableSection *SymTab); void readSectionHeaders(); SectionBase &makeSection(const Elf_Shdr &Shdr); @@ -582,7 +613,8 @@ public: StringTableSection *SectionNames = nullptr; SymbolTableSection *SymbolTable = nullptr; - Object(std::shared_ptr<MemoryBuffer> Data) : OwnedData(Data) {} + explicit Object(std::shared_ptr<MemoryBuffer> Data) + : OwnedData(std::move(Data)) {} virtual ~Object() = default; void sortSections(); @@ -605,7 +637,6 @@ public: return *Segments.back(); } }; - } // end namespace llvm #endif // LLVM_TOOLS_OBJCOPY_OBJECT_H |