Index: tools/llvm-objcopy/Object.h =================================================================== --- tools/llvm-objcopy/Object.h +++ tools/llvm-objcopy/Object.h @@ -258,19 +258,29 @@ void finalize() override; }; -template class RelocationSection : public RelocSectionWithSymtabBase { +protected: + std::vector Relocations; + +public: + void addRelocation(Relocation Rel) { Relocations.push_back(Rel); } + + static bool classof(const SectionBase *S) { + if (S->Flags & ELF::SHF_ALLOC) + return false; + return S->Type == ELF::SHT_REL || S->Type == ELF::SHT_RELA; + } +}; + +template class RelocationSectionImpl : public RelocationSection { private: using Elf_Rel = typename ELFT::Rel; using Elf_Rela = typename ELFT::Rela; - std::vector Relocations; - template void writeRel(T *Buf) const; public: - void addRelocation(Relocation Rel) { Relocations.push_back(Rel); } void writeSection(FileOutputBuffer &Out) const override; static bool classof(const SectionBase *S) { @@ -329,32 +339,21 @@ } }; -template class Object { -private: +class Object { +protected: using SecPtr = std::unique_ptr; using SegPtr = std::unique_ptr; - using Elf_Shdr = typename ELFT::Shdr; - using Elf_Ehdr = typename ELFT::Ehdr; - using Elf_Phdr = typename ELFT::Phdr; - - void initSymbolTable(const object::ELFFile &ElfFile, - SymbolTableSection *SymTab, SectionTableRef SecTable); - SecPtr makeSection(const object::ELFFile &ElfFile, - const Elf_Shdr &Shdr); - void readProgramHeaders(const object::ELFFile &ElfFile); - SectionTableRef readSectionHeaders(const object::ELFFile &ElfFile); - -protected: StringTableSection *SectionNames = nullptr; SymbolTableSection *SymbolTable = nullptr; std::vector Sections; std::vector Segments; - void writeHeader(FileOutputBuffer &Out) const; - void writeProgramHeaders(FileOutputBuffer &Out) const; void writeSectionData(FileOutputBuffer &Out) const; - void writeSectionHeaders(FileOutputBuffer &Out) const; + + virtual uint64_t shdrSize() const = 0; + virtual uint64_t ehdrSize() const = 0; + virtual uint64_t addrSize() const = 0; public: uint8_t Ident[16]; @@ -366,7 +365,6 @@ uint32_t Flags; bool WriteSectionHeaders = true; - Object(const object::ELFObjectFile &Obj); virtual ~Object() = default; const SymbolTableSection *getSymTab() const { return SymbolTable; } @@ -377,7 +375,7 @@ virtual void write(FileOutputBuffer &Out) const = 0; }; -template class ELFObject : public Object { +template class ObjectImpl : public virtual Object { private: using SecPtr = std::unique_ptr; using SegPtr = std::unique_ptr; @@ -386,18 +384,60 @@ using Elf_Ehdr = typename ELFT::Ehdr; using Elf_Phdr = typename ELFT::Phdr; + void initSymbolTable(const object::ELFFile &ElfFile, + SymbolTableSection *SymTab, SectionTableRef SecTable); + SecPtr makeSection(const object::ELFFile &ElfFile, + const Elf_Shdr &Shdr); + void readProgramHeaders(const object::ELFFile &ElfFile); + SectionTableRef readSectionHeaders(const object::ELFFile &ElfFile); + +protected: + void writeHeader(FileOutputBuffer &Out) const; + void writeProgramHeaders(FileOutputBuffer &Out) const; + void writeSectionHeaders(FileOutputBuffer &Out) const; + + virtual uint64_t shdrSize() const { return sizeof(Elf_Shdr); } + virtual uint64_t ehdrSize() const { return sizeof(Elf_Ehdr); } + virtual uint64_t addrSize() const { return sizeof(typename ELFT::Addr); } + +public: + ObjectImpl(const object::ELFObjectFile &Obj); + virtual ~ObjectImpl() = default; +}; + +class ELFObject : public virtual Object { +private: + using SecPtr = std::unique_ptr; + using SegPtr = std::unique_ptr; + void sortSections(); void assignOffsets(); public: - ELFObject(const object::ELFObjectFile &Obj) : Object(Obj) {} + virtual ~ELFObject() = default; void finalize() override; size_t totalSize() const override; +}; + +template +class ELFObjectImpl : public ObjectImpl, public ELFObject { +private: + using SecPtr = std::unique_ptr; + using SegPtr = std::unique_ptr; + + using Elf_Shdr = typename ELFT::Shdr; + using Elf_Ehdr = typename ELFT::Ehdr; + using Elf_Phdr = typename ELFT::Phdr; + +public: + ELFObjectImpl(const object::ELFObjectFile &Obj) + : ObjectImpl(Obj) {} + void write(FileOutputBuffer &Out) const override; }; -template class BinaryObject : public Object { +class BinaryObject : public virtual Object { private: using SecPtr = std::unique_ptr; using SegPtr = std::unique_ptr; @@ -405,13 +445,20 @@ uint64_t TotalSize; public: - BinaryObject(const object::ELFObjectFile &Obj) : Object(Obj) {} + virtual ~BinaryObject() = default; void finalize() override; size_t totalSize() const override; void write(FileOutputBuffer &Out) const override; }; +template +class BinaryObjectImpl : public ObjectImpl, public BinaryObject { +public: + BinaryObjectImpl(const object::ELFObjectFile &Obj) + : ObjectImpl(Obj) {} +}; + } // end namespace llvm #endif // LLVM_TOOLS_OBJCOPY_OBJECT_H Index: tools/llvm-objcopy/Object.cpp =================================================================== --- tools/llvm-objcopy/Object.cpp +++ tools/llvm-objcopy/Object.cpp @@ -269,7 +269,7 @@ template template -void RelocationSection::writeRel(T *Buf) const { +void RelocationSectionImpl::writeRel(T *Buf) const { for (const auto &Reloc : Relocations) { Buf->r_offset = Reloc.Offset; setAddend(*Buf, Reloc.Addend); @@ -279,7 +279,7 @@ } template -void RelocationSection::writeSection(FileOutputBuffer &Out) const { +void RelocationSectionImpl::writeSection(FileOutputBuffer &Out) const { uint8_t *Buf = Out.getBufferStart() + Offset; if (Type == SHT_REL) writeRel(reinterpret_cast(Buf)); @@ -350,7 +350,7 @@ } template -void Object::readProgramHeaders(const ELFFile &ElfFile) { +void ObjectImpl::readProgramHeaders(const ELFFile &ElfFile) { uint32_t Index = 0; for (const auto &Phdr : unwrapOrError(ElfFile.program_headers())) { ArrayRef Data{ElfFile.base() + Phdr.p_offset, @@ -397,9 +397,9 @@ } template -void Object::initSymbolTable(const object::ELFFile &ElfFile, - SymbolTableSection *SymTab, - SectionTableRef SecTable) { +void ObjectImpl::initSymbolTable(const object::ELFFile &ElfFile, + SymbolTableSection *SymTab, + SectionTableRef SecTable) { const Elf_Shdr &Shdr = *unwrapOrError(ElfFile.getSection(SymTab->Index)); StringRef StrTabData = unwrapOrError(ElfFile.getStringTableForSymtab(Shdr)); @@ -434,9 +434,9 @@ ToSet = Rela.r_addend; } -template -void initRelocations(RelocationSection *Relocs, - SymbolTableSection *SymbolTable, T RelRange) { +template +void initRelocations(RelocationSection *Relocs, SymbolTableSection *SymbolTable, + T RelRange) { for (const auto &Rel : RelRange) { Relocation ToAdd; ToAdd.Offset = Rel.r_offset; @@ -463,8 +463,8 @@ template std::unique_ptr -Object::makeSection(const object::ELFFile &ElfFile, - const Elf_Shdr &Shdr) { +ObjectImpl::makeSection(const object::ELFFile &ElfFile, + const Elf_Shdr &Shdr) { ArrayRef Data; switch (Shdr.sh_type) { case SHT_REL: @@ -473,7 +473,7 @@ Data = unwrapOrError(ElfFile.getSectionContents(&Shdr)); return llvm::make_unique(Data); } - return llvm::make_unique>(); + return llvm::make_unique>(); case SHT_STRTAB: // If a string table is allocated we don't want to mess with it. That would // mean altering the memory image. There are no special link types or @@ -509,7 +509,8 @@ } template -SectionTableRef Object::readSectionHeaders(const ELFFile &ElfFile) { +SectionTableRef +ObjectImpl::readSectionHeaders(const ELFFile &ElfFile) { uint32_t Index = 0; for (const auto &Shdr : unwrapOrError(ElfFile.sections())) { if (Index == 0) { @@ -549,7 +550,7 @@ if (Section.get() == SymbolTable) continue; Section->initialize(SecTable); - if (auto RelSec = dyn_cast>(Section.get())) { + if (auto RelSec = dyn_cast>(Section.get())) { auto Shdr = unwrapOrError(ElfFile.sections()).begin() + RelSec->Index; if (RelSec->Type == SHT_REL) initRelocations(RelSec, SymbolTable, unwrapOrError(ElfFile.rels(Shdr))); @@ -562,7 +563,8 @@ return SecTable; } -template Object::Object(const ELFObjectFile &Obj) { +template +ObjectImpl::ObjectImpl(const ELFObjectFile &Obj) { const auto &ElfFile = *Obj.getELFFile(); const auto &Ehdr = *ElfFile.getHeader(); @@ -585,7 +587,7 @@ } template -void Object::writeHeader(FileOutputBuffer &Out) const { +void ObjectImpl::writeHeader(FileOutputBuffer &Out) const { uint8_t *Buf = Out.getBufferStart(); Elf_Ehdr &Ehdr = *reinterpret_cast(Buf); std::copy(Ident, Ident + 16, Ehdr.e_ident); @@ -611,13 +613,13 @@ } template -void Object::writeProgramHeaders(FileOutputBuffer &Out) const { +void ObjectImpl::writeProgramHeaders(FileOutputBuffer &Out) const { for (auto &Phdr : Segments) Phdr->template writeHeader(Out); } template -void Object::writeSectionHeaders(FileOutputBuffer &Out) const { +void ObjectImpl::writeSectionHeaders(FileOutputBuffer &Out) const { uint8_t *Buf = Out.getBufferStart() + SHOffset; // This reference serves to write the dummy section header at the begining // of the file. It is not used for anything else @@ -637,15 +639,12 @@ Section->template writeHeader(Out); } -template -void Object::writeSectionData(FileOutputBuffer &Out) const { +void Object::writeSectionData(FileOutputBuffer &Out) const { for (auto &Section : Sections) Section->writeSection(Out); } -template -void Object::removeSections( - std::function ToRemove) { +void Object::removeSections(std::function ToRemove) { auto Iter = std::stable_partition( std::begin(Sections), std::end(Sections), [=](const SecPtr &Sec) { @@ -678,7 +677,7 @@ Sections.erase(Iter, std::end(Sections)); } -template void ELFObject::sortSections() { +void ELFObject::sortSections() { // Put all sections in offset order. Maintain the ordering as closely as // possible while meeting that demand however. auto CompareSections = [](const SecPtr &A, const SecPtr &B) { @@ -767,7 +766,7 @@ return Offset; } -template void ELFObject::assignOffsets() { +void ELFObject::assignOffsets() { // We need a temporary list of segments that has a special order to it // so that we know that anytime ->ParentSegment is set that segment has // already had its offset properly set. @@ -783,26 +782,27 @@ if (!OrderedSegments.empty()) { Offset = OrderedSegments[0]->Offset; } else { - Offset = sizeof(Elf_Ehdr); + Offset = ehdrSize(); } Offset = LayoutSegments(OrderedSegments, Offset); Offset = LayoutSections(this->Sections, Offset); // If we need to write the section header table out then we need to align the // Offset so that SHOffset is valid. if (this->WriteSectionHeaders) - Offset = alignTo(Offset, sizeof(typename ELFT::Addr)); + Offset = alignTo(Offset, addrSize()); this->SHOffset = Offset; } -template size_t ELFObject::totalSize() const { +size_t ELFObject::totalSize() const { // We already have the section header offset so we can calculate the total // size by just adding up the size of each section header. - auto NullSectionSize = this->WriteSectionHeaders ? sizeof(Elf_Shdr) : 0; - return this->SHOffset + this->Sections.size() * sizeof(Elf_Shdr) + - NullSectionSize; + auto ShdrSize = shdrSize(); + auto NullSectionSize = this->WriteSectionHeaders ? ShdrSize : 0; + return this->SHOffset + this->Sections.size() * ShdrSize + NullSectionSize; } -template void ELFObject::write(FileOutputBuffer &Out) const { +template +void ELFObjectImpl::write(FileOutputBuffer &Out) const { this->writeHeader(Out); this->writeProgramHeaders(Out); this->writeSectionData(Out); @@ -810,7 +810,7 @@ this->writeSectionHeaders(Out); } -template void ELFObject::finalize() { +void ELFObject::finalize() { // Make sure we add the names of all the sections. if (this->SectionNames != nullptr) for (const auto &Section : this->Sections) { @@ -828,22 +828,20 @@ this->SectionNames->finalize(); // Finally now that all offsets and indexes have been set we can finalize any // remaining issues. - uint64_t Offset = this->SHOffset + sizeof(Elf_Shdr); + auto ShdrSize = shdrSize(); + uint64_t Offset = this->SHOffset + ShdrSize; for (auto &Section : this->Sections) { Section->HeaderOffset = Offset; - Offset += sizeof(Elf_Shdr); + Offset += ShdrSize; if (this->WriteSectionHeaders) Section->NameIndex = this->SectionNames->findIndex(Section->Name); Section->finalize(); } } -template size_t BinaryObject::totalSize() const { - return TotalSize; -} +size_t BinaryObject::totalSize() const { return TotalSize; } -template -void BinaryObject::write(FileOutputBuffer &Out) const { +void BinaryObject::write(FileOutputBuffer &Out) const { for (auto &Section : this->Sections) { if ((Section->Flags & SHF_ALLOC) == 0) continue; @@ -851,7 +849,7 @@ } } -template void BinaryObject::finalize() { +void BinaryObject::finalize() { // TODO: Create a filter range to construct OrderedSegments from so that this // code can be deduped with assignOffsets above. This should also solve the // todo below for LayoutSections. @@ -920,19 +918,19 @@ namespace llvm { -template class Object; -template class Object; -template class Object; -template class Object; +template class ObjectImpl; +template class ObjectImpl; +template class ObjectImpl; +template class ObjectImpl; -template class ELFObject; -template class ELFObject; -template class ELFObject; -template class ELFObject; +template class ELFObjectImpl; +template class ELFObjectImpl; +template class ELFObjectImpl; +template class ELFObjectImpl; -template class BinaryObject; -template class BinaryObject; -template class BinaryObject; -template class BinaryObject; +template class BinaryObjectImpl; +template class BinaryObjectImpl; +template class BinaryObjectImpl; +template class BinaryObjectImpl; } // end namespace llvm Index: tools/llvm-objcopy/llvm-objcopy.cpp =================================================================== --- tools/llvm-objcopy/llvm-objcopy.cpp +++ tools/llvm-objcopy/llvm-objcopy.cpp @@ -119,8 +119,7 @@ return Sec.Name.endswith(".dwo"); } -template -bool OnlyKeepDWOPred(const Object &Obj, const SectionBase &Sec) { +bool OnlyKeepDWOPred(const Object &Obj, const SectionBase &Sec) { // We can't remove the section header string table. if (&Sec == Obj.getSectionHeaderStrTab()) return false; @@ -129,8 +128,7 @@ return !IsDWOSection(Sec); } -template -void WriteObjectFile(const Object &Obj, StringRef File) { +void WriteObjectFile(const Object &Obj, StringRef File) { std::unique_ptr Buffer; Expected> BufferOrErr = FileOutputBuffer::create(File, Obj.totalSize(), @@ -148,11 +146,10 @@ template void SplitDWOToFile(const ELFObjectFile &ObjFile, StringRef File) { // Construct a second output file for the DWO sections. - ELFObject DWOFile(ObjFile); + ELFObjectImpl DWOFile(ObjFile); - DWOFile.removeSections([&](const SectionBase &Sec) { - return OnlyKeepDWOPred(DWOFile, Sec); - }); + DWOFile.removeSections( + [&](const SectionBase &Sec) { return OnlyKeepDWOPred(DWOFile, Sec); }); DWOFile.finalize(); WriteObjectFile(DWOFile, File); } @@ -164,20 +161,7 @@ // any previous removals. Lastly whether or not something is removed shouldn't // depend a) on the order the options occur in or b) on some opaque priority // system. The only priority is that keeps/copies overrule removes. -template -void CopyBinary(const ELFObjectFile &ObjFile) { - std::unique_ptr> Obj; - - if (!OutputFormat.empty() && OutputFormat != "binary") - error("invalid output format '" + OutputFormat + "'"); - if (!OutputFormat.empty() && OutputFormat == "binary") - Obj = llvm::make_unique>(ObjFile); - else - Obj = llvm::make_unique>(ObjFile); - - if (!SplitDWO.empty()) - SplitDWOToFile(ObjFile, SplitDWO.getValue()); - +void HandleArgs(std::unique_ptr Obj) { SectionPred RemovePred = [](const SectionBase &) { return false; }; // Removes: @@ -292,6 +276,24 @@ WriteObjectFile(*Obj, OutputFilename.getValue()); } +template void CopyBinary(const ELFObjectFile &ObjFile) { + std::unique_ptr Obj; + + if (!OutputFormat.empty() && OutputFormat != "binary") + error("invalid output format '" + OutputFormat + "'"); + if (!OutputFormat.empty() && OutputFormat == "binary") + Obj = llvm::make_unique>(ObjFile); + else + Obj = llvm::make_unique>(ObjFile); + + // We don't want extra output files to be effected by options. Additionally + // SplitDWOToFile needs the original ObjFile object to work. + if (!SplitDWO.empty()) + SplitDWOToFile(ObjFile, SplitDWO.getValue()); + + HandleArgs(std::move(Obj)); +} + int main(int argc, char **argv) { // Print a stack trace if we signal out. sys::PrintStackTraceOnErrorSignal(argv[0]);