[llvm-objcopy] Initial COFF support
This is an initial implementation of no-op passthrough copying of COFF
with objcopy.
Differential Revision: https://reviews.llvm.org/D54939
llvm-svn: 349605
diff --git a/llvm/tools/llvm-objcopy/COFF/Reader.cpp b/llvm/tools/llvm-objcopy/COFF/Reader.cpp
new file mode 100644
index 0000000..a8a3576
--- /dev/null
+++ b/llvm/tools/llvm-objcopy/COFF/Reader.cpp
@@ -0,0 +1,141 @@
+//===- Reader.cpp ---------------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Reader.h"
+#include "Object.h"
+#include "llvm-objcopy.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/Support/ErrorHandling.h"
+#include <cstddef>
+#include <cstdint>
+
+namespace llvm {
+namespace objcopy {
+namespace coff {
+
+using namespace object;
+
+Reader::~Reader() {}
+
+void COFFReader::readExecutableHeaders(Object &Obj) const {
+ const dos_header *DH = COFFObj.getDOSHeader();
+ Obj.Is64 = COFFObj.is64();
+ if (!DH)
+ return;
+
+ Obj.IsPE = true;
+ Obj.DosHeader = *DH;
+ if (DH->AddressOfNewExeHeader > sizeof(*DH))
+ Obj.DosStub = ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(&DH[1]),
+ DH->AddressOfNewExeHeader - sizeof(*DH));
+
+ if (COFFObj.is64()) {
+ const pe32plus_header *PE32Plus = nullptr;
+ if (auto EC = COFFObj.getPE32PlusHeader(PE32Plus))
+ reportError(COFFObj.getFileName(), std::move(EC));
+ Obj.PeHeader = *PE32Plus;
+ } else {
+ const pe32_header *PE32 = nullptr;
+ if (auto EC = COFFObj.getPE32Header(PE32))
+ reportError(COFFObj.getFileName(), std::move(EC));
+ copyPeHeader(Obj.PeHeader, *PE32);
+ // The pe32plus_header (stored in Object) lacks the BaseOfData field.
+ Obj.BaseOfData = PE32->BaseOfData;
+ }
+
+ for (size_t I = 0; I < Obj.PeHeader.NumberOfRvaAndSize; I++) {
+ const data_directory *Dir;
+ if (auto EC = COFFObj.getDataDirectory(I, Dir))
+ reportError(COFFObj.getFileName(), std::move(EC));
+ Obj.DataDirectories.emplace_back(*Dir);
+ }
+}
+
+void COFFReader::readSections(Object &Obj) const {
+ // Section indexing starts from 1.
+ for (size_t I = 1, E = COFFObj.getNumberOfSections(); I <= E; I++) {
+ const coff_section *Sec;
+ if (auto EC = COFFObj.getSection(I, Sec))
+ reportError(COFFObj.getFileName(), std::move(EC));
+ Obj.Sections.push_back(Section());
+ Section &S = Obj.Sections.back();
+ S.Header = *Sec;
+ if (auto EC = COFFObj.getSectionContents(Sec, S.Contents))
+ reportError(COFFObj.getFileName(), std::move(EC));
+ ArrayRef<coff_relocation> Relocs = COFFObj.getRelocations(Sec);
+ S.Relocs.insert(S.Relocs.end(), Relocs.begin(), Relocs.end());
+ if (auto EC = COFFObj.getSectionName(Sec, S.Name))
+ reportError(COFFObj.getFileName(), std::move(EC));
+ if (Sec->hasExtendedRelocations())
+ reportError(
+ COFFObj.getFileName(),
+ make_error<StringError>("Extended relocations not supported yet",
+ object_error::parse_failed));
+ }
+}
+
+void COFFReader::readSymbols(Object &Obj, bool IsBigObj) const {
+ for (uint32_t I = 0, E = COFFObj.getRawNumberOfSymbols(); I < E;) {
+ Expected<COFFSymbolRef> SymOrErr = COFFObj.getSymbol(I);
+ if (!SymOrErr)
+ reportError(COFFObj.getFileName(), SymOrErr.takeError());
+ COFFSymbolRef SymRef = *SymOrErr;
+
+ Obj.Symbols.push_back(Symbol());
+ Symbol &Sym = Obj.Symbols.back();
+ // Copy symbols from the original form into an intermediate coff_symbol32.
+ if (IsBigObj)
+ copySymbol(Sym.Sym,
+ *reinterpret_cast<const coff_symbol32 *>(SymRef.getRawPtr()));
+ else
+ copySymbol(Sym.Sym,
+ *reinterpret_cast<const coff_symbol16 *>(SymRef.getRawPtr()));
+ if (auto EC = COFFObj.getSymbolName(SymRef, Sym.Name))
+ reportError(COFFObj.getFileName(), std::move(EC));
+ Sym.AuxData = COFFObj.getSymbolAuxData(SymRef);
+ assert((Sym.AuxData.size() %
+ (IsBigObj ? sizeof(coff_symbol32) : sizeof(coff_symbol16))) == 0);
+ I += 1 + SymRef.getNumberOfAuxSymbols();
+ }
+}
+
+std::unique_ptr<Object> COFFReader::create() const {
+ auto Obj = llvm::make_unique<Object>();
+
+ const coff_file_header *CFH = nullptr;
+ const coff_bigobj_file_header *CBFH = nullptr;
+ COFFObj.getCOFFHeader(CFH);
+ COFFObj.getCOFFBigObjHeader(CBFH);
+ bool IsBigObj = false;
+ if (CFH) {
+ Obj->CoffFileHeader = *CFH;
+ } else {
+ if (!CBFH)
+ reportError(COFFObj.getFileName(),
+ make_error<StringError>("No COFF file header returned",
+ object_error::parse_failed));
+ // Only copying the few fields from the bigobj header that we need
+ // and won't recreate in the end.
+ Obj->CoffFileHeader.Machine = CBFH->Machine;
+ Obj->CoffFileHeader.TimeDateStamp = CBFH->TimeDateStamp;
+ IsBigObj = true;
+ }
+
+ readExecutableHeaders(*Obj);
+ readSections(*Obj);
+ readSymbols(*Obj, IsBigObj);
+
+ return Obj;
+}
+
+} // end namespace coff
+} // end namespace objcopy
+} // end namespace llvm