summaryrefslogtreecommitdiffstats
path: root/llvm/tools
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/tools')
-rw-r--r--llvm/tools/llvm-objcopy/Object.cpp104
-rw-r--r--llvm/tools/llvm-objcopy/Object.h71
-rw-r--r--llvm/tools/llvm-objcopy/llvm-objcopy.cpp114
3 files changed, 203 insertions, 86 deletions
diff --git a/llvm/tools/llvm-objcopy/Object.cpp b/llvm/tools/llvm-objcopy/Object.cpp
index 68420670d52..f803ffe1d81 100644
--- a/llvm/tools/llvm-objcopy/Object.cpp
+++ b/llvm/tools/llvm-objcopy/Object.cpp
@@ -30,12 +30,43 @@ using namespace llvm;
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 *Buf = BufPtr->getBufferStart();
- Buf += Obj.ProgramHdrSegment.Offset + Seg.Index * sizeof(Elf_Phdr);
- Elf_Phdr &Phdr = *reinterpret_cast<Elf_Phdr *>(Buf);
+ uint8_t *B = Buf.getBufferStart();
+ B += Obj.ProgramHdrSegment.Offset + Seg.Index * sizeof(Elf_Phdr);
+ Elf_Phdr &Phdr = *reinterpret_cast<Elf_Phdr *>(B);
Phdr.p_type = Seg.Type;
Phdr.p_flags = Seg.Flags;
Phdr.p_offset = Seg.Offset;
@@ -53,9 +84,9 @@ void SectionBase::finalize() {}
void SectionBase::markSymbols() {}
template <class ELFT> void ELFWriter<ELFT>::writeShdr(const SectionBase &Sec) {
- uint8_t *Buf = BufPtr->getBufferStart();
- Buf += Sec.HeaderOffset;
- typename ELFT::Shdr &Shdr = *reinterpret_cast<typename ELFT::Shdr *>(Buf);
+ uint8_t *B = Buf.getBufferStart();
+ B += Sec.HeaderOffset;
+ typename ELFT::Shdr &Shdr = *reinterpret_cast<typename ELFT::Shdr *>(B);
Shdr.sh_name = Sec.NameIndex;
Shdr.sh_type = Sec.Type;
Shdr.sh_flags = Sec.Flags;
@@ -410,9 +441,7 @@ void Section::initialize(SectionTableRef SecTable) {
}
}
-void Section::finalize() {
- this->Link = LinkSection ? LinkSection->Index : 0;
-}
+void Section::finalize() { this->Link = LinkSection ? LinkSection->Index : 0; }
void GnuDebugLinkSection::init(StringRef File, StringRef Data) {
FileName = sys::path::filename(File);
@@ -814,41 +843,33 @@ Writer::~Writer() {}
Reader::~Reader() {}
-ELFReader::ELFReader(StringRef File) {
- auto BinaryOrErr = createBinary(File);
- if (!BinaryOrErr)
- reportError(File, BinaryOrErr.takeError());
- auto OwnedBin = std::move(BinaryOrErr.get());
- std::tie(Bin, Data) = OwnedBin.takeBinary();
-}
-
ElfType ELFReader::getElfType() const {
- if (isa<ELFObjectFile<ELF32LE>>(Bin.get()))
+ if (isa<ELFObjectFile<ELF32LE>>(Bin))
return ELFT_ELF32LE;
- if (isa<ELFObjectFile<ELF64LE>>(Bin.get()))
+ if (isa<ELFObjectFile<ELF64LE>>(Bin))
return ELFT_ELF64LE;
- if (isa<ELFObjectFile<ELF32BE>>(Bin.get()))
+ if (isa<ELFObjectFile<ELF32BE>>(Bin))
return ELFT_ELF32BE;
- if (isa<ELFObjectFile<ELF64BE>>(Bin.get()))
+ if (isa<ELFObjectFile<ELF64BE>>(Bin))
return ELFT_ELF64BE;
llvm_unreachable("Invalid ELFType");
}
std::unique_ptr<Object> ELFReader::create() const {
auto Obj = llvm::make_unique<Object>();
- if (auto *o = dyn_cast<ELFObjectFile<ELF32LE>>(Bin.get())) {
+ 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.get())) {
+ } 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.get())) {
+ } 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.get())) {
+ } else if (auto *o = dyn_cast<ELFObjectFile<ELF64BE>>(Bin)) {
ELFBuilder<ELF64BE> Builder(*o, *Obj);
Builder.build();
return Obj;
@@ -857,8 +878,8 @@ std::unique_ptr<Object> ELFReader::create() const {
}
template <class ELFT> void ELFWriter<ELFT>::writeEhdr() {
- uint8_t *Buf = BufPtr->getBufferStart();
- Elf_Ehdr &Ehdr = *reinterpret_cast<Elf_Ehdr *>(Buf);
+ uint8_t *B = Buf.getBufferStart();
+ Elf_Ehdr &Ehdr = *reinterpret_cast<Elf_Ehdr *>(B);
std::copy(Obj.Ident, Obj.Ident + 16, Ehdr.e_ident);
Ehdr.e_type = Obj.Type;
Ehdr.e_machine = Obj.Machine;
@@ -887,10 +908,10 @@ template <class ELFT> void ELFWriter<ELFT>::writePhdrs() {
}
template <class ELFT> void ELFWriter<ELFT>::writeShdrs() {
- uint8_t *Buf = BufPtr->getBufferStart() + Obj.SHOffset;
+ uint8_t *B = Buf.getBufferStart() + Obj.SHOffset;
// This reference serves to write the dummy section header at the begining
// of the file. It is not used for anything else
- Elf_Shdr &Shdr = *reinterpret_cast<Elf_Shdr *>(Buf);
+ Elf_Shdr &Shdr = *reinterpret_cast<Elf_Shdr *>(B);
Shdr.sh_name = 0;
Shdr.sh_type = SHT_NULL;
Shdr.sh_flags = 0;
@@ -1076,17 +1097,8 @@ template <class ELFT> void ELFWriter<ELFT>::write() {
writeSectionData();
if (WriteSectionHeaders)
writeShdrs();
- if (auto E = BufPtr->commit())
- reportError(File, errorToErrorCode(std::move(E)));
-}
-
-void Writer::createBuffer(uint64_t Size) {
- auto BufferOrErr =
- FileOutputBuffer::create(File, Size, FileOutputBuffer::F_executable);
- handleAllErrors(BufferOrErr.takeError(), [this](const ErrorInfoBase &) {
- error("failed to open " + File);
- });
- BufPtr = std::move(*BufferOrErr);
+ if (auto E = Buf.commit())
+ reportError(Buf.getName(), errorToErrorCode(std::move(E)));
}
template <class ELFT> void ELFWriter<ELFT>::finalize() {
@@ -1123,8 +1135,8 @@ template <class ELFT> void ELFWriter<ELFT>::finalize() {
Section.finalize();
}
- createBuffer(totalSize());
- SecWriter = llvm::make_unique<ELFSectionWriter<ELFT>>(*BufPtr);
+ Buf.allocate(totalSize());
+ SecWriter = llvm::make_unique<ELFSectionWriter<ELFT>>(Buf);
}
void BinaryWriter::write() {
@@ -1133,8 +1145,8 @@ void BinaryWriter::write() {
continue;
Section.accept(*SecWriter);
}
- if (auto E = BufPtr->commit())
- reportError(File, errorToErrorCode(std::move(E)));
+ if (auto E = Buf.commit())
+ reportError(Buf.getName(), errorToErrorCode(std::move(E)));
}
void BinaryWriter::finalize() {
@@ -1216,8 +1228,8 @@ void BinaryWriter::finalize() {
TotalSize = std::max(TotalSize, Section->Offset + Section->Size);
}
- createBuffer(TotalSize);
- SecWriter = llvm::make_unique<BinarySectionWriter>(*BufPtr);
+ Buf.allocate(TotalSize);
+ SecWriter = llvm::make_unique<BinarySectionWriter>(Buf);
}
namespace llvm {
diff --git a/llvm/tools/llvm-objcopy/Object.h b/llvm/tools/llvm-objcopy/Object.h
index 48de0e543a0..2e20b5b299f 100644
--- a/llvm/tools/llvm-objcopy/Object.h
+++ b/llvm/tools/llvm-objcopy/Object.h
@@ -27,6 +27,7 @@
namespace llvm {
+class Buffer;
class SectionBase;
class Section;
class OwnedDataSection;
@@ -77,7 +78,7 @@ public:
class SectionWriter : public SectionVisitor {
protected:
- FileOutputBuffer &Out;
+ Buffer &Out;
public:
virtual ~SectionWriter(){};
@@ -91,7 +92,7 @@ public:
virtual void visit(const GnuDebugLinkSection &Sec) override = 0;
virtual void visit(const GroupSection &Sec) override = 0;
- SectionWriter(FileOutputBuffer &Buf) : Out(Buf) {}
+ explicit SectionWriter(Buffer &Buf) : Out(Buf) {}
};
template <class ELFT> class ELFSectionWriter : public SectionWriter {
@@ -107,7 +108,7 @@ public:
void visit(const GnuDebugLinkSection &Sec) override;
void visit(const GroupSection &Sec) override;
- ELFSectionWriter(FileOutputBuffer &Buf) : SectionWriter(Buf) {}
+ explicit ELFSectionWriter(Buffer &Buf) : SectionWriter(Buf) {}
};
#define MAKE_SEC_WRITER_FRIEND \
@@ -123,24 +124,62 @@ public:
void visit(const GnuDebugLinkSection &Sec) override;
void visit(const GroupSection &Sec) override;
- BinarySectionWriter(FileOutputBuffer &Buf) : SectionWriter(Buf) {}
+ 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:
- StringRef File;
Object &Obj;
- std::unique_ptr<FileOutputBuffer> BufPtr;
-
- void createBuffer(uint64_t Size);
+ Buffer &Buf;
public:
virtual ~Writer();
-
virtual void finalize() = 0;
virtual void write() = 0;
- Writer(StringRef File, Object &Obj) : File(File), Obj(Obj) {}
+ Writer(Object &O, Buffer &B) : Obj(O), Buf(B) {}
};
template <class ELFT> class ELFWriter : public Writer {
@@ -169,8 +208,8 @@ public:
void finalize() override;
void write() override;
- ELFWriter(StringRef File, Object &Obj, bool WSH)
- : Writer(File, Obj), WriteSectionHeaders(WSH) {}
+ ELFWriter(Object &Obj, Buffer &Buf, bool WSH)
+ : Writer(Obj, Buf), WriteSectionHeaders(WSH) {}
};
class BinaryWriter : public Writer {
@@ -183,7 +222,7 @@ public:
~BinaryWriter() {}
void finalize() override;
void write() override;
- BinaryWriter(StringRef File, Object &Obj) : Writer(File, Obj) {}
+ BinaryWriter(Object &Obj, Buffer &Buf) : Writer(Obj, Buf) {}
};
class SectionBase {
@@ -569,14 +608,12 @@ public:
};
class ELFReader : public Reader {
-private:
- std::unique_ptr<Binary> Bin;
- std::shared_ptr<MemoryBuffer> Data;
+ Binary *Bin;
public:
ElfType getElfType() const;
std::unique_ptr<Object> create() const override;
- ELFReader(StringRef File);
+ explicit ELFReader(Binary *B) : Bin(B){};
};
class Object {
diff --git a/llvm/tools/llvm-objcopy/llvm-objcopy.cpp b/llvm/tools/llvm-objcopy/llvm-objcopy.cpp
index bf58f342ee4..c28862f073a 100644
--- a/llvm/tools/llvm-objcopy/llvm-objcopy.cpp
+++ b/llvm/tools/llvm-objcopy/llvm-objcopy.cpp
@@ -13,6 +13,8 @@
#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/ELFObjectFile.h"
#include "llvm/Object/ELFTypes.h"
@@ -191,23 +193,23 @@ bool OnlyKeepDWOPred(const Object &Obj, const SectionBase &Sec) {
}
std::unique_ptr<Writer> CreateWriter(const CopyConfig &Config, Object &Obj,
- StringRef File, ElfType OutputElfType) {
+ Buffer &Buf, ElfType OutputElfType) {
if (Config.OutputFormat == "binary") {
- return llvm::make_unique<BinaryWriter>(File, Obj);
+ 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>>(File, Obj,
+ return llvm::make_unique<ELFWriter<ELF32LE>>(Obj, Buf,
!Config.StripSections);
case ELFT_ELF64LE:
- return llvm::make_unique<ELFWriter<ELF64LE>>(File, Obj,
+ return llvm::make_unique<ELFWriter<ELF64LE>>(Obj, Buf,
!Config.StripSections);
case ELFT_ELF32BE:
- return llvm::make_unique<ELFWriter<ELF32BE>>(File, Obj,
+ return llvm::make_unique<ELFWriter<ELF32BE>>(Obj, Buf,
!Config.StripSections);
case ELFT_ELF64BE:
- return llvm::make_unique<ELFWriter<ELF64BE>>(File, Obj,
+ return llvm::make_unique<ELFWriter<ELF64BE>>(Obj, Buf,
!Config.StripSections);
}
llvm_unreachable("Invalid output format");
@@ -218,7 +220,8 @@ void SplitDWOToFile(const CopyConfig &Config, const Reader &Reader,
auto DWOFile = Reader.create();
DWOFile->removeSections(
[&](const SectionBase &Sec) { return OnlyKeepDWOPred(*DWOFile, Sec); });
- auto Writer = CreateWriter(Config, *DWOFile, File, OutputElfType);
+ FileBuffer FB(File);
+ auto Writer = CreateWriter(Config, *DWOFile, FB, OutputElfType);
Writer->finalize();
Writer->write();
}
@@ -441,26 +444,91 @@ void HandleArgs(const CopyConfig &Config, Object &Obj, const Reader &Reader,
Obj.addSection<GnuDebugLinkSection>(Config.AddGnuDebugLink);
}
-std::unique_ptr<Reader> CreateReader(StringRef InputFilename,
- ElfType &OutputElfType) {
- // Right now we can only read ELF files so there's only one reader;
- auto Out = llvm::make_unique<ELFReader>(InputFilename);
- // We need to set the default ElfType for output.
- OutputElfType = Out->getElfType();
- return std::move(Out);
-}
+void ExecuteElfObjcopyOnBinary(const CopyConfig &Config, Binary &Binary,
+ Buffer &Out) {
+ ELFReader Reader(&Binary);
+ std::unique_ptr<Object> Obj = Reader.create();
-void ExecuteElfObjcopy(const CopyConfig &Config) {
- ElfType OutputElfType;
- auto Reader = CreateReader(Config.InputFilename, OutputElfType);
- auto Obj = Reader->create();
- auto Writer =
- CreateWriter(Config, *Obj, Config.OutputFilename, OutputElfType);
- HandleArgs(Config, *Obj, *Reader, OutputElfType);
+ HandleArgs(Config, *Obj, Reader, Reader.getElfType());
+
+ std::unique_ptr<Writer> Writer =
+ CreateWriter(Config, *Obj, Out, Reader.getElfType());
Writer->finalize();
Writer->write();
}
+// For regular archives this function simply calls llvm::writeArchive,
+// For thin archives it writes the archive file itself as well as its members.
+Error deepWriteArchive(StringRef ArcName, ArrayRef<NewArchiveMember> NewMembers,
+ bool WriteSymtab, object::Archive::Kind Kind,
+ bool Deterministic, bool Thin) {
+ Error E =
+ writeArchive(ArcName, NewMembers, WriteSymtab, Kind, Deterministic, Thin);
+ if (!Thin || E)
+ return E;
+ for (const NewArchiveMember &Member : NewMembers) {
+ // Internally, FileBuffer will use the buffer created by
+ // FileOutputBuffer::create, for regular files (that is the case for
+ // deepWriteArchive) FileOutputBuffer::create will return OnDiskBuffer.
+ // OnDiskBuffer uses a temporary file and then renames it. So in reality
+ // there is no inefficiency / duplicated in-memory buffers in this case. For
+ // now in-memory buffers can not be completely avoided since
+ // NewArchiveMember still requires them even though writeArchive does not
+ // write them on disk.
+ FileBuffer FB(Member.MemberName);
+ FB.allocate(Member.Buf->getBufferSize());
+ std::copy(Member.Buf->getBufferStart(), Member.Buf->getBufferEnd(),
+ FB.getBufferStart());
+ if (auto E = FB.commit())
+ return E;
+ }
+ return Error::success();
+}
+
+void ExecuteElfObjcopyOnArchive(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());
+ Expected<StringRef> ChildNameOrErr = Child.getName();
+ if (!ChildNameOrErr)
+ reportError(Ar.getFileName(), ChildNameOrErr.takeError());
+
+ MemBuffer MB(ChildNameOrErr.get());
+ ExecuteElfObjcopyOnBinary(Config, **ChildOrErr, MB);
+
+ Expected<NewArchiveMember> Member =
+ NewArchiveMember::getOldMember(Child, true);
+ if (!Member)
+ reportError(Ar.getFileName(), Member.takeError());
+ Member->Buf = MB.releaseMemoryBuffer();
+ Member->MemberName = Member->Buf->getBufferIdentifier();
+ NewArchiveMembers.push_back(std::move(*Member));
+ }
+
+ if (Err)
+ reportError(Config.InputFilename, std::move(Err));
+ if (Error E =
+ deepWriteArchive(Config.OutputFilename, NewArchiveMembers,
+ Ar.hasSymbolTable(), Ar.kind(), true, Ar.isThin()))
+ reportError(Config.OutputFilename, std::move(E));
+}
+
+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.
@@ -584,7 +652,7 @@ CopyConfig ParseStripOptions(ArrayRef<const char *> ArgsArr) {
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);
OpenPOWER on IntegriCloud