summaryrefslogtreecommitdiff
path: root/contrib/llvm/tools/llvm-objcopy
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2019-01-20 11:41:25 +0000
committerDimitry Andric <dim@FreeBSD.org>2019-01-20 11:41:25 +0000
commitd9484dd61cc151c4f34c31e07f693fefa66316b5 (patch)
treeab0560b3da293f1fafd3269c59692e929418f5c2 /contrib/llvm/tools/llvm-objcopy
parent79e0962d4c3cf1f0acf359a9d69cb3ac68c414c4 (diff)
parentd8e91e46262bc44006913e6796843909f1ac7bcd (diff)
Notes
Diffstat (limited to 'contrib/llvm/tools/llvm-objcopy')
-rw-r--r--contrib/llvm/tools/llvm-objcopy/Buffer.cpp51
-rw-r--r--contrib/llvm/tools/llvm-objcopy/Buffer.h66
-rw-r--r--contrib/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp98
-rw-r--r--contrib/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.h31
-rw-r--r--contrib/llvm/tools/llvm-objcopy/COFF/Object.cpp70
-rw-r--r--contrib/llvm/tools/llvm-objcopy/COFF/Object.h148
-rw-r--r--contrib/llvm/tools/llvm-objcopy/COFF/Reader.cpp171
-rw-r--r--contrib/llvm/tools/llvm-objcopy/COFF/Reader.h43
-rw-r--r--contrib/llvm/tools/llvm-objcopy/COFF/Writer.cpp337
-rw-r--r--contrib/llvm/tools/llvm-objcopy/COFF/Writer.h61
-rw-r--r--contrib/llvm/tools/llvm-objcopy/CopyConfig.cpp474
-rw-r--r--contrib/llvm/tools/llvm-objcopy/CopyConfig.h119
-rw-r--r--contrib/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp584
-rw-r--r--contrib/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.h34
-rw-r--r--contrib/llvm/tools/llvm-objcopy/ELF/Object.cpp (renamed from contrib/llvm/tools/llvm-objcopy/Object.cpp)514
-rw-r--r--contrib/llvm/tools/llvm-objcopy/ELF/Object.h (renamed from contrib/llvm/tools/llvm-objcopy/Object.h)231
-rw-r--r--contrib/llvm/tools/llvm-objcopy/ObjcopyOpts.td243
-rw-r--r--contrib/llvm/tools/llvm-objcopy/StripOpts.td86
-rw-r--r--contrib/llvm/tools/llvm-objcopy/llvm-objcopy.cpp682
-rw-r--r--contrib/llvm/tools/llvm-objcopy/llvm-objcopy.h2
20 files changed, 3176 insertions, 869 deletions
diff --git a/contrib/llvm/tools/llvm-objcopy/Buffer.cpp b/contrib/llvm/tools/llvm-objcopy/Buffer.cpp
new file mode 100644
index 000000000000..8044b023aaad
--- /dev/null
+++ b/contrib/llvm/tools/llvm-objcopy/Buffer.cpp
@@ -0,0 +1,51 @@
+//===- Buffer.cpp ---------------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Buffer.h"
+#include "llvm-objcopy.h"
+#include "llvm/Support/FileOutputBuffer.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include <memory>
+
+namespace llvm {
+namespace objcopy {
+
+Buffer::~Buffer() {}
+
+void FileBuffer::allocate(size_t Size) {
+ Expected<std::unique_ptr<FileOutputBuffer>> BufferOrErr =
+ FileOutputBuffer::create(getName(), Size, FileOutputBuffer::F_executable);
+ handleAllErrors(BufferOrErr.takeError(), [this](const ErrorInfoBase &E) {
+ error("failed to open " + getName() + ": " + E.message());
+ });
+ Buf = std::move(*BufferOrErr);
+}
+
+Error FileBuffer::commit() { return Buf->commit(); }
+
+uint8_t *FileBuffer::getBufferStart() {
+ return reinterpret_cast<uint8_t *>(Buf->getBufferStart());
+}
+
+void MemBuffer::allocate(size_t Size) {
+ Buf = WritableMemoryBuffer::getNewMemBuffer(Size, getName());
+}
+
+Error MemBuffer::commit() { return Error::success(); }
+
+uint8_t *MemBuffer::getBufferStart() {
+ return reinterpret_cast<uint8_t *>(Buf->getBufferStart());
+}
+
+std::unique_ptr<WritableMemoryBuffer> MemBuffer::releaseMemoryBuffer() {
+ return std::move(Buf);
+}
+
+} // end namespace objcopy
+} // end namespace llvm
diff --git a/contrib/llvm/tools/llvm-objcopy/Buffer.h b/contrib/llvm/tools/llvm-objcopy/Buffer.h
new file mode 100644
index 000000000000..e5b9c5b2d22b
--- /dev/null
+++ b/contrib/llvm/tools/llvm-objcopy/Buffer.h
@@ -0,0 +1,66 @@
+//===- Buffer.h -------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_OBJCOPY_BUFFER_H
+#define LLVM_TOOLS_OBJCOPY_BUFFER_H
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/FileOutputBuffer.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include <memory>
+
+namespace llvm {
+namespace objcopy {
+
+// The class Buffer abstracts out the common interface of FileOutputBuffer and
+// WritableMemoryBuffer so that the hierarchy of Writers depends on this
+// abstract interface and doesn't depend on a particular implementation.
+// TODO: refactor the buffer classes in LLVM to enable us to use them here
+// directly.
+class Buffer {
+ StringRef Name;
+
+public:
+ virtual ~Buffer();
+ virtual void allocate(size_t Size) = 0;
+ virtual uint8_t *getBufferStart() = 0;
+ virtual Error commit() = 0;
+
+ explicit Buffer(StringRef Name) : Name(Name) {}
+ StringRef getName() const { return Name; }
+};
+
+class FileBuffer : public Buffer {
+ std::unique_ptr<FileOutputBuffer> Buf;
+
+public:
+ void allocate(size_t Size) override;
+ uint8_t *getBufferStart() override;
+ Error commit() override;
+
+ explicit FileBuffer(StringRef FileName) : Buffer(FileName) {}
+};
+
+class MemBuffer : public Buffer {
+ std::unique_ptr<WritableMemoryBuffer> Buf;
+
+public:
+ void allocate(size_t Size) override;
+ uint8_t *getBufferStart() override;
+ Error commit() override;
+
+ explicit MemBuffer(StringRef Name) : Buffer(Name) {}
+
+ std::unique_ptr<WritableMemoryBuffer> releaseMemoryBuffer();
+};
+
+} // end namespace objcopy
+} // end namespace llvm
+
+#endif // LLVM_TOOLS_OBJCOPY_BUFFER_H
diff --git a/contrib/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp b/contrib/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp
new file mode 100644
index 000000000000..6b386d29979c
--- /dev/null
+++ b/contrib/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp
@@ -0,0 +1,98 @@
+//===- COFFObjcopy.cpp ----------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "COFFObjcopy.h"
+#include "Buffer.h"
+#include "CopyConfig.h"
+#include "Object.h"
+#include "Reader.h"
+#include "Writer.h"
+#include "llvm-objcopy.h"
+
+#include "llvm/Object/Binary.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/Support/Errc.h"
+#include <cassert>
+
+namespace llvm {
+namespace objcopy {
+namespace coff {
+
+using namespace object;
+using namespace COFF;
+
+static Error handleArgs(const CopyConfig &Config, Object &Obj) {
+ // StripAll removes all symbols and thus also removes all relocations.
+ if (Config.StripAll || Config.StripAllGNU)
+ for (Section &Sec : Obj.Sections)
+ Sec.Relocs.clear();
+
+ // If we need to do per-symbol removals, initialize the Referenced field.
+ if (Config.StripUnneeded || Config.DiscardAll ||
+ !Config.SymbolsToRemove.empty())
+ if (Error E = Obj.markSymbols())
+ return E;
+
+ // Actually do removals of symbols.
+ Obj.removeSymbols([&](const Symbol &Sym) {
+ // For StripAll, all relocations have been stripped and we remove all
+ // symbols.
+ if (Config.StripAll || Config.StripAllGNU)
+ return true;
+
+ if (is_contained(Config.SymbolsToRemove, Sym.Name)) {
+ // Explicitly removing a referenced symbol is an error.
+ if (Sym.Referenced)
+ reportError(Config.OutputFilename,
+ make_error<StringError>(
+ "not stripping symbol '" + Sym.Name +
+ "' because it is named in a relocation.",
+ llvm::errc::invalid_argument));
+ return true;
+ }
+
+ if (!Sym.Referenced) {
+ // With --strip-unneeded, GNU objcopy removes all unreferenced local
+ // symbols, and any unreferenced undefined external.
+ if (Config.StripUnneeded &&
+ (Sym.Sym.StorageClass == IMAGE_SYM_CLASS_STATIC ||
+ Sym.Sym.SectionNumber == 0))
+ return true;
+
+ // GNU objcopy keeps referenced local symbols and external symbols
+ // if --discard-all is set, similar to what --strip-unneeded does,
+ // but undefined local symbols are kept when --discard-all is set.
+ if (Config.DiscardAll && Sym.Sym.StorageClass == IMAGE_SYM_CLASS_STATIC &&
+ Sym.Sym.SectionNumber != 0)
+ return true;
+ }
+
+ return false;
+ });
+ return Error::success();
+}
+
+void executeObjcopyOnBinary(const CopyConfig &Config,
+ object::COFFObjectFile &In, Buffer &Out) {
+ COFFReader Reader(In);
+ Expected<std::unique_ptr<Object>> ObjOrErr = Reader.create();
+ if (!ObjOrErr)
+ reportError(Config.InputFilename, ObjOrErr.takeError());
+ Object *Obj = ObjOrErr->get();
+ assert(Obj && "Unable to deserialize COFF object");
+ if (Error E = handleArgs(Config, *Obj))
+ reportError(Config.InputFilename, std::move(E));
+ COFFWriter Writer(*Obj, Out);
+ if (Error E = Writer.write())
+ reportError(Config.OutputFilename, std::move(E));
+}
+
+} // end namespace coff
+} // end namespace objcopy
+} // end namespace llvm
diff --git a/contrib/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.h b/contrib/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.h
new file mode 100644
index 000000000000..bf70bd9b4d84
--- /dev/null
+++ b/contrib/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.h
@@ -0,0 +1,31 @@
+//===- COFFObjcopy.h --------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_OBJCOPY_COFFOBJCOPY_H
+#define LLVM_TOOLS_OBJCOPY_COFFOBJCOPY_H
+
+namespace llvm {
+
+namespace object {
+class COFFObjectFile;
+} // end namespace object
+
+namespace objcopy {
+struct CopyConfig;
+class Buffer;
+
+namespace coff {
+void executeObjcopyOnBinary(const CopyConfig &Config,
+ object::COFFObjectFile &In, Buffer &Out);
+
+} // end namespace coff
+} // end namespace objcopy
+} // end namespace llvm
+
+#endif // LLVM_TOOLS_OBJCOPY_COFFOBJCOPY_H
diff --git a/contrib/llvm/tools/llvm-objcopy/COFF/Object.cpp b/contrib/llvm/tools/llvm-objcopy/COFF/Object.cpp
new file mode 100644
index 000000000000..315d3a778623
--- /dev/null
+++ b/contrib/llvm/tools/llvm-objcopy/COFF/Object.cpp
@@ -0,0 +1,70 @@
+//===- Object.cpp ---------------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Object.h"
+#include <algorithm>
+
+namespace llvm {
+namespace objcopy {
+namespace coff {
+
+using namespace object;
+
+void Object::addSymbols(ArrayRef<Symbol> NewSymbols) {
+ for (Symbol S : NewSymbols) {
+ S.UniqueId = NextSymbolUniqueId++;
+ Symbols.emplace_back(S);
+ }
+ updateSymbols();
+}
+
+void Object::updateSymbols() {
+ SymbolMap = DenseMap<size_t, Symbol *>(Symbols.size());
+ size_t RawSymIndex = 0;
+ for (Symbol &Sym : Symbols) {
+ SymbolMap[Sym.UniqueId] = &Sym;
+ Sym.RawIndex = RawSymIndex;
+ RawSymIndex += 1 + Sym.Sym.NumberOfAuxSymbols;
+ }
+}
+
+const Symbol *Object::findSymbol(size_t UniqueId) const {
+ auto It = SymbolMap.find(UniqueId);
+ if (It == SymbolMap.end())
+ return nullptr;
+ return It->second;
+}
+
+void Object::removeSymbols(function_ref<bool(const Symbol &)> ToRemove) {
+ Symbols.erase(
+ std::remove_if(std::begin(Symbols), std::end(Symbols),
+ [ToRemove](const Symbol &Sym) { return ToRemove(Sym); }),
+ std::end(Symbols));
+ updateSymbols();
+}
+
+Error Object::markSymbols() {
+ for (Symbol &Sym : Symbols)
+ Sym.Referenced = false;
+ for (const Section &Sec : Sections) {
+ for (const Relocation &R : Sec.Relocs) {
+ auto It = SymbolMap.find(R.Target);
+ if (It == SymbolMap.end())
+ return make_error<StringError>("Relocation target " + Twine(R.Target) +
+ " not found",
+ object_error::invalid_symbol_index);
+ It->second->Referenced = true;
+ }
+ }
+ return Error::success();
+}
+
+} // end namespace coff
+} // end namespace objcopy
+} // end namespace llvm
diff --git a/contrib/llvm/tools/llvm-objcopy/COFF/Object.h b/contrib/llvm/tools/llvm-objcopy/COFF/Object.h
new file mode 100644
index 000000000000..7531fb4cf39e
--- /dev/null
+++ b/contrib/llvm/tools/llvm-objcopy/COFF/Object.h
@@ -0,0 +1,148 @@
+//===- Object.h -------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_OBJCOPY_COFF_OBJECT_H
+#define LLVM_TOOLS_OBJCOPY_COFF_OBJECT_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/iterator_range.h"
+#include "llvm/BinaryFormat/COFF.h"
+#include "llvm/Object/COFF.h"
+#include <cstddef>
+#include <cstdint>
+#include <vector>
+
+namespace llvm {
+namespace objcopy {
+namespace coff {
+
+struct Relocation {
+ Relocation() {}
+ Relocation(const object::coff_relocation& R) : Reloc(R) {}
+
+ object::coff_relocation Reloc;
+ size_t Target;
+ StringRef TargetName; // Used for diagnostics only
+};
+
+struct Section {
+ object::coff_section Header;
+ ArrayRef<uint8_t> Contents;
+ std::vector<Relocation> Relocs;
+ StringRef Name;
+};
+
+struct Symbol {
+ object::coff_symbol32 Sym;
+ StringRef Name;
+ ArrayRef<uint8_t> AuxData;
+ size_t UniqueId;
+ size_t RawIndex;
+ bool Referenced;
+};
+
+struct Object {
+ bool IsPE = false;
+
+ object::dos_header DosHeader;
+ ArrayRef<uint8_t> DosStub;
+
+ object::coff_file_header CoffFileHeader;
+
+ bool Is64 = false;
+ object::pe32plus_header PeHeader;
+ uint32_t BaseOfData = 0; // pe32plus_header lacks this field.
+
+ std::vector<object::data_directory> DataDirectories;
+ std::vector<Section> Sections;
+
+ ArrayRef<Symbol> getSymbols() const { return Symbols; }
+ // This allows mutating individual Symbols, but not mutating the list
+ // of symbols itself.
+ iterator_range<std::vector<Symbol>::iterator> getMutableSymbols() {
+ return make_range(Symbols.begin(), Symbols.end());
+ }
+
+ const Symbol *findSymbol(size_t UniqueId) const;
+
+ void addSymbols(ArrayRef<Symbol> NewSymbols);
+ void removeSymbols(function_ref<bool(const Symbol &)> ToRemove);
+
+ // Set the Referenced field on all Symbols, based on relocations in
+ // all sections.
+ Error markSymbols();
+
+private:
+ std::vector<Symbol> Symbols;
+ DenseMap<size_t, Symbol *> SymbolMap;
+
+ size_t NextSymbolUniqueId = 0;
+
+ // Update SymbolMap and RawIndex in each Symbol.
+ void updateSymbols();
+};
+
+// Copy between coff_symbol16 and coff_symbol32.
+// The source and destination files can use either coff_symbol16 or
+// coff_symbol32, while we always store them as coff_symbol32 in the
+// intermediate data structure.
+template <class Symbol1Ty, class Symbol2Ty>
+void copySymbol(Symbol1Ty &Dest, const Symbol2Ty &Src) {
+ static_assert(sizeof(Dest.Name.ShortName) == sizeof(Src.Name.ShortName),
+ "Mismatched name sizes");
+ memcpy(Dest.Name.ShortName, Src.Name.ShortName, sizeof(Dest.Name.ShortName));
+ Dest.Value = Src.Value;
+ Dest.SectionNumber = Src.SectionNumber;
+ Dest.Type = Src.Type;
+ Dest.StorageClass = Src.StorageClass;
+ Dest.NumberOfAuxSymbols = Src.NumberOfAuxSymbols;
+}
+
+// Copy between pe32_header and pe32plus_header.
+// We store the intermediate state in a pe32plus_header.
+template <class PeHeader1Ty, class PeHeader2Ty>
+void copyPeHeader(PeHeader1Ty &Dest, const PeHeader2Ty &Src) {
+ Dest.Magic = Src.Magic;
+ Dest.MajorLinkerVersion = Src.MajorLinkerVersion;
+ Dest.MinorLinkerVersion = Src.MinorLinkerVersion;
+ Dest.SizeOfCode = Src.SizeOfCode;
+ Dest.SizeOfInitializedData = Src.SizeOfInitializedData;
+ Dest.SizeOfUninitializedData = Src.SizeOfUninitializedData;
+ Dest.AddressOfEntryPoint = Src.AddressOfEntryPoint;
+ Dest.BaseOfCode = Src.BaseOfCode;
+ Dest.ImageBase = Src.ImageBase;
+ Dest.SectionAlignment = Src.SectionAlignment;
+ Dest.FileAlignment = Src.FileAlignment;
+ Dest.MajorOperatingSystemVersion = Src.MajorOperatingSystemVersion;
+ Dest.MinorOperatingSystemVersion = Src.MinorOperatingSystemVersion;
+ Dest.MajorImageVersion = Src.MajorImageVersion;
+ Dest.MinorImageVersion = Src.MinorImageVersion;
+ Dest.MajorSubsystemVersion = Src.MajorSubsystemVersion;
+ Dest.MinorSubsystemVersion = Src.MinorSubsystemVersion;
+ Dest.Win32VersionValue = Src.Win32VersionValue;
+ Dest.SizeOfImage = Src.SizeOfImage;
+ Dest.SizeOfHeaders = Src.SizeOfHeaders;
+ Dest.CheckSum = Src.CheckSum;
+ Dest.Subsystem = Src.Subsystem;
+ Dest.DLLCharacteristics = Src.DLLCharacteristics;
+ Dest.SizeOfStackReserve = Src.SizeOfStackReserve;
+ Dest.SizeOfStackCommit = Src.SizeOfStackCommit;
+ Dest.SizeOfHeapReserve = Src.SizeOfHeapReserve;
+ Dest.SizeOfHeapCommit = Src.SizeOfHeapCommit;
+ Dest.LoaderFlags = Src.LoaderFlags;
+ Dest.NumberOfRvaAndSize = Src.NumberOfRvaAndSize;
+}
+
+} // end namespace coff
+} // end namespace objcopy
+} // end namespace llvm
+
+#endif // LLVM_TOOLS_OBJCOPY_COFF_OBJECT_H
diff --git a/contrib/llvm/tools/llvm-objcopy/COFF/Reader.cpp b/contrib/llvm/tools/llvm-objcopy/COFF/Reader.cpp
new file mode 100644
index 000000000000..a01768392d7d
--- /dev/null
+++ b/contrib/llvm/tools/llvm-objcopy/COFF/Reader.cpp
@@ -0,0 +1,171 @@
+//===- 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;
+
+Error COFFReader::readExecutableHeaders(Object &Obj) const {
+ const dos_header *DH = COFFObj.getDOSHeader();
+ Obj.Is64 = COFFObj.is64();
+ if (!DH)
+ return Error::success();
+
+ 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))
+ return errorCodeToError(EC);
+ Obj.PeHeader = *PE32Plus;
+ } else {
+ const pe32_header *PE32 = nullptr;
+ if (auto EC = COFFObj.getPE32Header(PE32))
+ return errorCodeToError(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))
+ return errorCodeToError(EC);
+ Obj.DataDirectories.emplace_back(*Dir);
+ }
+ return Error::success();
+}
+
+Error 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))
+ return errorCodeToError(EC);
+ Obj.Sections.push_back(Section());
+ Section &S = Obj.Sections.back();
+ S.Header = *Sec;
+ if (auto EC = COFFObj.getSectionContents(Sec, S.Contents))
+ return errorCodeToError(EC);
+ ArrayRef<coff_relocation> Relocs = COFFObj.getRelocations(Sec);
+ for (const coff_relocation &R : Relocs)
+ S.Relocs.push_back(R);
+ if (auto EC = COFFObj.getSectionName(Sec, S.Name))
+ return errorCodeToError(EC);
+ if (Sec->hasExtendedRelocations())
+ return make_error<StringError>("Extended relocations not supported yet",
+ object_error::parse_failed);
+ }
+ return Error::success();
+}
+
+Error COFFReader::readSymbols(Object &Obj, bool IsBigObj) const {
+ std::vector<Symbol> Symbols;
+ Symbols.reserve(COFFObj.getRawNumberOfSymbols());
+ for (uint32_t I = 0, E = COFFObj.getRawNumberOfSymbols(); I < E;) {
+ Expected<COFFSymbolRef> SymOrErr = COFFObj.getSymbol(I);
+ if (!SymOrErr)
+ return SymOrErr.takeError();
+ COFFSymbolRef SymRef = *SymOrErr;
+
+ Symbols.push_back(Symbol());
+ Symbol &Sym = 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))
+ return errorCodeToError(EC);
+ Sym.AuxData = COFFObj.getSymbolAuxData(SymRef);
+ assert((Sym.AuxData.size() %
+ (IsBigObj ? sizeof(coff_symbol32) : sizeof(coff_symbol16))) == 0);
+ I += 1 + SymRef.getNumberOfAuxSymbols();
+ }
+ Obj.addSymbols(Symbols);
+ return Error::success();
+}
+
+Error COFFReader::setRelocTargets(Object &Obj) const {
+ std::vector<const Symbol *> RawSymbolTable;
+ for (const Symbol &Sym : Obj.getSymbols()) {
+ RawSymbolTable.push_back(&Sym);
+ for (size_t I = 0; I < Sym.Sym.NumberOfAuxSymbols; I++)
+ RawSymbolTable.push_back(nullptr);
+ }
+ for (Section &Sec : Obj.Sections) {
+ for (Relocation &R : Sec.Relocs) {
+ if (R.Reloc.SymbolTableIndex >= RawSymbolTable.size())
+ return make_error<StringError>("SymbolTableIndex out of range",
+ object_error::parse_failed);
+ const Symbol *Sym = RawSymbolTable[R.Reloc.SymbolTableIndex];
+ if (Sym == nullptr)
+ return make_error<StringError>("Invalid SymbolTableIndex",
+ object_error::parse_failed);
+ R.Target = Sym->UniqueId;
+ R.TargetName = Sym->Name;
+ }
+ }
+ return Error::success();
+}
+
+Expected<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)
+ return 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;
+ }
+
+ if (Error E = readExecutableHeaders(*Obj))
+ return std::move(E);
+ if (Error E = readSections(*Obj))
+ return std::move(E);
+ if (Error E = readSymbols(*Obj, IsBigObj))
+ return std::move(E);
+ if (Error E = setRelocTargets(*Obj))
+ return std::move(E);
+
+ return std::move(Obj);
+}
+
+} // end namespace coff
+} // end namespace objcopy
+} // end namespace llvm
diff --git a/contrib/llvm/tools/llvm-objcopy/COFF/Reader.h b/contrib/llvm/tools/llvm-objcopy/COFF/Reader.h
new file mode 100644
index 000000000000..ca7057d08c9f
--- /dev/null
+++ b/contrib/llvm/tools/llvm-objcopy/COFF/Reader.h
@@ -0,0 +1,43 @@
+//===- Reader.h -------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_OBJCOPY_COFF_READER_H
+#define LLVM_TOOLS_OBJCOPY_COFF_READER_H
+
+#include "Buffer.h"
+#include "llvm/BinaryFormat/COFF.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/Support/Error.h"
+
+namespace llvm {
+namespace objcopy {
+namespace coff {
+
+struct Object;
+
+using object::COFFObjectFile;
+
+class COFFReader {
+ const COFFObjectFile &COFFObj;
+
+ Error readExecutableHeaders(Object &Obj) const;
+ Error readSections(Object &Obj) const;
+ Error readSymbols(Object &Obj, bool IsBigObj) const;
+ Error setRelocTargets(Object &Obj) const;
+
+public:
+ explicit COFFReader(const COFFObjectFile &O) : COFFObj(O) {}
+ Expected<std::unique_ptr<Object>> create() const;
+};
+
+} // end namespace coff
+} // end namespace objcopy
+} // end namespace llvm
+
+#endif // LLVM_TOOLS_OBJCOPY_COFF_READER_H
diff --git a/contrib/llvm/tools/llvm-objcopy/COFF/Writer.cpp b/contrib/llvm/tools/llvm-objcopy/COFF/Writer.cpp
new file mode 100644
index 000000000000..385d43b1bae5
--- /dev/null
+++ b/contrib/llvm/tools/llvm-objcopy/COFF/Writer.cpp
@@ -0,0 +1,337 @@
+//===- Writer.cpp ---------------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Writer.h"
+#include "Object.h"
+#include "llvm-objcopy.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/COFF.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/Support/ErrorHandling.h"
+#include <cstddef>
+#include <cstdint>
+
+namespace llvm {
+namespace objcopy {
+namespace coff {
+
+using namespace object;
+using namespace COFF;
+
+Error COFFWriter::finalizeRelocTargets() {
+ for (Section &Sec : Obj.Sections) {
+ for (Relocation &R : Sec.Relocs) {
+ const Symbol *Sym = Obj.findSymbol(R.Target);
+ if (Sym == nullptr)
+ return make_error<StringError>("Relocation target " + R.TargetName +
+ " (" + Twine(R.Target) +
+ ") not found",
+ object_error::invalid_symbol_index);
+ R.Reloc.SymbolTableIndex = Sym->RawIndex;
+ }
+ }
+ return Error::success();
+}
+
+void COFFWriter::layoutSections() {
+ for (auto &S : Obj.Sections) {
+ if (S.Header.SizeOfRawData > 0)
+ S.Header.PointerToRawData = FileSize;
+ FileSize += S.Header.SizeOfRawData; // For executables, this is already
+ // aligned to FileAlignment.
+ S.Header.NumberOfRelocations = S.Relocs.size();
+ S.Header.PointerToRelocations =
+ S.Header.NumberOfRelocations > 0 ? FileSize : 0;
+ FileSize += S.Relocs.size() * sizeof(coff_relocation);
+ FileSize = alignTo(FileSize, FileAlignment);
+
+ if (S.Header.Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA)
+ SizeOfInitializedData += S.Header.SizeOfRawData;
+ }
+}
+
+size_t COFFWriter::finalizeStringTable() {
+ for (auto &S : Obj.Sections)
+ if (S.Name.size() > COFF::NameSize)
+ StrTabBuilder.add(S.Name);
+
+ for (const auto &S : Obj.getSymbols())
+ if (S.Name.size() > COFF::NameSize)
+ StrTabBuilder.add(S.Name);
+
+ StrTabBuilder.finalize();
+
+ for (auto &S : Obj.Sections) {
+ if (S.Name.size() > COFF::NameSize) {
+ snprintf(S.Header.Name, sizeof(S.Header.Name), "/%d",
+ (int)StrTabBuilder.getOffset(S.Name));
+ } else {
+ strncpy(S.Header.Name, S.Name.data(), COFF::NameSize);
+ }
+ }
+ for (auto &S : Obj.getMutableSymbols()) {
+ if (S.Name.size() > COFF::NameSize) {
+ S.Sym.Name.Offset.Zeroes = 0;
+ S.Sym.Name.Offset.Offset = StrTabBuilder.getOffset(S.Name);
+ } else {
+ strncpy(S.Sym.Name.ShortName, S.Name.data(), COFF::NameSize);
+ }
+ }
+ return StrTabBuilder.getSize();
+}
+
+template <class SymbolTy>
+std::pair<size_t, size_t> COFFWriter::finalizeSymbolTable() {
+ size_t SymTabSize = Obj.getSymbols().size() * sizeof(SymbolTy);
+ for (const auto &S : Obj.getSymbols())
+ SymTabSize += S.AuxData.size();
+ return std::make_pair(SymTabSize, sizeof(SymbolTy));
+}
+
+Error COFFWriter::finalize(bool IsBigObj) {
+ if (Error E = finalizeRelocTargets())
+ return E;
+
+ size_t SizeOfHeaders = 0;
+ FileAlignment = 1;
+ size_t PeHeaderSize = 0;
+ if (Obj.IsPE) {
+ Obj.DosHeader.AddressOfNewExeHeader =
+ sizeof(Obj.DosHeader) + Obj.DosStub.size();
+ SizeOfHeaders += Obj.DosHeader.AddressOfNewExeHeader + sizeof(PEMagic);
+
+ FileAlignment = Obj.PeHeader.FileAlignment;
+ Obj.PeHeader.NumberOfRvaAndSize = Obj.DataDirectories.size();
+
+ PeHeaderSize = Obj.Is64 ? sizeof(pe32plus_header) : sizeof(pe32_header);
+ SizeOfHeaders +=
+ PeHeaderSize + sizeof(data_directory) * Obj.DataDirectories.size();
+ }
+ Obj.CoffFileHeader.NumberOfSections = Obj.Sections.size();
+ SizeOfHeaders +=
+ IsBigObj ? sizeof(coff_bigobj_file_header) : sizeof(coff_file_header);
+ SizeOfHeaders += sizeof(coff_section) * Obj.Sections.size();
+ SizeOfHeaders = alignTo(SizeOfHeaders, FileAlignment);
+
+ Obj.CoffFileHeader.SizeOfOptionalHeader =
+ PeHeaderSize + sizeof(data_directory) * Obj.DataDirectories.size();
+
+ FileSize = SizeOfHeaders;
+ SizeOfInitializedData = 0;
+
+ layoutSections();
+
+ if (Obj.IsPE) {
+ Obj.PeHeader.SizeOfHeaders = SizeOfHeaders;
+ Obj.PeHeader.SizeOfInitializedData = SizeOfInitializedData;
+
+ if (!Obj.Sections.empty()) {
+ const Section &S = Obj.Sections.back();
+ Obj.PeHeader.SizeOfImage =
+ alignTo(S.Header.VirtualAddress + S.Header.VirtualSize,
+ Obj.PeHeader.SectionAlignment);
+ }
+
+ // If the PE header had a checksum, clear it, since it isn't valid
+ // any longer. (We don't calculate a new one.)
+ Obj.PeHeader.CheckSum = 0;
+ }
+
+ size_t StrTabSize = finalizeStringTable();
+ size_t SymTabSize, SymbolSize;
+ std::tie(SymTabSize, SymbolSize) = IsBigObj
+ ? finalizeSymbolTable<coff_symbol32>()
+ : finalizeSymbolTable<coff_symbol16>();
+
+ size_t PointerToSymbolTable = FileSize;
+ // StrTabSize <= 4 is the size of an empty string table, only consisting
+ // of the length field.
+ if (SymTabSize == 0 && StrTabSize <= 4 && Obj.IsPE) {
+ // For executables, don't point to the symbol table and skip writing
+ // the length field, if both the symbol and string tables are empty.
+ PointerToSymbolTable = 0;
+ StrTabSize = 0;
+ }
+
+ size_t NumRawSymbols = SymTabSize / SymbolSize;
+ Obj.CoffFileHeader.PointerToSymbolTable = PointerToSymbolTable;
+ Obj.CoffFileHeader.NumberOfSymbols = NumRawSymbols;
+ FileSize += SymTabSize + StrTabSize;
+ FileSize = alignTo(FileSize, FileAlignment);
+
+ return Error::success();
+}
+
+void COFFWriter::writeHeaders(bool IsBigObj) {
+ uint8_t *Ptr = Buf.getBufferStart();
+ if (Obj.IsPE) {
+ memcpy(Ptr, &Obj.DosHeader, sizeof(Obj.DosHeader));
+ Ptr += sizeof(Obj.DosHeader);
+ memcpy(Ptr, Obj.DosStub.data(), Obj.DosStub.size());
+ Ptr += Obj.DosStub.size();
+ memcpy(Ptr, PEMagic, sizeof(PEMagic));
+ Ptr += sizeof(PEMagic);
+ }
+ if (!IsBigObj) {
+ memcpy(Ptr, &Obj.CoffFileHeader, sizeof(Obj.CoffFileHeader));
+ Ptr += sizeof(Obj.CoffFileHeader);
+ } else {
+ // Generate a coff_bigobj_file_header, filling it in with the values
+ // from Obj.CoffFileHeader. All extra fields that don't exist in
+ // coff_file_header can be set to hardcoded values.
+ coff_bigobj_file_header BigObjHeader;
+ BigObjHeader.Sig1 = IMAGE_FILE_MACHINE_UNKNOWN;
+ BigObjHeader.Sig2 = 0xffff;
+ BigObjHeader.Version = BigObjHeader::MinBigObjectVersion;
+ BigObjHeader.Machine = Obj.CoffFileHeader.Machine;
+ BigObjHeader.TimeDateStamp = Obj.CoffFileHeader.TimeDateStamp;
+ memcpy(BigObjHeader.UUID, BigObjMagic, sizeof(BigObjMagic));
+ BigObjHeader.unused1 = 0;
+ BigObjHeader.unused2 = 0;
+ BigObjHeader.unused3 = 0;
+ BigObjHeader.unused4 = 0;
+ // The value in Obj.CoffFileHeader.NumberOfSections is truncated, thus
+ // get the original one instead.
+ BigObjHeader.NumberOfSections = Obj.Sections.size();
+ BigObjHeader.PointerToSymbolTable = Obj.CoffFileHeader.PointerToSymbolTable;
+ BigObjHeader.NumberOfSymbols = Obj.CoffFileHeader.NumberOfSymbols;
+
+ memcpy(Ptr, &BigObjHeader, sizeof(BigObjHeader));
+ Ptr += sizeof(BigObjHeader);
+ }
+ if (Obj.IsPE) {
+ if (Obj.Is64) {
+ memcpy(Ptr, &Obj.PeHeader, sizeof(Obj.PeHeader));
+ Ptr += sizeof(Obj.PeHeader);
+ } else {
+ pe32_header PeHeader;
+ copyPeHeader(PeHeader, Obj.PeHeader);
+ // The pe32plus_header (stored in Object) lacks the BaseOfData field.
+ PeHeader.BaseOfData = Obj.BaseOfData;
+
+ memcpy(Ptr, &PeHeader, sizeof(PeHeader));
+ Ptr += sizeof(PeHeader);
+ }
+ for (const auto &DD : Obj.DataDirectories) {
+ memcpy(Ptr, &DD, sizeof(DD));
+ Ptr += sizeof(DD);
+ }
+ }
+ for (const auto &S : Obj.Sections) {
+ memcpy(Ptr, &S.Header, sizeof(S.Header));
+ Ptr += sizeof(S.Header);
+ }
+}
+
+void COFFWriter::writeSections() {
+ for (const auto &S : Obj.Sections) {
+ uint8_t *Ptr = Buf.getBufferStart() + S.Header.PointerToRawData;
+ std::copy(S.Contents.begin(), S.Contents.end(), Ptr);
+
+ // For executable sections, pad the remainder of the raw data size with
+ // 0xcc, which is int3 on x86.
+ if ((S.Header.Characteristics & IMAGE_SCN_CNT_CODE) &&
+ S.Header.SizeOfRawData > S.Contents.size())
+ memset(Ptr + S.Contents.size(), 0xcc,
+ S.Header.SizeOfRawData - S.Contents.size());
+
+ Ptr += S.Header.SizeOfRawData;
+ for (const auto &R : S.Relocs) {
+ memcpy(Ptr, &R.Reloc, sizeof(R.Reloc));
+ Ptr += sizeof(R.Reloc);
+ }
+ }
+}
+
+template <class SymbolTy> void COFFWriter::writeSymbolStringTables() {
+ uint8_t *Ptr = Buf.getBufferStart() + Obj.CoffFileHeader.PointerToSymbolTable;
+ for (const auto &S : Obj.getSymbols()) {
+ // Convert symbols back to the right size, from coff_symbol32.
+ copySymbol<SymbolTy, coff_symbol32>(*reinterpret_cast<SymbolTy *>(Ptr),
+ S.Sym);
+ Ptr += sizeof(SymbolTy);
+ std::copy(S.AuxData.begin(), S.AuxData.end(), Ptr);
+ Ptr += S.AuxData.size();
+ }
+ if (StrTabBuilder.getSize() > 4 || !Obj.IsPE) {
+ // Always write a string table in object files, even an empty one.
+ StrTabBuilder.write(Ptr);
+ Ptr += StrTabBuilder.getSize();
+ }
+}
+
+Error COFFWriter::write(bool IsBigObj) {
+ if (Error E = finalize(IsBigObj))
+ return E;
+
+ Buf.allocate(FileSize);
+
+ writeHeaders(IsBigObj);
+ writeSections();
+ if (IsBigObj)
+ writeSymbolStringTables<coff_symbol32>();
+ else
+ writeSymbolStringTables<coff_symbol16>();
+
+ if (Obj.IsPE)
+ if (Error E = patchDebugDirectory())
+ return E;
+
+ return Buf.commit();
+}
+
+// Locate which sections contain the debug directories, iterate over all
+// the debug_directory structs in there, and set the PointerToRawData field
+// in all of them, according to their new physical location in the file.
+Error COFFWriter::patchDebugDirectory() {
+ if (Obj.DataDirectories.size() < DEBUG_DIRECTORY)
+ return Error::success();
+ const data_directory *Dir = &Obj.DataDirectories[DEBUG_DIRECTORY];
+ if (Dir->Size <= 0)
+ return Error::success();
+ for (const auto &S : Obj.Sections) {
+ if (Dir->RelativeVirtualAddress >= S.Header.VirtualAddress &&
+ Dir->RelativeVirtualAddress <
+ S.Header.VirtualAddress + S.Header.SizeOfRawData) {
+ if (Dir->RelativeVirtualAddress + Dir->Size >
+ S.Header.VirtualAddress + S.Header.SizeOfRawData)
+ return make_error<StringError>(
+ "Debug directory extends past end of section",
+ object_error::parse_failed);
+
+ size_t Offset = Dir->RelativeVirtualAddress - S.Header.VirtualAddress;
+ uint8_t *Ptr = Buf.getBufferStart() + S.Header.PointerToRawData + Offset;
+ uint8_t *End = Ptr + Dir->Size;
+ while (Ptr < End) {
+ debug_directory *Debug = reinterpret_cast<debug_directory *>(Ptr);
+ Debug->PointerToRawData =
+ S.Header.PointerToRawData + Offset + sizeof(debug_directory);
+ Ptr += sizeof(debug_directory) + Debug->SizeOfData;
+ Offset += sizeof(debug_directory) + Debug->SizeOfData;
+ }
+ // Debug directory found and patched, all done.
+ return Error::success();
+ }
+ }
+ return make_error<StringError>("Debug directory not found",
+ object_error::parse_failed);
+}
+
+Error COFFWriter::write() {
+ bool IsBigObj = Obj.Sections.size() > MaxNumberOfSections16;
+ if (IsBigObj && Obj.IsPE)
+ return make_error<StringError>("Too many sections for executable",
+ object_error::parse_failed);
+ return write(IsBigObj);
+}
+
+} // end namespace coff
+} // end namespace objcopy
+} // end namespace llvm
diff --git a/contrib/llvm/tools/llvm-objcopy/COFF/Writer.h b/contrib/llvm/tools/llvm-objcopy/COFF/Writer.h
new file mode 100644
index 000000000000..ab66e0cc1134
--- /dev/null
+++ b/contrib/llvm/tools/llvm-objcopy/COFF/Writer.h
@@ -0,0 +1,61 @@
+//===- Writer.h -------------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_OBJCOPY_COFF_WRITER_H
+#define LLVM_TOOLS_OBJCOPY_COFF_WRITER_H
+
+#include "Buffer.h"
+#include "llvm/MC/StringTableBuilder.h"
+#include "llvm/Support/Error.h"
+#include <cstddef>
+#include <utility>
+
+namespace llvm {
+namespace objcopy {
+namespace coff {
+
+struct Object;
+
+class COFFWriter {
+ Object &Obj;
+ Buffer &Buf;
+
+ size_t FileSize;
+ size_t FileAlignment;
+ size_t SizeOfInitializedData;
+ StringTableBuilder StrTabBuilder;
+
+ Error finalizeRelocTargets();
+ void layoutSections();
+ size_t finalizeStringTable();
+ template <class SymbolTy> std::pair<size_t, size_t> finalizeSymbolTable();
+
+ Error finalize(bool IsBigObj);
+
+ void writeHeaders(bool IsBigObj);
+ void writeSections();
+ template <class SymbolTy> void writeSymbolStringTables();
+
+ Error write(bool IsBigObj);
+
+ Error patchDebugDirectory();
+
+public:
+ virtual ~COFFWriter() {}
+ Error write();
+
+ COFFWriter(Object &Obj, Buffer &Buf)
+ : Obj(Obj), Buf(Buf), StrTabBuilder(StringTableBuilder::WinCOFF) {}
+};
+
+} // end namespace coff
+} // end namespace objcopy
+} // end namespace llvm
+
+#endif // LLVM_TOOLS_OBJCOPY_COFF_WRITER_H
diff --git a/contrib/llvm/tools/llvm-objcopy/CopyConfig.cpp b/contrib/llvm/tools/llvm-objcopy/CopyConfig.cpp
new file mode 100644
index 000000000000..3737f571ae61
--- /dev/null
+++ b/contrib/llvm/tools/llvm-objcopy/CopyConfig.cpp
@@ -0,0 +1,474 @@
+//===- CopyConfig.cpp -----------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CopyConfig.h"
+#include "llvm-objcopy.h"
+
+#include "llvm/ADT/BitmaskEnum.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Object/ELFTypes.h"
+#include "llvm/Option/Arg.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Compression.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include <memory>
+#include <string>
+
+namespace llvm {
+namespace objcopy {
+
+namespace {
+enum ObjcopyID {
+ OBJCOPY_INVALID = 0, // This is not an option ID.
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
+ HELPTEXT, METAVAR, VALUES) \
+ OBJCOPY_##ID,
+#include "ObjcopyOpts.inc"
+#undef OPTION
+};
+
+#define PREFIX(NAME, VALUE) const char *const OBJCOPY_##NAME[] = VALUE;
+#include "ObjcopyOpts.inc"
+#undef PREFIX
+
+static const opt::OptTable::Info ObjcopyInfoTable[] = {
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
+ HELPTEXT, METAVAR, VALUES) \
+ {OBJCOPY_##PREFIX, \
+ NAME, \
+ HELPTEXT, \
+ METAVAR, \
+ OBJCOPY_##ID, \
+ opt::Option::KIND##Class, \
+ PARAM, \
+ FLAGS, \
+ OBJCOPY_##GROUP, \
+ OBJCOPY_##ALIAS, \
+ ALIASARGS, \
+ VALUES},
+#include "ObjcopyOpts.inc"
+#undef OPTION
+};
+
+class ObjcopyOptTable : public opt::OptTable {
+public:
+ ObjcopyOptTable() : OptTable(ObjcopyInfoTable) {}
+};
+
+enum StripID {
+ STRIP_INVALID = 0, // This is not an option ID.
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
+ HELPTEXT, METAVAR, VALUES) \
+ STRIP_##ID,
+#include "StripOpts.inc"
+#undef OPTION
+};
+
+#define PREFIX(NAME, VALUE) const char *const STRIP_##NAME[] = VALUE;
+#include "StripOpts.inc"
+#undef PREFIX
+
+static const opt::OptTable::Info StripInfoTable[] = {
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
+ HELPTEXT, METAVAR, VALUES) \
+ {STRIP_##PREFIX, NAME, HELPTEXT, \
+ METAVAR, STRIP_##ID, opt::Option::KIND##Class, \
+ PARAM, FLAGS, STRIP_##GROUP, \
+ STRIP_##ALIAS, ALIASARGS, VALUES},
+#include "StripOpts.inc"
+#undef OPTION
+};
+
+class StripOptTable : public opt::OptTable {
+public:
+ StripOptTable() : OptTable(StripInfoTable) {}
+};
+
+enum SectionFlag {
+ SecNone = 0,
+ SecAlloc = 1 << 0,
+ SecLoad = 1 << 1,
+ SecNoload = 1 << 2,
+ SecReadonly = 1 << 3,
+ SecDebug = 1 << 4,
+ SecCode = 1 << 5,
+ SecData = 1 << 6,
+ SecRom = 1 << 7,
+ SecMerge = 1 << 8,
+ SecStrings = 1 << 9,
+ SecContents = 1 << 10,
+ SecShare = 1 << 11,
+ LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ SecShare)
+};
+
+} // namespace
+
+static SectionFlag parseSectionRenameFlag(StringRef SectionName) {
+ return llvm::StringSwitch<SectionFlag>(SectionName)
+ .Case("alloc", SectionFlag::SecAlloc)
+ .Case("load", SectionFlag::SecLoad)
+ .Case("noload", SectionFlag::SecNoload)
+ .Case("readonly", SectionFlag::SecReadonly)
+ .Case("debug", SectionFlag::SecDebug)
+ .Case("code", SectionFlag::SecCode)
+ .Case("data", SectionFlag::SecData)
+ .Case("rom", SectionFlag::SecRom)
+ .Case("merge", SectionFlag::SecMerge)
+ .Case("strings", SectionFlag::SecStrings)
+ .Case("contents", SectionFlag::SecContents)
+ .Case("share", SectionFlag::SecShare)
+ .Default(SectionFlag::SecNone);
+}
+
+static SectionRename parseRenameSectionValue(StringRef FlagValue) {
+ if (!FlagValue.contains('='))
+ error("Bad format for --rename-section: missing '='");
+
+ // Initial split: ".foo" = ".bar,f1,f2,..."
+ auto Old2New = FlagValue.split('=');
+ SectionRename SR;
+ SR.OriginalName = Old2New.first;
+
+ // Flags split: ".bar" "f1" "f2" ...
+ SmallVector<StringRef, 6> NameAndFlags;
+ Old2New.second.split(NameAndFlags, ',');
+ SR.NewName = NameAndFlags[0];
+
+ if (NameAndFlags.size() > 1) {
+ SectionFlag Flags = SectionFlag::SecNone;
+ for (size_t I = 1, Size = NameAndFlags.size(); I < Size; ++I) {
+ SectionFlag Flag = parseSectionRenameFlag(NameAndFlags[I]);
+ if (Flag == SectionFlag::SecNone)
+ error("Unrecognized section flag '" + NameAndFlags[I] +
+ "'. Flags supported for GNU compatibility: alloc, load, noload, "
+ "readonly, debug, code, data, rom, share, contents, merge, "
+ "strings.");
+ Flags |= Flag;
+ }
+
+ SR.NewFlags = 0;
+ if (Flags & SectionFlag::SecAlloc)
+ *SR.NewFlags |= ELF::SHF_ALLOC;
+ if (!(Flags & SectionFlag::SecReadonly))
+ *SR.NewFlags |= ELF::SHF_WRITE;
+ if (Flags & SectionFlag::SecCode)
+ *SR.NewFlags |= ELF::SHF_EXECINSTR;
+ if (Flags & SectionFlag::SecMerge)
+ *SR.NewFlags |= ELF::SHF_MERGE;
+ if (Flags & SectionFlag::SecStrings)
+ *SR.NewFlags |= ELF::SHF_STRINGS;
+ }
+
+ return SR;
+}
+
+static const StringMap<MachineInfo> ArchMap{
+ // Name, {EMachine, 64bit, LittleEndian}
+ {"aarch64", {ELF::EM_AARCH64, true, true}},
+ {"arm", {ELF::EM_ARM, false, true}},
+ {"i386", {ELF::EM_386, false, true}},
+ {"i386:x86-64", {ELF::EM_X86_64, true, true}},
+ {"powerpc:common64", {ELF::EM_PPC64, true, true}},
+ {"sparc", {ELF::EM_SPARC, false, true}},
+ {"x86-64", {ELF::EM_X86_64, true, true}},
+};
+
+static const MachineInfo &getMachineInfo(StringRef Arch) {
+ auto Iter = ArchMap.find(Arch);
+ if (Iter == std::end(ArchMap))
+ error("Invalid architecture: '" + Arch + "'");
+ return Iter->getValue();
+}
+
+static const StringMap<MachineInfo> OutputFormatMap{
+ // Name, {EMachine, 64bit, LittleEndian}
+ {"elf32-i386", {ELF::EM_386, false, true}},
+ {"elf32-powerpcle", {ELF::EM_PPC, false, true}},
+ {"elf32-x86-64", {ELF::EM_X86_64, false, true}},
+ {"elf64-powerpcle", {ELF::EM_PPC64, true, true}},
+ {"elf64-x86-64", {ELF::EM_X86_64, true, true}},
+};
+
+static const MachineInfo &getOutputFormatMachineInfo(StringRef Format) {
+ auto Iter = OutputFormatMap.find(Format);
+ if (Iter == std::end(OutputFormatMap))
+ error("Invalid output format: '" + Format + "'");
+ return Iter->getValue();
+}
+
+static void addGlobalSymbolsFromFile(std::vector<std::string> &Symbols,
+ StringRef Filename) {
+ SmallVector<StringRef, 16> Lines;
+ auto BufOrErr = MemoryBuffer::getFile(Filename);
+ if (!BufOrErr)
+ reportError(Filename, BufOrErr.getError());
+
+ BufOrErr.get()->getBuffer().split(Lines, '\n');
+ for (StringRef Line : Lines) {
+ // Ignore everything after '#', trim whitespace, and only add the symbol if
+ // it's not empty.
+ auto TrimmedLine = Line.split('#').first.trim();
+ if (!TrimmedLine.empty())
+ Symbols.push_back(TrimmedLine.str());
+ }
+}
+
+// ParseObjcopyOptions returns the config and sets the input arguments. If a
+// help flag is set then ParseObjcopyOptions will print the help messege and
+// exit.
+DriverConfig parseObjcopyOptions(ArrayRef<const char *> ArgsArr) {
+ ObjcopyOptTable T;
+ unsigned MissingArgumentIndex, MissingArgumentCount;
+ llvm::opt::InputArgList InputArgs =
+ T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount);
+
+ if (InputArgs.size() == 0) {
+ T.PrintHelp(errs(), "llvm-objcopy input [output]", "objcopy tool");
+ exit(1);
+ }
+
+ if (InputArgs.hasArg(OBJCOPY_help)) {
+ T.PrintHelp(outs(), "llvm-objcopy input [output]", "objcopy tool");
+ exit(0);
+ }
+
+ if (InputArgs.hasArg(OBJCOPY_version)) {
+ outs() << "llvm-objcopy, compatible with GNU objcopy\n";
+ cl::PrintVersionMessage();
+ exit(0);
+ }
+
+ SmallVector<const char *, 2> Positional;
+
+ for (auto Arg : InputArgs.filtered(OBJCOPY_UNKNOWN))
+ error("unknown argument '" + Arg->getAsString(InputArgs) + "'");
+
+ for (auto Arg : InputArgs.filtered(OBJCOPY_INPUT))
+ Positional.push_back(Arg->getValue());
+
+ if (Positional.empty())
+ error("No input file specified");
+
+ if (Positional.size() > 2)
+ error("Too many positional arguments");
+
+ CopyConfig Config;
+ Config.InputFilename = Positional[0];
+ Config.OutputFilename = Positional[Positional.size() == 1 ? 0 : 1];
+ if (InputArgs.hasArg(OBJCOPY_target) &&
+ (InputArgs.hasArg(OBJCOPY_input_target) ||
+ InputArgs.hasArg(OBJCOPY_output_target)))
+ error("--target cannot be used with --input-target or --output-target");
+
+ if (InputArgs.hasArg(OBJCOPY_target)) {
+ Config.InputFormat = InputArgs.getLastArgValue(OBJCOPY_target);
+ Config.OutputFormat = InputArgs.getLastArgValue(OBJCOPY_target);
+ } else {
+ Config.InputFormat = InputArgs.getLastArgValue(OBJCOPY_input_target);
+ Config.OutputFormat = InputArgs.getLastArgValue(OBJCOPY_output_target);
+ }
+ if (Config.InputFormat == "binary") {
+ auto BinaryArch = InputArgs.getLastArgValue(OBJCOPY_binary_architecture);
+ if (BinaryArch.empty())
+ error("Specified binary input without specifiying an architecture");
+ Config.BinaryArch = getMachineInfo(BinaryArch);
+ }
+ if (!Config.OutputFormat.empty() && Config.OutputFormat != "binary")
+ Config.OutputArch = getOutputFormatMachineInfo(Config.OutputFormat);
+
+ if (auto Arg = InputArgs.getLastArg(OBJCOPY_compress_debug_sections,
+ OBJCOPY_compress_debug_sections_eq)) {
+ Config.CompressionType = DebugCompressionType::Z;
+
+ if (Arg->getOption().getID() == OBJCOPY_compress_debug_sections_eq) {
+ Config.CompressionType =
+ StringSwitch<DebugCompressionType>(
+ InputArgs.getLastArgValue(OBJCOPY_compress_debug_sections_eq))
+ .Case("zlib-gnu", DebugCompressionType::GNU)
+ .Case("zlib", DebugCompressionType::Z)
+ .Default(DebugCompressionType::None);
+ if (Config.CompressionType == DebugCompressionType::None)
+ error("Invalid or unsupported --compress-debug-sections format: " +
+ InputArgs.getLastArgValue(OBJCOPY_compress_debug_sections_eq));
+ if (!zlib::isAvailable())
+ error("LLVM was not compiled with LLVM_ENABLE_ZLIB: can not compress.");
+ }
+ }
+
+ Config.AddGnuDebugLink = InputArgs.getLastArgValue(OBJCOPY_add_gnu_debuglink);
+ Config.BuildIdLinkDir = InputArgs.getLastArgValue(OBJCOPY_build_id_link_dir);
+ if (InputArgs.hasArg(OBJCOPY_build_id_link_input))
+ Config.BuildIdLinkInput =
+ InputArgs.getLastArgValue(OBJCOPY_build_id_link_input);
+ if (InputArgs.hasArg(OBJCOPY_build_id_link_output))
+ Config.BuildIdLinkOutput =
+ InputArgs.getLastArgValue(OBJCOPY_build_id_link_output);
+ Config.SplitDWO = InputArgs.getLastArgValue(OBJCOPY_split_dwo);
+ Config.SymbolsPrefix = InputArgs.getLastArgValue(OBJCOPY_prefix_symbols);
+
+ for (auto Arg : InputArgs.filtered(OBJCOPY_redefine_symbol)) {
+ if (!StringRef(Arg->getValue()).contains('='))
+ error("Bad format for --redefine-sym");
+ auto Old2New = StringRef(Arg->getValue()).split('=');
+ if (!Config.SymbolsToRename.insert(Old2New).second)
+ error("Multiple redefinition of symbol " + Old2New.first);
+ }
+
+ for (auto Arg : InputArgs.filtered(OBJCOPY_rename_section)) {
+ SectionRename SR = parseRenameSectionValue(StringRef(Arg->getValue()));
+ if (!Config.SectionsToRename.try_emplace(SR.OriginalName, SR).second)
+ error("Multiple renames of section " + SR.OriginalName);
+ }
+
+ for (auto Arg : InputArgs.filtered(OBJCOPY_remove_section))
+ Config.ToRemove.push_back(Arg->getValue());
+ for (auto Arg : InputArgs.filtered(OBJCOPY_keep_section))
+ Config.KeepSection.push_back(Arg->getValue());
+ for (auto Arg : InputArgs.filtered(OBJCOPY_only_section))
+ Config.OnlySection.push_back(Arg->getValue());
+ for (auto Arg : InputArgs.filtered(OBJCOPY_add_section))
+ Config.AddSection.push_back(Arg->getValue());
+ for (auto Arg : InputArgs.filtered(OBJCOPY_dump_section))
+ Config.DumpSection.push_back(Arg->getValue());
+ Config.StripAll = InputArgs.hasArg(OBJCOPY_strip_all);
+ Config.StripAllGNU = InputArgs.hasArg(OBJCOPY_strip_all_gnu);
+ Config.StripDebug = InputArgs.hasArg(OBJCOPY_strip_debug);
+ Config.StripDWO = InputArgs.hasArg(OBJCOPY_strip_dwo);
+ Config.StripSections = InputArgs.hasArg(OBJCOPY_strip_sections);
+ Config.StripNonAlloc = InputArgs.hasArg(OBJCOPY_strip_non_alloc);
+ Config.StripUnneeded = InputArgs.hasArg(OBJCOPY_strip_unneeded);
+ Config.ExtractDWO = InputArgs.hasArg(OBJCOPY_extract_dwo);
+ Config.LocalizeHidden = InputArgs.hasArg(OBJCOPY_localize_hidden);
+ Config.Weaken = InputArgs.hasArg(OBJCOPY_weaken);
+ Config.DiscardAll = InputArgs.hasArg(OBJCOPY_discard_all);
+ Config.OnlyKeepDebug = InputArgs.hasArg(OBJCOPY_only_keep_debug);
+ Config.KeepFileSymbols = InputArgs.hasArg(OBJCOPY_keep_file_symbols);
+ Config.DecompressDebugSections =
+ InputArgs.hasArg(OBJCOPY_decompress_debug_sections);
+ for (auto Arg : InputArgs.filtered(OBJCOPY_localize_symbol))
+ Config.SymbolsToLocalize.push_back(Arg->getValue());
+ for (auto Arg : InputArgs.filtered(OBJCOPY_keep_global_symbol))
+ Config.SymbolsToKeepGlobal.push_back(Arg->getValue());
+ for (auto Arg : InputArgs.filtered(OBJCOPY_keep_global_symbols))
+ addGlobalSymbolsFromFile(Config.SymbolsToKeepGlobal, Arg->getValue());
+ for (auto Arg : InputArgs.filtered(OBJCOPY_globalize_symbol))
+ Config.SymbolsToGlobalize.push_back(Arg->getValue());
+ for (auto Arg : InputArgs.filtered(OBJCOPY_weaken_symbol))
+ Config.SymbolsToWeaken.push_back(Arg->getValue());
+ for (auto Arg : InputArgs.filtered(OBJCOPY_strip_symbol))
+ Config.SymbolsToRemove.push_back(Arg->getValue());
+ for (auto Arg : InputArgs.filtered(OBJCOPY_keep_symbol))
+ Config.SymbolsToKeep.push_back(Arg->getValue());
+
+ Config.DeterministicArchives = InputArgs.hasFlag(
+ OBJCOPY_enable_deterministic_archives,
+ OBJCOPY_disable_deterministic_archives, /*default=*/true);
+
+ Config.PreserveDates = InputArgs.hasArg(OBJCOPY_preserve_dates);
+
+ if (Config.DecompressDebugSections &&
+ Config.CompressionType != DebugCompressionType::None) {
+ error("Cannot specify --compress-debug-sections at the same time as "
+ "--decompress-debug-sections at the same time");
+ }
+
+ if (Config.DecompressDebugSections && !zlib::isAvailable())
+ error("LLVM was not compiled with LLVM_ENABLE_ZLIB: cannot decompress.");
+
+ DriverConfig DC;
+ DC.CopyConfigs.push_back(std::move(Config));
+ return DC;
+}
+
+// ParseStripOptions returns the config and sets the input arguments. If a
+// help flag is set then ParseStripOptions will print the help messege and
+// exit.
+DriverConfig parseStripOptions(ArrayRef<const char *> ArgsArr) {
+ StripOptTable T;
+ unsigned MissingArgumentIndex, MissingArgumentCount;
+ llvm::opt::InputArgList InputArgs =
+ T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount);
+
+ if (InputArgs.size() == 0) {
+ T.PrintHelp(errs(), "llvm-strip [options] file...", "strip tool");
+ exit(1);
+ }
+
+ if (InputArgs.hasArg(STRIP_help)) {
+ T.PrintHelp(outs(), "llvm-strip [options] file...", "strip tool");
+ exit(0);
+ }
+
+ if (InputArgs.hasArg(STRIP_version)) {
+ outs() << "llvm-strip, compatible with GNU strip\n";
+ cl::PrintVersionMessage();
+ exit(0);
+ }
+
+ SmallVector<const char *, 2> Positional;
+ for (auto Arg : InputArgs.filtered(STRIP_UNKNOWN))
+ error("unknown argument '" + Arg->getAsString(InputArgs) + "'");
+ for (auto Arg : InputArgs.filtered(STRIP_INPUT))
+ Positional.push_back(Arg->getValue());
+
+ if (Positional.empty())
+ error("No input file specified");
+
+ if (Positional.size() > 1 && InputArgs.hasArg(STRIP_output))
+ error("Multiple input files cannot be used in combination with -o");
+
+ CopyConfig Config;
+ Config.StripDebug = InputArgs.hasArg(STRIP_strip_debug);
+
+ Config.DiscardAll = InputArgs.hasArg(STRIP_discard_all);
+ Config.StripUnneeded = InputArgs.hasArg(STRIP_strip_unneeded);
+ Config.StripAll = InputArgs.hasArg(STRIP_strip_all);
+ Config.StripAllGNU = InputArgs.hasArg(STRIP_strip_all_gnu);
+
+ if (!Config.StripDebug && !Config.StripUnneeded && !Config.DiscardAll &&
+ !Config.StripAllGNU)
+ Config.StripAll = true;
+
+ for (auto Arg : InputArgs.filtered(STRIP_keep_section))
+ Config.KeepSection.push_back(Arg->getValue());
+
+ for (auto Arg : InputArgs.filtered(STRIP_remove_section))
+ Config.ToRemove.push_back(Arg->getValue());
+
+ for (auto Arg : InputArgs.filtered(STRIP_keep_symbol))
+ Config.SymbolsToKeep.push_back(Arg->getValue());
+
+ Config.DeterministicArchives =
+ InputArgs.hasFlag(STRIP_enable_deterministic_archives,
+ STRIP_disable_deterministic_archives, /*default=*/true);
+
+ Config.PreserveDates = InputArgs.hasArg(STRIP_preserve_dates);
+
+ DriverConfig DC;
+ if (Positional.size() == 1) {
+ Config.InputFilename = Positional[0];
+ Config.OutputFilename =
+ InputArgs.getLastArgValue(STRIP_output, Positional[0]);
+ DC.CopyConfigs.push_back(std::move(Config));
+ } else {
+ for (const char *Filename : Positional) {
+ Config.InputFilename = Filename;
+ Config.OutputFilename = Filename;
+ DC.CopyConfigs.push_back(Config);
+ }
+ }
+
+ return DC;
+}
+
+} // namespace objcopy
+} // namespace llvm
diff --git a/contrib/llvm/tools/llvm-objcopy/CopyConfig.h b/contrib/llvm/tools/llvm-objcopy/CopyConfig.h
new file mode 100644
index 000000000000..71a2423ae1c8
--- /dev/null
+++ b/contrib/llvm/tools/llvm-objcopy/CopyConfig.h
@@ -0,0 +1,119 @@
+//===- CopyConfig.h -------------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_LLVM_OBJCOPY_COPY_CONFIG_H
+#define LLVM_TOOLS_LLVM_OBJCOPY_COPY_CONFIG_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+// Necessary for llvm::DebugCompressionType::None
+#include "llvm/Target/TargetOptions.h"
+#include <string>
+#include <vector>
+
+namespace llvm {
+namespace objcopy {
+
+// This type keeps track of the machine info for various architectures. This
+// lets us map architecture names to ELF types and the e_machine value of the
+// ELF file.
+struct MachineInfo {
+ uint16_t EMachine;
+ bool Is64Bit;
+ bool IsLittleEndian;
+};
+
+struct SectionRename {
+ StringRef OriginalName;
+ StringRef NewName;
+ Optional<uint64_t> NewFlags;
+};
+
+// Configuration for copying/stripping a single file.
+struct CopyConfig {
+ // Main input/output options
+ StringRef InputFilename;
+ StringRef InputFormat;
+ StringRef OutputFilename;
+ StringRef OutputFormat;
+
+ // Only applicable for --input-format=binary
+ MachineInfo BinaryArch;
+ // Only applicable when --output-format!=binary (e.g. elf64-x86-64).
+ Optional<MachineInfo> OutputArch;
+
+ // Advanced options
+ StringRef AddGnuDebugLink;
+ StringRef BuildIdLinkDir;
+ Optional<StringRef> BuildIdLinkInput;
+ Optional<StringRef> BuildIdLinkOutput;
+ StringRef SplitDWO;
+ StringRef SymbolsPrefix;
+
+ // Repeated options
+ std::vector<StringRef> AddSection;
+ std::vector<StringRef> DumpSection;
+ std::vector<StringRef> KeepSection;
+ std::vector<StringRef> OnlySection;
+ std::vector<StringRef> SymbolsToGlobalize;
+ std::vector<StringRef> SymbolsToKeep;
+ std::vector<StringRef> SymbolsToLocalize;
+ std::vector<StringRef> SymbolsToRemove;
+ std::vector<StringRef> SymbolsToWeaken;
+ std::vector<StringRef> ToRemove;
+ std::vector<std::string> SymbolsToKeepGlobal;
+
+ // Map options
+ StringMap<SectionRename> SectionsToRename;
+ StringMap<StringRef> SymbolsToRename;
+
+ // Boolean options
+ bool DeterministicArchives = true;
+ bool DiscardAll = false;
+ bool ExtractDWO = false;
+ bool KeepFileSymbols = false;
+ bool LocalizeHidden = false;
+ bool OnlyKeepDebug = false;
+ bool PreserveDates = false;
+ bool StripAll = false;
+ bool StripAllGNU = false;
+ bool StripDWO = false;
+ bool StripDebug = false;
+ bool StripNonAlloc = false;
+ bool StripSections = false;
+ bool StripUnneeded = false;
+ bool Weaken = false;
+ bool DecompressDebugSections = false;
+ DebugCompressionType CompressionType = DebugCompressionType::None;
+};
+
+// Configuration for the overall invocation of this tool. When invoked as
+// objcopy, will always contain exactly one CopyConfig. When invoked as strip,
+// will contain one or more CopyConfigs.
+struct DriverConfig {
+ SmallVector<CopyConfig, 1> CopyConfigs;
+};
+
+// ParseObjcopyOptions returns the config and sets the input arguments. If a
+// help flag is set then ParseObjcopyOptions will print the help messege and
+// exit.
+DriverConfig parseObjcopyOptions(ArrayRef<const char *> ArgsArr);
+
+// ParseStripOptions returns the config and sets the input arguments. If a
+// help flag is set then ParseStripOptions will print the help messege and
+// exit.
+DriverConfig parseStripOptions(ArrayRef<const char *> ArgsArr);
+
+} // namespace objcopy
+} // namespace llvm
+
+#endif
diff --git a/contrib/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp b/contrib/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp
new file mode 100644
index 000000000000..f5ab8e708267
--- /dev/null
+++ b/contrib/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp
@@ -0,0 +1,584 @@
+//===- ELFObjcopy.cpp -----------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ELFObjcopy.h"
+#include "Buffer.h"
+#include "CopyConfig.h"
+#include "Object.h"
+#include "llvm-objcopy.h"
+
+#include "llvm/ADT/BitmaskEnum.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/BinaryFormat/ELF.h"
+#include "llvm/MC/MCTargetOptions.h"
+#include "llvm/Object/Binary.h"
+#include "llvm/Object/ELFObjectFile.h"
+#include "llvm/Object/ELFTypes.h"
+#include "llvm/Object/Error.h"
+#include "llvm/Option/Option.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Compression.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/Memory.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cassert>
+#include <cstdlib>
+#include <functional>
+#include <iterator>
+#include <memory>
+#include <string>
+#include <system_error>
+#include <utility>
+
+namespace llvm {
+namespace objcopy {
+namespace elf {
+
+using namespace object;
+using namespace ELF;
+using SectionPred = std::function<bool(const SectionBase &Sec)>;
+
+static bool isDebugSection(const SectionBase &Sec) {
+ return StringRef(Sec.Name).startswith(".debug") ||
+ StringRef(Sec.Name).startswith(".zdebug") || Sec.Name == ".gdb_index";
+}
+
+static bool isDWOSection(const SectionBase &Sec) {
+ return StringRef(Sec.Name).endswith(".dwo");
+}
+
+static bool onlyKeepDWOPred(const Object &Obj, const SectionBase &Sec) {
+ // We can't remove the section header string table.
+ 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);
+}
+
+static ElfType getOutputElfType(const Binary &Bin) {
+ // Infer output ELF type from the input ELF object
+ if (isa<ELFObjectFile<ELF32LE>>(Bin))
+ return ELFT_ELF32LE;
+ if (isa<ELFObjectFile<ELF64LE>>(Bin))
+ return ELFT_ELF64LE;
+ if (isa<ELFObjectFile<ELF32BE>>(Bin))
+ return ELFT_ELF32BE;
+ if (isa<ELFObjectFile<ELF64BE>>(Bin))
+ return ELFT_ELF64BE;
+ llvm_unreachable("Invalid ELFType");
+}
+
+static ElfType getOutputElfType(const MachineInfo &MI) {
+ // Infer output ELF type from the binary arch specified
+ if (MI.Is64Bit)
+ return MI.IsLittleEndian ? ELFT_ELF64LE : ELFT_ELF64BE;
+ else
+ return MI.IsLittleEndian ? ELFT_ELF32LE : ELFT_ELF32BE;
+}
+
+static std::unique_ptr<Writer> createWriter(const CopyConfig &Config,
+ Object &Obj, Buffer &Buf,
+ ElfType OutputElfType) {
+ if (Config.OutputFormat == "binary") {
+ return llvm::make_unique<BinaryWriter>(Obj, Buf);
+ }
+ // Depending on the initial ELFT and OutputFormat we need a different Writer.
+ switch (OutputElfType) {
+ case ELFT_ELF32LE:
+ return llvm::make_unique<ELFWriter<ELF32LE>>(Obj, Buf,
+ !Config.StripSections);
+ case ELFT_ELF64LE:
+ return llvm::make_unique<ELFWriter<ELF64LE>>(Obj, Buf,
+ !Config.StripSections);
+ case ELFT_ELF32BE:
+ return llvm::make_unique<ELFWriter<ELF32BE>>(Obj, Buf,
+ !Config.StripSections);
+ case ELFT_ELF64BE:
+ return llvm::make_unique<ELFWriter<ELF64BE>>(Obj, Buf,
+ !Config.StripSections);
+ }
+ llvm_unreachable("Invalid output format");
+}
+
+template <class ELFT>
+static Expected<ArrayRef<uint8_t>>
+findBuildID(const object::ELFFile<ELFT> &In) {
+ for (const auto &Phdr : unwrapOrError(In.program_headers())) {
+ if (Phdr.p_type != PT_NOTE)
+ continue;
+ Error Err = Error::success();
+ for (const auto &Note : In.notes(Phdr, Err))
+ if (Note.getType() == NT_GNU_BUILD_ID && Note.getName() == ELF_NOTE_GNU)
+ return Note.getDesc();
+ if (Err)
+ return std::move(Err);
+ }
+ return createStringError(llvm::errc::invalid_argument,
+ "Could not find build ID.");
+}
+
+static Expected<ArrayRef<uint8_t>>
+findBuildID(const object::ELFObjectFileBase &In) {
+ if (auto *O = dyn_cast<ELFObjectFile<ELF32LE>>(&In))
+ return findBuildID(*O->getELFFile());
+ else if (auto *O = dyn_cast<ELFObjectFile<ELF64LE>>(&In))
+ return findBuildID(*O->getELFFile());
+ else if (auto *O = dyn_cast<ELFObjectFile<ELF32BE>>(&In))
+ return findBuildID(*O->getELFFile());
+ else if (auto *O = dyn_cast<ELFObjectFile<ELF64BE>>(&In))
+ return findBuildID(*O->getELFFile());
+
+ llvm_unreachable("Bad file format");
+}
+
+static void linkToBuildIdDir(const CopyConfig &Config, StringRef ToLink,
+ StringRef Suffix, ArrayRef<uint8_t> BuildIdBytes) {
+ SmallString<128> Path = Config.BuildIdLinkDir;
+ sys::path::append(Path, llvm::toHex(BuildIdBytes[0], /*LowerCase*/ true));
+ if (auto EC = sys::fs::create_directories(Path))
+ error("cannot create build ID link directory " + Path + ": " +
+ EC.message());
+
+ sys::path::append(Path,
+ llvm::toHex(BuildIdBytes.slice(1), /*LowerCase*/ true));
+ Path += Suffix;
+ if (auto EC = sys::fs::create_hard_link(ToLink, Path)) {
+ // Hard linking failed, try to remove the file first if it exists.
+ if (sys::fs::exists(Path))
+ sys::fs::remove(Path);
+ EC = sys::fs::create_hard_link(ToLink, Path);
+ if (EC)
+ error("cannot link " + ToLink + " to " + Path + ": " + EC.message());
+ }
+}
+
+static void splitDWOToFile(const CopyConfig &Config, const Reader &Reader,
+ StringRef File, ElfType OutputElfType) {
+ auto DWOFile = Reader.create();
+ DWOFile->removeSections(
+ [&](const SectionBase &Sec) { return onlyKeepDWOPred(*DWOFile, Sec); });
+ if (Config.OutputArch)
+ DWOFile->Machine = Config.OutputArch.getValue().EMachine;
+ FileBuffer FB(File);
+ auto Writer = createWriter(Config, *DWOFile, FB, OutputElfType);
+ Writer->finalize();
+ Writer->write();
+}
+
+static Error dumpSectionToFile(StringRef SecName, StringRef Filename,
+ Object &Obj) {
+ for (auto &Sec : Obj.sections()) {
+ if (Sec.Name == SecName) {
+ if (Sec.OriginalData.empty())
+ return make_error<StringError>("Can't dump section \"" + SecName +
+ "\": it has no contents",
+ object_error::parse_failed);
+ Expected<std::unique_ptr<FileOutputBuffer>> BufferOrErr =
+ FileOutputBuffer::create(Filename, Sec.OriginalData.size());
+ if (!BufferOrErr)
+ return BufferOrErr.takeError();
+ std::unique_ptr<FileOutputBuffer> Buf = std::move(*BufferOrErr);
+ std::copy(Sec.OriginalData.begin(), Sec.OriginalData.end(),
+ Buf->getBufferStart());
+ if (Error E = Buf->commit())
+ return E;
+ return Error::success();
+ }
+ }
+ return make_error<StringError>("Section not found",
+ object_error::parse_failed);
+}
+
+static bool isCompressed(const SectionBase &Section) {
+ const char *Magic = "ZLIB";
+ return StringRef(Section.Name).startswith(".zdebug") ||
+ (Section.OriginalData.size() > strlen(Magic) &&
+ !strncmp(reinterpret_cast<const char *>(Section.OriginalData.data()),
+ Magic, strlen(Magic))) ||
+ (Section.Flags & ELF::SHF_COMPRESSED);
+}
+
+static bool isCompressable(const SectionBase &Section) {
+ return !isCompressed(Section) && isDebugSection(Section) &&
+ Section.Name != ".gdb_index";
+}
+
+static void replaceDebugSections(
+ const CopyConfig &Config, Object &Obj, SectionPred &RemovePred,
+ function_ref<bool(const SectionBase &)> shouldReplace,
+ function_ref<SectionBase *(const SectionBase *)> addSection) {
+ SmallVector<SectionBase *, 13> ToReplace;
+ SmallVector<RelocationSection *, 13> RelocationSections;
+ for (auto &Sec : Obj.sections()) {
+ if (RelocationSection *R = dyn_cast<RelocationSection>(&Sec)) {
+ if (shouldReplace(*R->getSection()))
+ RelocationSections.push_back(R);
+ continue;
+ }
+
+ if (shouldReplace(Sec))
+ ToReplace.push_back(&Sec);
+ }
+
+ for (SectionBase *S : ToReplace) {
+ SectionBase *NewSection = addSection(S);
+
+ for (RelocationSection *RS : RelocationSections) {
+ if (RS->getSection() == S)
+ RS->setSection(NewSection);
+ }
+ }
+
+ RemovePred = [shouldReplace, RemovePred](const SectionBase &Sec) {
+ return shouldReplace(Sec) || RemovePred(Sec);
+ };
+}
+
+// This function handles the high level operations of GNU objcopy including
+// handling command line options. It's important to outline certain properties
+// we expect to hold of the command line operations. Any operation that "keeps"
+// should keep regardless of a remove. Additionally any removal should respect
+// 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.
+static void handleArgs(const CopyConfig &Config, Object &Obj,
+ const Reader &Reader, ElfType OutputElfType) {
+
+ if (!Config.SplitDWO.empty()) {
+ splitDWOToFile(Config, Reader, Config.SplitDWO, OutputElfType);
+ }
+ if (Config.OutputArch)
+ Obj.Machine = Config.OutputArch.getValue().EMachine;
+
+ // TODO: update or remove symbols only if there is an option that affects
+ // them.
+ if (Obj.SymbolTable) {
+ Obj.SymbolTable->updateSymbols([&](Symbol &Sym) {
+ if (!Sym.isCommon() &&
+ ((Config.LocalizeHidden &&
+ (Sym.Visibility == STV_HIDDEN || Sym.Visibility == STV_INTERNAL)) ||
+ is_contained(Config.SymbolsToLocalize, Sym.Name)))
+ Sym.Binding = STB_LOCAL;
+
+ // Note: these two globalize flags have very similar names but different
+ // meanings:
+ //
+ // --globalize-symbol: promote a symbol to global
+ // --keep-global-symbol: all symbols except for these should be made local
+ //
+ // If --globalize-symbol is specified for a given symbol, it will be
+ // global in the output file even if it is not included via
+ // --keep-global-symbol. Because of that, make sure to check
+ // --globalize-symbol second.
+ if (!Config.SymbolsToKeepGlobal.empty() &&
+ !is_contained(Config.SymbolsToKeepGlobal, Sym.Name) &&
+ Sym.getShndx() != SHN_UNDEF)
+ Sym.Binding = STB_LOCAL;
+
+ if (is_contained(Config.SymbolsToGlobalize, Sym.Name) &&
+ Sym.getShndx() != SHN_UNDEF)
+ Sym.Binding = STB_GLOBAL;
+
+ if (is_contained(Config.SymbolsToWeaken, Sym.Name) &&
+ Sym.Binding == STB_GLOBAL)
+ Sym.Binding = STB_WEAK;
+
+ if (Config.Weaken && Sym.Binding == STB_GLOBAL &&
+ Sym.getShndx() != SHN_UNDEF)
+ Sym.Binding = STB_WEAK;
+
+ const auto I = Config.SymbolsToRename.find(Sym.Name);
+ if (I != Config.SymbolsToRename.end())
+ Sym.Name = I->getValue();
+
+ if (!Config.SymbolsPrefix.empty() && Sym.Type != STT_SECTION)
+ Sym.Name = (Config.SymbolsPrefix + Sym.Name).str();
+ });
+
+ // The purpose of this loop is to mark symbols referenced by sections
+ // (like GroupSection or RelocationSection). This way, we know which
+ // symbols are still 'needed' and which are not.
+ if (Config.StripUnneeded) {
+ for (auto &Section : Obj.sections())
+ Section.markSymbols();
+ }
+
+ Obj.removeSymbols([&](const Symbol &Sym) {
+ if (is_contained(Config.SymbolsToKeep, Sym.Name) ||
+ (Config.KeepFileSymbols && Sym.Type == STT_FILE))
+ return false;
+
+ if (Config.DiscardAll && Sym.Binding == STB_LOCAL &&
+ Sym.getShndx() != SHN_UNDEF && Sym.Type != STT_FILE &&
+ Sym.Type != STT_SECTION)
+ return true;
+
+ if (Config.StripAll || Config.StripAllGNU)
+ return true;
+
+ if (is_contained(Config.SymbolsToRemove, Sym.Name))
+ return true;
+
+ if (Config.StripUnneeded && !Sym.Referenced &&
+ (Sym.Binding == STB_LOCAL || Sym.getShndx() == SHN_UNDEF) &&
+ Sym.Type != STT_FILE && Sym.Type != STT_SECTION)
+ return true;
+
+ return false;
+ });
+ }
+
+ SectionPred RemovePred = [](const SectionBase &) { return false; };
+
+ // Removes:
+ if (!Config.ToRemove.empty()) {
+ RemovePred = [&Config](const SectionBase &Sec) {
+ return is_contained(Config.ToRemove, Sec.Name);
+ };
+ }
+
+ if (Config.StripDWO || !Config.SplitDWO.empty())
+ RemovePred = [RemovePred](const SectionBase &Sec) {
+ return isDWOSection(Sec) || RemovePred(Sec);
+ };
+
+ if (Config.ExtractDWO)
+ RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {
+ return onlyKeepDWOPred(Obj, Sec) || RemovePred(Sec);
+ };
+
+ if (Config.StripAllGNU)
+ RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {
+ if (RemovePred(Sec))
+ return true;
+ if ((Sec.Flags & SHF_ALLOC) != 0)
+ return false;
+ if (&Sec == Obj.SectionNames)
+ return false;
+ switch (Sec.Type) {
+ case SHT_SYMTAB:
+ case SHT_REL:
+ case SHT_RELA:
+ case SHT_STRTAB:
+ return true;
+ }
+ return isDebugSection(Sec);
+ };
+
+ if (Config.StripSections) {
+ RemovePred = [RemovePred](const SectionBase &Sec) {
+ return RemovePred(Sec) || (Sec.Flags & SHF_ALLOC) == 0;
+ };
+ }
+
+ if (Config.StripDebug) {
+ RemovePred = [RemovePred](const SectionBase &Sec) {
+ return RemovePred(Sec) || isDebugSection(Sec);
+ };
+ }
+
+ if (Config.StripNonAlloc)
+ RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {
+ if (RemovePred(Sec))
+ return true;
+ if (&Sec == Obj.SectionNames)
+ return false;
+ return (Sec.Flags & SHF_ALLOC) == 0;
+ };
+
+ if (Config.StripAll)
+ RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {
+ if (RemovePred(Sec))
+ return true;
+ if (&Sec == Obj.SectionNames)
+ return false;
+ if (StringRef(Sec.Name).startswith(".gnu.warning"))
+ return false;
+ return (Sec.Flags & SHF_ALLOC) == 0;
+ };
+
+ // Explicit copies:
+ if (!Config.OnlySection.empty()) {
+ RemovePred = [&Config, RemovePred, &Obj](const SectionBase &Sec) {
+ // Explicitly keep these sections regardless of previous removes.
+ if (is_contained(Config.OnlySection, Sec.Name))
+ return false;
+
+ // Allow all implicit removes.
+ if (RemovePred(Sec))
+ return true;
+
+ // Keep special sections.
+ if (Obj.SectionNames == &Sec)
+ return false;
+ if (Obj.SymbolTable == &Sec ||
+ (Obj.SymbolTable && Obj.SymbolTable->getStrTab() == &Sec))
+ return false;
+
+ // Remove everything else.
+ return true;
+ };
+ }
+
+ if (!Config.KeepSection.empty()) {
+ RemovePred = [&Config, RemovePred](const SectionBase &Sec) {
+ // Explicitly keep these sections regardless of previous removes.
+ if (is_contained(Config.KeepSection, Sec.Name))
+ return false;
+ // Otherwise defer to RemovePred.
+ return RemovePred(Sec);
+ };
+ }
+
+ // This has to be the last predicate assignment.
+ // If the option --keep-symbol has been specified
+ // and at least one of those symbols is present
+ // (equivalently, the updated symbol table is not empty)
+ // the symbol table and the string table should not be removed.
+ if ((!Config.SymbolsToKeep.empty() || Config.KeepFileSymbols) &&
+ Obj.SymbolTable && !Obj.SymbolTable->empty()) {
+ RemovePred = [&Obj, RemovePred](const SectionBase &Sec) {
+ if (&Sec == Obj.SymbolTable || &Sec == Obj.SymbolTable->getStrTab())
+ return false;
+ return RemovePred(Sec);
+ };
+ }
+
+ if (Config.CompressionType != DebugCompressionType::None)
+ replaceDebugSections(Config, Obj, RemovePred, isCompressable,
+ [&Config, &Obj](const SectionBase *S) {
+ return &Obj.addSection<CompressedSection>(
+ *S, Config.CompressionType);
+ });
+ else if (Config.DecompressDebugSections)
+ replaceDebugSections(
+ Config, Obj, RemovePred,
+ [](const SectionBase &S) { return isa<CompressedSection>(&S); },
+ [&Obj](const SectionBase *S) {
+ auto CS = cast<CompressedSection>(S);
+ return &Obj.addSection<DecompressedSection>(*CS);
+ });
+
+ Obj.removeSections(RemovePred);
+
+ if (!Config.SectionsToRename.empty()) {
+ for (auto &Sec : Obj.sections()) {
+ const auto Iter = Config.SectionsToRename.find(Sec.Name);
+ if (Iter != Config.SectionsToRename.end()) {
+ const SectionRename &SR = Iter->second;
+ Sec.Name = SR.NewName;
+ if (SR.NewFlags.hasValue()) {
+ // Preserve some flags which should not be dropped when setting flags.
+ // Also, preserve anything OS/processor dependant.
+ const uint64_t PreserveMask = ELF::SHF_COMPRESSED | ELF::SHF_EXCLUDE |
+ ELF::SHF_GROUP | ELF::SHF_LINK_ORDER |
+ ELF::SHF_MASKOS | ELF::SHF_MASKPROC |
+ ELF::SHF_TLS | ELF::SHF_INFO_LINK;
+ Sec.Flags = (Sec.Flags & PreserveMask) |
+ (SR.NewFlags.getValue() & ~PreserveMask);
+ }
+ }
+ }
+ }
+
+ if (!Config.AddSection.empty()) {
+ for (const auto &Flag : Config.AddSection) {
+ std::pair<StringRef, StringRef> SecPair = Flag.split("=");
+ StringRef SecName = SecPair.first;
+ StringRef File = SecPair.second;
+ ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
+ MemoryBuffer::getFile(File);
+ if (!BufOrErr)
+ reportError(File, BufOrErr.getError());
+ std::unique_ptr<MemoryBuffer> Buf = std::move(*BufOrErr);
+ ArrayRef<uint8_t> Data(
+ reinterpret_cast<const uint8_t *>(Buf->getBufferStart()),
+ Buf->getBufferSize());
+ OwnedDataSection &NewSection =
+ Obj.addSection<OwnedDataSection>(SecName, Data);
+ if (SecName.startswith(".note") && SecName != ".note.GNU-stack")
+ NewSection.Type = SHT_NOTE;
+ }
+ }
+
+ if (!Config.DumpSection.empty()) {
+ for (const auto &Flag : Config.DumpSection) {
+ std::pair<StringRef, StringRef> SecPair = Flag.split("=");
+ StringRef SecName = SecPair.first;
+ StringRef File = SecPair.second;
+ if (Error E = dumpSectionToFile(SecName, File, Obj))
+ reportError(Config.InputFilename, std::move(E));
+ }
+ }
+
+ if (!Config.AddGnuDebugLink.empty())
+ Obj.addSection<GnuDebugLinkSection>(Config.AddGnuDebugLink);
+}
+
+void executeObjcopyOnRawBinary(const CopyConfig &Config, MemoryBuffer &In,
+ Buffer &Out) {
+ BinaryReader Reader(Config.BinaryArch, &In);
+ std::unique_ptr<Object> Obj = Reader.create();
+
+ // Prefer OutputArch (-O<format>) if set, otherwise fallback to BinaryArch
+ // (-B<arch>).
+ const ElfType OutputElfType = getOutputElfType(
+ Config.OutputArch ? Config.OutputArch.getValue() : Config.BinaryArch);
+ handleArgs(Config, *Obj, Reader, OutputElfType);
+ std::unique_ptr<Writer> Writer =
+ createWriter(Config, *Obj, Out, OutputElfType);
+ Writer->finalize();
+ Writer->write();
+}
+
+void executeObjcopyOnBinary(const CopyConfig &Config,
+ object::ELFObjectFileBase &In, Buffer &Out) {
+ ELFReader Reader(&In);
+ std::unique_ptr<Object> Obj = Reader.create();
+ // Prefer OutputArch (-O<format>) if set, otherwise infer it from the input.
+ const ElfType OutputElfType =
+ Config.OutputArch ? getOutputElfType(Config.OutputArch.getValue())
+ : getOutputElfType(In);
+ ArrayRef<uint8_t> BuildIdBytes;
+
+ if (!Config.BuildIdLinkDir.empty()) {
+ BuildIdBytes = unwrapOrError(findBuildID(In));
+ if (BuildIdBytes.size() < 2)
+ error("build ID in file '" + Config.InputFilename +
+ "' is smaller than two bytes");
+ }
+
+ if (!Config.BuildIdLinkDir.empty() && Config.BuildIdLinkInput) {
+ linkToBuildIdDir(Config, Config.InputFilename,
+ Config.BuildIdLinkInput.getValue(), BuildIdBytes);
+ }
+ handleArgs(Config, *Obj, Reader, OutputElfType);
+ std::unique_ptr<Writer> Writer =
+ createWriter(Config, *Obj, Out, OutputElfType);
+ Writer->finalize();
+ Writer->write();
+ if (!Config.BuildIdLinkDir.empty() && Config.BuildIdLinkOutput) {
+ linkToBuildIdDir(Config, Config.OutputFilename,
+ Config.BuildIdLinkOutput.getValue(), BuildIdBytes);
+ }
+}
+
+} // end namespace elf
+} // end namespace objcopy
+} // end namespace llvm
diff --git a/contrib/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.h b/contrib/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.h
new file mode 100644
index 000000000000..43f41c00ce5b
--- /dev/null
+++ b/contrib/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.h
@@ -0,0 +1,34 @@
+//===- ELFObjcopy.h ---------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TOOLS_OBJCOPY_ELFOBJCOPY_H
+#define LLVM_TOOLS_OBJCOPY_ELFOBJCOPY_H
+
+namespace llvm {
+class MemoryBuffer;
+
+namespace object {
+class ELFObjectFileBase;
+} // end namespace object
+
+namespace objcopy {
+struct CopyConfig;
+class Buffer;
+
+namespace elf {
+void executeObjcopyOnRawBinary(const CopyConfig &Config, MemoryBuffer &In,
+ Buffer &Out);
+void executeObjcopyOnBinary(const CopyConfig &Config,
+ object::ELFObjectFileBase &In, Buffer &Out);
+
+} // end namespace elf
+} // end namespace objcopy
+} // end namespace llvm
+
+#endif // LLVM_TOOLS_OBJCOPY_ELFOBJCOPY_H
diff --git a/contrib/llvm/tools/llvm-objcopy/Object.cpp b/contrib/llvm/tools/llvm-objcopy/ELF/Object.cpp
index 7e88f5263a39..3d3e029c09eb 100644
--- a/contrib/llvm/tools/llvm-objcopy/Object.cpp
+++ b/contrib/llvm/tools/llvm-objcopy/ELF/Object.cpp
@@ -15,7 +15,9 @@
#include "llvm/ADT/Twine.h"
#include "llvm/ADT/iterator_range.h"
#include "llvm/BinaryFormat/ELF.h"
+#include "llvm/MC/MCTargetOptions.h"
#include "llvm/Object/ELFObjectFile.h"
+#include "llvm/Support/Compression.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FileOutputBuffer.h"
#include "llvm/Support/Path.h"
@@ -26,45 +28,14 @@
#include <utility>
#include <vector>
-using namespace llvm;
-using namespace llvm::objcopy;
+namespace llvm {
+namespace objcopy {
+namespace elf {
+
using namespace object;
using namespace ELF;
-Buffer::~Buffer() {}
-
-void FileBuffer::allocate(size_t Size) {
- Expected<std::unique_ptr<FileOutputBuffer>> BufferOrErr =
- FileOutputBuffer::create(getName(), Size, FileOutputBuffer::F_executable);
- handleAllErrors(BufferOrErr.takeError(), [this](const ErrorInfoBase &E) {
- error("failed to open " + getName() + ": " + E.message());
- });
- Buf = std::move(*BufferOrErr);
-}
-
-Error FileBuffer::commit() { return Buf->commit(); }
-
-uint8_t *FileBuffer::getBufferStart() {
- return reinterpret_cast<uint8_t *>(Buf->getBufferStart());
-}
-
-void MemBuffer::allocate(size_t Size) {
- Buf = WritableMemoryBuffer::getNewMemBuffer(Size, getName());
-}
-
-Error MemBuffer::commit() { return Error::success(); }
-
-uint8_t *MemBuffer::getBufferStart() {
- return reinterpret_cast<uint8_t *>(Buf->getBufferStart());
-}
-
-std::unique_ptr<WritableMemoryBuffer> MemBuffer::releaseMemoryBuffer() {
- return std::move(Buf);
-}
-
template <class ELFT> void ELFWriter<ELFT>::writePhdr(const Segment &Seg) {
- using Elf_Phdr = typename ELFT::Phdr;
-
uint8_t *B = Buf.getBufferStart();
B += Obj.ProgramHdrSegment.Offset + Seg.Index * sizeof(Elf_Phdr);
Elf_Phdr &Phdr = *reinterpret_cast<Elf_Phdr *>(B);
@@ -87,7 +58,7 @@ void SectionBase::markSymbols() {}
template <class ELFT> void ELFWriter<ELFT>::writeShdr(const SectionBase &Sec) {
uint8_t *B = Buf.getBufferStart();
B += Sec.HeaderOffset;
- typename ELFT::Shdr &Shdr = *reinterpret_cast<typename ELFT::Shdr *>(B);
+ Elf_Shdr &Shdr = *reinterpret_cast<Elf_Shdr *>(B);
Shdr.sh_name = Sec.NameIndex;
Shdr.sh_type = Sec.Type;
Shdr.sh_flags = Sec.Flags;
@@ -100,7 +71,46 @@ template <class ELFT> void ELFWriter<ELFT>::writeShdr(const SectionBase &Sec) {
Shdr.sh_entsize = Sec.EntrySize;
}
-SectionVisitor::~SectionVisitor() {}
+template <class ELFT> void ELFSectionSizer<ELFT>::visit(Section &Sec) {}
+
+template <class ELFT>
+void ELFSectionSizer<ELFT>::visit(OwnedDataSection &Sec) {}
+
+template <class ELFT>
+void ELFSectionSizer<ELFT>::visit(StringTableSection &Sec) {}
+
+template <class ELFT>
+void ELFSectionSizer<ELFT>::visit(DynamicRelocationSection &Sec) {}
+
+template <class ELFT>
+void ELFSectionSizer<ELFT>::visit(SymbolTableSection &Sec) {
+ Sec.EntrySize = sizeof(Elf_Sym);
+ Sec.Size = Sec.Symbols.size() * Sec.EntrySize;
+ // Align to the largest field in Elf_Sym.
+ Sec.Align = ELFT::Is64Bits ? sizeof(Elf_Xword) : sizeof(Elf_Word);
+}
+
+template <class ELFT>
+void ELFSectionSizer<ELFT>::visit(RelocationSection &Sec) {
+ Sec.EntrySize = Sec.Type == SHT_REL ? sizeof(Elf_Rel) : sizeof(Elf_Rela);
+ Sec.Size = Sec.Relocations.size() * Sec.EntrySize;
+ // Align to the largest field in Elf_Rel(a).
+ Sec.Align = ELFT::Is64Bits ? sizeof(Elf_Xword) : sizeof(Elf_Word);
+}
+
+template <class ELFT>
+void ELFSectionSizer<ELFT>::visit(GnuDebugLinkSection &Sec) {}
+
+template <class ELFT> void ELFSectionSizer<ELFT>::visit(GroupSection &Sec) {}
+
+template <class ELFT>
+void ELFSectionSizer<ELFT>::visit(SectionIndexSection &Sec) {}
+
+template <class ELFT>
+void ELFSectionSizer<ELFT>::visit(CompressedSection &Sec) {}
+
+template <class ELFT>
+void ELFSectionSizer<ELFT>::visit(DecompressedSection &Sec) {}
void BinarySectionWriter::visit(const SectionIndexSection &Sec) {
error("Cannot write symbol section index table '" + Sec.Name + "' ");
@@ -126,20 +136,169 @@ void SectionWriter::visit(const Section &Sec) {
if (Sec.Type == SHT_NOBITS)
return;
uint8_t *Buf = Out.getBufferStart() + Sec.Offset;
- std::copy(std::begin(Sec.Contents), std::end(Sec.Contents), Buf);
+ llvm::copy(Sec.Contents, Buf);
}
void Section::accept(SectionVisitor &Visitor) const { Visitor.visit(*this); }
+void Section::accept(MutableSectionVisitor &Visitor) { 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);
+ llvm::copy(Sec.Data, Buf);
+}
+
+static const std::vector<uint8_t> ZlibGnuMagic = {'Z', 'L', 'I', 'B'};
+
+static bool isDataGnuCompressed(ArrayRef<uint8_t> Data) {
+ return Data.size() > ZlibGnuMagic.size() &&
+ std::equal(ZlibGnuMagic.begin(), ZlibGnuMagic.end(), Data.data());
+}
+
+template <class ELFT>
+static std::tuple<uint64_t, uint64_t>
+getDecompressedSizeAndAlignment(ArrayRef<uint8_t> Data) {
+ const bool IsGnuDebug = isDataGnuCompressed(Data);
+ const uint64_t DecompressedSize =
+ IsGnuDebug
+ ? support::endian::read64be(reinterpret_cast<const uint64_t *>(
+ Data.data() + ZlibGnuMagic.size()))
+ : reinterpret_cast<const Elf_Chdr_Impl<ELFT> *>(Data.data())->ch_size;
+ const uint64_t DecompressedAlign =
+ IsGnuDebug ? 1
+ : reinterpret_cast<const Elf_Chdr_Impl<ELFT> *>(Data.data())
+ ->ch_addralign;
+
+ return std::make_tuple(DecompressedSize, DecompressedAlign);
+}
+
+template <class ELFT>
+void ELFSectionWriter<ELFT>::visit(const DecompressedSection &Sec) {
+ uint8_t *Buf = Out.getBufferStart() + Sec.Offset;
+
+ if (!zlib::isAvailable()) {
+ std::copy(Sec.OriginalData.begin(), Sec.OriginalData.end(), Buf);
+ return;
+ }
+
+ const size_t DataOffset = isDataGnuCompressed(Sec.OriginalData)
+ ? (ZlibGnuMagic.size() + sizeof(Sec.Size))
+ : sizeof(Elf_Chdr_Impl<ELFT>);
+
+ StringRef CompressedContent(
+ reinterpret_cast<const char *>(Sec.OriginalData.data()) + DataOffset,
+ Sec.OriginalData.size() - DataOffset);
+
+ SmallVector<char, 128> DecompressedContent;
+ if (Error E = zlib::uncompress(CompressedContent, DecompressedContent,
+ static_cast<size_t>(Sec.Size)))
+ reportError(Sec.Name, std::move(E));
+
+ std::copy(DecompressedContent.begin(), DecompressedContent.end(), Buf);
+}
+
+void BinarySectionWriter::visit(const DecompressedSection &Sec) {
+ error("Cannot write compressed section '" + Sec.Name + "' ");
+}
+
+void DecompressedSection::accept(SectionVisitor &Visitor) const {
+ Visitor.visit(*this);
+}
+
+void DecompressedSection::accept(MutableSectionVisitor &Visitor) {
+ Visitor.visit(*this);
}
void OwnedDataSection::accept(SectionVisitor &Visitor) const {
Visitor.visit(*this);
}
+void OwnedDataSection::accept(MutableSectionVisitor &Visitor) {
+ Visitor.visit(*this);
+}
+
+void BinarySectionWriter::visit(const CompressedSection &Sec) {
+ error("Cannot write compressed section '" + Sec.Name + "' ");
+}
+
+template <class ELFT>
+void ELFSectionWriter<ELFT>::visit(const CompressedSection &Sec) {
+ uint8_t *Buf = Out.getBufferStart();
+ Buf += Sec.Offset;
+
+ if (Sec.CompressionType == DebugCompressionType::None) {
+ std::copy(Sec.OriginalData.begin(), Sec.OriginalData.end(), Buf);
+ return;
+ }
+
+ if (Sec.CompressionType == DebugCompressionType::GNU) {
+ const char *Magic = "ZLIB";
+ memcpy(Buf, Magic, strlen(Magic));
+ Buf += strlen(Magic);
+ const uint64_t DecompressedSize =
+ support::endian::read64be(&Sec.DecompressedSize);
+ memcpy(Buf, &DecompressedSize, sizeof(DecompressedSize));
+ Buf += sizeof(DecompressedSize);
+ } else {
+ Elf_Chdr_Impl<ELFT> Chdr;
+ Chdr.ch_type = ELF::ELFCOMPRESS_ZLIB;
+ Chdr.ch_size = Sec.DecompressedSize;
+ Chdr.ch_addralign = Sec.DecompressedAlign;
+ memcpy(Buf, &Chdr, sizeof(Chdr));
+ Buf += sizeof(Chdr);
+ }
+
+ std::copy(Sec.CompressedData.begin(), Sec.CompressedData.end(), Buf);
+}
+
+CompressedSection::CompressedSection(const SectionBase &Sec,
+ DebugCompressionType CompressionType)
+ : SectionBase(Sec), CompressionType(CompressionType),
+ DecompressedSize(Sec.OriginalData.size()), DecompressedAlign(Sec.Align) {
+
+ if (!zlib::isAvailable()) {
+ CompressionType = DebugCompressionType::None;
+ return;
+ }
+
+ if (Error E = zlib::compress(
+ StringRef(reinterpret_cast<const char *>(OriginalData.data()),
+ OriginalData.size()),
+ CompressedData))
+ reportError(Name, std::move(E));
+
+ size_t ChdrSize;
+ if (CompressionType == DebugCompressionType::GNU) {
+ Name = ".z" + Sec.Name.substr(1);
+ ChdrSize = sizeof("ZLIB") - 1 + sizeof(uint64_t);
+ } else {
+ Flags |= ELF::SHF_COMPRESSED;
+ ChdrSize =
+ std::max(std::max(sizeof(object::Elf_Chdr_Impl<object::ELF64LE>),
+ sizeof(object::Elf_Chdr_Impl<object::ELF64BE>)),
+ std::max(sizeof(object::Elf_Chdr_Impl<object::ELF32LE>),
+ sizeof(object::Elf_Chdr_Impl<object::ELF32BE>)));
+ }
+ Size = ChdrSize + CompressedData.size();
+ Align = 8;
+}
+
+CompressedSection::CompressedSection(ArrayRef<uint8_t> CompressedData,
+ uint64_t DecompressedSize,
+ uint64_t DecompressedAlign)
+ : CompressionType(DebugCompressionType::None),
+ DecompressedSize(DecompressedSize), DecompressedAlign(DecompressedAlign) {
+ OriginalData = CompressedData;
+}
+
+void CompressedSection::accept(SectionVisitor &Visitor) const {
+ Visitor.visit(*this);
+}
+
+void CompressedSection::accept(MutableSectionVisitor &Visitor) {
+ Visitor.visit(*this);
+}
+
void StringTableSection::addString(StringRef Name) {
StrTabBuilder.add(Name);
Size = StrTabBuilder.getSize();
@@ -159,11 +318,15 @@ void StringTableSection::accept(SectionVisitor &Visitor) const {
Visitor.visit(*this);
}
+void StringTableSection::accept(MutableSectionVisitor &Visitor) {
+ Visitor.visit(*this);
+}
+
template <class ELFT>
void ELFSectionWriter<ELFT>::visit(const SectionIndexSection &Sec) {
uint8_t *Buf = Out.getBufferStart() + Sec.Offset;
- auto *IndexesBuffer = reinterpret_cast<typename ELFT::Word *>(Buf);
- std::copy(std::begin(Sec.Indexes), std::end(Sec.Indexes), IndexesBuffer);
+ auto *IndexesBuffer = reinterpret_cast<Elf_Word *>(Buf);
+ llvm::copy(Sec.Indexes, IndexesBuffer);
}
void SectionIndexSection::initialize(SectionTableRef SecTable) {
@@ -182,6 +345,10 @@ void SectionIndexSection::accept(SectionVisitor &Visitor) const {
Visitor.visit(*this);
}
+void SectionIndexSection::accept(MutableSectionVisitor &Visitor) {
+ Visitor.visit(*this);
+}
+
static bool isValidReservedSectionIndex(uint16_t Index, uint16_t Machine) {
switch (Index) {
case SHN_ABS:
@@ -226,18 +393,20 @@ uint16_t Symbol::getShndx() const {
llvm_unreachable("Symbol with invalid ShndxType encountered");
}
+bool Symbol::isCommon() const { return getShndx() == SHN_COMMON; }
+
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,
+void SymbolTableSection::addSymbol(Twine Name, uint8_t Bind, uint8_t Type,
SectionBase *DefinedIn, uint64_t Value,
uint8_t Visibility, uint16_t Shndx,
- uint64_t Sz) {
+ uint64_t Size) {
Symbol Sym;
- Sym.Name = Name;
+ Sym.Name = Name.str();
Sym.Binding = Bind;
Sym.Type = Type;
Sym.DefinedIn = DefinedIn;
@@ -251,7 +420,7 @@ void SymbolTableSection::addSymbol(StringRef Name, uint8_t Bind, uint8_t Type,
}
Sym.Value = Value;
Sym.Visibility = Visibility;
- Sym.Size = Sz;
+ Sym.Size = Size;
Sym.Index = Symbols.size();
Symbols.emplace_back(llvm::make_unique<Symbol>(Sym));
Size += this->EntrySize;
@@ -344,7 +513,7 @@ template <class ELFT>
void ELFSectionWriter<ELFT>::visit(const SymbolTableSection &Sec) {
uint8_t *Buf = Out.getBufferStart();
Buf += Sec.Offset;
- typename ELFT::Sym *Sym = reinterpret_cast<typename ELFT::Sym *>(Buf);
+ Elf_Sym *Sym = reinterpret_cast<Elf_Sym *>(Buf);
// Loop though symbols setting each entry of the symbol table.
for (auto &Symbol : Sec.Symbols) {
Sym->st_name = Symbol->NameIndex;
@@ -362,6 +531,10 @@ void SymbolTableSection::accept(SectionVisitor &Visitor) const {
Visitor.visit(*this);
}
+void SymbolTableSection::accept(MutableSectionVisitor &Visitor) {
+ Visitor.visit(*this);
+}
+
template <class SymTabType>
void RelocSectionWithSymtabBase<SymTabType>::removeSectionReferences(
const SectionBase *Sec) {
@@ -377,11 +550,13 @@ void RelocSectionWithSymtabBase<SymTabType>::removeSectionReferences(
template <class SymTabType>
void RelocSectionWithSymtabBase<SymTabType>::initialize(
SectionTableRef SecTable) {
- setSymTab(SecTable.getSectionOfType<SymTabType>(
- Link,
- "Link field value " + Twine(Link) + " in section " + Name + " is invalid",
- "Link field value " + Twine(Link) + " in section " + Name +
- " is not a symbol table"));
+ if (Link != SHN_UNDEF)
+ setSymTab(SecTable.getSectionOfType<SymTabType>(
+ Link,
+ "Link field value " + Twine(Link) + " in section " + Name +
+ " is invalid",
+ "Link field value " + Twine(Link) + " in section " + Name +
+ " is not a symbol table"));
if (Info != SHN_UNDEF)
setSection(SecTable.getSection(Info, "Info field value " + Twine(Info) +
@@ -393,7 +568,8 @@ void RelocSectionWithSymtabBase<SymTabType>::initialize(
template <class SymTabType>
void RelocSectionWithSymtabBase<SymTabType>::finalize() {
- this->Link = Symbols->Index;
+ this->Link = Symbols ? Symbols->Index : 0;
+
if (SecToApplyRel != nullptr)
this->Info = SecToApplyRel->Index;
}
@@ -429,11 +605,15 @@ void RelocationSection::accept(SectionVisitor &Visitor) const {
Visitor.visit(*this);
}
+void RelocationSection::accept(MutableSectionVisitor &Visitor) {
+ Visitor.visit(*this);
+}
+
void RelocationSection::removeSymbols(
function_ref<bool(const Symbol &)> ToRemove) {
for (const Relocation &Reloc : Relocations)
if (ToRemove(*Reloc.RelocSymbol))
- error("not stripping symbol `" + Reloc.RelocSymbol->Name +
+ error("not stripping symbol '" + Reloc.RelocSymbol->Name +
"' because it is named in a relocation");
}
@@ -443,7 +623,7 @@ void RelocationSection::markSymbols() {
}
void SectionWriter::visit(const DynamicRelocationSection &Sec) {
- std::copy(std::begin(Sec.Contents), std::end(Sec.Contents),
+ llvm::copy(Sec.Contents,
Out.getBufferStart() + Sec.Offset);
}
@@ -451,6 +631,10 @@ void DynamicRelocationSection::accept(SectionVisitor &Visitor) const {
Visitor.visit(*this);
}
+void DynamicRelocationSection::accept(MutableSectionVisitor &Visitor) {
+ Visitor.visit(*this);
+}
+
void Section::removeSectionReferences(const SectionBase *Sec) {
if (LinkSection == Sec) {
error("Section " + LinkSection->Name +
@@ -506,12 +690,12 @@ void GnuDebugLinkSection::init(StringRef File, StringRef Data) {
// establish the order that sections should go in. By using the maximum
// possible offset we cause this section to wind up at the end.
OriginalOffset = std::numeric_limits<uint64_t>::max();
- JamCRC crc;
- crc.update(ArrayRef<char>(Data.data(), Data.size()));
+ JamCRC CRC;
+ CRC.update(ArrayRef<char>(Data.data(), Data.size()));
// The CRC32 value needs to be complemented because the JamCRC dosn't
// finalize the CRC32 value. It also dosn't negate the initial CRC32 value
// but it starts by default at 0xFFFFFFFF which is the complement of zero.
- CRC32 = ~crc.getCRC();
+ CRC32 = ~CRC.getCRC();
}
GnuDebugLinkSection::GnuDebugLinkSection(StringRef File) : FileName(File) {
@@ -530,13 +714,17 @@ void ELFSectionWriter<ELFT>::visit(const GnuDebugLinkSection &Sec) {
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);
+ llvm::copy(Sec.FileName, File);
}
void GnuDebugLinkSection::accept(SectionVisitor &Visitor) const {
Visitor.visit(*this);
}
+void GnuDebugLinkSection::accept(MutableSectionVisitor &Visitor) {
+ Visitor.visit(*this);
+}
+
template <class ELFT>
void ELFSectionWriter<ELFT>::visit(const GroupSection &Sec) {
ELF::Elf32_Word *Buf =
@@ -550,6 +738,10 @@ void GroupSection::accept(SectionVisitor &Visitor) const {
Visitor.visit(*this);
}
+void GroupSection::accept(MutableSectionVisitor &Visitor) {
+ 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) {
@@ -589,6 +781,79 @@ static bool compareSegmentsByPAddr(const Segment *A, const Segment *B) {
return A->Index < B->Index;
}
+void BinaryELFBuilder::initFileHeader() {
+ Obj->Flags = 0x0;
+ Obj->Type = ET_REL;
+ Obj->OSABI = ELFOSABI_NONE;
+ Obj->ABIVersion = 0;
+ Obj->Entry = 0x0;
+ Obj->Machine = EMachine;
+ Obj->Version = 1;
+}
+
+void BinaryELFBuilder::initHeaderSegment() { Obj->ElfHdrSegment.Index = 0; }
+
+StringTableSection *BinaryELFBuilder::addStrTab() {
+ auto &StrTab = Obj->addSection<StringTableSection>();
+ StrTab.Name = ".strtab";
+
+ Obj->SectionNames = &StrTab;
+ return &StrTab;
+}
+
+SymbolTableSection *BinaryELFBuilder::addSymTab(StringTableSection *StrTab) {
+ auto &SymTab = Obj->addSection<SymbolTableSection>();
+
+ SymTab.Name = ".symtab";
+ SymTab.Link = StrTab->Index;
+
+ // The symbol table always needs a null symbol
+ SymTab.addSymbol("", 0, 0, nullptr, 0, 0, 0, 0);
+
+ Obj->SymbolTable = &SymTab;
+ return &SymTab;
+}
+
+void BinaryELFBuilder::addData(SymbolTableSection *SymTab) {
+ auto Data = ArrayRef<uint8_t>(
+ reinterpret_cast<const uint8_t *>(MemBuf->getBufferStart()),
+ MemBuf->getBufferSize());
+ auto &DataSection = Obj->addSection<Section>(Data);
+ DataSection.Name = ".data";
+ DataSection.Type = ELF::SHT_PROGBITS;
+ DataSection.Size = Data.size();
+ DataSection.Flags = ELF::SHF_ALLOC | ELF::SHF_WRITE;
+
+ std::string SanitizedFilename = MemBuf->getBufferIdentifier().str();
+ std::replace_if(std::begin(SanitizedFilename), std::end(SanitizedFilename),
+ [](char C) { return !isalnum(C); }, '_');
+ Twine Prefix = Twine("_binary_") + SanitizedFilename;
+
+ SymTab->addSymbol(Prefix + "_start", STB_GLOBAL, STT_NOTYPE, &DataSection,
+ /*Value=*/0, STV_DEFAULT, 0, 0);
+ SymTab->addSymbol(Prefix + "_end", STB_GLOBAL, STT_NOTYPE, &DataSection,
+ /*Value=*/DataSection.Size, STV_DEFAULT, 0, 0);
+ SymTab->addSymbol(Prefix + "_size", STB_GLOBAL, STT_NOTYPE, nullptr,
+ /*Value=*/DataSection.Size, STV_DEFAULT, SHN_ABS, 0);
+}
+
+void BinaryELFBuilder::initSections() {
+ for (auto &Section : Obj->sections()) {
+ Section.initialize(Obj->sections());
+ }
+}
+
+std::unique_ptr<Object> BinaryELFBuilder::build() {
+ initFileHeader();
+ initHeaderSegment();
+ StringTableSection *StrTab = addStrTab();
+ SymbolTableSection *SymTab = addSymTab(StrTab);
+ initSections();
+ addData(SymTab);
+
+ return std::move(Obj);
+}
+
template <class ELFT> void ELFBuilder<ELFT>::setParentSegment(Segment &Child) {
for (auto &Parent : Obj.segments()) {
// Every segment will overlap with itself but we don't want a segment to
@@ -633,15 +898,6 @@ template <class ELFT> void ELFBuilder<ELFT>::readProgramHeaders() {
}
auto &ElfHdr = Obj.ElfHdrSegment;
- // Creating multiple PT_PHDR segments technically is not valid, but PT_LOAD
- // segments must not overlap, and other types fit even less.
- ElfHdr.Type = PT_PHDR;
- ElfHdr.Flags = 0;
- ElfHdr.OriginalOffset = ElfHdr.Offset = 0;
- ElfHdr.VAddr = 0;
- ElfHdr.PAddr = 0;
- ElfHdr.FileSize = ElfHdr.MemSize = sizeof(Elf_Ehdr);
- ElfHdr.Align = 0;
ElfHdr.Index = Index++;
const auto &Ehdr = *ElfFile.getHeader();
@@ -725,8 +981,7 @@ void ELFBuilder<ELFT>::initSymbolTable(SymbolTableSection *SymTab) {
Elf_Word Index = ShndxData[&Sym - Symbols.begin()];
DefSection = Obj.sections().getSection(
Index,
- "Symbol '" + Name + "' has invalid section index " +
- Twine(Index));
+ "Symbol '" + Name + "' has invalid section index " + Twine(Index));
} else if (Sym.st_shndx >= SHN_LORESERVE) {
if (!isValidReservedSectionIndex(Sym.st_shndx, Obj.Machine)) {
error(
@@ -828,10 +1083,20 @@ SectionBase &ELFBuilder<ELFT>::makeSection(const Elf_Shdr &Shdr) {
}
case SHT_NOBITS:
return Obj.addSection<Section>(Data);
- default:
+ default: {
Data = unwrapOrError(ElfFile.getSectionContents(&Shdr));
+
+ if (isDataGnuCompressed(Data) || (Shdr.sh_flags & ELF::SHF_COMPRESSED)) {
+ uint64_t DecompressedSize, DecompressedAlign;
+ std::tie(DecompressedSize, DecompressedAlign) =
+ getDecompressedSizeAndAlignment<ELFT>(Data);
+ return Obj.addSection<CompressedSection>(Data, DecompressedSize,
+ DecompressedAlign);
+ }
+
return Obj.addSection<Section>(Data);
}
+ }
}
template <class ELFT> void ELFBuilder<ELFT>::readSectionHeaders() {
@@ -854,6 +1119,9 @@ template <class ELFT> void ELFBuilder<ELFT>::readSectionHeaders() {
Sec.Align = Shdr.sh_addralign;
Sec.EntrySize = Shdr.sh_entsize;
Sec.Index = Index++;
+ Sec.OriginalData =
+ ArrayRef<uint8_t>(ElfFile.base() + Shdr.sh_offset,
+ (Shdr.sh_type == SHT_NOBITS) ? 0 : Shdr.sh_size);
}
// If a section index table exists we'll need to initialize it before we
@@ -894,7 +1162,8 @@ template <class ELFT> void ELFBuilder<ELFT>::readSectionHeaders() {
template <class ELFT> void ELFBuilder<ELFT>::build() {
const auto &Ehdr = *ElfFile.getHeader();
- std::copy(Ehdr.e_ident, Ehdr.e_ident + 16, Obj.Ident);
+ Obj.OSABI = Ehdr.e_ident[EI_OSABI];
+ Obj.ABIVersion = Ehdr.e_ident[EI_ABIVERSION];
Obj.Type = Ehdr.e_type;
Obj.Machine = Ehdr.e_machine;
Obj.Version = Ehdr.e_version;
@@ -926,34 +1195,26 @@ Writer::~Writer() {}
Reader::~Reader() {}
-ElfType ELFReader::getElfType() const {
- if (isa<ELFObjectFile<ELF32LE>>(Bin))
- return ELFT_ELF32LE;
- if (isa<ELFObjectFile<ELF64LE>>(Bin))
- return ELFT_ELF64LE;
- if (isa<ELFObjectFile<ELF32BE>>(Bin))
- return ELFT_ELF32BE;
- if (isa<ELFObjectFile<ELF64BE>>(Bin))
- return ELFT_ELF64BE;
- llvm_unreachable("Invalid ELFType");
+std::unique_ptr<Object> BinaryReader::create() const {
+ return BinaryELFBuilder(MInfo.EMachine, MemBuf).build();
}
std::unique_ptr<Object> ELFReader::create() const {
auto Obj = llvm::make_unique<Object>();
- if (auto *o = dyn_cast<ELFObjectFile<ELF32LE>>(Bin)) {
- ELFBuilder<ELF32LE> Builder(*o, *Obj);
+ if (auto *O = dyn_cast<ELFObjectFile<ELF32LE>>(Bin)) {
+ ELFBuilder<ELF32LE> Builder(*O, *Obj);
Builder.build();
return Obj;
- } else if (auto *o = dyn_cast<ELFObjectFile<ELF64LE>>(Bin)) {
- ELFBuilder<ELF64LE> Builder(*o, *Obj);
+ } else if (auto *O = dyn_cast<ELFObjectFile<ELF64LE>>(Bin)) {
+ ELFBuilder<ELF64LE> Builder(*O, *Obj);
Builder.build();
return Obj;
- } else if (auto *o = dyn_cast<ELFObjectFile<ELF32BE>>(Bin)) {
- ELFBuilder<ELF32BE> Builder(*o, *Obj);
+ } else if (auto *O = dyn_cast<ELFObjectFile<ELF32BE>>(Bin)) {
+ ELFBuilder<ELF32BE> Builder(*O, *Obj);
Builder.build();
return Obj;
- } else if (auto *o = dyn_cast<ELFObjectFile<ELF64BE>>(Bin)) {
- ELFBuilder<ELF64BE> Builder(*o, *Obj);
+ } else if (auto *O = dyn_cast<ELFObjectFile<ELF64BE>>(Bin)) {
+ ELFBuilder<ELF64BE> Builder(*O, *Obj);
Builder.build();
return Obj;
}
@@ -963,18 +1224,31 @@ std::unique_ptr<Object> ELFReader::create() const {
template <class ELFT> void ELFWriter<ELFT>::writeEhdr() {
uint8_t *B = Buf.getBufferStart();
Elf_Ehdr &Ehdr = *reinterpret_cast<Elf_Ehdr *>(B);
- std::copy(Obj.Ident, Obj.Ident + 16, Ehdr.e_ident);
+ std::fill(Ehdr.e_ident, Ehdr.e_ident + 16, 0);
+ Ehdr.e_ident[EI_MAG0] = 0x7f;
+ Ehdr.e_ident[EI_MAG1] = 'E';
+ Ehdr.e_ident[EI_MAG2] = 'L';
+ Ehdr.e_ident[EI_MAG3] = 'F';
+ Ehdr.e_ident[EI_CLASS] = ELFT::Is64Bits ? ELFCLASS64 : ELFCLASS32;
+ Ehdr.e_ident[EI_DATA] =
+ ELFT::TargetEndianness == support::big ? ELFDATA2MSB : ELFDATA2LSB;
+ Ehdr.e_ident[EI_VERSION] = EV_CURRENT;
+ Ehdr.e_ident[EI_OSABI] = Obj.OSABI;
+ Ehdr.e_ident[EI_ABIVERSION] = Obj.ABIVersion;
+
Ehdr.e_type = Obj.Type;
Ehdr.e_machine = Obj.Machine;
Ehdr.e_version = Obj.Version;
Ehdr.e_entry = Obj.Entry;
- Ehdr.e_phoff = Obj.ProgramHdrSegment.Offset;
+ // We have to use the fully-qualified name llvm::size
+ // since some compilers complain on ambiguous resolution.
+ Ehdr.e_phnum = llvm::size(Obj.segments());
+ Ehdr.e_phoff = (Ehdr.e_phnum != 0) ? Obj.ProgramHdrSegment.Offset : 0;
+ Ehdr.e_phentsize = (Ehdr.e_phnum != 0) ? sizeof(Elf_Phdr) : 0;
Ehdr.e_flags = Obj.Flags;
Ehdr.e_ehsize = sizeof(Elf_Ehdr);
- Ehdr.e_phentsize = sizeof(Elf_Phdr);
- Ehdr.e_phnum = size(Obj.segments());
- Ehdr.e_shentsize = sizeof(Elf_Shdr);
- if (WriteSectionHeaders) {
+ if (WriteSectionHeaders && size(Obj.sections()) != 0) {
+ Ehdr.e_shentsize = sizeof(Elf_Shdr);
Ehdr.e_shoff = Obj.SHOffset;
// """
// If the number of sections is greater than or equal to
@@ -998,6 +1272,7 @@ template <class ELFT> void ELFWriter<ELFT>::writeEhdr() {
else
Ehdr.e_shstrndx = Obj.SectionNames->Index;
} else {
+ Ehdr.e_shentsize = 0;
Ehdr.e_shoff = 0;
Ehdr.e_shnum = 0;
Ehdr.e_shstrndx = 0;
@@ -1106,7 +1381,7 @@ static uint64_t alignToAddr(uint64_t Offset, uint64_t Addr, uint64_t Align) {
}
// Orders segments such that if x = y->ParentSegment then y comes before x.
-static void OrderSegments(std::vector<Segment *> &Segments) {
+static void orderSegments(std::vector<Segment *> &Segments) {
std::stable_sort(std::begin(Segments), std::end(Segments),
compareSegmentsByOffset);
}
@@ -1148,7 +1423,7 @@ static uint64_t LayoutSegments(std::vector<Segment *> &Segments,
// 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 Range>
-static uint64_t LayoutSections(Range Sections, uint64_t Offset) {
+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
@@ -1172,6 +1447,17 @@ static uint64_t LayoutSections(Range Sections, uint64_t Offset) {
return Offset;
}
+template <class ELFT> void ELFWriter<ELFT>::initEhdrSegment() {
+ auto &ElfHdr = Obj.ElfHdrSegment;
+ ElfHdr.Type = PT_PHDR;
+ ElfHdr.Flags = 0;
+ ElfHdr.OriginalOffset = ElfHdr.Offset = 0;
+ ElfHdr.VAddr = 0;
+ ElfHdr.PAddr = 0;
+ ElfHdr.FileSize = ElfHdr.MemSize = sizeof(Elf_Ehdr);
+ ElfHdr.Align = 0;
+}
+
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
@@ -1181,17 +1467,17 @@ template <class ELFT> void ELFWriter<ELFT>::assignOffsets() {
OrderedSegments.push_back(&Segment);
OrderedSegments.push_back(&Obj.ElfHdrSegment);
OrderedSegments.push_back(&Obj.ProgramHdrSegment);
- OrderSegments(OrderedSegments);
+ orderSegments(OrderedSegments);
// Offset is used as the start offset of the first segment to be laid out.
// Since the ELF Header (ElfHdrSegment) must be at the start of the file,
// we start at offset 0.
uint64_t Offset = 0;
Offset = LayoutSegments(OrderedSegments, Offset);
- Offset = LayoutSections(Obj.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 (WriteSectionHeaders)
- Offset = alignTo(Offset, sizeof(typename ELFT::Addr));
+ Offset = alignTo(Offset, sizeof(Elf_Addr));
Obj.SHOffset = Offset;
}
@@ -1263,10 +1549,17 @@ template <class ELFT> void ELFWriter<ELFT>::finalize() {
Obj.SectionNames->addString(Section.Name);
}
+ initEhdrSegment();
+
// Before we can prepare for layout the indexes need to be finalized.
+ // Also, the output arch may not be the same as the input arch, so fix up
+ // size-related fields before doing layout calculations.
uint64_t Index = 0;
- for (auto &Sec : Obj.sections())
+ auto SecSizer = llvm::make_unique<ELFSectionSizer<ELFT>>();
+ for (auto &Sec : Obj.sections()) {
Sec.Index = Index++;
+ Sec.accept(*SecSizer);
+ }
// The symbol table does not update all other sections on update. For
// instance, symbol names are not added as new symbols are added. This means
@@ -1324,10 +1617,10 @@ void BinaryWriter::finalize() {
// loading and physical addresses are intended for ROM loading.
// However, if no segment has a physical address, we'll fallback to using
// virtual addresses for all.
- if (std::all_of(std::begin(OrderedSegments), std::end(OrderedSegments),
- [](const Segment *Segment) { return Segment->PAddr == 0; }))
- for (const auto &Segment : OrderedSegments)
- Segment->PAddr = Segment->VAddr;
+ if (all_of(OrderedSegments,
+ [](const Segment *Seg) { return Seg->PAddr == 0; }))
+ for (Segment *Seg : OrderedSegments)
+ Seg->PAddr = Seg->VAddr;
std::stable_sort(std::begin(OrderedSegments), std::end(OrderedSegments),
compareSegmentsByPAddr);
@@ -1342,8 +1635,8 @@ void BinaryWriter::finalize() {
uint64_t Offset = 0;
// Modify the first segment so that there is no gap at the start. This allows
- // our layout algorithm to proceed as expected while not out writing out the
- // gap at the start.
+ // our layout algorithm to proceed as expected while not writing out the gap
+ // at the start.
if (!OrderedSegments.empty()) {
auto Seg = OrderedSegments[0];
auto Sec = Seg->firstSection();
@@ -1371,7 +1664,7 @@ void BinaryWriter::finalize() {
continue;
AllocatedSections.push_back(&Section);
}
- LayoutSections(make_pointee_range(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
@@ -1387,9 +1680,6 @@ void BinaryWriter::finalize() {
SecWriter = llvm::make_unique<BinarySectionWriter>(Buf);
}
-namespace llvm {
-namespace objcopy {
-
template class ELFBuilder<ELF64LE>;
template class ELFBuilder<ELF64BE>;
template class ELFBuilder<ELF32LE>;
@@ -1399,5 +1689,7 @@ template class ELFWriter<ELF64LE>;
template class ELFWriter<ELF64BE>;
template class ELFWriter<ELF32LE>;
template class ELFWriter<ELF32BE>;
+
+} // end namespace elf
} // end namespace objcopy
} // end namespace llvm
diff --git a/contrib/llvm/tools/llvm-objcopy/Object.h b/contrib/llvm/tools/llvm-objcopy/ELF/Object.h
index 76748d5fc641..e5730cd543ee 100644
--- a/contrib/llvm/tools/llvm-objcopy/Object.h
+++ b/contrib/llvm/tools/llvm-objcopy/ELF/Object.h
@@ -10,6 +10,8 @@
#ifndef LLVM_TOOLS_OBJCOPY_OBJECT_H
#define LLVM_TOOLS_OBJCOPY_OBJECT_H
+#include "Buffer.h"
+#include "CopyConfig.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
@@ -26,9 +28,10 @@
#include <vector>
namespace llvm {
+enum class DebugCompressionType;
namespace objcopy {
+namespace elf {
-class Buffer;
class SectionBase;
class Section;
class OwnedDataSection;
@@ -39,6 +42,8 @@ class DynamicRelocationSection;
class GnuDebugLinkSection;
class GroupSection;
class SectionIndexSection;
+class CompressedSection;
+class DecompressedSection;
class Segment;
class Object;
struct Symbol;
@@ -66,7 +71,7 @@ enum ElfType { ELFT_ELF32LE, ELFT_ELF64LE, ELFT_ELF32BE, ELFT_ELF64BE };
class SectionVisitor {
public:
- virtual ~SectionVisitor();
+ virtual ~SectionVisitor() = default;
virtual void visit(const Section &Sec) = 0;
virtual void visit(const OwnedDataSection &Sec) = 0;
@@ -77,6 +82,25 @@ public:
virtual void visit(const GnuDebugLinkSection &Sec) = 0;
virtual void visit(const GroupSection &Sec) = 0;
virtual void visit(const SectionIndexSection &Sec) = 0;
+ virtual void visit(const CompressedSection &Sec) = 0;
+ virtual void visit(const DecompressedSection &Sec) = 0;
+};
+
+class MutableSectionVisitor {
+public:
+ virtual ~MutableSectionVisitor() = default;
+
+ virtual void visit(Section &Sec) = 0;
+ virtual void visit(OwnedDataSection &Sec) = 0;
+ virtual void visit(StringTableSection &Sec) = 0;
+ virtual void visit(SymbolTableSection &Sec) = 0;
+ virtual void visit(RelocationSection &Sec) = 0;
+ virtual void visit(DynamicRelocationSection &Sec) = 0;
+ virtual void visit(GnuDebugLinkSection &Sec) = 0;
+ virtual void visit(GroupSection &Sec) = 0;
+ virtual void visit(SectionIndexSection &Sec) = 0;
+ virtual void visit(CompressedSection &Sec) = 0;
+ virtual void visit(DecompressedSection &Sec) = 0;
};
class SectionWriter : public SectionVisitor {
@@ -95,6 +119,8 @@ public:
virtual void visit(const GnuDebugLinkSection &Sec) override = 0;
virtual void visit(const GroupSection &Sec) override = 0;
virtual void visit(const SectionIndexSection &Sec) override = 0;
+ virtual void visit(const CompressedSection &Sec) override = 0;
+ virtual void visit(const DecompressedSection &Sec) override = 0;
explicit SectionWriter(Buffer &Buf) : Out(Buf) {}
};
@@ -104,6 +130,7 @@ private:
using Elf_Word = typename ELFT::Word;
using Elf_Rel = typename ELFT::Rel;
using Elf_Rela = typename ELFT::Rela;
+ using Elf_Sym = typename ELFT::Sym;
public:
virtual ~ELFSectionWriter() {}
@@ -112,13 +139,38 @@ public:
void visit(const GnuDebugLinkSection &Sec) override;
void visit(const GroupSection &Sec) override;
void visit(const SectionIndexSection &Sec) override;
+ void visit(const CompressedSection &Sec) override;
+ void visit(const DecompressedSection &Sec) override;
explicit ELFSectionWriter(Buffer &Buf) : SectionWriter(Buf) {}
};
+template <class ELFT> class ELFSectionSizer : public MutableSectionVisitor {
+private:
+ using Elf_Rel = typename ELFT::Rel;
+ using Elf_Rela = typename ELFT::Rela;
+ using Elf_Sym = typename ELFT::Sym;
+ using Elf_Word = typename ELFT::Word;
+ using Elf_Xword = typename ELFT::Xword;
+
+public:
+ void visit(Section &Sec) override;
+ void visit(OwnedDataSection &Sec) override;
+ void visit(StringTableSection &Sec) override;
+ void visit(DynamicRelocationSection &Sec) override;
+ void visit(SymbolTableSection &Sec) override;
+ void visit(RelocationSection &Sec) override;
+ void visit(GnuDebugLinkSection &Sec) override;
+ void visit(GroupSection &Sec) override;
+ void visit(SectionIndexSection &Sec) override;
+ void visit(CompressedSection &Sec) override;
+ void visit(DecompressedSection &Sec) override;
+};
+
#define MAKE_SEC_WRITER_FRIEND \
friend class SectionWriter; \
- template <class ELFT> friend class ELFSectionWriter;
+ template <class ELFT> friend class ELFSectionWriter; \
+ template <class ELFT> friend class ELFSectionSizer;
class BinarySectionWriter : public SectionWriter {
public:
@@ -129,52 +181,12 @@ public:
void visit(const GnuDebugLinkSection &Sec) override;
void visit(const GroupSection &Sec) override;
void visit(const SectionIndexSection &Sec) override;
+ void visit(const CompressedSection &Sec) override;
+ void visit(const DecompressedSection &Sec) override;
explicit BinarySectionWriter(Buffer &Buf) : SectionWriter(Buf) {}
};
-// The class Buffer abstracts out the common interface of FileOutputBuffer and
-// WritableMemoryBuffer so that the hierarchy of Writers depends on this
-// abstract interface and doesn't depend on a particular implementation.
-// TODO: refactor the buffer classes in LLVM to enable us to use them here
-// directly.
-class Buffer {
- StringRef Name;
-
-public:
- virtual ~Buffer();
- virtual void allocate(size_t Size) = 0;
- virtual uint8_t *getBufferStart() = 0;
- virtual Error commit() = 0;
-
- explicit Buffer(StringRef Name) : Name(Name) {}
- StringRef getName() const { return Name; }
-};
-
-class FileBuffer : public Buffer {
- std::unique_ptr<FileOutputBuffer> Buf;
-
-public:
- void allocate(size_t Size) override;
- uint8_t *getBufferStart() override;
- Error commit() override;
-
- explicit FileBuffer(StringRef FileName) : Buffer(FileName) {}
-};
-
-class MemBuffer : public Buffer {
- std::unique_ptr<WritableMemoryBuffer> Buf;
-
-public:
- void allocate(size_t Size) override;
- uint8_t *getBufferStart() override;
- Error commit() override;
-
- explicit MemBuffer(StringRef Name) : Buffer(Name) {}
-
- std::unique_ptr<WritableMemoryBuffer> releaseMemoryBuffer();
-};
-
class Writer {
protected:
Object &Obj;
@@ -190,10 +202,13 @@ public:
template <class ELFT> class ELFWriter : public Writer {
private:
+ using Elf_Addr = typename ELFT::Addr;
using Elf_Shdr = typename ELFT::Shdr;
using Elf_Phdr = typename ELFT::Phdr;
using Elf_Ehdr = typename ELFT::Ehdr;
+ void initEhdrSegment();
+
void writeEhdr();
void writePhdr(const Segment &Seg);
void writeShdr(const SectionBase &Sec);
@@ -233,7 +248,7 @@ public:
class SectionBase {
public:
- StringRef Name;
+ std::string Name;
Segment *ParentSegment = nullptr;
uint64_t HeaderOffset;
uint64_t OriginalOffset = std::numeric_limits<uint64_t>::max();
@@ -250,6 +265,10 @@ public:
uint64_t Offset = 0;
uint64_t Size = 0;
uint64_t Type = ELF::SHT_NULL;
+ ArrayRef<uint8_t> OriginalData;
+
+ SectionBase() = default;
+ SectionBase(const SectionBase &) = default;
virtual ~SectionBase() = default;
@@ -258,6 +277,7 @@ public:
virtual void removeSectionReferences(const SectionBase *Sec);
virtual void removeSymbols(function_ref<bool(const Symbol &)> ToRemove);
virtual void accept(SectionVisitor &Visitor) const = 0;
+ virtual void accept(MutableSectionVisitor &Visitor) = 0;
virtual void markSymbols();
};
@@ -275,21 +295,21 @@ private:
};
std::set<const SectionBase *, SectionCompare> Sections;
- ArrayRef<uint8_t> Contents;
public:
- uint64_t Align;
- uint64_t FileSize;
+ uint32_t Type;
uint32_t Flags;
- uint32_t Index;
- uint64_t MemSize;
uint64_t Offset;
- uint64_t PAddr;
- uint64_t Type;
uint64_t VAddr;
+ uint64_t PAddr;
+ uint64_t FileSize;
+ uint64_t MemSize;
+ uint64_t Align;
+ uint32_t Index;
uint64_t OriginalOffset;
Segment *ParentSegment = nullptr;
+ ArrayRef<uint8_t> Contents;
explicit Segment(ArrayRef<uint8_t> Data) : Contents(Data) {}
Segment() {}
@@ -314,6 +334,7 @@ public:
explicit Section(ArrayRef<uint8_t> Data) : Contents(Data) {}
void accept(SectionVisitor &Visitor) const override;
+ void accept(MutableSectionVisitor &Visitor) override;
void removeSectionReferences(const SectionBase *Sec) override;
void initialize(SectionTableRef SecTable) override;
void finalize() override;
@@ -327,13 +348,57 @@ class OwnedDataSection : public SectionBase {
public:
OwnedDataSection(StringRef SecName, ArrayRef<uint8_t> Data)
: Data(std::begin(Data), std::end(Data)) {
- Name = SecName;
+ Name = SecName.str();
Type = ELF::SHT_PROGBITS;
Size = Data.size();
OriginalOffset = std::numeric_limits<uint64_t>::max();
}
void accept(SectionVisitor &Sec) const override;
+ void accept(MutableSectionVisitor &Visitor) override;
+};
+
+class CompressedSection : public SectionBase {
+ MAKE_SEC_WRITER_FRIEND
+
+ DebugCompressionType CompressionType;
+ uint64_t DecompressedSize;
+ uint64_t DecompressedAlign;
+ SmallVector<char, 128> CompressedData;
+
+public:
+ CompressedSection(const SectionBase &Sec,
+ DebugCompressionType CompressionType);
+ CompressedSection(ArrayRef<uint8_t> CompressedData, uint64_t DecompressedSize,
+ uint64_t DecompressedAlign);
+
+ uint64_t getDecompressedSize() const { return DecompressedSize; }
+ uint64_t getDecompressedAlign() const { return DecompressedAlign; }
+
+ void accept(SectionVisitor &Visitor) const override;
+ void accept(MutableSectionVisitor &Visitor) override;
+
+ static bool classof(const SectionBase *S) {
+ return (S->Flags & ELF::SHF_COMPRESSED) ||
+ (StringRef(S->Name).startswith(".zdebug"));
+ }
+};
+
+class DecompressedSection : public SectionBase {
+ MAKE_SEC_WRITER_FRIEND
+
+public:
+ explicit DecompressedSection(const CompressedSection &Sec)
+ : SectionBase(Sec) {
+ Size = Sec.getDecompressedSize();
+ Align = Sec.getDecompressedAlign();
+ Flags = (Flags & ~ELF::SHF_COMPRESSED);
+ if (StringRef(Name).startswith(".zdebug"))
+ Name = "." + Name.substr(2);
+ }
+
+ void accept(SectionVisitor &Visitor) const override;
+ void accept(MutableSectionVisitor &Visitor) override;
};
// There are two types of string tables that can exist, dynamic and not dynamic.
@@ -358,6 +423,7 @@ public:
uint32_t findIndex(StringRef Name) const;
void finalize() override;
void accept(SectionVisitor &Visitor) const override;
+ void accept(MutableSectionVisitor &Visitor) override;
static bool classof(const SectionBase *S) {
if (S->Flags & ELF::SHF_ALLOC)
@@ -386,7 +452,7 @@ struct Symbol {
SectionBase *DefinedIn = nullptr;
SymbolShndxType ShndxType;
uint32_t Index;
- StringRef Name;
+ std::string Name;
uint32_t NameIndex;
uint64_t Size;
uint8_t Type;
@@ -395,6 +461,7 @@ struct Symbol {
bool Referenced = false;
uint16_t getShndx() const;
+ bool isCommon() const;
};
class SectionIndexSection : public SectionBase {
@@ -414,6 +481,7 @@ public:
void initialize(SectionTableRef SecTable) override;
void finalize() override;
void accept(SectionVisitor &Visitor) const override;
+ void accept(MutableSectionVisitor &Visitor) override;
SectionIndexSection() {
Name = ".symtab_shndx";
@@ -437,9 +505,11 @@ protected:
using SymPtr = std::unique_ptr<Symbol>;
public:
- void addSymbol(StringRef Name, uint8_t Bind, uint8_t Type,
- SectionBase *DefinedIn, uint64_t Value, uint8_t Visibility,
- uint16_t Shndx, uint64_t Sz);
+ SymbolTableSection() { Type = ELF::SHT_SYMTAB; }
+
+ void addSymbol(Twine Name, uint8_t Bind, uint8_t Type, SectionBase *DefinedIn,
+ uint64_t Value, uint8_t Visibility, uint16_t Shndx,
+ uint64_t Size);
void prepareForLayout();
// An 'empty' symbol table still contains a null symbol.
bool empty() const { return Symbols.size() == 1; }
@@ -456,6 +526,7 @@ public:
void initialize(SectionTableRef SecTable) override;
void finalize() override;
void accept(SectionVisitor &Visitor) const override;
+ void accept(MutableSectionVisitor &Visitor) override;
void removeSymbols(function_ref<bool(const Symbol &)> ToRemove) override;
static bool classof(const SectionBase *S) {
@@ -517,6 +588,7 @@ class RelocationSection
public:
void addRelocation(Relocation Rel) { Relocations.push_back(Rel); }
void accept(SectionVisitor &Visitor) const override;
+ void accept(MutableSectionVisitor &Visitor) override;
void removeSymbols(function_ref<bool(const Symbol &)> ToRemove) override;
void markSymbols() override;
@@ -549,8 +621,8 @@ public:
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 accept(MutableSectionVisitor &Visitor) override;
void finalize() override;
void removeSymbols(function_ref<bool(const Symbol &)> ToRemove) override;
void markSymbols() override;
@@ -589,6 +661,7 @@ public:
explicit DynamicRelocationSection(ArrayRef<uint8_t> Data) : Contents(Data) {}
void accept(SectionVisitor &) const override;
+ void accept(MutableSectionVisitor &Visitor) override;
static bool classof(const SectionBase *S) {
if (!(S->Flags & ELF::SHF_ALLOC))
@@ -610,6 +683,7 @@ public:
// If we add this section from an external source we can use this ctor.
explicit GnuDebugLinkSection(StringRef File);
void accept(SectionVisitor &Visitor) const override;
+ void accept(MutableSectionVisitor &Visitor) override;
};
class Reader {
@@ -623,11 +697,29 @@ using object::ELFFile;
using object::ELFObjectFile;
using object::OwningBinary;
+class BinaryELFBuilder {
+ uint16_t EMachine;
+ MemoryBuffer *MemBuf;
+ std::unique_ptr<Object> Obj;
+
+ void initFileHeader();
+ void initHeaderSegment();
+ StringTableSection *addStrTab();
+ SymbolTableSection *addSymTab(StringTableSection *StrTab);
+ void addData(SymbolTableSection *SymTab);
+ void initSections();
+
+public:
+ BinaryELFBuilder(uint16_t EM, MemoryBuffer *MB)
+ : EMachine(EM), MemBuf(MB), Obj(llvm::make_unique<Object>()) {}
+
+ std::unique_ptr<Object> build();
+};
+
template <class ELFT> class ELFBuilder {
private:
using Elf_Addr = typename ELFT::Addr;
using Elf_Shdr = typename ELFT::Shdr;
- using Elf_Ehdr = typename ELFT::Ehdr;
using Elf_Word = typename ELFT::Word;
const ELFFile<ELFT> &ElfFile;
@@ -647,13 +739,22 @@ public:
void build();
};
+class BinaryReader : public Reader {
+ const MachineInfo &MInfo;
+ MemoryBuffer *MemBuf;
+
+public:
+ BinaryReader(const MachineInfo &MI, MemoryBuffer *MB)
+ : MInfo(MI), MemBuf(MB) {}
+ std::unique_ptr<Object> create() const override;
+};
+
class ELFReader : public Reader {
Binary *Bin;
public:
- ElfType getElfType() const;
std::unique_ptr<Object> create() const override;
- explicit ELFReader(Binary *B) : Bin(B){};
+ explicit ELFReader(Binary *B) : Bin(B) {}
};
class Object {
@@ -682,7 +783,8 @@ public:
Segment ElfHdrSegment;
Segment ProgramHdrSegment;
- uint8_t Ident[16];
+ uint8_t OSABI;
+ uint8_t ABIVersion;
uint64_t Entry;
uint64_t SHOffset;
uint32_t Type;
@@ -708,6 +810,7 @@ public:
auto Sec = llvm::make_unique<T>(std::forward<Ts>(Args)...);
auto Ptr = Sec.get();
Sections.emplace_back(std::move(Sec));
+ Ptr->Index = Sections.size();
return *Ptr;
}
Segment &addSegment(ArrayRef<uint8_t> Data) {
@@ -715,6 +818,8 @@ public:
return *Segments.back();
}
};
+
+} // end namespace elf
} // end namespace objcopy
} // end namespace llvm
diff --git a/contrib/llvm/tools/llvm-objcopy/ObjcopyOpts.td b/contrib/llvm/tools/llvm-objcopy/ObjcopyOpts.td
index 2af2108d98d3..1f7e64e4091c 100644
--- a/contrib/llvm/tools/llvm-objcopy/ObjcopyOpts.td
+++ b/contrib/llvm/tools/llvm-objcopy/ObjcopyOpts.td
@@ -1,55 +1,98 @@
include "llvm/Option/OptParser.td"
-multiclass Eq<string name> {
- def NAME: Separate<["--", "-"], name>;
- def NAME # _eq: Joined<["--", "-"], name # "=">, Alias<!cast<Separate>(NAME)>;
+multiclass Eq<string name, string help> {
+ def NAME : Separate<["--", "-"], name>;
+ def NAME #_eq : Joined<["--", "-"], name #"=">,
+ Alias<!cast<Separate>(NAME)>,
+ HelpText<help>;
}
def help : Flag<["-", "--"], "help">;
-defm binary_architecture : Eq<"binary-architecture">,
- HelpText<"Used when transforming an architecture-less format (such as binary) to another format">;
-def B : JoinedOrSeparate<["-"], "B">,
- Alias<binary_architecture>;
-defm input_target : Eq<"input-target">,
- HelpText<"Format of the input file">,
+
+defm binary_architecture
+ : Eq<"binary-architecture", "Used when transforming an architecture-less "
+ "format (such as binary) to another format">;
+def B : JoinedOrSeparate<["-"], "B">, Alias<binary_architecture>;
+
+defm target : Eq<"target", "Format of the input and output file">,
+ Values<"binary">;
+def F : JoinedOrSeparate<["-"], "F">, Alias<target>;
+
+defm input_target : Eq<"input-target", "Format of the input file">,
Values<"binary">;
-defm output_target : Eq<"output-target">,
- HelpText<"Format of the output file">,
+def I : JoinedOrSeparate<["-"], "I">, Alias<input_target>;
+
+defm output_target : Eq<"output-target", "Format of the output file">,
Values<"binary">;
-def O : JoinedOrSeparate<["-"], "O">,
- Alias<output_target>;
-defm split_dwo : Eq<"split-dwo">,
- MetaVarName<"dwo-file">,
- HelpText<"Equivalent to extract-dwo on the input file to <dwo-file>, then strip-dwo on the input file">;
-defm add_gnu_debuglink : Eq<"add-gnu-debuglink">,
- MetaVarName<"debug-file">,
- HelpText<"Add a .gnu_debuglink for <debug-file>">;
-defm remove_section : Eq<"remove-section">,
- MetaVarName<"section">,
- HelpText<"Remove <section>">;
-defm rename_section : Eq<"rename-section">,
- MetaVarName<"old=new">,
- HelpText<"Renames a section from old to new">;
-defm redefine_symbol : Eq<"redefine-sym">,
- MetaVarName<"old=new">,
- HelpText<"Change the name of a symbol old to new">;
-def R : JoinedOrSeparate<["-"], "R">,
- Alias<remove_section>;
-defm keep : Eq<"keep">,
- MetaVarName<"section">,
- HelpText<"Keep <section>">;
-defm only_keep : Eq<"only-keep">,
- MetaVarName<"section">,
- HelpText<"Remove all but <section>">;
-def j : JoinedOrSeparate<["-"], "j">,
- Alias<only_keep>;
-defm add_section : Eq<"add-section">,
- MetaVarName<"section=file">,
- HelpText<"Make a section named <section> with the contents of <file>.">;
-def strip_all : Flag<["-", "--"], "strip-all">,
- HelpText<"Remove non-allocated sections other than .gnu.warning* sections">;
+def O : JoinedOrSeparate<["-"], "O">, Alias<output_target>;
+
+def compress_debug_sections : Flag<["--", "-"], "compress-debug-sections">;
+def compress_debug_sections_eq
+ : Joined<["--", "-"], "compress-debug-sections=">,
+ MetaVarName<"[ zlib | zlib-gnu ]">,
+ HelpText<"Compress DWARF debug sections using specified style. Supported "
+ "styles: 'zlib-gnu' and 'zlib'">;
+def decompress_debug_sections : Flag<["-", "--"], "decompress-debug-sections">,
+ HelpText<"Decompress DWARF debug sections.">;
+defm split_dwo
+ : Eq<"split-dwo", "Equivalent to extract-dwo on the input file to "
+ "<dwo-file>, then strip-dwo on the input file">,
+ MetaVarName<"dwo-file">;
+
+def enable_deterministic_archives
+ : Flag<["-", "--"], "enable-deterministic-archives">,
+ HelpText<"Enable deterministic mode when copying archives (use zero for "
+ "UIDs, GIDs, and timestamps).">;
+def D : Flag<["-"], "D">,
+ Alias<enable_deterministic_archives>,
+ HelpText<"Alias for --enable-deterministic-archives">;
+
+def disable_deterministic_archives
+ : Flag<["-", "--"], "disable-deterministic-archives">,
+ HelpText<"Disable deterministic mode when copying archives (use real "
+ "values for UIDs, GIDs, and timestamps).">;
+def U : Flag<["-"], "U">,
+ Alias<disable_deterministic_archives>,
+ HelpText<"Alias for --disable-deterministic-archives">;
+
+def preserve_dates : Flag<["-", "--"], "preserve-dates">,
+ HelpText<"Preserve access and modification timestamps">;
+def p : Flag<["-"], "p">, Alias<preserve_dates>;
+
+defm add_gnu_debuglink
+ : Eq<"add-gnu-debuglink", "Add a .gnu_debuglink for <debug-file>">,
+ MetaVarName<"debug-file">;
+
+defm remove_section : Eq<"remove-section", "Remove <section>">,
+ MetaVarName<"section">;
+def R : JoinedOrSeparate<["-"], "R">, Alias<remove_section>;
+
+defm rename_section
+ : Eq<"rename-section",
+ "Renames a section from old to new, optionally with specified flags. "
+ "Flags supported for GNU compatibility: alloc, load, noload, "
+ "readonly, debug, code, data, rom, share, contents, merge, strings.">,
+ MetaVarName<"old=new[,flag1,...]">;
+defm redefine_symbol
+ : Eq<"redefine-sym", "Change the name of a symbol old to new">,
+ MetaVarName<"old=new">;
+defm keep_section : Eq<"keep-section", "Keep <section>">,
+ MetaVarName<"section">;
+defm only_section : Eq<"only-section", "Remove all but <section>">,
+ MetaVarName<"section">;
+def j : JoinedOrSeparate<["-"], "j">, Alias<only_section>;
+defm add_section
+ : Eq<"add-section",
+ "Make a section named <section> with the contents of <file>.">,
+ MetaVarName<"section=file">;
+
+def strip_all
+ : Flag<["-", "--"], "strip-all">,
+ HelpText<
+ "Remove non-allocated sections other than .gnu.warning* sections">;
+def S : Flag<["-"], "S">, Alias<strip_all>;
def strip_all_gnu : Flag<["-", "--"], "strip-all-gnu">,
- HelpText<"Compaitable with GNU objcopy's --strip-all">;
+ HelpText<"Compatible with GNU objcopy's --strip-all">;
def strip_debug : Flag<["-", "--"], "strip-debug">,
HelpText<"Remove all debug information">;
def strip_dwo : Flag<["-", "--"], "strip-dwo">,
@@ -58,42 +101,80 @@ def strip_sections : Flag<["-", "--"], "strip-sections">,
HelpText<"Remove all section headers">;
def strip_non_alloc : Flag<["-", "--"], "strip-non-alloc">,
HelpText<"Remove all non-allocated sections">;
-def extract_dwo : Flag<["-", "--"], "extract-dwo">,
- HelpText<"Remove all sections that are not DWARF .dwo sections from file">;
-def localize_hidden : Flag<["-", "--"], "localize-hidden">,
- HelpText<"Mark all symbols that have hidden or internal visibility as local">;
-defm localize_symbol : Eq<"localize-symbol">,
- MetaVarName<"symbol">,
- HelpText<"Mark <symbol> as local">;
-def L : JoinedOrSeparate<["-"], "L">,
- Alias<localize_symbol>;
-defm globalize_symbol : Eq<"globalize-symbol">,
- MetaVarName<"symbol">,
- HelpText<"Mark <symbol> as global">;
-defm weaken_symbol : Eq<"weaken-symbol">,
- MetaVarName<"symbol">,
- HelpText<"Mark <symbol> as weak">;
-def W : JoinedOrSeparate<["-"], "W">,
- Alias<weaken_symbol>;
-def weaken : Flag<["-", "--"], "weaken">,
- HelpText<"Mark all global symbols as weak">;
-def discard_all : Flag<["-", "--"], "discard-all">,
- HelpText<"Remove all local symbols except file and section symbols">;
-def x : Flag<["-"], "x">,
- Alias<discard_all>;
-defm strip_symbol : Eq<"strip-symbol">,
- MetaVarName<"symbol">,
- HelpText<"Remove symbol <symbol>">;
-def N : JoinedOrSeparate<["-"], "N">,
- Alias<strip_symbol>;
-defm keep_symbol : Eq<"keep-symbol">,
- MetaVarName<"symbol">,
- HelpText<"Do not remove symbol <symbol>">;
-def K : JoinedOrSeparate<["-"], "K">,
- Alias<keep_symbol>;
-def only_keep_debug : Flag<["-", "--"], "only-keep-debug">,
- HelpText<"Currently ignored. Only for compaitability with GNU objcopy.">;
def strip_unneeded : Flag<["-", "--"], "strip-unneeded">,
- HelpText<"Remove all symbols not needed by relocations">;
+ HelpText<"Remove all symbols not needed by relocations">;
+
+def extract_dwo
+ : Flag<["-", "--"], "extract-dwo">,
+ HelpText<
+ "Remove all sections that are not DWARF .dwo sections from file">;
+
+def localize_hidden
+ : Flag<["-", "--"], "localize-hidden">,
+ HelpText<
+ "Mark all symbols that have hidden or internal visibility as local">;
+defm localize_symbol : Eq<"localize-symbol", "Mark <symbol> as local">,
+ MetaVarName<"symbol">;
+def L : JoinedOrSeparate<["-"], "L">, Alias<localize_symbol>;
+
+defm globalize_symbol : Eq<"globalize-symbol", "Mark <symbol> as global">,
+ MetaVarName<"symbol">;
+defm keep_global_symbol
+ : Eq<"keep-global-symbol",
+ "Convert all symbols except <symbol> to local. May be repeated to "
+ "convert all except a set of symbols to local.">,
+ MetaVarName<"symbol">;
+def G : JoinedOrSeparate<["-"], "G">, Alias<keep_global_symbol>;
+
+defm keep_global_symbols
+ : Eq<"keep-global-symbols",
+ "Reads a list of symbols from <filename> and runs as if "
+ "--keep-global-symbol=<symbol> is set for each one. <filename> "
+ "contains one symbol per line and may contain comments beginning with "
+ "'#'. Leading and trailing whitespace is stripped from each line. May "
+ "be repeated to read symbols from many files.">,
+ MetaVarName<"filename">;
+
+defm weaken_symbol : Eq<"weaken-symbol", "Mark <symbol> as weak">,
+ MetaVarName<"symbol">;
+def W : JoinedOrSeparate<["-"], "W">, Alias<weaken_symbol>;
+def weaken : Flag<["-", "--"], "weaken">,
+ HelpText<"Mark all global symbols as weak">;
+def discard_all
+ : Flag<["-", "--"], "discard-all">,
+ HelpText<"Remove all local symbols except file and section symbols">;
+def x : Flag<["-"], "x">, Alias<discard_all>;
+defm strip_symbol : Eq<"strip-symbol", "Remove symbol <symbol>">,
+ MetaVarName<"symbol">;
+def N : JoinedOrSeparate<["-"], "N">, Alias<strip_symbol>;
+defm keep_symbol : Eq<"keep-symbol", "Do not remove symbol <symbol>">,
+ MetaVarName<"symbol">;
+def K : JoinedOrSeparate<["-"], "K">, Alias<keep_symbol>;
+def only_keep_debug
+ : Flag<["-", "--"], "only-keep-debug">,
+ HelpText<"Currently ignored. Only for compatibility with GNU objcopy.">;
def keep_file_symbols : Flag<["-", "--"], "keep-file-symbols">,
- HelpText<"Do not remove file symbols">;
+ HelpText<"Do not remove file symbols">;
+defm dump_section
+ : Eq<"dump-section",
+ "Dump contents of section named <section> into file <file>">,
+ MetaVarName<"section=file">;
+defm prefix_symbols
+ : Eq<"prefix-symbols", "Add <prefix> to the start of every symbol name">,
+ MetaVarName<"prefix">;
+
+def version : Flag<["-", "--"], "version">,
+ HelpText<"Print the version and exit.">;
+def V : Flag<["-"], "V">, Alias<version>;
+defm build_id_link_dir
+ : Eq<"build-id-link-dir", "Set directory for --build-id-link-input and "
+ "--build-id-link-output to <dir>">,
+ MetaVarName<"dir">;
+defm build_id_link_input
+ : Eq<"build-id-link-input", "Hard-link the input to <dir>/xx/xxx<suffix> "
+ "name derived from hex build ID">,
+ MetaVarName<"suffix">;
+defm build_id_link_output
+ : Eq<"build-id-link-output", "Hard-link the output to <dir>/xx/xxx<suffix> "
+ "name derived from hex build ID">,
+ MetaVarName<"suffix">;
diff --git a/contrib/llvm/tools/llvm-objcopy/StripOpts.td b/contrib/llvm/tools/llvm-objcopy/StripOpts.td
index 333b0d288efa..fa98e27e9321 100644
--- a/contrib/llvm/tools/llvm-objcopy/StripOpts.td
+++ b/contrib/llvm/tools/llvm-objcopy/StripOpts.td
@@ -1,49 +1,67 @@
include "llvm/Option/OptParser.td"
-multiclass Eq<string name> {
- def NAME: Separate<["--", "-"], name>;
- def NAME # _eq: Joined<["--", "-"], name # "=">, Alias<!cast<Separate>(NAME)>;
+multiclass Eq<string name, string help> {
+ def NAME : Separate<["--", "-"], name>;
+ def NAME #_eq : Joined<["--", "-"], name #"=">,
+ Alias<!cast<Separate>(NAME)>,
+ HelpText<help>;
}
def help : Flag<["-", "--"], "help">;
-defm output : Eq<"o">,
- MetaVarName<"output">,
- HelpText<"Write output to <file>">;
+def enable_deterministic_archives
+ : Flag<["-", "--"], "enable-deterministic-archives">,
+ HelpText<"Enable deterministic mode when stripping archives (use zero "
+ "for UIDs, GIDs, and timestamps).">;
+def D : Flag<["-"], "D">,
+ Alias<enable_deterministic_archives>,
+ HelpText<"Alias for --enable-deterministic-archives">;
-def strip_all : Flag<["-", "--"], "strip-all">,
- HelpText<"Remove non-allocated sections other than .gnu.warning* sections">;
+def disable_deterministic_archives
+ : Flag<["-", "--"], "disable-deterministic-archives">,
+ HelpText<"Disable deterministic mode when stripping archives (use real "
+ "values for UIDs, GIDs, and timestamps).">;
+def U : Flag<["-"], "U">,
+ Alias<disable_deterministic_archives>,
+ HelpText<"Alias for --disable-deterministic-archives">;
-def strip_debug : Flag<["-", "--"], "strip-debug">,
- HelpText<"Remove debugging symbols only">;
-
-def d : Flag<["-"], "d">,
- Alias<strip_debug>;
-
-def g : Flag<["-"], "g">,
- Alias<strip_debug>;
+defm output : Eq<"o", "Write output to <file>">, MetaVarName<"output">;
-def S : Flag<["-"], "S">,
- Alias<strip_debug>;
+def preserve_dates : Flag<["-", "--"], "preserve-dates">,
+ HelpText<"Preserve access and modification timestamps">;
+def p : Flag<["-"], "p">, Alias<preserve_dates>;
-defm remove_section : Eq<"remove-section">,
- MetaVarName<"section">,
- HelpText<"Remove <section>">;
+def strip_all
+ : Flag<["-", "--"], "strip-all">,
+ HelpText<
+ "Remove non-allocated sections other than .gnu.warning* sections">;
+def s : Flag<["-"], "s">, Alias<strip_all>;
-def R : JoinedOrSeparate<["-"], "R">,
- Alias<remove_section>;
+def strip_all_gnu : Flag<["-", "--"], "strip-all-gnu">,
+ HelpText<"Compatible with GNU strip's --strip-all">;
+def strip_debug : Flag<["-", "--"], "strip-debug">,
+ HelpText<"Remove debugging symbols only">;
+def d : Flag<["-"], "d">, Alias<strip_debug>;
+def g : Flag<["-"], "g">, Alias<strip_debug>;
+def S : Flag<["-"], "S">, Alias<strip_debug>;
+def strip_unneeded : Flag<["-", "--"], "strip-unneeded">,
+ HelpText<"Remove all symbols not needed by relocations">;
-defm keep_symbol : Eq<"keep-symbol">,
- MetaVarName<"symbol">,
- HelpText<"Do not remove symbol <symbol>">;
+defm remove_section : Eq<"remove-section", "Remove <section>">,
+ MetaVarName<"section">;
+def R : JoinedOrSeparate<["-"], "R">, Alias<remove_section>;
-def K : JoinedOrSeparate<["-"], "K">,
- Alias<keep_symbol>;
+defm keep_section : Eq<"keep-section", "Keep <section>">,
+ MetaVarName<"section">;
+defm keep_symbol : Eq<"keep-symbol", "Do not remove symbol <symbol>">,
+ MetaVarName<"symbol">;
+def K : JoinedOrSeparate<["-"], "K">, Alias<keep_symbol>;
-def discard_all : Flag<["-", "--"], "discard-all">,
- HelpText<"Remove all local symbols except file and section symbols">;
-def x : Flag<["-"], "x">,
- Alias<discard_all>;
+def discard_all
+ : Flag<["-", "--"], "discard-all">,
+ HelpText<"Remove all local symbols except file and section symbols">;
+def x : Flag<["-"], "x">, Alias<discard_all>;
-def strip_unneeded : Flag<["-", "--"], "strip-unneeded">,
- HelpText<"Remove all symbols not needed by relocations">;
+def version : Flag<["-", "--"], "version">,
+ HelpText<"Print the version and exit.">;
+def V : Flag<["-"], "V">, Alias<version>;
diff --git a/contrib/llvm/tools/llvm-objcopy/llvm-objcopy.cpp b/contrib/llvm/tools/llvm-objcopy/llvm-objcopy.cpp
index 21a1622db765..fb1ff18b015b 100644
--- a/contrib/llvm/tools/llvm-objcopy/llvm-objcopy.cpp
+++ b/contrib/llvm/tools/llvm-objcopy/llvm-objcopy.cpp
@@ -8,14 +8,19 @@
//===----------------------------------------------------------------------===//
#include "llvm-objcopy.h"
-#include "Object.h"
+#include "Buffer.h"
+#include "COFF/COFFObjcopy.h"
+#include "CopyConfig.h"
+#include "ELF/ELFObjcopy.h"
+
#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
-#include "llvm/BinaryFormat/ELF.h"
#include "llvm/Object/Archive.h"
#include "llvm/Object/ArchiveWriter.h"
#include "llvm/Object/Binary.h"
+#include "llvm/Object/COFF.h"
#include "llvm/Object/ELFObjectFile.h"
#include "llvm/Object/ELFTypes.h"
#include "llvm/Object/Error.h"
@@ -23,137 +28,23 @@
#include "llvm/Option/ArgList.h"
#include "llvm/Option/Option.h"
#include "llvm/Support/Casting.h"
-#include "llvm/Support/CommandLine.h"
-#include "llvm/Support/Compiler.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/ErrorOr.h"
-#include "llvm/Support/FileOutputBuffer.h"
#include "llvm/Support/InitLLVM.h"
+#include "llvm/Support/Memory.h"
#include "llvm/Support/Path.h"
+#include "llvm/Support/Process.h"
+#include "llvm/Support/WithColor.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <cassert>
#include <cstdlib>
-#include <functional>
-#include <iterator>
#include <memory>
#include <string>
#include <system_error>
#include <utility>
-using namespace llvm;
-using namespace llvm::objcopy;
-using namespace object;
-using namespace ELF;
-
-namespace {
-
-enum ObjcopyID {
- OBJCOPY_INVALID = 0, // This is not an option ID.
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR, VALUES) \
- OBJCOPY_##ID,
-#include "ObjcopyOpts.inc"
-#undef OPTION
-};
-
-#define PREFIX(NAME, VALUE) const char *const OBJCOPY_##NAME[] = VALUE;
-#include "ObjcopyOpts.inc"
-#undef PREFIX
-
-static const opt::OptTable::Info ObjcopyInfoTable[] = {
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR, VALUES) \
- {OBJCOPY_##PREFIX, \
- NAME, \
- HELPTEXT, \
- METAVAR, \
- OBJCOPY_##ID, \
- opt::Option::KIND##Class, \
- PARAM, \
- FLAGS, \
- OBJCOPY_##GROUP, \
- OBJCOPY_##ALIAS, \
- ALIASARGS, \
- VALUES},
-#include "ObjcopyOpts.inc"
-#undef OPTION
-};
-
-class ObjcopyOptTable : public opt::OptTable {
-public:
- ObjcopyOptTable() : OptTable(ObjcopyInfoTable, true) {}
-};
-
-enum StripID {
- STRIP_INVALID = 0, // This is not an option ID.
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR, VALUES) \
- STRIP_##ID,
-#include "StripOpts.inc"
-#undef OPTION
-};
-
-#define PREFIX(NAME, VALUE) const char *const STRIP_##NAME[] = VALUE;
-#include "StripOpts.inc"
-#undef PREFIX
-
-static const opt::OptTable::Info StripInfoTable[] = {
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
- HELPTEXT, METAVAR, VALUES) \
- {STRIP_##PREFIX, NAME, HELPTEXT, \
- METAVAR, STRIP_##ID, opt::Option::KIND##Class, \
- PARAM, FLAGS, STRIP_##GROUP, \
- STRIP_##ALIAS, ALIASARGS, VALUES},
-#include "StripOpts.inc"
-#undef OPTION
-};
-
-class StripOptTable : public opt::OptTable {
-public:
- StripOptTable() : OptTable(StripInfoTable, true) {}
-};
-
-struct CopyConfig {
- StringRef OutputFilename;
- StringRef InputFilename;
- StringRef OutputFormat;
- StringRef InputFormat;
- StringRef BinaryArch;
-
- StringRef SplitDWO;
- StringRef AddGnuDebugLink;
- std::vector<StringRef> ToRemove;
- std::vector<StringRef> Keep;
- std::vector<StringRef> OnlyKeep;
- std::vector<StringRef> AddSection;
- std::vector<StringRef> SymbolsToLocalize;
- std::vector<StringRef> SymbolsToGlobalize;
- std::vector<StringRef> SymbolsToWeaken;
- std::vector<StringRef> SymbolsToRemove;
- std::vector<StringRef> SymbolsToKeep;
- StringMap<StringRef> SectionsToRename;
- StringMap<StringRef> SymbolsToRename;
- bool StripAll = false;
- bool StripAllGNU = false;
- bool StripDebug = false;
- bool StripSections = false;
- bool StripNonAlloc = false;
- bool StripDWO = false;
- bool StripUnneeded = false;
- bool ExtractDWO = false;
- bool LocalizeHidden = false;
- bool Weaken = false;
- bool DiscardAll = false;
- bool OnlyKeepDebug = false;
- bool KeepFileSymbols = false;
-};
-
-using SectionPred = std::function<bool(const SectionBase &Sec)>;
-
-} // namespace
-
namespace llvm {
namespace objcopy {
@@ -161,14 +52,15 @@ namespace objcopy {
StringRef ToolName;
LLVM_ATTRIBUTE_NORETURN void error(Twine Message) {
- errs() << ToolName << ": " << Message << ".\n";
+ WithColor::error(errs(), ToolName) << Message << ".\n";
errs().flush();
exit(1);
}
LLVM_ATTRIBUTE_NORETURN void reportError(StringRef File, std::error_code EC) {
assert(EC);
- errs() << ToolName << ": '" << File << "': " << EC.message() << ".\n";
+ WithColor::error(errs(), ToolName)
+ << "'" << File << "': " << EC.message() << ".\n";
exit(1);
}
@@ -176,304 +68,18 @@ LLVM_ATTRIBUTE_NORETURN void reportError(StringRef File, Error E) {
assert(E);
std::string Buf;
raw_string_ostream OS(Buf);
- logAllUnhandledErrors(std::move(E), OS, "");
+ logAllUnhandledErrors(std::move(E), OS);
OS.flush();
- errs() << ToolName << ": '" << File << "': " << Buf;
+ WithColor::error(errs(), ToolName) << "'" << File << "': " << Buf;
exit(1);
}
} // end namespace objcopy
} // end namespace llvm
-static bool IsDebugSection(const SectionBase &Sec) {
- return Sec.Name.startswith(".debug") || Sec.Name.startswith(".zdebug") ||
- Sec.Name == ".gdb_index";
-}
-
-static bool IsDWOSection(const SectionBase &Sec) {
- return Sec.Name.endswith(".dwo");
-}
-
-static bool OnlyKeepDWOPred(const Object &Obj, const SectionBase &Sec) {
- // We can't remove the section header string table.
- 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);
-}
-
-static std::unique_ptr<Writer> CreateWriter(const CopyConfig &Config,
- Object &Obj, Buffer &Buf,
- ElfType OutputElfType) {
- if (Config.OutputFormat == "binary") {
- return llvm::make_unique<BinaryWriter>(Obj, Buf);
- }
- // Depending on the initial ELFT and OutputFormat we need a different Writer.
- switch (OutputElfType) {
- case ELFT_ELF32LE:
- return llvm::make_unique<ELFWriter<ELF32LE>>(Obj, Buf,
- !Config.StripSections);
- case ELFT_ELF64LE:
- return llvm::make_unique<ELFWriter<ELF64LE>>(Obj, Buf,
- !Config.StripSections);
- case ELFT_ELF32BE:
- return llvm::make_unique<ELFWriter<ELF32BE>>(Obj, Buf,
- !Config.StripSections);
- case ELFT_ELF64BE:
- return llvm::make_unique<ELFWriter<ELF64BE>>(Obj, Buf,
- !Config.StripSections);
- }
- llvm_unreachable("Invalid output format");
-}
-
-static void SplitDWOToFile(const CopyConfig &Config, const Reader &Reader,
- StringRef File, ElfType OutputElfType) {
- auto DWOFile = Reader.create();
- DWOFile->removeSections(
- [&](const SectionBase &Sec) { return OnlyKeepDWOPred(*DWOFile, Sec); });
- FileBuffer FB(File);
- auto Writer = CreateWriter(Config, *DWOFile, FB, OutputElfType);
- Writer->finalize();
- Writer->write();
-}
-
-// This function handles the high level operations of GNU objcopy including
-// handling command line options. It's important to outline certain properties
-// we expect to hold of the command line operations. Any operation that "keeps"
-// should keep regardless of a remove. Additionally any removal should respect
-// 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.
-static void HandleArgs(const CopyConfig &Config, Object &Obj,
- const Reader &Reader, ElfType OutputElfType) {
-
- if (!Config.SplitDWO.empty()) {
- SplitDWOToFile(Config, Reader, Config.SplitDWO, OutputElfType);
- }
-
- // TODO: update or remove symbols only if there is an option that affects
- // them.
- if (Obj.SymbolTable) {
- Obj.SymbolTable->updateSymbols([&](Symbol &Sym) {
- if ((Config.LocalizeHidden &&
- (Sym.Visibility == STV_HIDDEN || Sym.Visibility == STV_INTERNAL)) ||
- (!Config.SymbolsToLocalize.empty() &&
- is_contained(Config.SymbolsToLocalize, Sym.Name)))
- Sym.Binding = STB_LOCAL;
-
- if (!Config.SymbolsToGlobalize.empty() &&
- is_contained(Config.SymbolsToGlobalize, Sym.Name))
- Sym.Binding = STB_GLOBAL;
-
- if (!Config.SymbolsToWeaken.empty() &&
- is_contained(Config.SymbolsToWeaken, Sym.Name) &&
- Sym.Binding == STB_GLOBAL)
- Sym.Binding = STB_WEAK;
-
- if (Config.Weaken && Sym.Binding == STB_GLOBAL &&
- Sym.getShndx() != SHN_UNDEF)
- Sym.Binding = STB_WEAK;
-
- const auto I = Config.SymbolsToRename.find(Sym.Name);
- if (I != Config.SymbolsToRename.end())
- Sym.Name = I->getValue();
- });
-
- // The purpose of this loop is to mark symbols referenced by sections
- // (like GroupSection or RelocationSection). This way, we know which
- // symbols are still 'needed' and wich are not.
- if (Config.StripUnneeded) {
- for (auto &Section : Obj.sections())
- Section.markSymbols();
- }
-
- Obj.removeSymbols([&](const Symbol &Sym) {
- if ((!Config.SymbolsToKeep.empty() &&
- is_contained(Config.SymbolsToKeep, Sym.Name)) ||
- (Config.KeepFileSymbols && Sym.Type == STT_FILE))
- return false;
-
- if (Config.DiscardAll && Sym.Binding == STB_LOCAL &&
- Sym.getShndx() != SHN_UNDEF && Sym.Type != STT_FILE &&
- Sym.Type != STT_SECTION)
- return true;
-
- if (Config.StripAll || Config.StripAllGNU)
- return true;
-
- if (!Config.SymbolsToRemove.empty() &&
- is_contained(Config.SymbolsToRemove, Sym.Name)) {
- return true;
- }
-
- if (Config.StripUnneeded && !Sym.Referenced &&
- (Sym.Binding == STB_LOCAL || Sym.getShndx() == SHN_UNDEF) &&
- Sym.Type != STT_FILE && Sym.Type != STT_SECTION)
- return true;
-
- return false;
- });
- }
-
- SectionPred RemovePred = [](const SectionBase &) { return false; };
-
- // Removes:
- if (!Config.ToRemove.empty()) {
- RemovePred = [&Config](const SectionBase &Sec) {
- return find(Config.ToRemove, Sec.Name) != Config.ToRemove.end();
- };
- }
-
- if (Config.StripDWO || !Config.SplitDWO.empty())
- RemovePred = [RemovePred](const SectionBase &Sec) {
- return IsDWOSection(Sec) || RemovePred(Sec);
- };
-
- if (Config.ExtractDWO)
- RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {
- return OnlyKeepDWOPred(Obj, Sec) || RemovePred(Sec);
- };
-
- if (Config.StripAllGNU)
- RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {
- if (RemovePred(Sec))
- return true;
- if ((Sec.Flags & SHF_ALLOC) != 0)
- return false;
- if (&Sec == Obj.SectionNames)
- return false;
- switch (Sec.Type) {
- case SHT_SYMTAB:
- case SHT_REL:
- case SHT_RELA:
- case SHT_STRTAB:
- return true;
- }
- return IsDebugSection(Sec);
- };
-
- if (Config.StripSections) {
- RemovePred = [RemovePred](const SectionBase &Sec) {
- return RemovePred(Sec) || (Sec.Flags & SHF_ALLOC) == 0;
- };
- }
-
- if (Config.StripDebug) {
- RemovePred = [RemovePred](const SectionBase &Sec) {
- return RemovePred(Sec) || IsDebugSection(Sec);
- };
- }
-
- if (Config.StripNonAlloc)
- RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {
- if (RemovePred(Sec))
- return true;
- if (&Sec == Obj.SectionNames)
- return false;
- return (Sec.Flags & SHF_ALLOC) == 0;
- };
-
- if (Config.StripAll)
- RemovePred = [RemovePred, &Obj](const SectionBase &Sec) {
- if (RemovePred(Sec))
- return true;
- if (&Sec == Obj.SectionNames)
- return false;
- if (Sec.Name.startswith(".gnu.warning"))
- return false;
- return (Sec.Flags & SHF_ALLOC) == 0;
- };
-
- // Explicit copies:
- if (!Config.OnlyKeep.empty()) {
- RemovePred = [&Config, RemovePred, &Obj](const SectionBase &Sec) {
- // Explicitly keep these sections regardless of previous removes.
- if (find(Config.OnlyKeep, Sec.Name) != Config.OnlyKeep.end())
- return false;
-
- // Allow all implicit removes.
- if (RemovePred(Sec))
- return true;
-
- // Keep special sections.
- if (Obj.SectionNames == &Sec)
- return false;
- if (Obj.SymbolTable == &Sec ||
- (Obj.SymbolTable && Obj.SymbolTable->getStrTab() == &Sec))
- return false;
-
- // Remove everything else.
- return true;
- };
- }
-
- if (!Config.Keep.empty()) {
- RemovePred = [Config, RemovePred](const SectionBase &Sec) {
- // Explicitly keep these sections regardless of previous removes.
- if (find(Config.Keep, Sec.Name) != Config.Keep.end())
- return false;
- // Otherwise defer to RemovePred.
- return RemovePred(Sec);
- };
- }
-
- // This has to be the last predicate assignment.
- // If the option --keep-symbol has been specified
- // and at least one of those symbols is present
- // (equivalently, the updated symbol table is not empty)
- // the symbol table and the string table should not be removed.
- if ((!Config.SymbolsToKeep.empty() || Config.KeepFileSymbols) &&
- Obj.SymbolTable && !Obj.SymbolTable->empty()) {
- RemovePred = [&Obj, RemovePred](const SectionBase &Sec) {
- if (&Sec == Obj.SymbolTable || &Sec == Obj.SymbolTable->getStrTab())
- return false;
- return RemovePred(Sec);
- };
- }
-
- Obj.removeSections(RemovePred);
-
- if (!Config.SectionsToRename.empty()) {
- for (auto &Sec : Obj.sections()) {
- const auto Iter = Config.SectionsToRename.find(Sec.Name);
- if (Iter != Config.SectionsToRename.end())
- Sec.Name = Iter->second;
- }
- }
-
- if (!Config.AddSection.empty()) {
- for (const auto &Flag : Config.AddSection) {
- auto SecPair = Flag.split("=");
- auto SecName = SecPair.first;
- auto File = SecPair.second;
- auto BufOrErr = MemoryBuffer::getFile(File);
- if (!BufOrErr)
- reportError(File, BufOrErr.getError());
- auto Buf = std::move(*BufOrErr);
- auto BufPtr = reinterpret_cast<const uint8_t *>(Buf->getBufferStart());
- auto BufSize = Buf->getBufferSize();
- Obj.addSection<OwnedDataSection>(SecName,
- ArrayRef<uint8_t>(BufPtr, BufSize));
- }
- }
-
- if (!Config.AddGnuDebugLink.empty())
- Obj.addSection<GnuDebugLinkSection>(Config.AddGnuDebugLink);
-}
-
-static void ExecuteElfObjcopyOnBinary(const CopyConfig &Config, Binary &Binary,
- Buffer &Out) {
- ELFReader Reader(&Binary);
- std::unique_ptr<Object> Obj = Reader.create();
-
- HandleArgs(Config, *Obj, Reader, Reader.getElfType());
-
- std::unique_ptr<Writer> Writer =
- CreateWriter(Config, *Obj, Out, Reader.getElfType());
- Writer->finalize();
- Writer->write();
-}
+using namespace llvm;
+using namespace llvm::object;
+using namespace llvm::objcopy;
// For regular archives this function simply calls llvm::writeArchive,
// For thin archives it writes the archive file itself as well as its members.
@@ -504,22 +110,48 @@ static Error deepWriteArchive(StringRef ArcName,
return Error::success();
}
-static void ExecuteElfObjcopyOnArchive(const CopyConfig &Config, const Archive &Ar) {
+/// The function executeObjcopyOnRawBinary does the dispatch based on the format
+/// of the output specified by the command line options.
+static void executeObjcopyOnRawBinary(const CopyConfig &Config,
+ MemoryBuffer &In, Buffer &Out) {
+ // TODO: llvm-objcopy should parse CopyConfig.OutputFormat to recognize
+ // formats other than ELF / "binary" and invoke
+ // elf::executeObjcopyOnRawBinary, macho::executeObjcopyOnRawBinary or
+ // coff::executeObjcopyOnRawBinary accordingly.
+ return elf::executeObjcopyOnRawBinary(Config, In, Out);
+}
+
+/// The function executeObjcopyOnBinary does the dispatch based on the format
+/// of the input binary (ELF, MachO or COFF).
+static void executeObjcopyOnBinary(const CopyConfig &Config, object::Binary &In,
+ Buffer &Out) {
+ if (auto *ELFBinary = dyn_cast<object::ELFObjectFileBase>(&In))
+ return elf::executeObjcopyOnBinary(Config, *ELFBinary, Out);
+ else if (auto *COFFBinary = dyn_cast<object::COFFObjectFile>(&In))
+ return coff::executeObjcopyOnBinary(Config, *COFFBinary, Out);
+ else
+ error("Unsupported object file format");
+}
+
+static void executeObjcopyOnArchive(const CopyConfig &Config,
+ const Archive &Ar) {
std::vector<NewArchiveMember> NewArchiveMembers;
Error Err = Error::success();
for (const Archive::Child &Child : Ar.children(Err)) {
Expected<std::unique_ptr<Binary>> ChildOrErr = Child.getAsBinary();
if (!ChildOrErr)
reportError(Ar.getFileName(), ChildOrErr.takeError());
+ Binary *Bin = ChildOrErr->get();
+
Expected<StringRef> ChildNameOrErr = Child.getName();
if (!ChildNameOrErr)
reportError(Ar.getFileName(), ChildNameOrErr.takeError());
MemBuffer MB(ChildNameOrErr.get());
- ExecuteElfObjcopyOnBinary(Config, **ChildOrErr, MB);
+ executeObjcopyOnBinary(Config, *Bin, MB);
Expected<NewArchiveMember> Member =
- NewArchiveMember::getOldMember(Child, true);
+ NewArchiveMember::getOldMember(Child, Config.DeterministicArchives);
if (!Member)
reportError(Ar.getFileName(), Member.takeError());
Member->Buf = MB.releaseMemoryBuffer();
@@ -529,180 +161,72 @@ static void ExecuteElfObjcopyOnArchive(const CopyConfig &Config, const Archive &
if (Err)
reportError(Config.InputFilename, std::move(Err));
- if (Error E =
- deepWriteArchive(Config.OutputFilename, NewArchiveMembers,
- Ar.hasSymbolTable(), Ar.kind(), true, Ar.isThin()))
+ if (Error E = deepWriteArchive(Config.OutputFilename, NewArchiveMembers,
+ Ar.hasSymbolTable(), Ar.kind(),
+ Config.DeterministicArchives, Ar.isThin()))
reportError(Config.OutputFilename, std::move(E));
}
-static void ExecuteElfObjcopy(const CopyConfig &Config) {
- Expected<OwningBinary<llvm::object::Binary>> BinaryOrErr =
- createBinary(Config.InputFilename);
- if (!BinaryOrErr)
- reportError(Config.InputFilename, BinaryOrErr.takeError());
-
- if (Archive *Ar = dyn_cast<Archive>(BinaryOrErr.get().getBinary()))
- return ExecuteElfObjcopyOnArchive(Config, *Ar);
-
- FileBuffer FB(Config.OutputFilename);
- ExecuteElfObjcopyOnBinary(Config, *BinaryOrErr.get().getBinary(), FB);
-}
-
-// ParseObjcopyOptions returns the config and sets the input arguments. If a
-// help flag is set then ParseObjcopyOptions will print the help messege and
-// exit.
-static CopyConfig ParseObjcopyOptions(ArrayRef<const char *> ArgsArr) {
- ObjcopyOptTable T;
- unsigned MissingArgumentIndex, MissingArgumentCount;
- llvm::opt::InputArgList InputArgs =
- T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount);
-
- if (InputArgs.size() == 0) {
- T.PrintHelp(errs(), "llvm-objcopy <input> [ <output> ]", "objcopy tool");
- exit(1);
- }
-
- if (InputArgs.hasArg(OBJCOPY_help)) {
- T.PrintHelp(outs(), "llvm-objcopy <input> [ <output> ]", "objcopy tool");
- exit(0);
- }
-
- SmallVector<const char *, 2> Positional;
-
- for (auto Arg : InputArgs.filtered(OBJCOPY_UNKNOWN))
- error("unknown argument '" + Arg->getAsString(InputArgs) + "'");
-
- for (auto Arg : InputArgs.filtered(OBJCOPY_INPUT))
- Positional.push_back(Arg->getValue());
-
- if (Positional.empty())
- error("No input file specified");
-
- if (Positional.size() > 2)
- error("Too many positional arguments");
-
- CopyConfig Config;
- Config.InputFilename = Positional[0];
- Config.OutputFilename = Positional[Positional.size() == 1 ? 0 : 1];
- Config.InputFormat = InputArgs.getLastArgValue(OBJCOPY_input_target);
- Config.OutputFormat = InputArgs.getLastArgValue(OBJCOPY_output_target);
- Config.BinaryArch = InputArgs.getLastArgValue(OBJCOPY_binary_architecture);
-
- Config.SplitDWO = InputArgs.getLastArgValue(OBJCOPY_split_dwo);
- Config.AddGnuDebugLink = InputArgs.getLastArgValue(OBJCOPY_add_gnu_debuglink);
-
- for (auto Arg : InputArgs.filtered(OBJCOPY_redefine_symbol)) {
- if (!StringRef(Arg->getValue()).contains('='))
- error("Bad format for --redefine-sym");
- auto Old2New = StringRef(Arg->getValue()).split('=');
- if (!Config.SymbolsToRename.insert(Old2New).second)
- error("Multiple redefinition of symbol " + Old2New.first);
- }
-
- for (auto Arg : InputArgs.filtered(OBJCOPY_rename_section)) {
- if (!StringRef(Arg->getValue()).contains('='))
- error("Bad format for --rename-section");
- auto Old2New = StringRef(Arg->getValue()).split('=');
- if (!Config.SectionsToRename.insert(Old2New).second)
- error("Already have a section rename for " + Old2New.first);
- }
-
- for (auto Arg : InputArgs.filtered(OBJCOPY_remove_section))
- Config.ToRemove.push_back(Arg->getValue());
- for (auto Arg : InputArgs.filtered(OBJCOPY_keep))
- Config.Keep.push_back(Arg->getValue());
- for (auto Arg : InputArgs.filtered(OBJCOPY_only_keep))
- Config.OnlyKeep.push_back(Arg->getValue());
- for (auto Arg : InputArgs.filtered(OBJCOPY_add_section))
- Config.AddSection.push_back(Arg->getValue());
- Config.StripAll = InputArgs.hasArg(OBJCOPY_strip_all);
- Config.StripAllGNU = InputArgs.hasArg(OBJCOPY_strip_all_gnu);
- Config.StripDebug = InputArgs.hasArg(OBJCOPY_strip_debug);
- Config.StripDWO = InputArgs.hasArg(OBJCOPY_strip_dwo);
- Config.StripSections = InputArgs.hasArg(OBJCOPY_strip_sections);
- Config.StripNonAlloc = InputArgs.hasArg(OBJCOPY_strip_non_alloc);
- Config.StripUnneeded = InputArgs.hasArg(OBJCOPY_strip_unneeded);
- Config.ExtractDWO = InputArgs.hasArg(OBJCOPY_extract_dwo);
- Config.LocalizeHidden = InputArgs.hasArg(OBJCOPY_localize_hidden);
- Config.Weaken = InputArgs.hasArg(OBJCOPY_weaken);
- Config.DiscardAll = InputArgs.hasArg(OBJCOPY_discard_all);
- Config.OnlyKeepDebug = InputArgs.hasArg(OBJCOPY_only_keep_debug);
- Config.KeepFileSymbols = InputArgs.hasArg(OBJCOPY_keep_file_symbols);
- for (auto Arg : InputArgs.filtered(OBJCOPY_localize_symbol))
- Config.SymbolsToLocalize.push_back(Arg->getValue());
- for (auto Arg : InputArgs.filtered(OBJCOPY_globalize_symbol))
- Config.SymbolsToGlobalize.push_back(Arg->getValue());
- for (auto Arg : InputArgs.filtered(OBJCOPY_weaken_symbol))
- Config.SymbolsToWeaken.push_back(Arg->getValue());
- for (auto Arg : InputArgs.filtered(OBJCOPY_strip_symbol))
- Config.SymbolsToRemove.push_back(Arg->getValue());
- for (auto Arg : InputArgs.filtered(OBJCOPY_keep_symbol))
- Config.SymbolsToKeep.push_back(Arg->getValue());
-
- return Config;
-}
-
-// ParseStripOptions returns the config and sets the input arguments. If a
-// help flag is set then ParseStripOptions will print the help messege and
-// exit.
-static CopyConfig ParseStripOptions(ArrayRef<const char *> ArgsArr) {
- StripOptTable T;
- unsigned MissingArgumentIndex, MissingArgumentCount;
- llvm::opt::InputArgList InputArgs =
- T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount);
-
- if (InputArgs.size() == 0) {
- T.PrintHelp(errs(), "llvm-strip <input> [ <output> ]", "strip tool");
- exit(1);
+static void restoreDateOnFile(StringRef Filename,
+ const sys::fs::file_status &Stat) {
+ int FD;
+
+ if (auto EC =
+ sys::fs::openFileForWrite(Filename, FD, sys::fs::CD_OpenExisting))
+ reportError(Filename, EC);
+
+ if (auto EC = sys::fs::setLastAccessAndModificationTime(
+ FD, Stat.getLastAccessedTime(), Stat.getLastModificationTime()))
+ reportError(Filename, EC);
+
+ if (auto EC = sys::Process::SafelyCloseFileDescriptor(FD))
+ reportError(Filename, EC);
+}
+
+/// The function executeObjcopy does the higher level dispatch based on the type
+/// of input (raw binary, archive or single object file) and takes care of the
+/// format-agnostic modifications, i.e. preserving dates.
+static void executeObjcopy(const CopyConfig &Config) {
+ sys::fs::file_status Stat;
+ if (Config.PreserveDates)
+ if (auto EC = sys::fs::status(Config.InputFilename, Stat))
+ reportError(Config.InputFilename, EC);
+
+ if (Config.InputFormat == "binary") {
+ auto BufOrErr = MemoryBuffer::getFile(Config.InputFilename);
+ if (!BufOrErr)
+ reportError(Config.InputFilename, BufOrErr.getError());
+ FileBuffer FB(Config.OutputFilename);
+ executeObjcopyOnRawBinary(Config, *BufOrErr->get(), FB);
+ } else {
+ Expected<OwningBinary<llvm::object::Binary>> BinaryOrErr =
+ createBinary(Config.InputFilename);
+ if (!BinaryOrErr)
+ reportError(Config.InputFilename, BinaryOrErr.takeError());
+
+ if (Archive *Ar = dyn_cast<Archive>(BinaryOrErr.get().getBinary())) {
+ executeObjcopyOnArchive(Config, *Ar);
+ } else {
+ FileBuffer FB(Config.OutputFilename);
+ executeObjcopyOnBinary(Config, *BinaryOrErr.get().getBinary(), FB);
+ }
}
- if (InputArgs.hasArg(STRIP_help)) {
- T.PrintHelp(outs(), "llvm-strip <input> [ <output> ]", "strip tool");
- exit(0);
+ if (Config.PreserveDates) {
+ restoreDateOnFile(Config.OutputFilename, Stat);
+ if (!Config.SplitDWO.empty())
+ restoreDateOnFile(Config.SplitDWO, Stat);
}
-
- SmallVector<const char *, 2> Positional;
- for (auto Arg : InputArgs.filtered(STRIP_UNKNOWN))
- error("unknown argument '" + Arg->getAsString(InputArgs) + "'");
- for (auto Arg : InputArgs.filtered(STRIP_INPUT))
- Positional.push_back(Arg->getValue());
-
- if (Positional.empty())
- error("No input file specified");
-
- if (Positional.size() > 2)
- error("Support for multiple input files is not implemented yet");
-
- CopyConfig Config;
- Config.InputFilename = Positional[0];
- Config.OutputFilename =
- InputArgs.getLastArgValue(STRIP_output, Positional[0]);
-
- Config.StripDebug = InputArgs.hasArg(STRIP_strip_debug);
-
- Config.DiscardAll = InputArgs.hasArg(STRIP_discard_all);
- Config.StripUnneeded = InputArgs.hasArg(STRIP_strip_unneeded);
- Config.StripAll = InputArgs.hasArg(STRIP_strip_all);
-
- if (!Config.StripDebug && !Config.StripUnneeded && !Config.DiscardAll)
- Config.StripAll = true;
-
- for (auto Arg : InputArgs.filtered(STRIP_remove_section))
- Config.ToRemove.push_back(Arg->getValue());
-
- for (auto Arg : InputArgs.filtered(STRIP_keep_symbol))
- Config.SymbolsToKeep.push_back(Arg->getValue());
-
- return Config;
}
int main(int argc, char **argv) {
InitLLVM X(argc, argv);
ToolName = argv[0];
- CopyConfig Config;
- if (sys::path::stem(ToolName).endswith_lower("strip"))
- Config = ParseStripOptions(makeArrayRef(argv + 1, argc));
+ DriverConfig DriverConfig;
+ if (sys::path::stem(ToolName).contains("strip"))
+ DriverConfig = parseStripOptions(makeArrayRef(argv + 1, argc));
else
- Config = ParseObjcopyOptions(makeArrayRef(argv + 1, argc));
- ExecuteElfObjcopy(Config);
+ DriverConfig = parseObjcopyOptions(makeArrayRef(argv + 1, argc));
+ for (const CopyConfig &CopyConfig : DriverConfig.CopyConfigs)
+ executeObjcopy(CopyConfig);
}
diff --git a/contrib/llvm/tools/llvm-objcopy/llvm-objcopy.h b/contrib/llvm/tools/llvm-objcopy/llvm-objcopy.h
index e222b65dc78f..d8edf3e29ee0 100644
--- a/contrib/llvm/tools/llvm-objcopy/llvm-objcopy.h
+++ b/contrib/llvm/tools/llvm-objcopy/llvm-objcopy.h
@@ -31,7 +31,7 @@ template <class T> T unwrapOrError(Expected<T> EO) {
return *EO;
std::string Buf;
raw_string_ostream OS(Buf);
- logAllUnhandledErrors(EO.takeError(), OS, "");
+ logAllUnhandledErrors(EO.takeError(), OS);
OS.flush();
error(Buf);
}