[llvm] r328143 - [llvm-objcopy] Implement support for section groups
Alexander Shaposhnikov via llvm-commits
llvm-commits at lists.llvm.org
Wed Mar 21 12:53:44 PDT 2018
Author: alexshap
Date: Wed Mar 21 12:53:44 2018
New Revision: 328143
URL: http://llvm.org/viewvc/llvm-project?rev=328143&view=rev
Log:
[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
Added:
llvm/trunk/test/tools/llvm-objcopy/Inputs/groups.o
- copied unchanged from r328025, llvm/trunk/test/tools/llvm-objcopy/Inputs/groups.o
llvm/trunk/test/tools/llvm-objcopy/group-big-endian.test
llvm/trunk/test/tools/llvm-objcopy/group-unchanged.test
- copied unchanged from r328025, llvm/trunk/test/tools/llvm-objcopy/group-unchanged.test
llvm/trunk/test/tools/llvm-objcopy/group.test
- copied unchanged from r328025, llvm/trunk/test/tools/llvm-objcopy/group.test
llvm/trunk/test/tools/llvm-objcopy/strip-dwo-groups.test
- copied unchanged from r328025, llvm/trunk/test/tools/llvm-objcopy/strip-dwo-groups.test
Modified:
llvm/trunk/tools/llvm-objcopy/Object.cpp
llvm/trunk/tools/llvm-objcopy/Object.h
Added: llvm/trunk/test/tools/llvm-objcopy/group-big-endian.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-objcopy/group-big-endian.test?rev=328143&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-objcopy/group-big-endian.test (added)
+++ llvm/trunk/test/tools/llvm-objcopy/group-big-endian.test Wed Mar 21 12:53:44 2018
@@ -0,0 +1,56 @@
+# RUN: yaml2obj %s > %t
+# RUN: llvm-objcopy -remove-section=.text.bar %t %t2
+# RUN: llvm-readobj -elf-section-groups %t2 | FileCheck %s
+
+# In this test the section .text.bar is getting removed, as a result,
+# the indices of the sections which go after .text.bar will change,
+# thus the fields Link, Info and the content of .group should be updated.
+
+# CHECK: Name: .group
+# CHECK-NEXT: Index: 1
+# CHECK-NEXT: Link: 3
+# CHECK-NEXT: Info: 2
+# CHECK-NEXT: Type: COMDAT (0x1)
+# CHECK-NEXT: Signature: foo
+# CHECK: .text.foo (2)
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2MSB
+ Type: ET_REL
+ Machine: EM_X86_64
+Sections:
+ - Name: .group
+ Type: SHT_GROUP
+ Link: .symtab
+ AddressAlign: 0x0000000000000004
+ Info: foo
+ Members:
+ - SectionOrType: GRP_COMDAT
+ - SectionOrType: .text.foo
+ - Name: .text.bar
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
+ AddressAlign: 0x0000000000000010
+ - Name: .text.foo
+ Type: SHT_PROGBITS
+ Flags: [ SHF_ALLOC, SHF_EXECINSTR, SHF_GROUP ]
+ AddressAlign: 0x0000000000000010
+Symbols:
+ Local:
+ - Name: .text.bar
+ Type: STT_SECTION
+ Section: .text.bar
+ - Name: .text.foo
+ Type: STT_SECTION
+ Section: .text.foo
+ Weak:
+ - Name: bar
+ Type: STT_FUNC
+ Section: .text.bar
+ Size: 0x0000000000000000
+ - Name: foo
+ Type: STT_FUNC
+ Section: .text.foo
+ Size: 0x0000000000000000
Modified: llvm/trunk/tools/llvm-objcopy/Object.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-objcopy/Object.cpp?rev=328143&r1=328142&r2=328143&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-objcopy/Object.cpp (original)
+++ llvm/trunk/tools/llvm-objcopy/Object.cpp Wed Mar 21 12:53:44 2018
@@ -77,7 +77,11 @@ void BinarySectionWriter::visit(const Re
}
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::removeSectionRe
[=](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<SymTabTy
" 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(Se
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(Section
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
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<EL
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<EL
}
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(S
}
} 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>::makeSecti
// 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<EL
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
Modified: llvm/trunk/tools/llvm-objcopy/Object.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-objcopy/Object.h?rev=328143&r1=328142&r2=328143&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-objcopy/Object.h (original)
+++ llvm/trunk/tools/llvm-objcopy/Object.h Wed Mar 21 12:53:44 2018
@@ -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 Sectio
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 Secti
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
More information about the llvm-commits
mailing list