[llvm] r323480 - [llvm-objcopy] Refactor llvm-objcopy to use reader and writer objects

Jake Ehrlich via llvm-commits llvm-commits at lists.llvm.org
Thu Jan 25 14:46:17 PST 2018


Author: jakehehrlich
Date: Thu Jan 25 14:46:17 2018
New Revision: 323480

URL: http://llvm.org/viewvc/llvm-project?rev=323480&view=rev
Log:
[llvm-objcopy] Refactor llvm-objcopy to use reader and writer objects

While writing code for input and output formats in llvm-objcopy it became
apparent that there was a code health problem. This change attempts to solve
that problem by refactoring the code to use Reader and Writer objects that can
read in different objects in different formats, convert them to a single shared
internal representation, and then write them to any other representation.

New classes:
Reader: the base class used to construct instances of the internal
representation
Writer: the base class used to write out instances of the internal
representation
ELFBuilder: a helper class for ELFWriter that takes an ELFFile and converts it
to a Object
SectionVisitor: it became necessary to remove writeSection from SectionBase
because, under the new Reader/Writer scheme, it's possible to convert between
ELF Types such as ELF32LE and ELF32BE. This isn't possible with writeSection
because it (dynamically) depends on the underlying section type *and*
(statically) depends on the ELF type. Bad things would happen if the underlying
sections for ELF32LE were used for writing to ELF64BE. To avoid this code smell
(which would have compiled, run, and output some nonsesnse) I decoupled writing
of sections from a class.
SectionWriter: This is just the ELFT templated implementation of
SectionVisitor. Many classes now have this class as a friend so that the
writing methods in this class can write out private data.
ELFWriter: This is the Writer that outputs to ELF
BinaryWriter: This is the Writer that outputs to Binary
ElfType: Because the ELF Type is not a part of the Object anymore we need a way
to construct the correct default Writer based on properties of the Reader. This
enum just keeps track of the ELF type of the input so it can be used as the
default output type as well.

Object has correspondingly undergone some serious changes as well. It now has
more generic methods for building and manipulating ELF binaries. This interface
makes ELFBuilder easy enough to use and will make the BinaryReader/Builder easy
to create as well. Most changes in this diff are cosmetic and deal with the
fact that a method has been moved from one class to another or a change from a
pointer to a reference. Almost no changes should result in a functional
difference (this is after all a refactor). One minor functional change was made
and the result can be seen in remove-shstrtab-error.test. The fact that it
fails hasn't changed but the error message has changed because that failure is
detected at a later point in the code now (because WriteSectionHeaders is a
property of the ElfWriter *not* a property of the Object). I'd say roughly
80-90% of this code is cosmetically different, 10-19% is different but
functionally the same, and 1-5% is functionally different despite not causing a
change in tests.

Differential Revision: https://reviews.llvm.org/D42222

Added:
    llvm/trunk/test/tools/llvm-objcopy/Inputs/alloc-symtab.o
    llvm/trunk/test/tools/llvm-objcopy/binary-out-error.test
Modified:
    llvm/trunk/test/tools/llvm-objcopy/remove-shstrtab-error.test
    llvm/trunk/tools/llvm-objcopy/Object.cpp
    llvm/trunk/tools/llvm-objcopy/Object.h
    llvm/trunk/tools/llvm-objcopy/llvm-objcopy.cpp
    llvm/trunk/tools/llvm-objcopy/llvm-objcopy.h

Added: llvm/trunk/test/tools/llvm-objcopy/Inputs/alloc-symtab.o
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-objcopy/Inputs/alloc-symtab.o?rev=323480&view=auto
==============================================================================
Binary files llvm/trunk/test/tools/llvm-objcopy/Inputs/alloc-symtab.o (added) and llvm/trunk/test/tools/llvm-objcopy/Inputs/alloc-symtab.o Thu Jan 25 14:46:17 2018 differ

Added: llvm/trunk/test/tools/llvm-objcopy/binary-out-error.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-objcopy/binary-out-error.test?rev=323480&view=auto
==============================================================================
--- llvm/trunk/test/tools/llvm-objcopy/binary-out-error.test (added)
+++ llvm/trunk/test/tools/llvm-objcopy/binary-out-error.test Thu Jan 25 14:46:17 2018
@@ -0,0 +1,2 @@
+# RUN: not llvm-objcopy -O binary %p/Inputs/alloc-symtab.o %t2 2>&1 >/dev/null | FileCheck %s --check-prefix=SYMTAB
+# SYMTAB: Cannot write symbol table '.symtab' out to binary

Modified: llvm/trunk/test/tools/llvm-objcopy/remove-shstrtab-error.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/llvm-objcopy/remove-shstrtab-error.test?rev=323480&r1=323479&r2=323480&view=diff
==============================================================================
--- llvm/trunk/test/tools/llvm-objcopy/remove-shstrtab-error.test (original)
+++ llvm/trunk/test/tools/llvm-objcopy/remove-shstrtab-error.test Thu Jan 25 14:46:17 2018
@@ -8,4 +8,4 @@ FileHeader:
   Type:            ET_REL
   Machine:         EM_X86_64
 
-# CHECK: Cannot remove .shstrtab because it is the section header string table.
+# CHECK: Cannot write section header table because section header string table was removed.

Modified: llvm/trunk/tools/llvm-objcopy/Object.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-objcopy/Object.cpp?rev=323480&r1=323479&r2=323480&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-objcopy/Object.cpp (original)
+++ llvm/trunk/tools/llvm-objcopy/Object.cpp Thu Jan 25 14:46:17 2018
@@ -30,61 +30,73 @@ using namespace llvm;
 using namespace object;
 using namespace ELF;
 
-template <class ELFT> void Segment::writeHeader(FileOutputBuffer &Out) const {
+template <class ELFT> void ELFWriter<ELFT>::writePhdr(const Segment &Seg) {
   using Elf_Ehdr = typename ELFT::Ehdr;
   using Elf_Phdr = typename ELFT::Phdr;
 
-  uint8_t *Buf = Out.getBufferStart();
-  Buf += sizeof(Elf_Ehdr) + Index * sizeof(Elf_Phdr);
+  uint8_t *Buf = BufPtr->getBufferStart();
+  Buf += sizeof(Elf_Ehdr) + Seg.Index * sizeof(Elf_Phdr);
   Elf_Phdr &Phdr = *reinterpret_cast<Elf_Phdr *>(Buf);
-  Phdr.p_type = Type;
-  Phdr.p_flags = Flags;
-  Phdr.p_offset = Offset;
-  Phdr.p_vaddr = VAddr;
-  Phdr.p_paddr = PAddr;
-  Phdr.p_filesz = FileSize;
-  Phdr.p_memsz = MemSize;
-  Phdr.p_align = Align;
-}
-
-void Segment::writeSegment(FileOutputBuffer &Out) const {
-  uint8_t *Buf = Out.getBufferStart() + Offset;
-  // We want to maintain segments' interstitial data and contents exactly.
-  // This lets us just copy segments directly.
-  std::copy(std::begin(Contents), std::end(Contents), Buf);
+  Phdr.p_type = Seg.Type;
+  Phdr.p_flags = Seg.Flags;
+  Phdr.p_offset = Seg.Offset;
+  Phdr.p_vaddr = Seg.VAddr;
+  Phdr.p_paddr = Seg.PAddr;
+  Phdr.p_filesz = Seg.FileSize;
+  Phdr.p_memsz = Seg.MemSize;
+  Phdr.p_align = Seg.Align;
 }
 
 void SectionBase::removeSectionReferences(const SectionBase *Sec) {}
 void SectionBase::initialize(SectionTableRef SecTable) {}
 void SectionBase::finalize() {}
 
-template <class ELFT>
-void SectionBase::writeHeader(FileOutputBuffer &Out) const {
-  uint8_t *Buf = Out.getBufferStart();
-  Buf += HeaderOffset;
+template <class ELFT> void ELFWriter<ELFT>::writeShdr(const SectionBase &Sec) {
+  uint8_t *Buf = BufPtr->getBufferStart();
+  Buf += Sec.HeaderOffset;
   typename ELFT::Shdr &Shdr = *reinterpret_cast<typename ELFT::Shdr *>(Buf);
-  Shdr.sh_name = NameIndex;
-  Shdr.sh_type = Type;
-  Shdr.sh_flags = Flags;
-  Shdr.sh_addr = Addr;
-  Shdr.sh_offset = Offset;
-  Shdr.sh_size = Size;
-  Shdr.sh_link = Link;
-  Shdr.sh_info = Info;
-  Shdr.sh_addralign = Align;
-  Shdr.sh_entsize = EntrySize;
+  Shdr.sh_name = Sec.NameIndex;
+  Shdr.sh_type = Sec.Type;
+  Shdr.sh_flags = Sec.Flags;
+  Shdr.sh_addr = Sec.Addr;
+  Shdr.sh_offset = Sec.Offset;
+  Shdr.sh_size = Sec.Size;
+  Shdr.sh_link = Sec.Link;
+  Shdr.sh_info = Sec.Info;
+  Shdr.sh_addralign = Sec.Align;
+  Shdr.sh_entsize = Sec.EntrySize;
+}
+
+SectionVisitor::~SectionVisitor() {}
+
+void BinarySectionWriter::visit(const SymbolTableSection &Sec) {
+  error("Cannot write symbol table '" + Sec.Name + "' out to binary");
+}
+
+void BinarySectionWriter::visit(const RelocationSection &Sec) {
+  error("Cannot write relocation section '" + Sec.Name + "' out to binary");
 }
 
-void Section::writeSection(FileOutputBuffer &Out) const {
-  if (Type == SHT_NOBITS)
+void BinarySectionWriter::visit(const GnuDebugLinkSection &Sec) {
+  error("Cannot write '.gnu_debuglink' out to binary");
+}
+
+void SectionWriter::visit(const Section &Sec) {
+  if (Sec.Type == SHT_NOBITS)
     return;
-  uint8_t *Buf = Out.getBufferStart() + Offset;
-  std::copy(std::begin(Contents), std::end(Contents), Buf);
+  uint8_t *Buf = Out.getBufferStart() + Sec.Offset;
+  std::copy(std::begin(Sec.Contents), std::end(Sec.Contents), Buf);
 }
 
-void OwnedDataSection::writeSection(FileOutputBuffer &Out) const {
-  uint8_t *Buf = Out.getBufferStart() + Offset;
-  std::copy(std::begin(Data), std::end(Data), Buf);
+void Section::accept(SectionVisitor &Visitor) const { Visitor.visit(*this); }
+
+void SectionWriter::visit(const OwnedDataSection &Sec) {
+  uint8_t *Buf = Out.getBufferStart() + Sec.Offset;
+  std::copy(std::begin(Sec.Data), std::end(Sec.Data), Buf);
+}
+
+void OwnedDataSection::accept(SectionVisitor &Visitor) const {
+  Visitor.visit(*this);
 }
 
 void StringTableSection::addString(StringRef Name) {
@@ -98,8 +110,12 @@ uint32_t StringTableSection::findIndex(S
 
 void StringTableSection::finalize() { StrTabBuilder.finalize(); }
 
-void StringTableSection::writeSection(FileOutputBuffer &Out) const {
-  StrTabBuilder.write(Out.getBufferStart() + Offset);
+void SectionWriter::visit(const StringTableSection &Sec) {
+  Sec.StrTabBuilder.write(Out.getBufferStart() + Sec.Offset);
+}
+
+void StringTableSection::accept(SectionVisitor &Visitor) const {
+  Visitor.visit(*this);
 }
 
 static bool isValidReservedSectionIndex(uint16_t Index, uint16_t Machine) {
@@ -234,12 +250,12 @@ const Symbol *SymbolTableSection::getSym
 }
 
 template <class ELFT>
-void SymbolTableSectionImpl<ELFT>::writeSection(FileOutputBuffer &Out) const {
+void ELFSectionWriter<ELFT>::visit(const SymbolTableSection &Sec) {
   uint8_t *Buf = Out.getBufferStart();
-  Buf += Offset;
+  Buf += Sec.Offset;
   typename ELFT::Sym *Sym = reinterpret_cast<typename ELFT::Sym *>(Buf);
   // Loop though symbols setting each entry of the symbol table.
-  for (auto &Symbol : Symbols) {
+  for (auto &Symbol : Sec.Symbols) {
     Sym->st_name = Symbol->NameIndex;
     Sym->st_value = Symbol->Value;
     Sym->st_size = Symbol->Size;
@@ -251,6 +267,10 @@ void SymbolTableSectionImpl<ELFT>::write
   }
 }
 
+void SymbolTableSection::accept(SectionVisitor &Visitor) const {
+  Visitor.visit(*this);
+}
+
 template <class SymTabType>
 void RelocSectionWithSymtabBase<SymTabType>::removeSectionReferences(
     const SectionBase *Sec) {
@@ -294,9 +314,8 @@ void setAddend(Elf_Rel_Impl<ELFT, true>
   Rela.r_addend = Addend;
 }
 
-template <class ELFT>
-template <class T>
-void RelocationSection<ELFT>::writeRel(T *Buf) const {
+template <class RelRange, class T>
+void writeRel(const RelRange &Relocations, T *Buf) {
   for (const auto &Reloc : Relocations) {
     Buf->r_offset = Reloc.Offset;
     setAddend(*Buf, Reloc.Addend);
@@ -306,17 +325,25 @@ void RelocationSection<ELFT>::writeRel(T
 }
 
 template <class ELFT>
-void RelocationSection<ELFT>::writeSection(FileOutputBuffer &Out) const {
-  uint8_t *Buf = Out.getBufferStart() + Offset;
-  if (Type == SHT_REL)
-    writeRel(reinterpret_cast<Elf_Rel *>(Buf));
+void ELFSectionWriter<ELFT>::visit(const RelocationSection &Sec) {
+  uint8_t *Buf = Out.getBufferStart() + Sec.Offset;
+  if (Sec.Type == SHT_REL)
+    writeRel(Sec.Relocations, reinterpret_cast<Elf_Rel *>(Buf));
   else
-    writeRel(reinterpret_cast<Elf_Rela *>(Buf));
+    writeRel(Sec.Relocations, reinterpret_cast<Elf_Rela *>(Buf));
 }
 
-void DynamicRelocationSection::writeSection(FileOutputBuffer &Out) const {
-  std::copy(std::begin(Contents), std::end(Contents),
-            Out.getBufferStart() + Offset);
+void RelocationSection::accept(SectionVisitor &Visitor) const {
+  Visitor.visit(*this);
+}
+
+void SectionWriter::visit(const DynamicRelocationSection &Sec) {
+  std::copy(std::begin(Sec.Contents), std::end(Sec.Contents),
+            Out.getBufferStart() + Sec.Offset);
+}
+
+void DynamicRelocationSection::accept(SectionVisitor &Visitor) const {
+  Visitor.visit(*this);
 }
 
 void SectionWithStrTab::removeSectionReferences(const SectionBase *Sec) {
@@ -344,8 +371,7 @@ void SectionWithStrTab::initialize(Secti
 
 void SectionWithStrTab::finalize() { this->Link = StrTab->Index; }
 
-template <class ELFT>
-void GnuDebugLinkSection<ELFT>::init(StringRef File, StringRef Data) {
+void GnuDebugLinkSection::init(StringRef File, StringRef Data) {
   FileName = sys::path::stem(File);
   // The format for the .gnu_debuglink starts with the stemmed file name and is
   // followed by a null terminator and then the CRC32 of the file. The CRC32
@@ -368,9 +394,7 @@ void GnuDebugLinkSection<ELFT>::init(Str
   CRC32 = ~crc.getCRC();
 }
 
-template <class ELFT>
-GnuDebugLinkSection<ELFT>::GnuDebugLinkSection(StringRef File)
-    : FileName(File) {
+GnuDebugLinkSection::GnuDebugLinkSection(StringRef File) : FileName(File) {
   // Read in the file to compute the CRC of it.
   auto DebugOrErr = MemoryBuffer::getFile(File);
   if (!DebugOrErr)
@@ -380,12 +404,17 @@ GnuDebugLinkSection<ELFT>::GnuDebugLinkS
 }
 
 template <class ELFT>
-void GnuDebugLinkSection<ELFT>::writeSection(FileOutputBuffer &Out) const {
-  auto Buf = Out.getBufferStart() + Offset;
+void ELFSectionWriter<ELFT>::visit(const GnuDebugLinkSection &Sec) {
+  auto Buf = Out.getBufferStart() + Sec.Offset;
   char *File = reinterpret_cast<char *>(Buf);
-  Elf_Word *CRC = reinterpret_cast<Elf_Word *>(Buf + Size - sizeof(Elf_Word));
-  *CRC = CRC32;
-  std::copy(std::begin(FileName), std::end(FileName), File);
+  Elf_Word *CRC =
+      reinterpret_cast<Elf_Word *>(Buf + Sec.Size - sizeof(Elf_Word));
+  *CRC = Sec.CRC32;
+  std::copy(std::begin(Sec.FileName), std::end(Sec.FileName), File);
+}
+
+void GnuDebugLinkSection::accept(SectionVisitor &Visitor) const {
+  Visitor.visit(*this);
 }
 
 // Returns true IFF a section is wholly inside the range of a segment
@@ -427,14 +456,12 @@ static bool compareSegmentsByPAddr(const
   return A->Index < B->Index;
 }
 
-template <class ELFT>
-void Object<ELFT>::readProgramHeaders(const ELFFile<ELFT> &ElfFile) {
+template <class ELFT> void ELFBuilder<ELFT>::readProgramHeaders() {
   uint32_t Index = 0;
   for (const auto &Phdr : unwrapOrError(ElfFile.program_headers())) {
     ArrayRef<uint8_t> Data{ElfFile.base() + Phdr.p_offset,
                            (size_t)Phdr.p_filesz};
-    Segments.emplace_back(llvm::make_unique<Segment>(Data));
-    Segment &Seg = *Segments.back();
+    Segment &Seg = Obj.addSegment(Data);
     Seg.Type = Phdr.p_type;
     Seg.Flags = Phdr.p_flags;
     Seg.OriginalOffset = Phdr.p_offset;
@@ -445,29 +472,29 @@ void Object<ELFT>::readProgramHeaders(co
     Seg.MemSize = Phdr.p_memsz;
     Seg.Align = Phdr.p_align;
     Seg.Index = Index++;
-    for (auto &Section : Sections) {
-      if (sectionWithinSegment(*Section, Seg)) {
-        Seg.addSection(&*Section);
-        if (!Section->ParentSegment ||
-            Section->ParentSegment->Offset > Seg.Offset) {
-          Section->ParentSegment = &Seg;
+    for (auto &Section : Obj.sections()) {
+      if (sectionWithinSegment(Section, Seg)) {
+        Seg.addSection(&Section);
+        if (!Section.ParentSegment ||
+            Section.ParentSegment->Offset > Seg.Offset) {
+          Section.ParentSegment = &Seg;
         }
       }
     }
   }
   // Now we do an O(n^2) loop through the segments in order to match up
   // segments.
-  for (auto &Child : Segments) {
-    for (auto &Parent : Segments) {
+  for (auto &Child : Obj.segments()) {
+    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.
-      if (&Child != &Parent && segmentOverlapsSegment(*Child, *Parent)) {
+      if (&Child != &Parent && segmentOverlapsSegment(Child, Parent)) {
         // We want a canonical "most parental" segment but this requires
         // inspecting the ParentSegment.
-        if (compareSegmentsByOffset(Parent.get(), Child.get()))
-          if (Child->ParentSegment == nullptr ||
-              compareSegmentsByOffset(Parent.get(), Child->ParentSegment)) {
-            Child->ParentSegment = Parent.get();
+        if (compareSegmentsByOffset(&Parent, &Child))
+          if (Child.ParentSegment == nullptr ||
+              compareSegmentsByOffset(&Parent, Child.ParentSegment)) {
+            Child.ParentSegment = &Parent;
           }
       }
     }
@@ -475,9 +502,7 @@ void Object<ELFT>::readProgramHeaders(co
 }
 
 template <class ELFT>
-void Object<ELFT>::initSymbolTable(const object::ELFFile<ELFT> &ElfFile,
-                                   SymbolTableSection *SymTab,
-                                   SectionTableRef SecTable) {
+void ELFBuilder<ELFT>::initSymbolTable(SymbolTableSection *SymTab) {
   const Elf_Shdr &Shdr = *unwrapOrError(ElfFile.getSection(SymTab->Index));
   StringRef StrTabData = unwrapOrError(ElfFile.getStringTableForSymtab(Shdr));
 
@@ -486,14 +511,14 @@ void Object<ELFT>::initSymbolTable(const
     StringRef Name = unwrapOrError(Sym.getName(StrTabData));
 
     if (Sym.st_shndx >= SHN_LORESERVE) {
-      if (!isValidReservedSectionIndex(Sym.st_shndx, Machine)) {
+      if (!isValidReservedSectionIndex(Sym.st_shndx, Obj.Machine)) {
         error(
             "Symbol '" + Name +
             "' has unsupported value greater than or equal to SHN_LORESERVE: " +
             Twine(Sym.st_shndx));
       }
     } else if (Sym.st_shndx != SHN_UNDEF) {
-      DefSection = SecTable.getSection(
+      DefSection = Obj.sections().getSection(
           Sym.st_shndx,
           "Symbol '" + Name + "' is defined in invalid section with index " +
               Twine(Sym.st_shndx));
@@ -512,9 +537,9 @@ static void getAddend(uint64_t &ToSet, c
   ToSet = Rela.r_addend;
 }
 
-template <class ELFT, class T>
-void initRelocations(RelocationSection<ELFT> *Relocs,
-                     SymbolTableSection *SymbolTable, T RelRange) {
+template <class T>
+void initRelocations(RelocationSection *Relocs, SymbolTableSection *SymbolTable,
+                     T RelRange) {
   for (const auto &Rel : RelRange) {
     Relocation ToAdd;
     ToAdd.Offset = Rel.r_offset;
@@ -540,147 +565,190 @@ T *SectionTableRef::getSectionOfType(uin
 }
 
 template <class ELFT>
-std::unique_ptr<SectionBase>
-Object<ELFT>::makeSection(const object::ELFFile<ELFT> &ElfFile,
-                          const Elf_Shdr &Shdr) {
+SectionBase &ELFBuilder<ELFT>::makeSection(const Elf_Shdr &Shdr) {
   ArrayRef<uint8_t> Data;
   switch (Shdr.sh_type) {
   case SHT_REL:
   case SHT_RELA:
     if (Shdr.sh_flags & SHF_ALLOC) {
       Data = unwrapOrError(ElfFile.getSectionContents(&Shdr));
-      return llvm::make_unique<DynamicRelocationSection>(Data);
+      return Obj.addSection<DynamicRelocationSection>(Data);
     }
-    return llvm::make_unique<RelocationSection<ELFT>>();
+    return Obj.addSection<RelocationSection>();
   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
     // anything so we can just use a Section.
     if (Shdr.sh_flags & SHF_ALLOC) {
       Data = unwrapOrError(ElfFile.getSectionContents(&Shdr));
-      return llvm::make_unique<Section>(Data);
+      return Obj.addSection<Section>(Data);
     }
-    return llvm::make_unique<StringTableSection>();
+    return Obj.addSection<StringTableSection>();
   case SHT_HASH:
   case SHT_GNU_HASH:
     // Hash tables should refer to SHT_DYNSYM which we're not going to change.
     // Because of this we don't need to mess with the hash tables either.
     Data = unwrapOrError(ElfFile.getSectionContents(&Shdr));
-    return llvm::make_unique<Section>(Data);
+    return Obj.addSection<Section>(Data);
   case SHT_DYNSYM:
     Data = unwrapOrError(ElfFile.getSectionContents(&Shdr));
-    return llvm::make_unique<DynamicSymbolTableSection>(Data);
+    return Obj.addSection<DynamicSymbolTableSection>(Data);
   case SHT_DYNAMIC:
     Data = unwrapOrError(ElfFile.getSectionContents(&Shdr));
-    return llvm::make_unique<DynamicSection>(Data);
+    return Obj.addSection<DynamicSection>(Data);
   case SHT_SYMTAB: {
-    auto SymTab = llvm::make_unique<SymbolTableSectionImpl<ELFT>>();
-    SymbolTable = SymTab.get();
-    return std::move(SymTab);
+    auto &SymTab = Obj.addSection<SymbolTableSection>();
+    Obj.SymbolTable = &SymTab;
+    return SymTab;
   }
   case SHT_NOBITS:
-    return llvm::make_unique<Section>(Data);
+    return Obj.addSection<Section>(Data);
   default:
     Data = unwrapOrError(ElfFile.getSectionContents(&Shdr));
-    return llvm::make_unique<Section>(Data);
+    return Obj.addSection<Section>(Data);
   }
 }
 
-template <class ELFT>
-SectionTableRef Object<ELFT>::readSectionHeaders(const ELFFile<ELFT> &ElfFile) {
+template <class ELFT> void ELFBuilder<ELFT>::readSectionHeaders() {
   uint32_t Index = 0;
   for (const auto &Shdr : unwrapOrError(ElfFile.sections())) {
     if (Index == 0) {
       ++Index;
       continue;
     }
-    SecPtr Sec = makeSection(ElfFile, Shdr);
-    Sec->Name = unwrapOrError(ElfFile.getSectionName(&Shdr));
-    Sec->Type = Shdr.sh_type;
-    Sec->Flags = Shdr.sh_flags;
-    Sec->Addr = Shdr.sh_addr;
-    Sec->Offset = Shdr.sh_offset;
-    Sec->OriginalOffset = Shdr.sh_offset;
-    Sec->Size = Shdr.sh_size;
-    Sec->Link = Shdr.sh_link;
-    Sec->Info = Shdr.sh_info;
-    Sec->Align = Shdr.sh_addralign;
-    Sec->EntrySize = Shdr.sh_entsize;
-    Sec->Index = Index++;
-    Sections.push_back(std::move(Sec));
+    auto &Sec = makeSection(Shdr);
+    Sec.Name = unwrapOrError(ElfFile.getSectionName(&Shdr));
+    Sec.Type = Shdr.sh_type;
+    Sec.Flags = Shdr.sh_flags;
+    Sec.Addr = Shdr.sh_addr;
+    Sec.Offset = Shdr.sh_offset;
+    Sec.OriginalOffset = Shdr.sh_offset;
+    Sec.Size = Shdr.sh_size;
+    Sec.Link = Shdr.sh_link;
+    Sec.Info = Shdr.sh_info;
+    Sec.Align = Shdr.sh_addralign;
+    Sec.EntrySize = Shdr.sh_entsize;
+    Sec.Index = Index++;
   }
 
-  SectionTableRef SecTable(Sections);
-
   // Now that all of the sections have been added we can fill out some extra
   // details about symbol tables. We need the symbol table filled out before
   // any relocations.
-  if (SymbolTable) {
-    SymbolTable->initialize(SecTable);
-    initSymbolTable(ElfFile, SymbolTable, SecTable);
+  if (Obj.SymbolTable) {
+    Obj.SymbolTable->initialize(Obj.sections());
+    initSymbolTable(Obj.SymbolTable);
   }
 
   // Now that all sections and symbols have been added we can add
   // relocations that reference symbols and set the link and info fields for
   // relocation sections.
-  for (auto &Section : Sections) {
-    if (Section.get() == SymbolTable)
+  for (auto &Section : Obj.sections()) {
+    if (&Section == Obj.SymbolTable)
       continue;
-    Section->initialize(SecTable);
-    if (auto RelSec = dyn_cast<RelocationSection<ELFT>>(Section.get())) {
+    Section.initialize(Obj.sections());
+    if (auto RelSec = dyn_cast<RelocationSection>(&Section)) {
       auto Shdr = unwrapOrError(ElfFile.sections()).begin() + RelSec->Index;
       if (RelSec->Type == SHT_REL)
-        initRelocations(RelSec, SymbolTable, unwrapOrError(ElfFile.rels(Shdr)));
+        initRelocations(RelSec, Obj.SymbolTable,
+                        unwrapOrError(ElfFile.rels(Shdr)));
       else
-        initRelocations(RelSec, SymbolTable,
+        initRelocations(RelSec, Obj.SymbolTable,
                         unwrapOrError(ElfFile.relas(Shdr)));
     }
   }
-
-  return SecTable;
 }
 
-template <class ELFT> Object<ELFT>::Object(const ELFObjectFile<ELFT> &Obj) {
-  const auto &ElfFile = *Obj.getELFFile();
+template <class ELFT> void ELFBuilder<ELFT>::build() {
   const auto &Ehdr = *ElfFile.getHeader();
 
-  std::copy(Ehdr.e_ident, Ehdr.e_ident + 16, Ident);
-  Type = Ehdr.e_type;
-  Machine = Ehdr.e_machine;
-  Version = Ehdr.e_version;
-  Entry = Ehdr.e_entry;
-  Flags = Ehdr.e_flags;
-
-  SectionTableRef SecTable = readSectionHeaders(ElfFile);
-  readProgramHeaders(ElfFile);
-
-  SectionNames = SecTable.getSectionOfType<StringTableSection>(
-      Ehdr.e_shstrndx,
-      "e_shstrndx field value " + Twine(Ehdr.e_shstrndx) + " in elf header " +
-          " is invalid",
-      "e_shstrndx field value " + Twine(Ehdr.e_shstrndx) + " in elf header " +
-          " is not a string table");
+  std::copy(Ehdr.e_ident, Ehdr.e_ident + 16, Obj.Ident);
+  Obj.Type = Ehdr.e_type;
+  Obj.Machine = Ehdr.e_machine;
+  Obj.Version = Ehdr.e_version;
+  Obj.Entry = Ehdr.e_entry;
+  Obj.Flags = Ehdr.e_flags;
+
+  readSectionHeaders();
+  readProgramHeaders();
+
+  Obj.SectionNames =
+      Obj.sections().template getSectionOfType<StringTableSection>(
+          Ehdr.e_shstrndx,
+          "e_shstrndx field value " + Twine(Ehdr.e_shstrndx) +
+              " in elf header " + " is invalid",
+          "e_shstrndx field value " + Twine(Ehdr.e_shstrndx) +
+              " in elf header " + " is not a string table");
+}
+
+// A generic size function which computes sizes of any random access range.
+template <class R> size_t size(R &&Range) {
+  return static_cast<size_t>(std::end(Range) - std::begin(Range));
+}
+
+Writer::~Writer() {}
+
+Reader::~Reader() {}
+
+ELFReader::ELFReader(StringRef File) {
+  auto BinaryOrErr = createBinary(File);
+  if (!BinaryOrErr)
+    reportError(File, BinaryOrErr.takeError());
+  auto Bin = std::move(BinaryOrErr.get());
+  std::tie(Binary, Data) = Bin.takeBinary();
+}
+
+ElfType ELFReader::getElfType() const {
+  if (auto *o = dyn_cast<ELFObjectFile<ELF32LE>>(Binary.get()))
+    return ELFT_ELF32LE;
+  if (auto *o = dyn_cast<ELFObjectFile<ELF64LE>>(Binary.get()))
+    return ELFT_ELF64LE;
+  if (auto *o = dyn_cast<ELFObjectFile<ELF32BE>>(Binary.get()))
+    return ELFT_ELF32BE;
+  if (auto *o = dyn_cast<ELFObjectFile<ELF64BE>>(Binary.get()))
+    return ELFT_ELF64BE;
+  llvm_unreachable("Invalid ELFType");
+}
+
+std::unique_ptr<Object> ELFReader::create() const {
+  auto Obj = llvm::make_unique<Object>(Data);
+  if (auto *o = dyn_cast<ELFObjectFile<ELF32LE>>(Binary.get())) {
+    ELFBuilder<ELF32LE> Builder(*o, *Obj);
+    Builder.build();
+    return Obj;
+  } else if (auto *o = dyn_cast<ELFObjectFile<ELF64LE>>(Binary.get())) {
+    ELFBuilder<ELF64LE> Builder(*o, *Obj);
+    Builder.build();
+    return Obj;
+  } else if (auto *o = dyn_cast<ELFObjectFile<ELF32BE>>(Binary.get())) {
+    ELFBuilder<ELF32BE> Builder(*o, *Obj);
+    Builder.build();
+    return Obj;
+  } else if (auto *o = dyn_cast<ELFObjectFile<ELF64BE>>(Binary.get())) {
+    ELFBuilder<ELF64BE> Builder(*o, *Obj);
+    Builder.build();
+    return Obj;
+  }
+  error("Invalid file type");
 }
 
-template <class ELFT>
-void Object<ELFT>::writeHeader(FileOutputBuffer &Out) const {
-  uint8_t *Buf = Out.getBufferStart();
+template <class ELFT> void ELFWriter<ELFT>::writeEhdr() {
+  uint8_t *Buf = BufPtr->getBufferStart();
   Elf_Ehdr &Ehdr = *reinterpret_cast<Elf_Ehdr *>(Buf);
-  std::copy(Ident, Ident + 16, Ehdr.e_ident);
-  Ehdr.e_type = Type;
-  Ehdr.e_machine = Machine;
-  Ehdr.e_version = Version;
-  Ehdr.e_entry = Entry;
+  std::copy(Obj.Ident, Obj.Ident + 16, Ehdr.e_ident);
+  Ehdr.e_type = Obj.Type;
+  Ehdr.e_machine = Obj.Machine;
+  Ehdr.e_version = Obj.Version;
+  Ehdr.e_entry = Obj.Entry;
   Ehdr.e_phoff = sizeof(Elf_Ehdr);
-  Ehdr.e_flags = Flags;
+  Ehdr.e_flags = Obj.Flags;
   Ehdr.e_ehsize = sizeof(Elf_Ehdr);
   Ehdr.e_phentsize = sizeof(Elf_Phdr);
-  Ehdr.e_phnum = Segments.size();
+  Ehdr.e_phnum = size(Obj.segments());
   Ehdr.e_shentsize = sizeof(Elf_Shdr);
   if (WriteSectionHeaders) {
-    Ehdr.e_shoff = SHOffset;
-    Ehdr.e_shnum = Sections.size() + 1;
-    Ehdr.e_shstrndx = SectionNames->Index;
+    Ehdr.e_shoff = Obj.SHOffset;
+    Ehdr.e_shnum = size(Obj.sections()) + 1;
+    Ehdr.e_shstrndx = Obj.SectionNames->Index;
   } else {
     Ehdr.e_shoff = 0;
     Ehdr.e_shnum = 0;
@@ -688,15 +756,13 @@ void Object<ELFT>::writeHeader(FileOutpu
   }
 }
 
-template <class ELFT>
-void Object<ELFT>::writeProgramHeaders(FileOutputBuffer &Out) const {
-  for (auto &Phdr : Segments)
-    Phdr->template writeHeader<ELFT>(Out);
+template <class ELFT> void ELFWriter<ELFT>::writePhdrs() {
+  for (auto &Seg : Obj.segments())
+    writePhdr(Seg);
 }
 
-template <class ELFT>
-void Object<ELFT>::writeSectionHeaders(FileOutputBuffer &Out) const {
-  uint8_t *Buf = Out.getBufferStart() + SHOffset;
+template <class ELFT> void ELFWriter<ELFT>::writeShdrs() {
+  uint8_t *Buf = BufPtr->getBufferStart() + Obj.SHOffset;
   // This reference serves to write the dummy section header at the begining
   // of the file. It is not used for anything else
   Elf_Shdr &Shdr = *reinterpret_cast<Elf_Shdr *>(Buf);
@@ -711,19 +777,16 @@ void Object<ELFT>::writeSectionHeaders(F
   Shdr.sh_addralign = 0;
   Shdr.sh_entsize = 0;
 
-  for (auto &Section : Sections)
-    Section->template writeHeader<ELFT>(Out);
+  for (auto &Sec : Obj.sections())
+    writeShdr(Sec);
 }
 
-template <class ELFT>
-void Object<ELFT>::writeSectionData(FileOutputBuffer &Out) const {
-  for (auto &Section : Sections)
-    Section->writeSection(Out);
+template <class ELFT> void ELFWriter<ELFT>::writeSectionData() {
+  for (auto &Sec : Obj.sections())
+    Sec.accept(*SecWriter);
 }
 
-template <class ELFT>
-void Object<ELFT>::removeSections(
-    std::function<bool(const SectionBase &)> ToRemove) {
+void Object::removeSections(std::function<bool(const SectionBase &)> ToRemove) {
 
   auto Iter = std::stable_partition(
       std::begin(Sections), std::end(Sections), [=](const SecPtr &Sec) {
@@ -737,10 +800,7 @@ void Object<ELFT>::removeSections(
       });
   if (SymbolTable != nullptr && ToRemove(*SymbolTable))
     SymbolTable = nullptr;
-  if (ToRemove(*SectionNames)) {
-    if (WriteSectionHeaders)
-      error("Cannot remove " + SectionNames->Name +
-            " because it is the section header string table.");
+  if (SectionNames != nullptr && ToRemove(*SectionNames)) {
     SectionNames = nullptr;
   }
   // Now make sure there are no remaining references to the sections that will
@@ -756,18 +816,7 @@ void Object<ELFT>::removeSections(
   Sections.erase(Iter, std::end(Sections));
 }
 
-template <class ELFT>
-void Object<ELFT>::addSection(StringRef SecName, ArrayRef<uint8_t> Data) {
-  auto Sec = llvm::make_unique<OwnedDataSection>(SecName, Data);
-  Sec->OriginalOffset = ~0ULL;
-  Sections.push_back(std::move(Sec));
-}
-
-template <class ELFT> void Object<ELFT>::addGnuDebugLink(StringRef File) {
-  Sections.emplace_back(llvm::make_unique<GnuDebugLinkSection<ELFT>>(File));
-}
-
-template <class ELFT> void ELFObject<ELFT>::sortSections() {
+void Object::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) {
@@ -832,8 +881,8 @@ static uint64_t LayoutSegments(std::vect
 // does not have a ParentSegment. It returns either the offset given if all
 // sections had a ParentSegment or an offset one past the last section if there
 // was a section that didn't have a ParentSegment.
-template <class SecPtr>
-static uint64_t LayoutSections(std::vector<SecPtr> &Sections, uint64_t Offset) {
+template <class Range>
+static uint64_t LayoutSections(Range Sections, uint64_t Offset) {
   // Now the offset of every segment has been set we can assign the offsets
   // of each section. For sections that are covered by a segment we should use
   // the segment's original offset and the section's original offset to compute
@@ -842,28 +891,28 @@ static uint64_t LayoutSections(std::vect
   // covered by segments we can just bump Offset to the next valid location.
   uint32_t Index = 1;
   for (auto &Section : Sections) {
-    Section->Index = Index++;
-    if (Section->ParentSegment != nullptr) {
-      auto Segment = Section->ParentSegment;
-      Section->Offset =
-          Segment->Offset + (Section->OriginalOffset - Segment->OriginalOffset);
+    Section.Index = Index++;
+    if (Section.ParentSegment != nullptr) {
+      auto Segment = *Section.ParentSegment;
+      Section.Offset =
+          Segment.Offset + (Section.OriginalOffset - Segment.OriginalOffset);
     } else {
-      Offset = alignTo(Offset, Section->Align == 0 ? 1 : Section->Align);
-      Section->Offset = Offset;
-      if (Section->Type != SHT_NOBITS)
-        Offset += Section->Size;
+      Offset = alignTo(Offset, Section.Align == 0 ? 1 : Section.Align);
+      Section.Offset = Offset;
+      if (Section.Type != SHT_NOBITS)
+        Offset += Section.Size;
     }
   }
   return Offset;
 }
 
-template <class ELFT> void ELFObject<ELFT>::assignOffsets() {
+template <class ELFT> void ELFWriter<ELFT>::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.
   std::vector<Segment *> OrderedSegments;
-  for (auto &Segment : this->Segments)
-    OrderedSegments.push_back(Segment.get());
+  for (auto &Segment : Obj.segments())
+    OrderedSegments.push_back(&Segment);
   OrderSegments(OrderedSegments);
   // The size of ELF + program headers will not change so it is ok to assume
   // that the first offset of the first segment is a good place to start
@@ -876,72 +925,88 @@ template <class ELFT> void ELFObject<ELF
     Offset = sizeof(Elf_Ehdr);
   }
   Offset = LayoutSegments(OrderedSegments, Offset);
-  Offset = LayoutSections(this->Sections, Offset);
+  Offset = LayoutSections(Obj.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)
+  if (WriteSectionHeaders)
     Offset = alignTo(Offset, sizeof(typename ELFT::Addr));
-  this->SHOffset = Offset;
+  Obj.SHOffset = Offset;
 }
 
-template <class ELFT> size_t ELFObject<ELFT>::totalSize() const {
+template <class ELFT> size_t ELFWriter<ELFT>::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) +
+  auto NullSectionSize = WriteSectionHeaders ? sizeof(Elf_Shdr) : 0;
+  return Obj.SHOffset + size(Obj.sections()) * sizeof(Elf_Shdr) +
          NullSectionSize;
 }
 
-template <class ELFT> void ELFObject<ELFT>::write(FileOutputBuffer &Out) const {
-  this->writeHeader(Out);
-  this->writeProgramHeaders(Out);
-  this->writeSectionData(Out);
-  if (this->WriteSectionHeaders)
-    this->writeSectionHeaders(Out);
-}
+template <class ELFT> void ELFWriter<ELFT>::write() {
+  writeEhdr();
+  writePhdrs();
+  writeSectionData();
+  if (WriteSectionHeaders)
+    writeShdrs();
+  if (auto E = BufPtr->commit())
+    reportError(File, errorToErrorCode(std::move(E)));
+}
+
+void Writer::createBuffer(uint64_t Size) {
+  auto BufferOrErr =
+      FileOutputBuffer::create(File, Size, FileOutputBuffer::F_executable);
+  handleAllErrors(BufferOrErr.takeError(), [this](const ErrorInfoBase &) {
+    error("failed to open " + File);
+  });
+  BufPtr = std::move(*BufferOrErr);
+}
+
+template <class ELFT> void ELFWriter<ELFT>::finalize() {
+  // It could happen that SectionNames has been removed and yet the user wants
+  // a section header table output. We need to throw an error if a user tries
+  // to do that.
+  if (Obj.SectionNames == nullptr && WriteSectionHeaders)
+    error("Cannot write section header table because section header string "
+          "table was removed.");
 
-template <class ELFT> void ELFObject<ELFT>::finalize() {
   // Make sure we add the names of all the sections.
-  if (this->SectionNames != nullptr)
-    for (const auto &Section : this->Sections) {
-      this->SectionNames->addString(Section->Name);
+  if (Obj.SectionNames != nullptr)
+    for (const auto &Section : Obj.sections()) {
+      Obj.SectionNames->addString(Section.Name);
     }
   // Make sure we add the names of all the symbols.
-  if (this->SymbolTable != nullptr)
-    this->SymbolTable->addSymbolNames();
+  if (Obj.SymbolTable != nullptr)
+    Obj.SymbolTable->addSymbolNames();
 
-  sortSections();
+  Obj.sortSections();
   assignOffsets();
 
   // Finalize SectionNames first so that we can assign name indexes.
-  if (this->SectionNames != nullptr)
-    this->SectionNames->finalize();
+  if (Obj.SectionNames != nullptr)
+    Obj.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);
-  for (auto &Section : this->Sections) {
-    Section->HeaderOffset = Offset;
+  uint64_t Offset = Obj.SHOffset + sizeof(Elf_Shdr);
+  for (auto &Section : Obj.sections()) {
+    Section.HeaderOffset = Offset;
     Offset += sizeof(Elf_Shdr);
-    if (this->WriteSectionHeaders)
-      Section->NameIndex = this->SectionNames->findIndex(Section->Name);
-    Section->finalize();
+    if (WriteSectionHeaders)
+      Section.NameIndex = Obj.SectionNames->findIndex(Section.Name);
+    Section.finalize();
   }
-}
 
-template <class ELFT> size_t BinaryObject<ELFT>::totalSize() const {
-  return TotalSize;
+  createBuffer(totalSize());
+  SecWriter = llvm::make_unique<ELFSectionWriter<ELFT>>(*BufPtr);
 }
 
-template <class ELFT>
-void BinaryObject<ELFT>::write(FileOutputBuffer &Out) const {
-  for (auto &Section : this->Sections) {
-    if ((Section->Flags & SHF_ALLOC) == 0)
+void BinaryWriter::write() {
+  for (auto &Section : Obj.sections()) {
+    if ((Section.Flags & SHF_ALLOC) == 0)
       continue;
-    Section->writeSection(Out);
+    Section.accept(*SecWriter);
   }
 }
 
-template <class ELFT> void BinaryObject<ELFT>::finalize() {
+void BinaryWriter::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.
@@ -950,10 +1015,9 @@ template <class ELFT> void BinaryObject<
   // already had it's offset properly set. We only want to consider the segments
   // that will affect layout of allocated sections so we only add those.
   std::vector<Segment *> OrderedSegments;
-  for (auto &Section : this->Sections) {
-    if ((Section->Flags & SHF_ALLOC) != 0 &&
-        Section->ParentSegment != nullptr) {
-      OrderedSegments.push_back(Section->ParentSegment);
+  for (auto &Section : Obj.sections()) {
+    if ((Section.Flags & SHF_ALLOC) != 0 && Section.ParentSegment != nullptr) {
+      OrderedSegments.push_back(Section.ParentSegment);
     }
   }
 
@@ -1004,12 +1068,12 @@ template <class ELFT> void BinaryObject<
   // not hold. Then pass such a range to LayoutSections instead of constructing
   // AllocatedSections here.
   std::vector<SectionBase *> AllocatedSections;
-  for (auto &Section : this->Sections) {
-    if ((Section->Flags & SHF_ALLOC) == 0)
+  for (auto &Section : Obj.sections()) {
+    if ((Section.Flags & SHF_ALLOC) == 0)
       continue;
-    AllocatedSections.push_back(Section.get());
+    AllocatedSections.push_back(&Section);
   }
-  LayoutSections(AllocatedSections, Offset);
+  LayoutSections(make_pointee_range(AllocatedSections), Offset);
 
   // Now that every section has been laid out we just need to compute the total
   // file size. This might not be the same as the offset returned by
@@ -1020,23 +1084,21 @@ template <class ELFT> void BinaryObject<
     if (Section->Type != SHT_NOBITS)
       TotalSize = std::max(TotalSize, Section->Offset + Section->Size);
   }
+
+  createBuffer(TotalSize);
+  SecWriter = llvm::make_unique<BinarySectionWriter>(*BufPtr);
 }
 
 namespace llvm {
 
-template class Object<ELF64LE>;
-template class Object<ELF64BE>;
-template class Object<ELF32LE>;
-template class Object<ELF32BE>;
-
-template class ELFObject<ELF64LE>;
-template class ELFObject<ELF64BE>;
-template class ELFObject<ELF32LE>;
-template class ELFObject<ELF32BE>;
-
-template class BinaryObject<ELF64LE>;
-template class BinaryObject<ELF64BE>;
-template class BinaryObject<ELF32LE>;
-template class BinaryObject<ELF32BE>;
+template class ELFBuilder<ELF64LE>;
+template class ELFBuilder<ELF64BE>;
+template class ELFBuilder<ELF32LE>;
+template class ELFBuilder<ELF32BE>;
+
+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=323480&r1=323479&r2=323480&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-objcopy/Object.h (original)
+++ llvm/trunk/tools/llvm-objcopy/Object.h Thu Jan 25 14:46:17 2018
@@ -16,6 +16,7 @@
 #include "llvm/BinaryFormat/ELF.h"
 #include "llvm/MC/StringTableBuilder.h"
 #include "llvm/Object/ELFObjectFile.h"
+#include "llvm/Support/FileOutputBuffer.h"
 #include "llvm/Support/JamCRC.h"
 #include <cstddef>
 #include <cstdint>
@@ -26,25 +27,159 @@
 
 namespace llvm {
 
-class FileOutputBuffer;
 class SectionBase;
+class Section;
+class OwnedDataSection;
+class StringTableSection;
+class SymbolTableSection;
+class RelocationSection;
+class DynamicRelocationSection;
+class GnuDebugLinkSection;
 class Segment;
+class Object;
 
 class SectionTableRef {
 private:
-  ArrayRef<std::unique_ptr<SectionBase>> Sections;
+  MutableArrayRef<std::unique_ptr<SectionBase>> Sections;
 
 public:
-  SectionTableRef(ArrayRef<std::unique_ptr<SectionBase>> Secs)
+  using iterator = pointee_iterator<std::unique_ptr<SectionBase> *>;
+
+  SectionTableRef(MutableArrayRef<std::unique_ptr<SectionBase>> Secs)
       : Sections(Secs) {}
   SectionTableRef(const SectionTableRef &) = default;
 
+  iterator begin() { return iterator(Sections.data()); }
+  iterator end() { return iterator(Sections.data() + Sections.size()); }
+
   SectionBase *getSection(uint16_t Index, Twine ErrMsg);
 
   template <class T>
   T *getSectionOfType(uint16_t Index, Twine IndexErrMsg, Twine TypeErrMsg);
 };
 
+enum ElfType { ELFT_ELF32LE, ELFT_ELF64LE, ELFT_ELF32BE, ELFT_ELF64BE };
+
+class SectionVisitor {
+public:
+  virtual ~SectionVisitor();
+
+  virtual void visit(const Section &Sec) = 0;
+  virtual void visit(const OwnedDataSection &Sec) = 0;
+  virtual void visit(const StringTableSection &Sec) = 0;
+  virtual void visit(const SymbolTableSection &Sec) = 0;
+  virtual void visit(const RelocationSection &Sec) = 0;
+  virtual void visit(const DynamicRelocationSection &Sec) = 0;
+  virtual void visit(const GnuDebugLinkSection &Sec) = 0;
+};
+
+class SectionWriter : public SectionVisitor {
+protected:
+  FileOutputBuffer &Out;
+
+public:
+  virtual ~SectionWriter(){};
+
+  void visit(const Section &Sec) override;
+  void visit(const OwnedDataSection &Sec) override;
+  void visit(const StringTableSection &Sec) override;
+  void visit(const DynamicRelocationSection &Sec) override;
+  virtual void visit(const SymbolTableSection &Sec) override = 0;
+  virtual void visit(const RelocationSection &Sec) override = 0;
+  virtual void visit(const GnuDebugLinkSection &Sec) override = 0;
+
+  SectionWriter(FileOutputBuffer &Buf) : Out(Buf) {}
+};
+
+template <class ELFT> class ELFSectionWriter : public SectionWriter {
+private:
+  using Elf_Word = typename ELFT::Word;
+  using Elf_Rel = typename ELFT::Rel;
+  using Elf_Rela = typename ELFT::Rela;
+
+public:
+  virtual ~ELFSectionWriter() {}
+  void visit(const SymbolTableSection &Sec) override;
+  void visit(const RelocationSection &Sec) override;
+  void visit(const GnuDebugLinkSection &Sec) override;
+
+  ELFSectionWriter(FileOutputBuffer &Buf) : SectionWriter(Buf) {}
+};
+
+#define MAKE_SEC_WRITER_FRIEND                                                 \
+  friend class SectionWriter;                                                  \
+  template <class ELFT> friend class ELFSectionWriter;
+
+class BinarySectionWriter : public SectionWriter {
+public:
+  virtual ~BinarySectionWriter() {}
+
+  void visit(const SymbolTableSection &Sec) override;
+  void visit(const RelocationSection &Sec) override;
+  void visit(const GnuDebugLinkSection &Sec) override;
+  BinarySectionWriter(FileOutputBuffer &Buf) : SectionWriter(Buf) {}
+};
+
+class Writer {
+protected:
+  StringRef File;
+  Object &Obj;
+  std::unique_ptr<FileOutputBuffer> BufPtr;
+
+  void createBuffer(uint64_t Size);
+
+public:
+  virtual ~Writer();
+
+  virtual void finalize() = 0;
+  virtual void write() = 0;
+
+  Writer(StringRef File, Object &Obj) : File(File), Obj(Obj) {}
+};
+
+template <class ELFT> class ELFWriter : public Writer {
+private:
+  using Elf_Shdr = typename ELFT::Shdr;
+  using Elf_Phdr = typename ELFT::Phdr;
+  using Elf_Ehdr = typename ELFT::Ehdr;
+
+  void writeEhdr();
+  void writePhdr(const Segment &Seg);
+  void writeShdr(const SectionBase &Sec);
+
+  void writePhdrs();
+  void writeShdrs();
+  void writeSectionData();
+
+  void assignOffsets();
+
+  std::unique_ptr<ELFSectionWriter<ELFT>> SecWriter;
+
+  size_t totalSize() const;
+
+public:
+  virtual ~ELFWriter() {}
+  bool WriteSectionHeaders = true;
+
+  void finalize() override;
+  void write() override;
+  ELFWriter(StringRef File, Object &Obj, bool WSH)
+      : Writer(File, Obj), WriteSectionHeaders(WSH) {}
+};
+
+class BinaryWriter : public Writer {
+private:
+  std::unique_ptr<BinarySectionWriter> SecWriter;
+
+  uint64_t TotalSize;
+
+public:
+  ~BinaryWriter() {}
+  void finalize() override;
+  void write() override;
+  BinaryWriter(StringRef File, Object &Obj) : Writer(File, Obj) {}
+};
+
 class SectionBase {
 public:
   StringRef Name;
@@ -69,8 +204,7 @@ public:
   virtual void initialize(SectionTableRef SecTable);
   virtual void finalize();
   virtual void removeSectionReferences(const SectionBase *Sec);
-  template <class ELFT> void writeHeader(FileOutputBuffer &Out) const;
-  virtual void writeSection(FileOutputBuffer &Out) const = 0;
+  virtual void accept(SectionVisitor &Visitor) const = 0;
 };
 
 class Segment {
@@ -113,21 +247,23 @@ public:
 
   void removeSection(const SectionBase *Sec) { Sections.erase(Sec); }
   void addSection(const SectionBase *Sec) { Sections.insert(Sec); }
-  template <class ELFT> void writeHeader(FileOutputBuffer &Out) const;
-  void writeSegment(FileOutputBuffer &Out) const;
 };
 
 class Section : public SectionBase {
+  MAKE_SEC_WRITER_FRIEND
+
 private:
   ArrayRef<uint8_t> Contents;
 
 public:
   Section(ArrayRef<uint8_t> Data) : Contents(Data) {}
 
-  void writeSection(FileOutputBuffer &Out) const override;
+  void accept(SectionVisitor &Visitor) const override;
 };
 
 class OwnedDataSection : public SectionBase {
+  MAKE_SEC_WRITER_FRIEND
+
 private:
   std::vector<uint8_t> Data;
 
@@ -137,8 +273,10 @@ public:
     Name = SecName;
     Type = ELF::SHT_PROGBITS;
     Size = Data.size();
+    OriginalOffset = std::numeric_limits<uint64_t>::max();
   }
-  void writeSection(FileOutputBuffer &Out) const override;
+
+  void accept(SectionVisitor &Sec) const override;
 };
 
 // There are two types of string tables that can exist, dynamic and not dynamic.
@@ -150,6 +288,8 @@ public:
 // classof method checks that the particular instance is not allocated. This
 // then agrees with the makeSection method used to construct most sections.
 class StringTableSection : public SectionBase {
+  MAKE_SEC_WRITER_FRIEND
+
 private:
   StringTableBuilder StrTabBuilder;
 
@@ -161,7 +301,7 @@ public:
   void addString(StringRef Name);
   uint32_t findIndex(StringRef Name) const;
   void finalize() override;
-  void writeSection(FileOutputBuffer &Out) const override;
+  void accept(SectionVisitor &Visitor) const override;
 
   static bool classof(const SectionBase *S) {
     if (S->Flags & ELF::SHF_ALLOC)
@@ -200,6 +340,8 @@ struct Symbol {
 };
 
 class SymbolTableSection : public SectionBase {
+  MAKE_SEC_WRITER_FRIEND
+
 protected:
   std::vector<std::unique_ptr<Symbol>> Symbols;
   StringTableSection *SymbolNames = nullptr;
@@ -218,17 +360,13 @@ public:
   void localize(std::function<bool(const Symbol &)> ToLocalize);
   void initialize(SectionTableRef SecTable) override;
   void finalize() override;
+  void accept(SectionVisitor &Visitor) const override;
 
   static bool classof(const SectionBase *S) {
     return S->Type == ELF::SHT_SYMTAB;
   }
 };
 
-// Only writeSection depends on the ELF type so we implement it in a subclass.
-template <class ELFT> class SymbolTableSectionImpl : public SymbolTableSection {
-  void writeSection(FileOutputBuffer &Out) const override;
-};
-
 struct Relocation {
   const Symbol *RelocSymbol = nullptr;
   uint64_t Offset;
@@ -275,20 +413,16 @@ public:
   void finalize() override;
 };
 
-template <class ELFT>
 class RelocationSection
     : public RelocSectionWithSymtabBase<SymbolTableSection> {
-private:
-  using Elf_Rel = typename ELFT::Rel;
-  using Elf_Rela = typename ELFT::Rela;
+  MAKE_SEC_WRITER_FRIEND
 
+private:
   std::vector<Relocation> Relocations;
 
-  template <class T> void writeRel(T *Buf) const;
-
 public:
   void addRelocation(Relocation Rel) { Relocations.push_back(Rel); }
-  void writeSection(FileOutputBuffer &Out) const override;
+  void accept(SectionVisitor &Visitor) const override;
 
   static bool classof(const SectionBase *S) {
     if (S->Flags & ELF::SHF_ALLOC)
@@ -331,13 +465,15 @@ public:
 
 class DynamicRelocationSection
     : public RelocSectionWithSymtabBase<DynamicSymbolTableSection> {
+  MAKE_SEC_WRITER_FRIEND
+
 private:
   ArrayRef<uint8_t> Contents;
 
 public:
   DynamicRelocationSection(ArrayRef<uint8_t> Data) : Contents(Data) {}
 
-  void writeSection(FileOutputBuffer &Out) const override;
+  void accept(SectionVisitor &) const override;
 
   static bool classof(const SectionBase *S) {
     if (!(S->Flags & ELF::SHF_ALLOC))
@@ -346,12 +482,10 @@ public:
   }
 };
 
-template <class ELFT> class GnuDebugLinkSection : public SectionBase {
+class GnuDebugLinkSection : public SectionBase {
+  MAKE_SEC_WRITER_FRIEND
+
 private:
-  // Elf_Word is 4-bytes on every format but has the same endianess as the elf
-  // type ELFT. We'll need to write the CRC32 out in the proper endianess so
-  // we'll make sure to use this type.
-  using Elf_Word = typename ELFT::Word;
 
   StringRef FileName;
   uint32_t CRC32;
@@ -361,92 +495,101 @@ private:
 public:
   // If we add this section from an external source we can use this ctor.
   GnuDebugLinkSection(StringRef File);
-  void writeSection(FileOutputBuffer &Out) const override;
+  void accept(SectionVisitor &Visitor) const override;
 };
 
-template <class ELFT> class Object {
-private:
-  using SecPtr = std::unique_ptr<SectionBase>;
-  using SegPtr = std::unique_ptr<Segment>;
+class Reader {
+public:
+  virtual ~Reader();
+  virtual std::unique_ptr<Object> create() const = 0;
+};
+
+using object::OwningBinary;
+using object::Binary;
+using object::ELFFile;
+using object::ELFObjectFile;
 
+template <class ELFT> class ELFBuilder {
+private:
   using Elf_Shdr = typename ELFT::Shdr;
-  using Elf_Ehdr = typename ELFT::Ehdr;
-  using Elf_Phdr = typename ELFT::Phdr;
 
-  void initSymbolTable(const object::ELFFile<ELFT> &ElfFile,
-                       SymbolTableSection *SymTab, SectionTableRef SecTable);
-  SecPtr makeSection(const object::ELFFile<ELFT> &ElfFile,
-                     const Elf_Shdr &Shdr);
-  void readProgramHeaders(const object::ELFFile<ELFT> &ElfFile);
-  SectionTableRef readSectionHeaders(const object::ELFFile<ELFT> &ElfFile);
+  const ELFFile<ELFT> &ElfFile;
+  Object &Obj;
 
-protected:
-  StringTableSection *SectionNames = nullptr;
-  SymbolTableSection *SymbolTable = nullptr;
-  std::vector<SecPtr> Sections;
-  std::vector<SegPtr> Segments;
-
-  void writeHeader(FileOutputBuffer &Out) const;
-  void writeProgramHeaders(FileOutputBuffer &Out) const;
-  void writeSectionData(FileOutputBuffer &Out) const;
-  void writeSectionHeaders(FileOutputBuffer &Out) const;
+  void readProgramHeaders();
+  void initSymbolTable(SymbolTableSection *SymTab);
+  void readSectionHeaders();
+  SectionBase &makeSection(const Elf_Shdr &Shdr);
 
 public:
-  uint8_t Ident[16];
-  uint64_t Entry;
-  uint64_t SHOffset;
-  uint32_t Type;
-  uint32_t Machine;
-  uint32_t Version;
-  uint32_t Flags;
-  bool WriteSectionHeaders = true;
-
-  Object(const object::ELFObjectFile<ELFT> &Obj);
-  virtual ~Object() = default;
+  ELFBuilder(const ELFObjectFile<ELFT> &ElfObj, Object &Obj)
+      : ElfFile(*ElfObj.getELFFile()), Obj(Obj) {}
 
-  SymbolTableSection *getSymTab() const { return SymbolTable; }
-  const SectionBase *getSectionHeaderStrTab() const { return SectionNames; }
-  void removeSections(std::function<bool(const SectionBase &)> ToRemove);
-  void addSection(StringRef SecName, ArrayRef<uint8_t> Data);
-  void addGnuDebugLink(StringRef File);
-  virtual size_t totalSize() const = 0;
-  virtual void finalize() = 0;
-  virtual void write(FileOutputBuffer &Out) const = 0;
+  void build();
 };
 
-template <class ELFT> class ELFObject : public Object<ELFT> {
+class ELFReader : public Reader {
 private:
-  using SecPtr = std::unique_ptr<SectionBase>;
-  using SegPtr = std::unique_ptr<Segment>;
-
-  using Elf_Shdr = typename ELFT::Shdr;
-  using Elf_Ehdr = typename ELFT::Ehdr;
-  using Elf_Phdr = typename ELFT::Phdr;
-
-  void sortSections();
-  void assignOffsets();
+  std::unique_ptr<Binary> Binary;
+  std::shared_ptr<MemoryBuffer> Data;
 
 public:
-  ELFObject(const object::ELFObjectFile<ELFT> &Obj) : Object<ELFT>(Obj) {}
-
-  void finalize() override;
-  size_t totalSize() const override;
-  void write(FileOutputBuffer &Out) const override;
+  ElfType getElfType() const;
+  std::unique_ptr<Object> create() const override;
+  ELFReader(StringRef File);
 };
 
-template <class ELFT> class BinaryObject : public Object<ELFT> {
+class Object {
 private:
   using SecPtr = std::unique_ptr<SectionBase>;
   using SegPtr = std::unique_ptr<Segment>;
 
-  uint64_t TotalSize;
+  std::shared_ptr<MemoryBuffer> OwnedData;
+  std::vector<SecPtr> Sections;
+  std::vector<SegPtr> Segments;
 
 public:
-  BinaryObject(const object::ELFObjectFile<ELFT> &Obj) : Object<ELFT>(Obj) {}
+  template <class T>
+  using Range = iterator_range<
+      pointee_iterator<typename std::vector<std::unique_ptr<T>>::iterator>>;
 
-  void finalize() override;
-  size_t totalSize() const override;
-  void write(FileOutputBuffer &Out) const override;
+  template <class T>
+  using ConstRange = iterator_range<pointee_iterator<
+      typename std::vector<std::unique_ptr<T>>::const_iterator>>;
+
+  uint8_t Ident[16];
+  uint64_t Entry;
+  uint64_t SHOffset;
+  uint32_t Type;
+  uint32_t Machine;
+  uint32_t Version;
+  uint32_t Flags;
+
+  StringTableSection *SectionNames = nullptr;
+  SymbolTableSection *SymbolTable = nullptr;
+
+  Object(std::shared_ptr<MemoryBuffer> Data) : OwnedData(Data) {}
+  virtual ~Object() = default;
+
+  void sortSections();
+  SectionTableRef sections() { return SectionTableRef(Sections); }
+  ConstRange<SectionBase> sections() const {
+    return make_pointee_range(Sections);
+  }
+  Range<Segment> segments() { return make_pointee_range(Segments); }
+  ConstRange<Segment> segments() const { return make_pointee_range(Segments); }
+
+  void removeSections(std::function<bool(const SectionBase &)> ToRemove);
+  template <class T, class... Ts> T &addSection(Ts &&... Args) {
+    auto Sec = llvm::make_unique<T>(std::forward<Ts>(Args)...);
+    auto Ptr = Sec.get();
+    Sections.emplace_back(std::move(Sec));
+    return *Ptr;
+  }
+  Segment &addSegment(ArrayRef<uint8_t> Data) {
+    Segments.emplace_back(llvm::make_unique<Segment>(Data));
+    return *Segments.back();
+  }
 };
 
 } // end namespace llvm

Modified: llvm/trunk/tools/llvm-objcopy/llvm-objcopy.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-objcopy/llvm-objcopy.cpp?rev=323480&r1=323479&r2=323480&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-objcopy/llvm-objcopy.cpp (original)
+++ llvm/trunk/tools/llvm-objcopy/llvm-objcopy.cpp Thu Jan 25 14:46:17 2018
@@ -130,42 +130,42 @@ using SectionPred = std::function<bool(c
 
 bool IsDWOSection(const SectionBase &Sec) { return Sec.Name.endswith(".dwo"); }
 
-template <class ELFT>
-bool OnlyKeepDWOPred(const Object<ELFT> &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())
+  if (&Sec == Obj.SectionNames)
     return false;
   // Short of keeping the string table we want to keep everything that is a DWO
   // section and remove everything else.
   return !IsDWOSection(Sec);
 }
 
-template <class ELFT>
-void WriteObjectFile(const Object<ELFT> &Obj, StringRef File) {
-  std::unique_ptr<FileOutputBuffer> Buffer;
-  Expected<std::unique_ptr<FileOutputBuffer>> BufferOrErr =
-      FileOutputBuffer::create(File, Obj.totalSize(),
-                               FileOutputBuffer::F_executable);
-  handleAllErrors(BufferOrErr.takeError(), [](const ErrorInfoBase &) {
-    error("failed to open " + OutputFilename);
-  });
-  Buffer = std::move(*BufferOrErr);
-
-  Obj.write(*Buffer);
-  if (auto E = Buffer->commit())
-    reportError(File, errorToErrorCode(std::move(E)));
-}
-
-template <class ELFT>
-void SplitDWOToFile(const ELFObjectFile<ELFT> &ObjFile, StringRef File) {
-  // Construct a second output file for the DWO sections.
-  ELFObject<ELFT> DWOFile(ObjFile);
-
-  DWOFile.removeSections([&](const SectionBase &Sec) {
-    return OnlyKeepDWOPred<ELFT>(DWOFile, Sec);
-  });
-  DWOFile.finalize();
-  WriteObjectFile(DWOFile, File);
+static ElfType OutputElfType;
+
+std::unique_ptr<Writer> CreateWriter(Object &Obj, StringRef File) {
+  if (OutputFormat == "binary") {
+    return llvm::make_unique<BinaryWriter>(OutputFilename, Obj);
+  }
+  // Depending on the initial ELFT and OutputFormat we need a different Writer.
+  switch (OutputElfType) {
+  case ELFT_ELF32LE:
+    return llvm::make_unique<ELFWriter<ELF32LE>>(File, Obj, !StripSections);
+  case ELFT_ELF64LE:
+    return llvm::make_unique<ELFWriter<ELF64LE>>(File, Obj, !StripSections);
+  case ELFT_ELF32BE:
+    return llvm::make_unique<ELFWriter<ELF32BE>>(File, Obj, !StripSections);
+  case ELFT_ELF64BE:
+    return llvm::make_unique<ELFWriter<ELF64BE>>(File, Obj, !StripSections);
+  }
+  llvm_unreachable("Invalid output format");
+}
+
+void SplitDWOToFile(const Reader &Reader, StringRef File) {
+  auto DWOFile = Reader.create();
+  DWOFile->removeSections(
+      [&](const SectionBase &Sec) { return OnlyKeepDWOPred(*DWOFile, Sec); });
+  auto Writer = CreateWriter(*DWOFile, File);
+  Writer->finalize();
+  Writer->write();
 }
 
 // This function handles the high level operations of GNU objcopy including
@@ -175,23 +175,16 @@ void SplitDWOToFile(const ELFObjectFile<
 // 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 <class ELFT> void CopyBinary(const ELFObjectFile<ELFT> &ObjFile) {
-  std::unique_ptr<Object<ELFT>> Obj;
+void HandleArgs(Object &Obj, const Reader &Reader) {
 
-  if (!OutputFormat.empty() && OutputFormat != "binary")
-    error("invalid output format '" + OutputFormat + "'");
-  if (!OutputFormat.empty() && OutputFormat == "binary")
-    Obj = llvm::make_unique<BinaryObject<ELFT>>(ObjFile);
-  else
-    Obj = llvm::make_unique<ELFObject<ELFT>>(ObjFile);
-
-  if (!SplitDWO.empty())
-    SplitDWOToFile<ELFT>(ObjFile, SplitDWO.getValue());
+  if (!SplitDWO.empty()) {
+    SplitDWOToFile(Reader, SplitDWO);
+  }
 
   // Localize:
 
   if (LocalizeHidden) {
-    Obj->getSymTab()->localize([](const Symbol &Sym) {
+    Obj.SymbolTable->localize([](const Symbol &Sym) {
       return Sym.Visibility == STV_HIDDEN || Sym.Visibility == STV_INTERNAL;
     });
   }
@@ -214,7 +207,7 @@ template <class ELFT> void CopyBinary(co
 
   if (ExtractDWO)
     RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {
-      return OnlyKeepDWOPred(*Obj, Sec) || RemovePred(Sec);
+      return OnlyKeepDWOPred(Obj, Sec) || RemovePred(Sec);
     };
 
   if (StripAllGNU)
@@ -223,7 +216,7 @@ template <class ELFT> void CopyBinary(co
         return true;
       if ((Sec.Flags & SHF_ALLOC) != 0)
         return false;
-      if (&Sec == Obj->getSectionHeaderStrTab())
+      if (&Sec == Obj.SectionNames)
         return false;
       switch (Sec.Type) {
       case SHT_SYMTAB:
@@ -239,7 +232,6 @@ template <class ELFT> void CopyBinary(co
     RemovePred = [RemovePred](const SectionBase &Sec) {
       return RemovePred(Sec) || (Sec.Flags & SHF_ALLOC) == 0;
     };
-    Obj->WriteSectionHeaders = false;
   }
 
   if (StripDebug) {
@@ -252,7 +244,7 @@ template <class ELFT> void CopyBinary(co
     RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {
       if (RemovePred(Sec))
         return true;
-      if (&Sec == Obj->getSectionHeaderStrTab())
+      if (&Sec == Obj.SectionNames)
         return false;
       return (Sec.Flags & SHF_ALLOC) == 0;
     };
@@ -261,7 +253,7 @@ template <class ELFT> void CopyBinary(co
     RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {
       if (RemovePred(Sec))
         return true;
-      if (&Sec == Obj->getSectionHeaderStrTab())
+      if (&Sec == Obj.SectionNames)
         return false;
       if (Sec.Name.startswith(".gnu.warning"))
         return false;
@@ -278,17 +270,15 @@ template <class ELFT> void CopyBinary(co
         return false;
 
       // Allow all implicit removes.
-      if (RemovePred(Sec)) {
+      if (RemovePred(Sec))
         return true;
-      }
 
       // Keep special sections.
-      if (Obj->getSectionHeaderStrTab() == &Sec) {
+      if (Obj.SectionNames == &Sec)
         return false;
-      }
-      if (Obj->getSymTab() == &Sec || Obj->getSymTab()->getStrTab() == &Sec) {
+      if (Obj.SymbolTable == &Sec || Obj.SymbolTable->getStrTab() == &Sec)
         return false;
-      }
+
       // Remove everything else.
       return true;
     };
@@ -305,7 +295,7 @@ template <class ELFT> void CopyBinary(co
     };
   }
 
-  Obj->removeSections(RemovePred);
+  Obj.removeSections(RemovePred);
 
   if (!AddSection.empty()) {
     for (const auto &Flag : AddSection) {
@@ -318,16 +308,22 @@ template <class ELFT> void CopyBinary(co
       auto Buf = std::move(*BufOrErr);
       auto BufPtr = reinterpret_cast<const uint8_t *>(Buf->getBufferStart());
       auto BufSize = Buf->getBufferSize();
-      Obj->addSection(SecName, ArrayRef<uint8_t>(BufPtr, BufSize));
+      Obj.addSection<OwnedDataSection>(SecName,
+                                       ArrayRef<uint8_t>(BufPtr, BufSize));
     }
   }
 
   if (!AddGnuDebugLink.empty()) {
-    Obj->addGnuDebugLink(AddGnuDebugLink);
+    Obj.addSection<GnuDebugLinkSection>(StringRef(AddGnuDebugLink));
   }
+}
 
-  Obj->finalize();
-  WriteObjectFile(*Obj, OutputFilename.getValue());
+std::unique_ptr<Reader> CreateReader() {
+  // Right now we can only read ELF files so there's only one reader;
+  auto Out = llvm::make_unique<ELFReader>(StringRef(InputFilename));
+  // We need to set the default ElfType for output.
+  OutputElfType = Out->getElfType();
+  return std::move(Out);
 }
 
 int main(int argc, char **argv) {
@@ -341,25 +337,11 @@ int main(int argc, char **argv) {
     cl::PrintHelpMessage();
     return 2;
   }
-  Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(InputFilename);
-  if (!BinaryOrErr)
-    reportError(InputFilename, BinaryOrErr.takeError());
-  Binary &Binary = *BinaryOrErr.get().getBinary();
-  if (auto *o = dyn_cast<ELFObjectFile<ELF64LE>>(&Binary)) {
-    CopyBinary(*o);
-    return 0;
-  }
-  if (auto *o = dyn_cast<ELFObjectFile<ELF32LE>>(&Binary)) {
-    CopyBinary(*o);
-    return 0;
-  }
-  if (auto *o = dyn_cast<ELFObjectFile<ELF64BE>>(&Binary)) {
-    CopyBinary(*o);
-    return 0;
-  }
-  if (auto *o = dyn_cast<ELFObjectFile<ELF32BE>>(&Binary)) {
-    CopyBinary(*o);
-    return 0;
-  }
-  reportError(InputFilename, object_error::invalid_file_type);
+
+  auto Reader = CreateReader();
+  auto Obj = Reader->create();
+  auto Writer = CreateWriter(*Obj, OutputFilename);
+  HandleArgs(*Obj, *Reader);
+  Writer->finalize();
+  Writer->write();
 }

Modified: llvm/trunk/tools/llvm-objcopy/llvm-objcopy.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-objcopy/llvm-objcopy.h?rev=323480&r1=323479&r2=323480&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-objcopy/llvm-objcopy.h (original)
+++ llvm/trunk/tools/llvm-objcopy/llvm-objcopy.h Thu Jan 25 14:46:17 2018
@@ -19,6 +19,9 @@
 namespace llvm {
 
 LLVM_ATTRIBUTE_NORETURN extern void error(Twine Message);
+LLVM_ATTRIBUTE_NORETURN extern void reportError(StringRef File, Error E);
+LLVM_ATTRIBUTE_NORETURN extern void reportError(StringRef File,
+                                                std::error_code EC);
 
 // This is taken from llvm-readobj.
 // [see here](llvm/tools/llvm-readobj/llvm-readobj.h:38)




More information about the llvm-commits mailing list