mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-28 04:26:07 +00:00
[llvm-objcopy][NFC] replace class Buffer/MemBuffer/FileBuffer with streams.
During D88827 it was requested to remove the local implementation of Memory/File Buffers: // TODO: refactor the buffer classes in LLVM to enable us to use them here // directly. This patch uses raw_ostream instead of Buffers. Generally, using streams could allow us to reduce memory usages. No need to load all data into the memory - the data could be streamed through a smaller buffer. Thus, this patch uses raw_ostream as an interface for output data: Error executeObjcopyOnBinary(CopyConfig &Config, object::Binary &In, raw_ostream &Out); Note 1. This patch does not change the implementation of Writers so that data would be directly stored into raw_ostream. This is assumed to be done later. Note 2. It would be better if Writers would be implemented in a such way that data could be streamed without seeking/updating. If that would be inconvenient then raw_ostream could be replaced with raw_pwrite_stream to have a possibility to seek back and update file headers. This is assumed to be done later if necessary. Note 3. Current FileOutputBuffer allows using a memory-mapped file. The raw_fd_ostream (which could be used if data should be stored in the file) does not allow us to use a memory-mapped file. Memory map functionality could be implemented for raw_fd_ostream: It is possible to add resize() method into raw_ostream. class raw_ostream { void resize(uint64_t size); } That method, implemented for raw_fd_ostream, could create a memory-mapped file. The streamed data would be written into that memory file then. Thus we would be able to use memory-mapped files with raw_fd_ostream. This is assumed to be done later if necessary. Differential Revision: https://reviews.llvm.org/D91028
This commit is contained in:
parent
619c1505f9
commit
4f16e177e1
@ -92,8 +92,7 @@ public:
|
||||
|
||||
Error writeUniversalBinary(ArrayRef<Slice> Slices, StringRef OutputFileName);
|
||||
|
||||
Expected<std::unique_ptr<MemoryBuffer>>
|
||||
writeUniversalBinaryToBuffer(ArrayRef<Slice> Slices);
|
||||
Error writeUniversalBinaryToStream(ArrayRef<Slice> Slices, raw_ostream &Out);
|
||||
|
||||
} // end namespace object
|
||||
|
||||
|
@ -263,8 +263,8 @@ buildFatArchList(ArrayRef<Slice> Slices) {
|
||||
return FatArchList;
|
||||
}
|
||||
|
||||
static Error writeUniversalBinaryToStream(ArrayRef<Slice> Slices,
|
||||
raw_ostream &Out) {
|
||||
Error object::writeUniversalBinaryToStream(ArrayRef<Slice> Slices,
|
||||
raw_ostream &Out) {
|
||||
MachO::fat_header FatHeader;
|
||||
FatHeader.magic = MachO::FAT_MAGIC;
|
||||
FatHeader.nfat_arch = Slices.size();
|
||||
@ -324,14 +324,3 @@ Error object::writeUniversalBinary(ArrayRef<Slice> Slices,
|
||||
}
|
||||
return Temp->keep(OutputFileName);
|
||||
}
|
||||
|
||||
Expected<std::unique_ptr<MemoryBuffer>>
|
||||
object::writeUniversalBinaryToBuffer(ArrayRef<Slice> Slices) {
|
||||
SmallVector<char, 0> Buffer;
|
||||
raw_svector_ostream Out(Buffer);
|
||||
|
||||
if (Error E = writeUniversalBinaryToStream(Slices, Out))
|
||||
return std::move(E);
|
||||
|
||||
return std::make_unique<SmallVectorMemoryBuffer>(std::move(Buffer));
|
||||
}
|
||||
|
@ -1,84 +0,0 @@
|
||||
//===- Buffer.cpp ---------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "Buffer.h"
|
||||
#include "llvm/Support/FileOutputBuffer.h"
|
||||
#include "llvm/Support/FileSystem.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include "llvm/Support/Process.h"
|
||||
#include <memory>
|
||||
|
||||
namespace llvm {
|
||||
namespace objcopy {
|
||||
|
||||
Buffer::~Buffer() {}
|
||||
|
||||
static Error createEmptyFile(StringRef FileName) {
|
||||
// Create an empty tempfile and atomically swap it in place with the desired
|
||||
// output file.
|
||||
Expected<sys::fs::TempFile> Temp =
|
||||
sys::fs::TempFile::create(FileName + ".temp-empty-%%%%%%%");
|
||||
return Temp ? Temp->keep(FileName) : Temp.takeError();
|
||||
}
|
||||
|
||||
Error FileBuffer::allocate(size_t Size) {
|
||||
// When a 0-sized file is requested, skip allocation but defer file
|
||||
// creation/truncation until commit() to avoid side effects if something
|
||||
// happens between allocate() and commit().
|
||||
if (Size == 0) {
|
||||
EmptyFile = true;
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Expected<std::unique_ptr<FileOutputBuffer>> BufferOrErr =
|
||||
FileOutputBuffer::create(getName(), Size,
|
||||
KeepOwnership
|
||||
? FileOutputBuffer::F_executable |
|
||||
FileOutputBuffer::F_keep_ownership
|
||||
: FileOutputBuffer::F_executable,
|
||||
UserID, GroupID);
|
||||
// FileOutputBuffer::create() returns an Error that is just a wrapper around
|
||||
// std::error_code. Wrap it in FileError to include the actual filename.
|
||||
if (!BufferOrErr)
|
||||
return createFileError(getName(), BufferOrErr.takeError());
|
||||
Buf = std::move(*BufferOrErr);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error FileBuffer::commit() {
|
||||
if (EmptyFile)
|
||||
return createEmptyFile(getName());
|
||||
|
||||
assert(Buf && "allocate() not called before commit()!");
|
||||
Error Err = Buf->commit();
|
||||
// FileOutputBuffer::commit() returns an Error that is just a wrapper around
|
||||
// std::error_code. Wrap it in FileError to include the actual filename.
|
||||
return Err ? createFileError(getName(), std::move(Err)) : std::move(Err);
|
||||
}
|
||||
|
||||
uint8_t *FileBuffer::getBufferStart() {
|
||||
return reinterpret_cast<uint8_t *>(Buf->getBufferStart());
|
||||
}
|
||||
|
||||
Error MemBuffer::allocate(size_t Size) {
|
||||
Buf = WritableMemoryBuffer::getNewMemBuffer(Size, getName());
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
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
|
@ -1,73 +0,0 @@
|
||||
//===- Buffer.h -------------------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#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 Error 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;
|
||||
// Indicates that allocate(0) was called, and commit() should create or
|
||||
// truncate a file instead of using a FileOutputBuffer.
|
||||
bool EmptyFile = false;
|
||||
bool KeepOwnership = false;
|
||||
unsigned UserID = 0;
|
||||
unsigned GroupID = 0;
|
||||
|
||||
public:
|
||||
Error allocate(size_t Size) override;
|
||||
uint8_t *getBufferStart() override;
|
||||
Error commit() override;
|
||||
|
||||
explicit FileBuffer(StringRef FileName) : Buffer(FileName) {}
|
||||
explicit FileBuffer(StringRef FileName, bool Keep, unsigned UID, unsigned GID)
|
||||
: Buffer(FileName), KeepOwnership(Keep), UserID(UID), GroupID(GID) {}
|
||||
};
|
||||
|
||||
class MemBuffer : public Buffer {
|
||||
std::unique_ptr<WritableMemoryBuffer> Buf;
|
||||
|
||||
public:
|
||||
Error 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
|
@ -22,7 +22,6 @@ tablegen(LLVM StripOpts.inc -gen-opt-parser-defs)
|
||||
add_public_tablegen_target(StripOptsTableGen)
|
||||
|
||||
add_llvm_tool(llvm-objcopy
|
||||
Buffer.cpp
|
||||
CopyConfig.cpp
|
||||
llvm-objcopy.cpp
|
||||
COFF/COFFObjcopy.cpp
|
||||
|
@ -7,7 +7,6 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "COFFObjcopy.h"
|
||||
#include "Buffer.h"
|
||||
#include "CopyConfig.h"
|
||||
#include "Object.h"
|
||||
#include "Reader.h"
|
||||
@ -270,7 +269,7 @@ static Error handleArgs(const CopyConfig &Config, Object &Obj) {
|
||||
}
|
||||
|
||||
Error executeObjcopyOnBinary(const CopyConfig &Config, COFFObjectFile &In,
|
||||
Buffer &Out) {
|
||||
raw_ostream &Out) {
|
||||
COFFReader Reader(In);
|
||||
Expected<std::unique_ptr<Object>> ObjOrErr = Reader.create();
|
||||
if (!ObjOrErr)
|
||||
|
@ -11,6 +11,7 @@
|
||||
|
||||
namespace llvm {
|
||||
class Error;
|
||||
class raw_ostream;
|
||||
|
||||
namespace object {
|
||||
class COFFObjectFile;
|
||||
@ -18,11 +19,10 @@ class COFFObjectFile;
|
||||
|
||||
namespace objcopy {
|
||||
struct CopyConfig;
|
||||
class Buffer;
|
||||
|
||||
namespace coff {
|
||||
Error executeObjcopyOnBinary(const CopyConfig &Config,
|
||||
object::COFFObjectFile &In, Buffer &Out);
|
||||
object::COFFObjectFile &In, raw_ostream &Out);
|
||||
|
||||
} // end namespace coff
|
||||
} // end namespace objcopy
|
||||
|
@ -9,7 +9,6 @@
|
||||
#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"
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/BinaryFormat/COFF.h"
|
||||
#include "llvm/Object/COFF.h"
|
||||
#include "llvm/Support/Errc.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
@ -240,7 +241,7 @@ Error COFFWriter::finalize(bool IsBigObj) {
|
||||
}
|
||||
|
||||
void COFFWriter::writeHeaders(bool IsBigObj) {
|
||||
uint8_t *Ptr = Buf.getBufferStart();
|
||||
uint8_t *Ptr = reinterpret_cast<uint8_t *>(Buf->getBufferStart());
|
||||
if (Obj.IsPE) {
|
||||
memcpy(Ptr, &Obj.DosHeader, sizeof(Obj.DosHeader));
|
||||
Ptr += sizeof(Obj.DosHeader);
|
||||
@ -302,7 +303,8 @@ void COFFWriter::writeHeaders(bool IsBigObj) {
|
||||
|
||||
void COFFWriter::writeSections() {
|
||||
for (const auto &S : Obj.getSections()) {
|
||||
uint8_t *Ptr = Buf.getBufferStart() + S.Header.PointerToRawData;
|
||||
uint8_t *Ptr = reinterpret_cast<uint8_t *>(Buf->getBufferStart()) +
|
||||
S.Header.PointerToRawData;
|
||||
ArrayRef<uint8_t> Contents = S.getContents();
|
||||
std::copy(Contents.begin(), Contents.end(), Ptr);
|
||||
|
||||
@ -331,7 +333,8 @@ void COFFWriter::writeSections() {
|
||||
}
|
||||
|
||||
template <class SymbolTy> void COFFWriter::writeSymbolStringTables() {
|
||||
uint8_t *Ptr = Buf.getBufferStart() + Obj.CoffFileHeader.PointerToSymbolTable;
|
||||
uint8_t *Ptr = reinterpret_cast<uint8_t *>(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),
|
||||
@ -366,8 +369,11 @@ Error COFFWriter::write(bool IsBigObj) {
|
||||
if (Error E = finalize(IsBigObj))
|
||||
return E;
|
||||
|
||||
if (Error E = Buf.allocate(FileSize))
|
||||
return E;
|
||||
Buf = WritableMemoryBuffer::getNewMemBuffer(FileSize);
|
||||
if (!Buf)
|
||||
return createStringError(llvm::errc::not_enough_memory,
|
||||
"failed to allocate memory buffer of " +
|
||||
Twine::utohexstr(FileSize) + " bytes.");
|
||||
|
||||
writeHeaders(IsBigObj);
|
||||
writeSections();
|
||||
@ -380,7 +386,10 @@ Error COFFWriter::write(bool IsBigObj) {
|
||||
if (Error E = patchDebugDirectory())
|
||||
return E;
|
||||
|
||||
return Buf.commit();
|
||||
// TODO: Implement direct writing to the output stream (without intermediate
|
||||
// memory buffer Buf).
|
||||
Out.write(Buf->getBufferStart(), Buf->getBufferSize());
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Expected<uint32_t> COFFWriter::virtualAddressToFileAddress(uint32_t RVA) {
|
||||
@ -412,7 +421,8 @@ Error COFFWriter::patchDebugDirectory() {
|
||||
"debug directory extends past end of section");
|
||||
|
||||
size_t Offset = Dir->RelativeVirtualAddress - S.Header.VirtualAddress;
|
||||
uint8_t *Ptr = Buf.getBufferStart() + S.Header.PointerToRawData + Offset;
|
||||
uint8_t *Ptr = reinterpret_cast<uint8_t *>(Buf->getBufferStart()) +
|
||||
S.Header.PointerToRawData + Offset;
|
||||
uint8_t *End = Ptr + Dir->Size;
|
||||
while (Ptr < End) {
|
||||
debug_directory *Debug = reinterpret_cast<debug_directory *>(Ptr);
|
||||
|
@ -9,9 +9,9 @@
|
||||
#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 "llvm/Support/MemoryBuffer.h"
|
||||
#include <cstddef>
|
||||
#include <utility>
|
||||
|
||||
@ -23,7 +23,8 @@ struct Object;
|
||||
|
||||
class COFFWriter {
|
||||
Object &Obj;
|
||||
Buffer &Buf;
|
||||
std::unique_ptr<WritableMemoryBuffer> Buf;
|
||||
raw_ostream &Out;
|
||||
|
||||
size_t FileSize;
|
||||
size_t FileAlignment;
|
||||
@ -51,8 +52,8 @@ public:
|
||||
virtual ~COFFWriter() {}
|
||||
Error write();
|
||||
|
||||
COFFWriter(Object &Obj, Buffer &Buf)
|
||||
: Obj(Obj), Buf(Buf), StrTabBuilder(StringTableBuilder::WinCOFF) {}
|
||||
COFFWriter(Object &Obj, raw_ostream &Out)
|
||||
: Obj(Obj), Out(Out), StrTabBuilder(StringTableBuilder::WinCOFF) {}
|
||||
};
|
||||
|
||||
} // end namespace coff
|
||||
|
@ -7,9 +7,9 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "ELFObjcopy.h"
|
||||
#include "Buffer.h"
|
||||
#include "CopyConfig.h"
|
||||
#include "Object.h"
|
||||
#include "llvm-objcopy.h"
|
||||
#include "llvm/ADT/BitmaskEnum.h"
|
||||
#include "llvm/ADT/DenseSet.h"
|
||||
#include "llvm/ADT/Optional.h"
|
||||
@ -133,36 +133,36 @@ static ElfType getOutputElfType(const MachineInfo &MI) {
|
||||
}
|
||||
|
||||
static std::unique_ptr<Writer> createELFWriter(const CopyConfig &Config,
|
||||
Object &Obj, Buffer &Buf,
|
||||
Object &Obj, raw_ostream &Out,
|
||||
ElfType OutputElfType) {
|
||||
// Depending on the initial ELFT and OutputFormat we need a different Writer.
|
||||
switch (OutputElfType) {
|
||||
case ELFT_ELF32LE:
|
||||
return std::make_unique<ELFWriter<ELF32LE>>(Obj, Buf, !Config.StripSections,
|
||||
return std::make_unique<ELFWriter<ELF32LE>>(Obj, Out, !Config.StripSections,
|
||||
Config.OnlyKeepDebug);
|
||||
case ELFT_ELF64LE:
|
||||
return std::make_unique<ELFWriter<ELF64LE>>(Obj, Buf, !Config.StripSections,
|
||||
return std::make_unique<ELFWriter<ELF64LE>>(Obj, Out, !Config.StripSections,
|
||||
Config.OnlyKeepDebug);
|
||||
case ELFT_ELF32BE:
|
||||
return std::make_unique<ELFWriter<ELF32BE>>(Obj, Buf, !Config.StripSections,
|
||||
return std::make_unique<ELFWriter<ELF32BE>>(Obj, Out, !Config.StripSections,
|
||||
Config.OnlyKeepDebug);
|
||||
case ELFT_ELF64BE:
|
||||
return std::make_unique<ELFWriter<ELF64BE>>(Obj, Buf, !Config.StripSections,
|
||||
return std::make_unique<ELFWriter<ELF64BE>>(Obj, Out, !Config.StripSections,
|
||||
Config.OnlyKeepDebug);
|
||||
}
|
||||
llvm_unreachable("Invalid output format");
|
||||
}
|
||||
|
||||
static std::unique_ptr<Writer> createWriter(const CopyConfig &Config,
|
||||
Object &Obj, Buffer &Buf,
|
||||
Object &Obj, raw_ostream &Out,
|
||||
ElfType OutputElfType) {
|
||||
switch (Config.OutputFormat) {
|
||||
case FileFormat::Binary:
|
||||
return std::make_unique<BinaryWriter>(Obj, Buf);
|
||||
return std::make_unique<BinaryWriter>(Obj, Out);
|
||||
case FileFormat::IHex:
|
||||
return std::make_unique<IHexWriter>(Obj, Buf);
|
||||
return std::make_unique<IHexWriter>(Obj, Out);
|
||||
default:
|
||||
return createELFWriter(Config, Obj, Buf, OutputElfType);
|
||||
return createELFWriter(Config, Obj, Out, OutputElfType);
|
||||
}
|
||||
}
|
||||
|
||||
@ -189,12 +189,14 @@ static Error splitDWOToFile(const CopyConfig &Config, const Reader &Reader,
|
||||
(*DWOFile)->Machine = Config.OutputArch.getValue().EMachine;
|
||||
(*DWOFile)->OSABI = Config.OutputArch.getValue().OSABI;
|
||||
}
|
||||
FileBuffer FB(File);
|
||||
std::unique_ptr<Writer> Writer =
|
||||
createWriter(Config, **DWOFile, FB, OutputElfType);
|
||||
if (Error E = Writer->finalize())
|
||||
return E;
|
||||
return Writer->write();
|
||||
|
||||
return writeToFile(File, [&](raw_ostream &OutFile) -> Error {
|
||||
std::unique_ptr<Writer> Writer =
|
||||
createWriter(Config, **DWOFile, OutFile, OutputElfType);
|
||||
if (Error E = Writer->finalize())
|
||||
return E;
|
||||
return Writer->write();
|
||||
});
|
||||
}
|
||||
|
||||
static Error dumpSectionToFile(StringRef SecName, StringRef Filename,
|
||||
@ -686,8 +688,8 @@ static Error handleArgs(const CopyConfig &Config, Object &Obj,
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
static Error writeOutput(const CopyConfig &Config, Object &Obj, Buffer &Out,
|
||||
ElfType OutputElfType) {
|
||||
static Error writeOutput(const CopyConfig &Config, Object &Obj,
|
||||
raw_ostream &Out, ElfType OutputElfType) {
|
||||
std::unique_ptr<Writer> Writer =
|
||||
createWriter(Config, Obj, Out, OutputElfType);
|
||||
if (Error E = Writer->finalize())
|
||||
@ -696,7 +698,7 @@ static Error writeOutput(const CopyConfig &Config, Object &Obj, Buffer &Out,
|
||||
}
|
||||
|
||||
Error executeObjcopyOnIHex(const CopyConfig &Config, MemoryBuffer &In,
|
||||
Buffer &Out) {
|
||||
raw_ostream &Out) {
|
||||
IHexReader Reader(&In);
|
||||
Expected<std::unique_ptr<Object>> Obj = Reader.create(true);
|
||||
if (!Obj)
|
||||
@ -710,7 +712,7 @@ Error executeObjcopyOnIHex(const CopyConfig &Config, MemoryBuffer &In,
|
||||
}
|
||||
|
||||
Error executeObjcopyOnRawBinary(const CopyConfig &Config, MemoryBuffer &In,
|
||||
Buffer &Out) {
|
||||
raw_ostream &Out) {
|
||||
uint8_t NewSymbolVisibility =
|
||||
Config.ELF->NewSymbolVisibility.getValueOr((uint8_t)ELF::STV_DEFAULT);
|
||||
BinaryReader Reader(&In, NewSymbolVisibility);
|
||||
@ -728,7 +730,7 @@ Error executeObjcopyOnRawBinary(const CopyConfig &Config, MemoryBuffer &In,
|
||||
}
|
||||
|
||||
Error executeObjcopyOnBinary(const CopyConfig &Config,
|
||||
object::ELFObjectFileBase &In, Buffer &Out) {
|
||||
object::ELFObjectFileBase &In, raw_ostream &Out) {
|
||||
ELFReader Reader(&In, Config.ExtractPartition);
|
||||
Expected<std::unique_ptr<Object>> Obj =
|
||||
Reader.create(!Config.SymbolsToAdd.empty());
|
||||
|
@ -12,6 +12,7 @@
|
||||
namespace llvm {
|
||||
class Error;
|
||||
class MemoryBuffer;
|
||||
class raw_ostream;
|
||||
|
||||
namespace object {
|
||||
class ELFObjectFileBase;
|
||||
@ -19,15 +20,14 @@ class ELFObjectFileBase;
|
||||
|
||||
namespace objcopy {
|
||||
struct CopyConfig;
|
||||
class Buffer;
|
||||
|
||||
namespace elf {
|
||||
Error executeObjcopyOnIHex(const CopyConfig &Config, MemoryBuffer &In,
|
||||
Buffer &Out);
|
||||
raw_ostream &Out);
|
||||
Error executeObjcopyOnRawBinary(const CopyConfig &Config, MemoryBuffer &In,
|
||||
Buffer &Out);
|
||||
raw_ostream &Out);
|
||||
Error executeObjcopyOnBinary(const CopyConfig &Config,
|
||||
object::ELFObjectFileBase &In, Buffer &Out);
|
||||
object::ELFObjectFileBase &In, raw_ostream &Out);
|
||||
|
||||
} // end namespace elf
|
||||
} // end namespace objcopy
|
||||
|
@ -37,8 +37,8 @@ using namespace object;
|
||||
using namespace ELF;
|
||||
|
||||
template <class ELFT> void ELFWriter<ELFT>::writePhdr(const Segment &Seg) {
|
||||
uint8_t *B = Buf.getBufferStart() + Obj.ProgramHdrSegment.Offset +
|
||||
Seg.Index * sizeof(Elf_Phdr);
|
||||
uint8_t *B = reinterpret_cast<uint8_t *>(Buf->getBufferStart()) +
|
||||
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;
|
||||
@ -67,7 +67,8 @@ void SectionBase::replaceSectionReferences(
|
||||
void SectionBase::onRemove() {}
|
||||
|
||||
template <class ELFT> void ELFWriter<ELFT>::writeShdr(const SectionBase &Sec) {
|
||||
uint8_t *B = Buf.getBufferStart() + Sec.HeaderOffset;
|
||||
uint8_t *B =
|
||||
reinterpret_cast<uint8_t *>(Buf->getBufferStart()) + Sec.HeaderOffset;
|
||||
Elf_Shdr &Shdr = *reinterpret_cast<Elf_Shdr *>(B);
|
||||
Shdr.sh_name = Sec.NameIndex;
|
||||
Shdr.sh_type = Sec.Type;
|
||||
@ -474,7 +475,7 @@ Error ELFSectionWriter<ELFT>::visit(const DecompressedSection &Sec) {
|
||||
return createStringError(errc::invalid_argument,
|
||||
"'" + Sec.Name + "': " + toString(std::move(Err)));
|
||||
|
||||
uint8_t *Buf = Out.getBufferStart() + Sec.Offset;
|
||||
uint8_t *Buf = reinterpret_cast<uint8_t *>(Out.getBufferStart()) + Sec.Offset;
|
||||
std::copy(DecompressedContent.begin(), DecompressedContent.end(), Buf);
|
||||
|
||||
return Error::success();
|
||||
@ -519,7 +520,7 @@ Error BinarySectionWriter::visit(const CompressedSection &Sec) {
|
||||
|
||||
template <class ELFT>
|
||||
Error ELFSectionWriter<ELFT>::visit(const CompressedSection &Sec) {
|
||||
uint8_t *Buf = Out.getBufferStart() + Sec.Offset;
|
||||
uint8_t *Buf = reinterpret_cast<uint8_t *>(Out.getBufferStart()) + Sec.Offset;
|
||||
if (Sec.CompressionType == DebugCompressionType::None) {
|
||||
std::copy(Sec.OriginalData.begin(), Sec.OriginalData.end(), Buf);
|
||||
return Error::success();
|
||||
@ -624,7 +625,8 @@ void StringTableSection::prepareForLayout() {
|
||||
}
|
||||
|
||||
Error SectionWriter::visit(const StringTableSection &Sec) {
|
||||
Sec.StrTabBuilder.write(Out.getBufferStart() + Sec.Offset);
|
||||
Sec.StrTabBuilder.write(reinterpret_cast<uint8_t *>(Out.getBufferStart()) +
|
||||
Sec.Offset);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
@ -638,7 +640,7 @@ Error StringTableSection::accept(MutableSectionVisitor &Visitor) {
|
||||
|
||||
template <class ELFT>
|
||||
Error ELFSectionWriter<ELFT>::visit(const SectionIndexSection &Sec) {
|
||||
uint8_t *Buf = Out.getBufferStart() + Sec.Offset;
|
||||
uint8_t *Buf = reinterpret_cast<uint8_t *>(Out.getBufferStart()) + Sec.Offset;
|
||||
llvm::copy(Sec.Indexes, reinterpret_cast<Elf_Word *>(Buf));
|
||||
return Error::success();
|
||||
}
|
||||
@ -979,7 +981,7 @@ static void writeRel(const RelRange &Relocations, T *Buf) {
|
||||
|
||||
template <class ELFT>
|
||||
Error ELFSectionWriter<ELFT>::visit(const RelocationSection &Sec) {
|
||||
uint8_t *Buf = Out.getBufferStart() + Sec.Offset;
|
||||
uint8_t *Buf = reinterpret_cast<uint8_t *>(Out.getBufferStart()) + Sec.Offset;
|
||||
if (Sec.Type == SHT_REL)
|
||||
writeRel(Sec.Relocations, reinterpret_cast<Elf_Rel *>(Buf));
|
||||
else
|
||||
@ -1160,7 +1162,8 @@ GnuDebugLinkSection::GnuDebugLinkSection(StringRef File,
|
||||
|
||||
template <class ELFT>
|
||||
Error ELFSectionWriter<ELFT>::visit(const GnuDebugLinkSection &Sec) {
|
||||
unsigned char *Buf = Out.getBufferStart() + Sec.Offset;
|
||||
unsigned char *Buf =
|
||||
reinterpret_cast<uint8_t *>(Out.getBufferStart()) + Sec.Offset;
|
||||
Elf_Word *CRC =
|
||||
reinterpret_cast<Elf_Word *>(Buf + Sec.Size - sizeof(Elf_Word));
|
||||
*CRC = Sec.CRC32;
|
||||
@ -1972,7 +1975,7 @@ Expected<std::unique_ptr<Object>> ELFReader::create(bool EnsureSymtab) const {
|
||||
}
|
||||
|
||||
template <class ELFT> void ELFWriter<ELFT>::writeEhdr() {
|
||||
Elf_Ehdr &Ehdr = *reinterpret_cast<Elf_Ehdr *>(Buf.getBufferStart());
|
||||
Elf_Ehdr &Ehdr = *reinterpret_cast<Elf_Ehdr *>(Buf->getBufferStart());
|
||||
std::fill(Ehdr.e_ident, Ehdr.e_ident + 16, 0);
|
||||
Ehdr.e_ident[EI_MAG0] = 0x7f;
|
||||
Ehdr.e_ident[EI_MAG1] = 'E';
|
||||
@ -2037,7 +2040,7 @@ template <class ELFT> void ELFWriter<ELFT>::writeShdrs() {
|
||||
// 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.getBufferStart() + Obj.SHOff);
|
||||
*reinterpret_cast<Elf_Shdr *>(Buf->getBufferStart() + Obj.SHOff);
|
||||
Shdr.sh_name = 0;
|
||||
Shdr.sh_type = SHT_NULL;
|
||||
Shdr.sh_flags = 0;
|
||||
@ -2077,7 +2080,7 @@ template <class ELFT> Error ELFWriter<ELFT>::writeSectionData() {
|
||||
template <class ELFT> void ELFWriter<ELFT>::writeSegmentData() {
|
||||
for (Segment &Seg : Obj.segments()) {
|
||||
size_t Size = std::min<size_t>(Seg.FileSize, Seg.getContents().size());
|
||||
std::memcpy(Buf.getBufferStart() + Seg.Offset, Seg.getContents().data(),
|
||||
std::memcpy(Buf->getBufferStart() + Seg.Offset, Seg.getContents().data(),
|
||||
Size);
|
||||
}
|
||||
|
||||
@ -2088,12 +2091,12 @@ template <class ELFT> void ELFWriter<ELFT>::writeSegmentData() {
|
||||
continue;
|
||||
uint64_t Offset =
|
||||
Sec.OriginalOffset - Parent->OriginalOffset + Parent->Offset;
|
||||
std::memset(Buf.getBufferStart() + Offset, 0, Sec.Size);
|
||||
std::memset(Buf->getBufferStart() + Offset, 0, Sec.Size);
|
||||
}
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
ELFWriter<ELFT>::ELFWriter(Object &Obj, Buffer &Buf, bool WSH,
|
||||
ELFWriter<ELFT>::ELFWriter(Object &Obj, raw_ostream &Buf, bool WSH,
|
||||
bool OnlyKeepDebug)
|
||||
: Writer(Obj, Buf), WriteSectionHeaders(WSH && Obj.HadShdrs),
|
||||
OnlyKeepDebug(OnlyKeepDebug) {}
|
||||
@ -2410,7 +2413,11 @@ template <class ELFT> Error ELFWriter<ELFT>::write() {
|
||||
return E;
|
||||
if (WriteSectionHeaders)
|
||||
writeShdrs();
|
||||
return Buf.commit();
|
||||
|
||||
// TODO: Implement direct writing to the output stream (without intermediate
|
||||
// memory buffer Buf).
|
||||
Out.write(Buf->getBufferStart(), Buf->getBufferSize());
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
static Error removeUnneededSections(Object &Obj) {
|
||||
@ -2532,9 +2539,14 @@ template <class ELFT> Error ELFWriter<ELFT>::finalize() {
|
||||
Sec.finalize();
|
||||
}
|
||||
|
||||
if (Error E = Buf.allocate(totalSize()))
|
||||
return E;
|
||||
SecWriter = std::make_unique<ELFSectionWriter<ELFT>>(Buf);
|
||||
size_t TotalSize = totalSize();
|
||||
Buf = WritableMemoryBuffer::getNewMemBuffer(TotalSize);
|
||||
if (!Buf)
|
||||
return createStringError(errc::not_enough_memory,
|
||||
"failed to allocate memory buffer of " +
|
||||
Twine::utohexstr(TotalSize) + " bytes");
|
||||
|
||||
SecWriter = std::make_unique<ELFSectionWriter<ELFT>>(*Buf);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
@ -2543,7 +2555,10 @@ Error BinaryWriter::write() {
|
||||
if (Error Err = Sec.accept(*SecWriter))
|
||||
return Err;
|
||||
|
||||
return Buf.commit();
|
||||
// TODO: Implement direct writing to the output stream (without intermediate
|
||||
// memory buffer Buf).
|
||||
Out.write(Buf->getBufferStart(), Buf->getBufferSize());
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error BinaryWriter::finalize() {
|
||||
@ -2571,9 +2586,12 @@ Error BinaryWriter::finalize() {
|
||||
TotalSize = std::max(TotalSize, Sec.Offset + Sec.Size);
|
||||
}
|
||||
|
||||
if (Error E = Buf.allocate(TotalSize))
|
||||
return E;
|
||||
SecWriter = std::make_unique<BinarySectionWriter>(Buf);
|
||||
Buf = WritableMemoryBuffer::getNewMemBuffer(TotalSize);
|
||||
if (!Buf)
|
||||
return createStringError(errc::not_enough_memory,
|
||||
"failed to allocate memory buffer of " +
|
||||
Twine::utohexstr(TotalSize) + " bytes");
|
||||
SecWriter = std::make_unique<BinarySectionWriter>(*Buf);
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
@ -2611,7 +2629,7 @@ uint64_t IHexWriter::writeEndOfFileRecord(uint8_t *Buf) {
|
||||
}
|
||||
|
||||
Error IHexWriter::write() {
|
||||
IHexSectionWriter Writer(Buf);
|
||||
IHexSectionWriter Writer(*Buf);
|
||||
// Write sections.
|
||||
for (const SectionBase *Sec : Sections)
|
||||
if (Error Err = Sec->accept(Writer))
|
||||
@ -2619,11 +2637,17 @@ Error IHexWriter::write() {
|
||||
|
||||
uint64_t Offset = Writer.getBufferOffset();
|
||||
// Write entry point address.
|
||||
Offset += writeEntryPointRecord(Buf.getBufferStart() + Offset);
|
||||
Offset += writeEntryPointRecord(
|
||||
reinterpret_cast<uint8_t *>(Buf->getBufferStart()) + Offset);
|
||||
// Write EOF.
|
||||
Offset += writeEndOfFileRecord(Buf.getBufferStart() + Offset);
|
||||
Offset += writeEndOfFileRecord(
|
||||
reinterpret_cast<uint8_t *>(Buf->getBufferStart()) + Offset);
|
||||
assert(Offset == TotalSize);
|
||||
return Buf.commit();
|
||||
|
||||
// TODO: Implement direct writing to the output stream (without intermediate
|
||||
// memory buffer Buf).
|
||||
Out.write(Buf->getBufferStart(), Buf->getBufferSize());
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
Error IHexWriter::checkSection(const SectionBase &Sec) {
|
||||
@ -2648,7 +2672,7 @@ Error IHexWriter::finalize() {
|
||||
// We can't write 64-bit addresses.
|
||||
if (addressOverflows32bit(Obj.Entry))
|
||||
return createStringError(errc::invalid_argument,
|
||||
"Entry point address 0x%llx overflows 32 bits.",
|
||||
"Entry point address 0x%llx overflows 32 bits",
|
||||
Obj.Entry);
|
||||
|
||||
// If any section we're to write has segment then we
|
||||
@ -2667,7 +2691,13 @@ Error IHexWriter::finalize() {
|
||||
Sections.insert(&Sec);
|
||||
}
|
||||
|
||||
IHexSectionWriterBase LengthCalc(Buf);
|
||||
std::unique_ptr<WritableMemoryBuffer> EmptyBuffer =
|
||||
WritableMemoryBuffer::getNewMemBuffer(0);
|
||||
if (!EmptyBuffer)
|
||||
return createStringError(errc::not_enough_memory,
|
||||
"failed to allocate memory buffer of 0 bytes");
|
||||
|
||||
IHexSectionWriterBase LengthCalc(*EmptyBuffer);
|
||||
for (const SectionBase *Sec : Sections)
|
||||
if (Error Err = Sec->accept(LengthCalc))
|
||||
return Err;
|
||||
@ -2677,8 +2707,13 @@ Error IHexWriter::finalize() {
|
||||
TotalSize = LengthCalc.getBufferOffset() +
|
||||
(Obj.Entry ? IHexRecord::getLineLength(4) : 0) +
|
||||
IHexRecord::getLineLength(0);
|
||||
if (Error E = Buf.allocate(TotalSize))
|
||||
return E;
|
||||
|
||||
Buf = WritableMemoryBuffer::getNewMemBuffer(TotalSize);
|
||||
if (!Buf)
|
||||
return createStringError(errc::not_enough_memory,
|
||||
"failed to allocate memory buffer of " +
|
||||
Twine::utohexstr(TotalSize) + " bytes");
|
||||
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,6 @@
|
||||
#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"
|
||||
@ -19,6 +18,7 @@
|
||||
#include "llvm/Object/ELFObjectFile.h"
|
||||
#include "llvm/Support/Errc.h"
|
||||
#include "llvm/Support/FileOutputBuffer.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
@ -106,7 +106,7 @@ public:
|
||||
|
||||
class SectionWriter : public SectionVisitor {
|
||||
protected:
|
||||
Buffer &Out;
|
||||
WritableMemoryBuffer &Out;
|
||||
|
||||
public:
|
||||
virtual ~SectionWriter() = default;
|
||||
@ -123,7 +123,7 @@ public:
|
||||
virtual Error visit(const CompressedSection &Sec) override = 0;
|
||||
virtual Error visit(const DecompressedSection &Sec) override = 0;
|
||||
|
||||
explicit SectionWriter(Buffer &Buf) : Out(Buf) {}
|
||||
explicit SectionWriter(WritableMemoryBuffer &Buf) : Out(Buf) {}
|
||||
};
|
||||
|
||||
template <class ELFT> class ELFSectionWriter : public SectionWriter {
|
||||
@ -143,7 +143,7 @@ public:
|
||||
Error visit(const CompressedSection &Sec) override;
|
||||
Error visit(const DecompressedSection &Sec) override;
|
||||
|
||||
explicit ELFSectionWriter(Buffer &Buf) : SectionWriter(Buf) {}
|
||||
explicit ELFSectionWriter(WritableMemoryBuffer &Buf) : SectionWriter(Buf) {}
|
||||
};
|
||||
|
||||
template <class ELFT> class ELFSectionSizer : public MutableSectionVisitor {
|
||||
@ -187,7 +187,8 @@ public:
|
||||
Error visit(const CompressedSection &Sec) override;
|
||||
Error visit(const DecompressedSection &Sec) override;
|
||||
|
||||
explicit BinarySectionWriter(Buffer &Buf) : SectionWriter(Buf) {}
|
||||
explicit BinarySectionWriter(WritableMemoryBuffer &Buf)
|
||||
: SectionWriter(Buf) {}
|
||||
};
|
||||
|
||||
using IHexLineData = SmallVector<char, 64>;
|
||||
@ -283,7 +284,8 @@ protected:
|
||||
virtual void writeData(uint8_t Type, uint16_t Addr, ArrayRef<uint8_t> Data);
|
||||
|
||||
public:
|
||||
explicit IHexSectionWriterBase(Buffer &Buf) : BinarySectionWriter(Buf) {}
|
||||
explicit IHexSectionWriterBase(WritableMemoryBuffer &Buf)
|
||||
: BinarySectionWriter(Buf) {}
|
||||
|
||||
uint64_t getBufferOffset() const { return Offset; }
|
||||
Error visit(const Section &Sec) final;
|
||||
@ -296,7 +298,7 @@ public:
|
||||
// Real IHEX section writer
|
||||
class IHexSectionWriter : public IHexSectionWriterBase {
|
||||
public:
|
||||
IHexSectionWriter(Buffer &Buf) : IHexSectionWriterBase(Buf) {}
|
||||
IHexSectionWriter(WritableMemoryBuffer &Buf) : IHexSectionWriterBase(Buf) {}
|
||||
|
||||
void writeData(uint8_t Type, uint16_t Addr, ArrayRef<uint8_t> Data) override;
|
||||
Error visit(const StringTableSection &Sec) override;
|
||||
@ -305,14 +307,15 @@ public:
|
||||
class Writer {
|
||||
protected:
|
||||
Object &Obj;
|
||||
Buffer &Buf;
|
||||
std::unique_ptr<WritableMemoryBuffer> Buf;
|
||||
raw_ostream &Out;
|
||||
|
||||
public:
|
||||
virtual ~Writer();
|
||||
virtual Error finalize() = 0;
|
||||
virtual Error write() = 0;
|
||||
|
||||
Writer(Object &O, Buffer &B) : Obj(O), Buf(B) {}
|
||||
Writer(Object &O, raw_ostream &Out) : Obj(O), Out(Out) {}
|
||||
};
|
||||
|
||||
template <class ELFT> class ELFWriter : public Writer {
|
||||
@ -349,7 +352,7 @@ public:
|
||||
|
||||
Error finalize() override;
|
||||
Error write() override;
|
||||
ELFWriter(Object &Obj, Buffer &Buf, bool WSH, bool OnlyKeepDebug);
|
||||
ELFWriter(Object &Obj, raw_ostream &Out, bool WSH, bool OnlyKeepDebug);
|
||||
};
|
||||
|
||||
class BinaryWriter : public Writer {
|
||||
@ -362,7 +365,7 @@ public:
|
||||
~BinaryWriter() {}
|
||||
Error finalize() override;
|
||||
Error write() override;
|
||||
BinaryWriter(Object &Obj, Buffer &Buf) : Writer(Obj, Buf) {}
|
||||
BinaryWriter(Object &Obj, raw_ostream &Out) : Writer(Obj, Out) {}
|
||||
};
|
||||
|
||||
class IHexWriter : public Writer {
|
||||
@ -381,7 +384,7 @@ public:
|
||||
~IHexWriter() {}
|
||||
Error finalize() override;
|
||||
Error write() override;
|
||||
IHexWriter(Object &Obj, Buffer &Buf) : Writer(Obj, Buf) {}
|
||||
IHexWriter(Object &Obj, raw_ostream &Out) : Writer(Obj, Out) {}
|
||||
};
|
||||
|
||||
class SectionBase {
|
||||
|
@ -17,6 +17,8 @@
|
||||
#include "llvm/Object/MachOUniversalWriter.h"
|
||||
#include "llvm/Support/Errc.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
#include "llvm/Support/FileOutputBuffer.h"
|
||||
#include "llvm/Support/SmallVectorMemoryBuffer.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace objcopy {
|
||||
@ -386,7 +388,7 @@ static Error handleArgs(const CopyConfig &Config, Object &Obj) {
|
||||
}
|
||||
|
||||
Error executeObjcopyOnBinary(const CopyConfig &Config,
|
||||
object::MachOObjectFile &In, Buffer &Out) {
|
||||
object::MachOObjectFile &In, raw_ostream &Out) {
|
||||
MachOReader Reader(In);
|
||||
Expected<std::unique_ptr<Object>> O = Reader.create();
|
||||
if (!O)
|
||||
@ -416,7 +418,7 @@ Error executeObjcopyOnBinary(const CopyConfig &Config,
|
||||
|
||||
Error executeObjcopyOnMachOUniversalBinary(CopyConfig &Config,
|
||||
const MachOUniversalBinary &In,
|
||||
Buffer &Out) {
|
||||
raw_ostream &Out) {
|
||||
SmallVector<OwningBinary<Binary>, 2> Binaries;
|
||||
SmallVector<Slice, 2> Slices;
|
||||
for (const auto &O : In.objects()) {
|
||||
@ -460,27 +462,28 @@ Error executeObjcopyOnMachOUniversalBinary(CopyConfig &Config,
|
||||
Config.InputFilename.str().c_str());
|
||||
}
|
||||
std::string ArchFlagName = O.getArchFlagName();
|
||||
MemBuffer MB(ArchFlagName);
|
||||
if (Error E = executeObjcopyOnBinary(Config, **ObjOrErr, MB))
|
||||
|
||||
SmallVector<char, 0> Buffer;
|
||||
raw_svector_ostream MemStream(Buffer);
|
||||
|
||||
if (Error E = executeObjcopyOnBinary(Config, **ObjOrErr, MemStream))
|
||||
return E;
|
||||
std::unique_ptr<WritableMemoryBuffer> OutputBuffer =
|
||||
MB.releaseMemoryBuffer();
|
||||
Expected<std::unique_ptr<Binary>> BinaryOrErr =
|
||||
object::createBinary(*OutputBuffer);
|
||||
|
||||
std::unique_ptr<MemoryBuffer> MB =
|
||||
std::make_unique<SmallVectorMemoryBuffer>(std::move(Buffer),
|
||||
ArchFlagName);
|
||||
Expected<std::unique_ptr<Binary>> BinaryOrErr = object::createBinary(*MB);
|
||||
if (!BinaryOrErr)
|
||||
return BinaryOrErr.takeError();
|
||||
Binaries.emplace_back(std::move(*BinaryOrErr), std::move(OutputBuffer));
|
||||
Binaries.emplace_back(std::move(*BinaryOrErr), std::move(MB));
|
||||
Slices.emplace_back(*cast<MachOObjectFile>(Binaries.back().getBinary()),
|
||||
O.getAlign());
|
||||
}
|
||||
Expected<std::unique_ptr<MemoryBuffer>> B =
|
||||
writeUniversalBinaryToBuffer(Slices);
|
||||
if (!B)
|
||||
return B.takeError();
|
||||
if (Error E = Out.allocate((*B)->getBufferSize()))
|
||||
return E;
|
||||
memcpy(Out.getBufferStart(), (*B)->getBufferStart(), (*B)->getBufferSize());
|
||||
return Out.commit();
|
||||
|
||||
if (Error Err = writeUniversalBinaryToStream(Slices, Out))
|
||||
return Err;
|
||||
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
} // end namespace macho
|
||||
|
@ -11,6 +11,7 @@
|
||||
|
||||
namespace llvm {
|
||||
class Error;
|
||||
class raw_ostream;
|
||||
|
||||
namespace object {
|
||||
class MachOObjectFile;
|
||||
@ -23,10 +24,11 @@ class Buffer;
|
||||
|
||||
namespace macho {
|
||||
Error executeObjcopyOnBinary(const CopyConfig &Config,
|
||||
object::MachOObjectFile &In, Buffer &Out);
|
||||
object::MachOObjectFile &In, raw_ostream &Out);
|
||||
|
||||
Error executeObjcopyOnMachOUniversalBinary(
|
||||
CopyConfig &Config, const object::MachOUniversalBinary &In, Buffer &Out);
|
||||
CopyConfig &Config, const object::MachOUniversalBinary &In,
|
||||
raw_ostream &Out);
|
||||
|
||||
} // end namespace macho
|
||||
} // end namespace objcopy
|
||||
|
@ -159,11 +159,12 @@ void MachOWriter::writeHeader() {
|
||||
|
||||
auto HeaderSize =
|
||||
Is64Bit ? sizeof(MachO::mach_header_64) : sizeof(MachO::mach_header);
|
||||
memcpy(B.getBufferStart(), &Header, HeaderSize);
|
||||
memcpy(Buf->getBufferStart(), &Header, HeaderSize);
|
||||
}
|
||||
|
||||
void MachOWriter::writeLoadCommands() {
|
||||
uint8_t *Begin = B.getBufferStart() + headerSize();
|
||||
uint8_t *Begin =
|
||||
reinterpret_cast<uint8_t *>(Buf->getBufferStart()) + headerSize();
|
||||
for (const LoadCommand &LC : O.LoadCommands) {
|
||||
// Construct a load command.
|
||||
MachO::macho_load_command MLC = LC.MachOLoadCommand;
|
||||
@ -257,7 +258,7 @@ void MachOWriter::writeSections() {
|
||||
|
||||
assert(Sec->Offset && "Section offset can not be zero");
|
||||
assert((Sec->Size == Sec->Content.size()) && "Incorrect section size");
|
||||
memcpy(B.getBufferStart() + Sec->Offset, Sec->Content.data(),
|
||||
memcpy(Buf->getBufferStart() + Sec->Offset, Sec->Content.data(),
|
||||
Sec->Content.size());
|
||||
for (size_t Index = 0; Index < Sec->Relocations.size(); ++Index) {
|
||||
RelocationInfo RelocInfo = Sec->Relocations[Index];
|
||||
@ -270,7 +271,7 @@ void MachOWriter::writeSections() {
|
||||
if (IsLittleEndian != sys::IsLittleEndianHost)
|
||||
MachO::swapStruct(
|
||||
reinterpret_cast<MachO::any_relocation_info &>(RelocInfo.Info));
|
||||
memcpy(B.getBufferStart() + Sec->RelOff +
|
||||
memcpy(Buf->getBufferStart() + Sec->RelOff +
|
||||
Index * sizeof(MachO::any_relocation_info),
|
||||
&RelocInfo.Info, sizeof(RelocInfo.Info));
|
||||
}
|
||||
@ -300,7 +301,7 @@ void MachOWriter::writeStringTable() {
|
||||
O.LoadCommands[*O.SymTabCommandIndex]
|
||||
.MachOLoadCommand.symtab_command_data;
|
||||
|
||||
uint8_t *StrTable = (uint8_t *)B.getBufferStart() + SymTabCommand.stroff;
|
||||
uint8_t *StrTable = (uint8_t *)Buf->getBufferStart() + SymTabCommand.stroff;
|
||||
LayoutBuilder.getStringTableBuilder().write(StrTable);
|
||||
}
|
||||
|
||||
@ -311,7 +312,7 @@ void MachOWriter::writeSymbolTable() {
|
||||
O.LoadCommands[*O.SymTabCommandIndex]
|
||||
.MachOLoadCommand.symtab_command_data;
|
||||
|
||||
char *SymTable = (char *)B.getBufferStart() + SymTabCommand.symoff;
|
||||
char *SymTable = (char *)Buf->getBufferStart() + SymTabCommand.symoff;
|
||||
for (auto Iter = O.SymTable.Symbols.begin(), End = O.SymTable.Symbols.end();
|
||||
Iter != End; Iter++) {
|
||||
SymbolEntry *Sym = Iter->get();
|
||||
@ -330,7 +331,7 @@ void MachOWriter::writeRebaseInfo() {
|
||||
const MachO::dyld_info_command &DyLdInfoCommand =
|
||||
O.LoadCommands[*O.DyLdInfoCommandIndex]
|
||||
.MachOLoadCommand.dyld_info_command_data;
|
||||
char *Out = (char *)B.getBufferStart() + DyLdInfoCommand.rebase_off;
|
||||
char *Out = (char *)Buf->getBufferStart() + DyLdInfoCommand.rebase_off;
|
||||
assert((DyLdInfoCommand.rebase_size == O.Rebases.Opcodes.size()) &&
|
||||
"Incorrect rebase opcodes size");
|
||||
memcpy(Out, O.Rebases.Opcodes.data(), O.Rebases.Opcodes.size());
|
||||
@ -342,7 +343,7 @@ void MachOWriter::writeBindInfo() {
|
||||
const MachO::dyld_info_command &DyLdInfoCommand =
|
||||
O.LoadCommands[*O.DyLdInfoCommandIndex]
|
||||
.MachOLoadCommand.dyld_info_command_data;
|
||||
char *Out = (char *)B.getBufferStart() + DyLdInfoCommand.bind_off;
|
||||
char *Out = (char *)Buf->getBufferStart() + DyLdInfoCommand.bind_off;
|
||||
assert((DyLdInfoCommand.bind_size == O.Binds.Opcodes.size()) &&
|
||||
"Incorrect bind opcodes size");
|
||||
memcpy(Out, O.Binds.Opcodes.data(), O.Binds.Opcodes.size());
|
||||
@ -354,7 +355,7 @@ void MachOWriter::writeWeakBindInfo() {
|
||||
const MachO::dyld_info_command &DyLdInfoCommand =
|
||||
O.LoadCommands[*O.DyLdInfoCommandIndex]
|
||||
.MachOLoadCommand.dyld_info_command_data;
|
||||
char *Out = (char *)B.getBufferStart() + DyLdInfoCommand.weak_bind_off;
|
||||
char *Out = (char *)Buf->getBufferStart() + DyLdInfoCommand.weak_bind_off;
|
||||
assert((DyLdInfoCommand.weak_bind_size == O.WeakBinds.Opcodes.size()) &&
|
||||
"Incorrect weak bind opcodes size");
|
||||
memcpy(Out, O.WeakBinds.Opcodes.data(), O.WeakBinds.Opcodes.size());
|
||||
@ -366,7 +367,7 @@ void MachOWriter::writeLazyBindInfo() {
|
||||
const MachO::dyld_info_command &DyLdInfoCommand =
|
||||
O.LoadCommands[*O.DyLdInfoCommandIndex]
|
||||
.MachOLoadCommand.dyld_info_command_data;
|
||||
char *Out = (char *)B.getBufferStart() + DyLdInfoCommand.lazy_bind_off;
|
||||
char *Out = (char *)Buf->getBufferStart() + DyLdInfoCommand.lazy_bind_off;
|
||||
assert((DyLdInfoCommand.lazy_bind_size == O.LazyBinds.Opcodes.size()) &&
|
||||
"Incorrect lazy bind opcodes size");
|
||||
memcpy(Out, O.LazyBinds.Opcodes.data(), O.LazyBinds.Opcodes.size());
|
||||
@ -378,7 +379,7 @@ void MachOWriter::writeExportInfo() {
|
||||
const MachO::dyld_info_command &DyLdInfoCommand =
|
||||
O.LoadCommands[*O.DyLdInfoCommandIndex]
|
||||
.MachOLoadCommand.dyld_info_command_data;
|
||||
char *Out = (char *)B.getBufferStart() + DyLdInfoCommand.export_off;
|
||||
char *Out = (char *)Buf->getBufferStart() + DyLdInfoCommand.export_off;
|
||||
assert((DyLdInfoCommand.export_size == O.Exports.Trie.size()) &&
|
||||
"Incorrect export trie size");
|
||||
memcpy(Out, O.Exports.Trie.data(), O.Exports.Trie.size());
|
||||
@ -393,7 +394,7 @@ void MachOWriter::writeIndirectSymbolTable() {
|
||||
.MachOLoadCommand.dysymtab_command_data;
|
||||
|
||||
uint32_t *Out =
|
||||
(uint32_t *)(B.getBufferStart() + DySymTabCommand.indirectsymoff);
|
||||
(uint32_t *)(Buf->getBufferStart() + DySymTabCommand.indirectsymoff);
|
||||
for (const IndirectSymbolEntry &Sym : O.IndirectSymTable.Symbols) {
|
||||
uint32_t Entry = (Sym.Symbol) ? (*Sym.Symbol)->Index : Sym.OriginalIndex;
|
||||
if (IsLittleEndian != sys::IsLittleEndianHost)
|
||||
@ -407,7 +408,7 @@ void MachOWriter::writeLinkData(Optional<size_t> LCIndex, const LinkData &LD) {
|
||||
return;
|
||||
const MachO::linkedit_data_command &LinkEditDataCommand =
|
||||
O.LoadCommands[*LCIndex].MachOLoadCommand.linkedit_data_command_data;
|
||||
char *Out = (char *)B.getBufferStart() + LinkEditDataCommand.dataoff;
|
||||
char *Out = (char *)Buf->getBufferStart() + LinkEditDataCommand.dataoff;
|
||||
assert((LinkEditDataCommand.datasize == LD.Data.size()) &&
|
||||
"Incorrect data size");
|
||||
memcpy(Out, LD.Data.data(), LD.Data.size());
|
||||
@ -511,14 +512,22 @@ void MachOWriter::writeTail() {
|
||||
Error MachOWriter::finalize() { return LayoutBuilder.layout(); }
|
||||
|
||||
Error MachOWriter::write() {
|
||||
if (Error E = B.allocate(totalSize()))
|
||||
return E;
|
||||
memset(B.getBufferStart(), 0, totalSize());
|
||||
size_t TotalSize = totalSize();
|
||||
Buf = WritableMemoryBuffer::getNewMemBuffer(TotalSize);
|
||||
if (!Buf)
|
||||
return createStringError(errc::not_enough_memory,
|
||||
"failed to allocate memory buffer of " +
|
||||
Twine::utohexstr(TotalSize) + " bytes");
|
||||
memset(Buf->getBufferStart(), 0, totalSize());
|
||||
writeHeader();
|
||||
writeLoadCommands();
|
||||
writeSections();
|
||||
writeTail();
|
||||
return B.commit();
|
||||
|
||||
// TODO: Implement direct writing to the output stream (without intermediate
|
||||
// memory buffer Buf).
|
||||
Out.write(Buf->getBufferStart(), Buf->getBufferSize());
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
} // end namespace macho
|
||||
|
@ -6,7 +6,6 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "../Buffer.h"
|
||||
#include "MachOLayoutBuilder.h"
|
||||
#include "MachOObjcopy.h"
|
||||
#include "Object.h"
|
||||
@ -24,7 +23,8 @@ class MachOWriter {
|
||||
bool Is64Bit;
|
||||
bool IsLittleEndian;
|
||||
uint64_t PageSize;
|
||||
Buffer &B;
|
||||
std::unique_ptr<WritableMemoryBuffer> Buf;
|
||||
raw_ostream &Out;
|
||||
MachOLayoutBuilder LayoutBuilder;
|
||||
|
||||
size_t headerSize() const;
|
||||
@ -53,9 +53,9 @@ class MachOWriter {
|
||||
|
||||
public:
|
||||
MachOWriter(Object &O, bool Is64Bit, bool IsLittleEndian, uint64_t PageSize,
|
||||
Buffer &B)
|
||||
raw_ostream &Out)
|
||||
: O(O), Is64Bit(Is64Bit), IsLittleEndian(IsLittleEndian),
|
||||
PageSize(PageSize), B(B), LayoutBuilder(O, Is64Bit, PageSize) {}
|
||||
PageSize(PageSize), Out(Out), LayoutBuilder(O, Is64Bit, PageSize) {}
|
||||
|
||||
size_t totalSize() const;
|
||||
Error finalize();
|
||||
|
@ -6,7 +6,7 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "Buffer.h"
|
||||
#include "llvm-objcopy.h"
|
||||
#include "COFF/COFFObjcopy.h"
|
||||
#include "CopyConfig.h"
|
||||
#include "ELF/ELFObjcopy.h"
|
||||
@ -17,6 +17,7 @@
|
||||
#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"
|
||||
@ -32,6 +33,7 @@
|
||||
#include "llvm/Option/Option.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/Errc.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/ErrorOr.h"
|
||||
@ -40,6 +42,7 @@
|
||||
#include "llvm/Support/Memory.h"
|
||||
#include "llvm/Support/Path.h"
|
||||
#include "llvm/Support/Process.h"
|
||||
#include "llvm/Support/SmallVectorMemoryBuffer.h"
|
||||
#include "llvm/Support/StringSaver.h"
|
||||
#include "llvm/Support/WithColor.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
@ -54,6 +57,44 @@
|
||||
namespace llvm {
|
||||
namespace objcopy {
|
||||
|
||||
Error writeToFile(StringRef OutputFileName,
|
||||
std::function<Error(raw_ostream &)> Write, bool KeepOwnership,
|
||||
unsigned UserID, unsigned GroupID) {
|
||||
if (OutputFileName == "-")
|
||||
return Write(outs());
|
||||
|
||||
if (OutputFileName == "/dev/null") {
|
||||
raw_null_ostream Out;
|
||||
return Write(Out);
|
||||
}
|
||||
|
||||
unsigned Mode = sys::fs::all_read | sys::fs::all_write | sys::fs::all_exe;
|
||||
Expected<sys::fs::TempFile> Temp =
|
||||
sys::fs::TempFile::create(OutputFileName + ".temp-objcopy-%%%%%%", Mode);
|
||||
if (!Temp)
|
||||
return createFileError(OutputFileName, Temp.takeError());
|
||||
|
||||
#ifndef _WIN32
|
||||
// Try to preserve file ownership if requested.
|
||||
if (KeepOwnership) {
|
||||
sys::fs::file_status Stat;
|
||||
if (!sys::fs::status(Temp->FD, Stat) && Stat.getUser() == 0)
|
||||
sys::fs::changeFileOwnership(Temp->FD, UserID, GroupID);
|
||||
}
|
||||
#endif
|
||||
|
||||
raw_fd_ostream Out(Temp->FD, false);
|
||||
|
||||
if (Error E = Write(Out)) {
|
||||
if (Error DiscardError = Temp->discard())
|
||||
return joinErrors(std::move(E), std::move(DiscardError));
|
||||
return E;
|
||||
}
|
||||
Out.flush();
|
||||
|
||||
return Temp->keep(OutputFileName);
|
||||
}
|
||||
|
||||
// The name this program was invoked as.
|
||||
StringRef ToolName;
|
||||
|
||||
@ -108,20 +149,21 @@ static Error deepWriteArchive(StringRef ArcName,
|
||||
return Error::success();
|
||||
|
||||
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.
|
||||
// For regular files (as 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);
|
||||
if (Error E = FB.allocate(Member.Buf->getBufferSize()))
|
||||
return E;
|
||||
Expected<std::unique_ptr<FileOutputBuffer>> FB = FileOutputBuffer::create(
|
||||
Member.MemberName, Member.Buf->getBufferSize(),
|
||||
FileOutputBuffer::F_executable | FileOutputBuffer::F_keep_ownership);
|
||||
if (!FB)
|
||||
return FB.takeError();
|
||||
std::copy(Member.Buf->getBufferStart(), Member.Buf->getBufferEnd(),
|
||||
FB.getBufferStart());
|
||||
if (Error E = FB.commit())
|
||||
(*FB)->getBufferStart());
|
||||
if (Error E = (*FB)->commit())
|
||||
return E;
|
||||
}
|
||||
return Error::success();
|
||||
@ -130,7 +172,7 @@ static Error deepWriteArchive(StringRef ArcName,
|
||||
/// The function executeObjcopyOnIHex does the dispatch based on the format
|
||||
/// of the output specified by the command line options.
|
||||
static Error executeObjcopyOnIHex(CopyConfig &Config, MemoryBuffer &In,
|
||||
Buffer &Out) {
|
||||
raw_ostream &Out) {
|
||||
// TODO: support output formats other than ELF.
|
||||
if (Error E = Config.parseELFConfig())
|
||||
return E;
|
||||
@ -140,7 +182,7 @@ static Error executeObjcopyOnIHex(CopyConfig &Config, MemoryBuffer &In,
|
||||
/// The function executeObjcopyOnRawBinary does the dispatch based on the format
|
||||
/// of the output specified by the command line options.
|
||||
static Error executeObjcopyOnRawBinary(CopyConfig &Config, MemoryBuffer &In,
|
||||
Buffer &Out) {
|
||||
raw_ostream &Out) {
|
||||
switch (Config.OutputFormat) {
|
||||
case FileFormat::ELF:
|
||||
// FIXME: Currently, we call elf::executeObjcopyOnRawBinary even if the
|
||||
@ -160,7 +202,7 @@ static Error executeObjcopyOnRawBinary(CopyConfig &Config, MemoryBuffer &In,
|
||||
/// The function executeObjcopyOnBinary does the dispatch based on the format
|
||||
/// of the input binary (ELF, MachO or COFF).
|
||||
static Error executeObjcopyOnBinary(CopyConfig &Config, object::Binary &In,
|
||||
Buffer &Out) {
|
||||
raw_ostream &Out) {
|
||||
if (auto *ELFBinary = dyn_cast<object::ELFObjectFileBase>(&In)) {
|
||||
if (Error E = Config.parseELFConfig())
|
||||
return E;
|
||||
@ -197,15 +239,19 @@ createNewArchiveMembers(CopyConfig &Config, const Archive &Ar) {
|
||||
return createFileError(Ar.getFileName() + "(" + *ChildNameOrErr + ")",
|
||||
ChildOrErr.takeError());
|
||||
|
||||
MemBuffer MB(ChildNameOrErr.get());
|
||||
if (Error E = executeObjcopyOnBinary(Config, *ChildOrErr->get(), MB))
|
||||
SmallVector<char, 0> Buffer;
|
||||
raw_svector_ostream MemStream(Buffer);
|
||||
|
||||
if (Error E = executeObjcopyOnBinary(Config, *ChildOrErr->get(), MemStream))
|
||||
return std::move(E);
|
||||
|
||||
Expected<NewArchiveMember> Member =
|
||||
NewArchiveMember::getOldMember(Child, Config.DeterministicArchives);
|
||||
if (!Member)
|
||||
return createFileError(Ar.getFileName(), Member.takeError());
|
||||
Member->Buf = MB.releaseMemoryBuffer();
|
||||
|
||||
Member->Buf = std::make_unique<SmallVectorMemoryBuffer>(
|
||||
std::move(Buffer), ChildNameOrErr.get());
|
||||
Member->MemberName = Member->Buf->getBufferIdentifier();
|
||||
NewArchiveMembers.push_back(std::move(*Member));
|
||||
}
|
||||
@ -280,7 +326,7 @@ static Error executeObjcopy(CopyConfig &Config) {
|
||||
Stat.permissions(static_cast<sys::fs::perms>(0777));
|
||||
}
|
||||
|
||||
using ProcessRawFn = Error (*)(CopyConfig &, MemoryBuffer &, Buffer &);
|
||||
using ProcessRawFn = Error (*)(CopyConfig &, MemoryBuffer &, raw_ostream &);
|
||||
ProcessRawFn ProcessRaw;
|
||||
switch (Config.InputFormat) {
|
||||
case FileFormat::Binary:
|
||||
@ -297,8 +343,11 @@ static Error executeObjcopy(CopyConfig &Config) {
|
||||
auto BufOrErr = MemoryBuffer::getFileOrSTDIN(Config.InputFilename);
|
||||
if (!BufOrErr)
|
||||
return createFileError(Config.InputFilename, BufOrErr.getError());
|
||||
FileBuffer FB(Config.OutputFilename);
|
||||
if (Error E = ProcessRaw(Config, *BufOrErr->get(), FB))
|
||||
|
||||
if (Error E = writeToFile(
|
||||
Config.OutputFilename, [&](raw_ostream &OutFile) -> Error {
|
||||
return ProcessRaw(Config, *BufOrErr->get(), OutFile);
|
||||
}))
|
||||
return E;
|
||||
} else {
|
||||
Expected<OwningBinary<llvm::object::Binary>> BinaryOrErr =
|
||||
@ -310,12 +359,15 @@ static Error executeObjcopy(CopyConfig &Config) {
|
||||
if (Error E = executeObjcopyOnArchive(Config, *Ar))
|
||||
return E;
|
||||
} else {
|
||||
FileBuffer FB(Config.OutputFilename,
|
||||
Config.InputFilename != "-" &&
|
||||
Config.InputFilename == Config.OutputFilename,
|
||||
Stat.getUser(), Stat.getGroup());
|
||||
if (Error E = executeObjcopyOnBinary(Config,
|
||||
*BinaryOrErr.get().getBinary(), FB))
|
||||
if (Error E = writeToFile(
|
||||
Config.OutputFilename,
|
||||
[&](raw_ostream &OutFile) -> Error {
|
||||
return executeObjcopyOnBinary(
|
||||
Config, *BinaryOrErr.get().getBinary(), OutFile);
|
||||
},
|
||||
Config.InputFilename != "-" &&
|
||||
Config.InputFilename == Config.OutputFilename,
|
||||
Stat.getUser(), Stat.getGroup()))
|
||||
return E;
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@
|
||||
#define LLVM_TOOLS_OBJCOPY_OBJCOPY_H
|
||||
|
||||
#include "llvm/Support/Error.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
@ -26,6 +27,18 @@ struct CopyConfig;
|
||||
Expected<std::vector<NewArchiveMember>>
|
||||
createNewArchiveMembers(CopyConfig &Config, const object::Archive &Ar);
|
||||
|
||||
/// A writeToFile helper creates an output stream, based on the specified
|
||||
/// \p OutputFileName: std::outs for the "-", raw_null_ostream for
|
||||
/// the "/dev/null", temporary file in the same directory as the final output
|
||||
/// file for other names. The final output file is atomically replaced with
|
||||
/// the temporary file after \p Write handler is finished. \p KeepOwnership
|
||||
/// used to setting specified \p UserID and \p GroupID for the resulting file
|
||||
/// if writeToFile is called under /root.
|
||||
Error writeToFile(StringRef OutputFileName,
|
||||
std::function<Error(raw_ostream &)> Write,
|
||||
bool KeepOwnership = false, unsigned UserID = 0,
|
||||
unsigned GroupID = 0);
|
||||
|
||||
} // end namespace objcopy
|
||||
} // end namespace llvm
|
||||
|
||||
|
@ -7,12 +7,12 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "WasmObjcopy.h"
|
||||
#include "Buffer.h"
|
||||
#include "CopyConfig.h"
|
||||
#include "Object.h"
|
||||
#include "Reader.h"
|
||||
#include "Writer.h"
|
||||
#include "llvm/Support/Errc.h"
|
||||
#include "llvm/Support/FileOutputBuffer.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace objcopy {
|
||||
@ -92,7 +92,7 @@ static Error handleArgs(const CopyConfig &Config, Object &Obj) {
|
||||
}
|
||||
|
||||
Error executeObjcopyOnBinary(const CopyConfig &Config,
|
||||
object::WasmObjectFile &In, Buffer &Out) {
|
||||
object::WasmObjectFile &In, raw_ostream &Out) {
|
||||
Reader TheReader(In);
|
||||
Expected<std::unique_ptr<Object>> ObjOrErr = TheReader.create();
|
||||
if (!ObjOrErr)
|
||||
|
@ -11,6 +11,7 @@
|
||||
|
||||
namespace llvm {
|
||||
class Error;
|
||||
class raw_ostream;
|
||||
|
||||
namespace object {
|
||||
class WasmObjectFile;
|
||||
@ -18,11 +19,10 @@ class WasmObjectFile;
|
||||
|
||||
namespace objcopy {
|
||||
struct CopyConfig;
|
||||
class Buffer;
|
||||
|
||||
namespace wasm {
|
||||
Error executeObjcopyOnBinary(const CopyConfig &Config,
|
||||
object::WasmObjectFile &In, Buffer &Out);
|
||||
object::WasmObjectFile &In, raw_ostream &Out);
|
||||
|
||||
} // end namespace wasm
|
||||
} // end namespace objcopy
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "Writer.h"
|
||||
#include "llvm/BinaryFormat/Wasm.h"
|
||||
#include "llvm/Support/Endian.h"
|
||||
#include "llvm/Support/Errc.h"
|
||||
#include "llvm/Support/LEB128.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
@ -54,12 +55,16 @@ size_t Writer::finalize() {
|
||||
}
|
||||
|
||||
Error Writer::write() {
|
||||
size_t FileSize = finalize();
|
||||
if (Error E = Buf.allocate(FileSize))
|
||||
return E;
|
||||
size_t TotalSize = finalize();
|
||||
std::unique_ptr<WritableMemoryBuffer> Buf =
|
||||
WritableMemoryBuffer::getNewMemBuffer(TotalSize);
|
||||
if (!Buf)
|
||||
return createStringError(errc::not_enough_memory,
|
||||
"failed to allocate memory buffer of " +
|
||||
Twine::utohexstr(TotalSize) + " bytes");
|
||||
|
||||
// Write the header.
|
||||
uint8_t *Ptr = Buf.getBufferStart();
|
||||
uint8_t *Ptr = reinterpret_cast<uint8_t *>(Buf->getBufferStart());
|
||||
Ptr = std::copy(Obj.Header.Magic.begin(), Obj.Header.Magic.end(), Ptr);
|
||||
support::endian::write32le(Ptr, Obj.Header.Version);
|
||||
Ptr += sizeof(Obj.Header.Version);
|
||||
@ -70,7 +75,11 @@ Error Writer::write() {
|
||||
ArrayRef<uint8_t> Contents = Obj.Sections[I].Contents;
|
||||
Ptr = std::copy(Contents.begin(), Contents.end(), Ptr);
|
||||
}
|
||||
return Buf.commit();
|
||||
|
||||
// TODO: Implement direct writing to the output stream (without intermediate
|
||||
// memory buffer Buf).
|
||||
Out.write(Buf->getBufferStart(), Buf->getBufferSize());
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
} // end namespace wasm
|
||||
|
@ -9,7 +9,6 @@
|
||||
#ifndef LLVM_TOOLS_LLVM_OBJCOPY_WASM_WRITER_H
|
||||
#define LLVM_TOOLS_LLVM_OBJCOPY_WASM_WRITER_H
|
||||
|
||||
#include "Buffer.h"
|
||||
#include "Object.h"
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
@ -20,13 +19,13 @@ namespace wasm {
|
||||
|
||||
class Writer {
|
||||
public:
|
||||
Writer(Object &Obj, Buffer &Buf) : Obj(Obj), Buf(Buf) {}
|
||||
Writer(Object &Obj, raw_ostream &Out) : Obj(Obj), Out(Out) {}
|
||||
Error write();
|
||||
|
||||
private:
|
||||
using SectionHeader = SmallVector<char, 8>;
|
||||
Object &Obj;
|
||||
Buffer &Buf;
|
||||
raw_ostream &Out;
|
||||
std::vector<SectionHeader> SectionHeaders;
|
||||
|
||||
/// Generate a wasm section section header for S.
|
||||
|
Loading…
x
Reference in New Issue
Block a user