From 6ecc6e62c1742ccf6e0d0e8f4f055c53e21d0141 Mon Sep 17 00:00:00 2001 From: Alexander Shaposhnikov Date: Wed, 21 Mar 2018 19:53:44 +0000 Subject: [PATCH] [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 llvm-svn: 328143 --- llvm/test/tools/llvm-objcopy/Inputs/groups.o | Bin 0 -> 5368 bytes llvm/test/tools/llvm-objcopy/group-big-endian.test | 56 +++++++++++ llvm/test/tools/llvm-objcopy/group-unchanged.test | 56 +++++++++++ llvm/test/tools/llvm-objcopy/group.test | 56 +++++++++++ llvm/test/tools/llvm-objcopy/strip-dwo-groups.test | 40 ++++++++ llvm/tools/llvm-objcopy/Object.cpp | 109 ++++++++++++++++----- llvm/tools/llvm-objcopy/Object.h | 73 ++++++++++---- 7 files changed, 345 insertions(+), 45 deletions(-) create mode 100644 llvm/test/tools/llvm-objcopy/Inputs/groups.o create mode 100644 llvm/test/tools/llvm-objcopy/group-big-endian.test create mode 100644 llvm/test/tools/llvm-objcopy/group-unchanged.test create mode 100644 llvm/test/tools/llvm-objcopy/group.test create mode 100644 llvm/test/tools/llvm-objcopy/strip-dwo-groups.test diff --git a/llvm/test/tools/llvm-objcopy/Inputs/groups.o b/llvm/test/tools/llvm-objcopy/Inputs/groups.o new file mode 100644 index 0000000000000000000000000000000000000000..e92b98046a37999b039dd1db84ddeb74a81c997b GIT binary patch literal 5368 zcmd5Ounk}s@SDgi~c23BC(YN=)RBC_f;#Ak$Q+xa6 znY{>e2ppk!BGxuCC;!6AiR(W8udn(oA6mubs=d0HUUwVK<=Sd`G?UBZ(zh&mUVS{9 ztyb4pGPTBHc5&Iu`i2=uX*YMIFyah3`HE96jTW5Y^3Yh`KAayND^%RWL-{eMRB&>m zm0LRpqNwRye#EXgL!R~b3mMyDnMMG=~OWnEOnU1Cbu zq9nYf<)%Nk2|V8d{{{Rm_yh1i!2bgO8~h*e7vRg_pTHrkRRkOb)4IjMJ>Vaq+g?o> z5g}g2kQI|M6b=_*Aj2|ZMP=kTWa}gzB1&SH=%OYTu_E33AcU+0T;kz#kY)IpfUX>i z#NqlBFl!SJ5hW3>)Wo_YvF*?;1B3pfSmJ>NqR$;UzS?VH$lAc-l<$kojvU;<|cCiWdext1kn2ZkX; zvk;)fIB$l8ao$KF5E0?JdwnQwM#VT18QK4AaZhw|uoavF_Y8~B;C3<$ZQITnIEnBn zE6@koX^0(Z3~0#L4-KW73aS%@_<&UW(HAqL_45`0N0Ac3@^ABmzO2$8khS%q*TP4oz5GvjZa_EYdr08txu#T>hQ_ zHUd7V)$gx4u>C&ne}*BceS(%Nq*rhX{L?Q1(fJ}GoNO4U^&z62K+HJLJk1bZVcWzr zLpXghnEI4JIQtUB`=4?4Ns|&pI5E>9B@otW-_SgT*%&R?&-iUh$Mp~%e2xMIoh>59 z{qu!>nm`cYtyv8|0Xoj}PZ$x|?^chVSFcBp&vQlN<*`uQ-S9LiL9|wS-U%NKa6Rw5 zhUGI zR#sfR@B=J}TVE@A=jv|L1Xt}918m?vM^NC`^crn0w&MWs?^OEBu&sLkCfo8~s8uRW z*9$JVEm*f&Uai#hKJLAGcf~G~MOz^Ouv+un%*lJt+|l&x@*`~q)#X)J0q)X5rGbHp z42I*`CA8;O{I*eZY|qY=n_fX==8oStdw799#J>equ`%@h#W7!3hxJw3I2svUaSwEa z@jhnLNhR<(Wt`6k_fJ63_aEaqbx3%e2ce*|z-Ncg_uIhw*-2~vtO{a#@~8JC=i>Hi zV1E4+T%)>@`Mtp^v;HUGO#bHk;u+<@`PrZQ-0oKY`>K9^4^#d0KIgi*rTOVp|H~?& zS(jP=?Htn>|HG<4o@dHW5ZBH4AAwPRszawYRL5L@vL)g+34!H66FmQ}cQo0wrEivr zkvaR*kEc$iZ4Q8mk^Ps-$sCtydpiJL3q8+836s{J_EhVHEO zXXrVWZhBGqn-@;g_QPHLFQ}K|CwkBhwr_U8$mMypD11%`BQo>TIq9^1e^To=<9pHF zQ24h@bN##yG0EjM74#@|G&1wopzD5}rV8#vd` z@I&zLH2yyI{hd*UH2>Fw*`L?t{vbbx+ir8}`*D672?VqLxn1(lcgUYc2s6J2e{<}V Q=_8eYNhPF)zGbHWue9(8sQ>@~ literal 0 HcmV?d00001 diff --git a/llvm/test/tools/llvm-objcopy/group-big-endian.test b/llvm/test/tools/llvm-objcopy/group-big-endian.test new file mode 100644 index 0000000..d5a0260 --- /dev/null +++ b/llvm/test/tools/llvm-objcopy/group-big-endian.test @@ -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 diff --git a/llvm/test/tools/llvm-objcopy/group-unchanged.test b/llvm/test/tools/llvm-objcopy/group-unchanged.test new file mode 100644 index 0000000..9e86172 --- /dev/null +++ b/llvm/test/tools/llvm-objcopy/group-unchanged.test @@ -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, since this section +# goes after all the sections comprising a group, the content of the +# section .group doesn't change. + +# 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: ELFDATA2LSB + 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.foo + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR, SHF_GROUP ] + AddressAlign: 0x0000000000000010 + - Name: .text.bar + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + AddressAlign: 0x0000000000000010 +Symbols: + Local: + - Name: .text.foo + Type: STT_SECTION + Section: .text.foo + - Name: .text.bar + Type: STT_SECTION + Section: .text.bar + Weak: + - Name: foo + Type: STT_FUNC + Section: .text.foo + Size: 0x0000000000000000 + - Name: bar + Type: STT_FUNC + Section: .text.bar + Size: 0x0000000000000000 diff --git a/llvm/test/tools/llvm-objcopy/group.test b/llvm/test/tools/llvm-objcopy/group.test new file mode 100644 index 0000000..4023f12 --- /dev/null +++ b/llvm/test/tools/llvm-objcopy/group.test @@ -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: ELFDATA2LSB + 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 diff --git a/llvm/test/tools/llvm-objcopy/strip-dwo-groups.test b/llvm/test/tools/llvm-objcopy/strip-dwo-groups.test new file mode 100644 index 0000000..957bb55 --- /dev/null +++ b/llvm/test/tools/llvm-objcopy/strip-dwo-groups.test @@ -0,0 +1,40 @@ +# RUN: cp %p/Inputs/groups.o %t +# RUN: llvm-objcopy -strip-dwo %t +# RUN: llvm-readobj -elf-section-groups %t | FileCheck %s + +// Source code of groups.o: +// +// template +// struct S { +// static constexpr T X = T(1); +// T getX() { return X; } +// }; +// void f() { +// S A; +// S B; +// int a = A.getX(); +// int b = B.getX(); +// } +// +// clang -g -gsplit-dwarf -std=c++11 -c groups.cpp -o groups.o + +// `llvm-objcopy -strip-dwo` strips out dwo sections, as a result, the index of +// the symbol table, the indices of the symbols and the indices of the sections +// which go after the removed ones will change. Consequently, the fields +// Link, Info and the content of .group need to be updated. In the past +// `llvm-objcopy -strip-dwo` used to produce invalid binaries with +// broken .group section, this test verifies the correctness of +// Link, Info and the content of this section. + +CHECK: Name: .group (179) +CHECK-NEXT: Index: 17 +CHECK-NEXT: Link: 19 +CHECK-NEXT: Info: 14 +CHECK: .text._ZN1SIiE4getXEv (2) + +CHECK: Name: .group (179) +CHECK-NEXT: Index: 18 +CHECK-NEXT: Link: 19 +CHECK-NEXT: Info: 13 +CHECK: .text._ZN1SIdE4getXEv (4) +CHECK-NEXT: .rela.text._ZN1SIdE4getXEv (21) diff --git a/llvm/tools/llvm-objcopy/Object.cpp b/llvm/tools/llvm-objcopy/Object.cpp index b3ad732..e4c268d 100644 --- a/llvm/tools/llvm-objcopy/Object.cpp +++ b/llvm/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 void RelocSectionWithSymtabBase::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::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(S) || isa(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 +void ELFSectionWriter::visit(const GroupSection &Sec) { + ELF::Elf32_Word *Buf = + reinterpret_cast(Out.getBufferStart() + Sec.Offset); + *Buf++ = Sec.FlagWord; + for (const auto *S : Sec.GroupMembers) + support::endian::write32(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 -void ELFBuilder::setParentSegment(Segment &Child) { +template void ELFBuilder::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 void ELFBuilder::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 void ELFBuilder::readProgramHeaders() { } template +void ELFBuilder::initGroupSection(GroupSection *GroupSec) { + auto SecTable = Obj.sections(); + auto SymTab = SecTable.template getSectionOfType( + 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(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(Word); + GroupSec->addMember(SecTable.getSection( + Index, "Group member index " + Twine(Index) + " in section " + + GroupSec->Name + " is invalid")); + } +} + +template void ELFBuilder::initSymbolTable(SymbolTableSection *SymTab) { const Elf_Shdr &Shdr = *unwrapOrError(ElfFile.getSection(SymTab->Index)); StringRef StrTabData = unwrapOrError(ElfFile.getStringTableForSymtab(Shdr)); @@ -552,9 +609,9 @@ void ELFBuilder::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::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
(Data); + case SHT_GROUP: + Data = unwrapOrError(ElfFile.getSectionContents(&Shdr)); + return Obj.addSection(Data); case SHT_DYNSYM: Data = unwrapOrError(ElfFile.getSectionContents(&Shdr)); return Obj.addSection(Data); @@ -687,6 +747,8 @@ template void ELFBuilder::readSectionHeaders() { else initRelocations(RelSec, Obj.SymbolTable, unwrapOrError(ElfFile.relas(Shdr))); + } else if (auto GroupSec = dyn_cast(&Section)) { + initGroupSection(GroupSec); } } } @@ -1131,5 +1193,4 @@ template class ELFWriter; template class ELFWriter; template class ELFWriter; template class ELFWriter; - } // end namespace llvm diff --git a/llvm/tools/llvm-objcopy/Object.h b/llvm/tools/llvm-objcopy/Object.h index 27beafc..bf8b522 100644 --- a/llvm/tools/llvm-objcopy/Object.h +++ b/llvm/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> Sections; public: using iterator = pointee_iterator *>; - SectionTableRef(MutableArrayRef> Secs) + explicit SectionTableRef(MutableArrayRef> 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 Data) : Contents(Data) {} + explicit Segment(ArrayRef Data) : Contents(Data) {} Segment() {} const SectionBase *firstSection() const { @@ -253,11 +258,10 @@ public: class Section : public SectionBase { MAKE_SEC_WRITER_FRIEND -private: ArrayRef Contents; public: - Section(ArrayRef Data) : Contents(Data) {} + explicit Section(ArrayRef 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 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> Symbols; @@ -402,7 +405,6 @@ public: // that code between the two symbol table types. template class RelocSectionWithSymtabBase : public RelocationSectionBase { -private: SymTabType *Symbols = nullptr; void setSymTab(SymTabType *SymTab) { Symbols = SymTab; } @@ -419,7 +421,6 @@ class RelocationSection : public RelocSectionWithSymtabBase { MAKE_SEC_WRITER_FRIEND -private: std::vector 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 GroupMembers; public: - SectionWithStrTab(ArrayRef Data) : Section(Data) {} + // TODO: Contents is present in several classes of the hierarchy. + // This needs to be refactored to avoid duplication. + ArrayRef Contents; + + explicit GroupSection(ArrayRef 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 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 Data) : SectionWithStrTab(Data) {} + explicit DynamicSymbolTableSection(ArrayRef 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 Data) : SectionWithStrTab(Data) {} + explicit DynamicSection(ArrayRef Data) : SectionWithStrTab(Data) {} static bool classof(const SectionBase *S) { return S->Type == ELF::SHT_DYNAMIC; @@ -473,7 +504,7 @@ private: ArrayRef Contents; public: - DynamicRelocationSection(ArrayRef Data) : Contents(Data) {} + explicit DynamicRelocationSection(ArrayRef 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 create() const = 0; }; -using object::OwningBinary; using object::Binary; using object::ELFFile; using object::ELFObjectFile; +using object::OwningBinary; template 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 Data) : OwnedData(Data) {} + explicit Object(std::shared_ptr 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 -- 2.7.4