diff --git a/llvm/include/llvm/Object/MachOUniversalWriter.h b/llvm/include/llvm/Object/MachOUniversalWriter.h --- a/llvm/include/llvm/Object/MachOUniversalWriter.h +++ b/llvm/include/llvm/Object/MachOUniversalWriter.h @@ -92,8 +92,7 @@ Error writeUniversalBinary(ArrayRef Slices, StringRef OutputFileName); -Expected> -writeUniversalBinaryToBuffer(ArrayRef Slices); +Error writeUniversalBinaryToStream(ArrayRef Slices, raw_ostream &Out); } // end namespace object diff --git a/llvm/lib/Object/MachOUniversalWriter.cpp b/llvm/lib/Object/MachOUniversalWriter.cpp --- a/llvm/lib/Object/MachOUniversalWriter.cpp +++ b/llvm/lib/Object/MachOUniversalWriter.cpp @@ -263,8 +263,8 @@ return FatArchList; } -static Error writeUniversalBinaryToStream(ArrayRef Slices, - raw_ostream &Out) { +Error object::writeUniversalBinaryToStream(ArrayRef Slices, + raw_ostream &Out) { MachO::fat_header FatHeader; FatHeader.magic = MachO::FAT_MAGIC; FatHeader.nfat_arch = Slices.size(); @@ -324,14 +324,3 @@ } return Temp->keep(OutputFileName); } - -Expected> -object::writeUniversalBinaryToBuffer(ArrayRef Slices) { - SmallVector Buffer; - raw_svector_ostream Out(Buffer); - - if (Error E = writeUniversalBinaryToStream(Slices, Out)) - return std::move(E); - - return std::make_unique(std::move(Buffer)); -} diff --git a/llvm/tools/llvm-objcopy/Buffer.h b/llvm/tools/llvm-objcopy/Buffer.h deleted file mode 100644 --- a/llvm/tools/llvm-objcopy/Buffer.h +++ /dev/null @@ -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 - -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 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 Buf; - -public: - Error allocate(size_t Size) override; - uint8_t *getBufferStart() override; - Error commit() override; - - explicit MemBuffer(StringRef Name) : Buffer(Name) {} - - std::unique_ptr releaseMemoryBuffer(); -}; - -} // end namespace objcopy -} // end namespace llvm - -#endif // LLVM_TOOLS_OBJCOPY_BUFFER_H diff --git a/llvm/tools/llvm-objcopy/Buffer.cpp b/llvm/tools/llvm-objcopy/Buffer.cpp deleted file mode 100644 --- a/llvm/tools/llvm-objcopy/Buffer.cpp +++ /dev/null @@ -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 - -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 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> 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(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(Buf->getBufferStart()); -} - -std::unique_ptr MemBuffer::releaseMemoryBuffer() { - return std::move(Buf); -} - -} // end namespace objcopy -} // end namespace llvm diff --git a/llvm/tools/llvm-objcopy/CMakeLists.txt b/llvm/tools/llvm-objcopy/CMakeLists.txt --- a/llvm/tools/llvm-objcopy/CMakeLists.txt +++ b/llvm/tools/llvm-objcopy/CMakeLists.txt @@ -22,7 +22,6 @@ add_public_tablegen_target(StripOptsTableGen) add_llvm_tool(llvm-objcopy - Buffer.cpp CopyConfig.cpp llvm-objcopy.cpp COFF/COFFObjcopy.cpp diff --git a/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.h b/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.h --- a/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.h +++ b/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.h @@ -11,6 +11,7 @@ namespace llvm { class Error; +class raw_ostream; namespace object { class COFFObjectFile; @@ -18,11 +19,10 @@ 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 diff --git a/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp b/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp --- a/llvm/tools/llvm-objcopy/COFF/COFFObjcopy.cpp +++ b/llvm/tools/llvm-objcopy/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 @@ } Error executeObjcopyOnBinary(const CopyConfig &Config, COFFObjectFile &In, - Buffer &Out) { + raw_ostream &Out) { COFFReader Reader(In); Expected> ObjOrErr = Reader.create(); if (!ObjOrErr) diff --git a/llvm/tools/llvm-objcopy/COFF/Reader.h b/llvm/tools/llvm-objcopy/COFF/Reader.h --- a/llvm/tools/llvm-objcopy/COFF/Reader.h +++ b/llvm/tools/llvm-objcopy/COFF/Reader.h @@ -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" diff --git a/llvm/tools/llvm-objcopy/COFF/Writer.h b/llvm/tools/llvm-objcopy/COFF/Writer.h --- a/llvm/tools/llvm-objcopy/COFF/Writer.h +++ b/llvm/tools/llvm-objcopy/COFF/Writer.h @@ -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 #include @@ -23,7 +23,8 @@ class COFFWriter { Object &Obj; - Buffer &Buf; + std::unique_ptr Buf; + raw_ostream &Out; size_t FileSize; size_t FileAlignment; @@ -51,8 +52,8 @@ 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 diff --git a/llvm/tools/llvm-objcopy/COFF/Writer.cpp b/llvm/tools/llvm-objcopy/COFF/Writer.cpp --- a/llvm/tools/llvm-objcopy/COFF/Writer.cpp +++ b/llvm/tools/llvm-objcopy/COFF/Writer.cpp @@ -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 #include @@ -240,7 +241,7 @@ } void COFFWriter::writeHeaders(bool IsBigObj) { - uint8_t *Ptr = Buf.getBufferStart(); + uint8_t *Ptr = reinterpret_cast(Buf->getBufferStart()); if (Obj.IsPE) { memcpy(Ptr, &Obj.DosHeader, sizeof(Obj.DosHeader)); Ptr += sizeof(Obj.DosHeader); @@ -302,7 +303,8 @@ void COFFWriter::writeSections() { for (const auto &S : Obj.getSections()) { - uint8_t *Ptr = Buf.getBufferStart() + S.Header.PointerToRawData; + uint8_t *Ptr = reinterpret_cast(Buf->getBufferStart()) + + S.Header.PointerToRawData; ArrayRef Contents = S.getContents(); std::copy(Contents.begin(), Contents.end(), Ptr); @@ -331,7 +333,8 @@ } template void COFFWriter::writeSymbolStringTables() { - uint8_t *Ptr = Buf.getBufferStart() + Obj.CoffFileHeader.PointerToSymbolTable; + uint8_t *Ptr = reinterpret_cast(Buf->getBufferStart()) + + Obj.CoffFileHeader.PointerToSymbolTable; for (const auto &S : Obj.getSymbols()) { // Convert symbols back to the right size, from coff_symbol32. copySymbol(*reinterpret_cast(Ptr), @@ -366,8 +369,11 @@ 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 @@ 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 COFFWriter::virtualAddressToFileAddress(uint32_t RVA) { @@ -412,7 +421,8 @@ "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(Buf->getBufferStart()) + + S.Header.PointerToRawData + Offset; uint8_t *End = Ptr + Dir->Size; while (Ptr < End) { debug_directory *Debug = reinterpret_cast(Ptr); diff --git a/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.h b/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.h --- a/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.h +++ b/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.h @@ -12,6 +12,7 @@ namespace llvm { class Error; class MemoryBuffer; +class raw_ostream; namespace object { class ELFObjectFileBase; @@ -19,15 +20,14 @@ 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 diff --git a/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp b/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp --- a/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp +++ b/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp @@ -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 std::unique_ptr 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>(Obj, Buf, !Config.StripSections, + return std::make_unique>(Obj, Out, !Config.StripSections, Config.OnlyKeepDebug); case ELFT_ELF64LE: - return std::make_unique>(Obj, Buf, !Config.StripSections, + return std::make_unique>(Obj, Out, !Config.StripSections, Config.OnlyKeepDebug); case ELFT_ELF32BE: - return std::make_unique>(Obj, Buf, !Config.StripSections, + return std::make_unique>(Obj, Out, !Config.StripSections, Config.OnlyKeepDebug); case ELFT_ELF64BE: - return std::make_unique>(Obj, Buf, !Config.StripSections, + return std::make_unique>(Obj, Out, !Config.StripSections, Config.OnlyKeepDebug); } llvm_unreachable("Invalid output format"); } static std::unique_ptr 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(Obj, Buf); + return std::make_unique(Obj, Out); case FileFormat::IHex: - return std::make_unique(Obj, Buf); + return std::make_unique(Obj, Out); default: - return createELFWriter(Config, Obj, Buf, OutputElfType); + return createELFWriter(Config, Obj, Out, OutputElfType); } } @@ -189,12 +189,14 @@ (*DWOFile)->Machine = Config.OutputArch.getValue().EMachine; (*DWOFile)->OSABI = Config.OutputArch.getValue().OSABI; } - FileBuffer FB(File); - std::unique_ptr 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 = + 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 @@ 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 = createWriter(Config, Obj, Out, OutputElfType); if (Error E = Writer->finalize()) @@ -696,7 +698,7 @@ } Error executeObjcopyOnIHex(const CopyConfig &Config, MemoryBuffer &In, - Buffer &Out) { + raw_ostream &Out) { IHexReader Reader(&In); Expected> Obj = Reader.create(true); if (!Obj) @@ -710,7 +712,7 @@ } 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 executeObjcopyOnBinary(const CopyConfig &Config, - object::ELFObjectFileBase &In, Buffer &Out) { + object::ELFObjectFileBase &In, raw_ostream &Out) { ELFReader Reader(&In, Config.ExtractPartition); Expected> Obj = Reader.create(!Config.SymbolsToAdd.empty()); diff --git a/llvm/tools/llvm-objcopy/ELF/Object.h b/llvm/tools/llvm-objcopy/ELF/Object.h --- a/llvm/tools/llvm-objcopy/ELF/Object.h +++ b/llvm/tools/llvm-objcopy/ELF/Object.h @@ -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 #include #include @@ -106,7 +106,7 @@ class SectionWriter : public SectionVisitor { protected: - Buffer &Out; + WritableMemoryBuffer &Out; public: virtual ~SectionWriter() = default; @@ -123,7 +123,7 @@ 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 ELFSectionWriter : public SectionWriter { @@ -143,7 +143,7 @@ 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 ELFSectionSizer : public MutableSectionVisitor { @@ -187,7 +187,8 @@ 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; @@ -283,7 +284,8 @@ virtual void writeData(uint8_t Type, uint16_t Addr, ArrayRef 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 @@ // 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 Data) override; Error visit(const StringTableSection &Sec) override; @@ -305,14 +307,15 @@ class Writer { protected: Object &Obj; - Buffer &Buf; + std::unique_ptr 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 ELFWriter : public Writer { @@ -349,7 +352,7 @@ 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 @@ ~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 @@ ~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 { diff --git a/llvm/tools/llvm-objcopy/ELF/Object.cpp b/llvm/tools/llvm-objcopy/ELF/Object.cpp --- a/llvm/tools/llvm-objcopy/ELF/Object.cpp +++ b/llvm/tools/llvm-objcopy/ELF/Object.cpp @@ -37,8 +37,8 @@ using namespace ELF; template void ELFWriter::writePhdr(const Segment &Seg) { - uint8_t *B = Buf.getBufferStart() + Obj.ProgramHdrSegment.Offset + - Seg.Index * sizeof(Elf_Phdr); + uint8_t *B = reinterpret_cast(Buf->getBufferStart()) + + Obj.ProgramHdrSegment.Offset + Seg.Index * sizeof(Elf_Phdr); Elf_Phdr &Phdr = *reinterpret_cast(B); Phdr.p_type = Seg.Type; Phdr.p_flags = Seg.Flags; @@ -67,7 +67,8 @@ void SectionBase::onRemove() {} template void ELFWriter::writeShdr(const SectionBase &Sec) { - uint8_t *B = Buf.getBufferStart() + Sec.HeaderOffset; + uint8_t *B = + reinterpret_cast(Buf->getBufferStart()) + Sec.HeaderOffset; Elf_Shdr &Shdr = *reinterpret_cast(B); Shdr.sh_name = Sec.NameIndex; Shdr.sh_type = Sec.Type; @@ -474,7 +475,7 @@ return createStringError(errc::invalid_argument, "'" + Sec.Name + "': " + toString(std::move(Err))); - uint8_t *Buf = Out.getBufferStart() + Sec.Offset; + uint8_t *Buf = reinterpret_cast(Out.getBufferStart()) + Sec.Offset; std::copy(DecompressedContent.begin(), DecompressedContent.end(), Buf); return Error::success(); @@ -519,7 +520,7 @@ template Error ELFSectionWriter::visit(const CompressedSection &Sec) { - uint8_t *Buf = Out.getBufferStart() + Sec.Offset; + uint8_t *Buf = reinterpret_cast(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 @@ } Error SectionWriter::visit(const StringTableSection &Sec) { - Sec.StrTabBuilder.write(Out.getBufferStart() + Sec.Offset); + Sec.StrTabBuilder.write(reinterpret_cast(Out.getBufferStart()) + + Sec.Offset); return Error::success(); } @@ -638,7 +640,7 @@ template Error ELFSectionWriter::visit(const SectionIndexSection &Sec) { - uint8_t *Buf = Out.getBufferStart() + Sec.Offset; + uint8_t *Buf = reinterpret_cast(Out.getBufferStart()) + Sec.Offset; llvm::copy(Sec.Indexes, reinterpret_cast(Buf)); return Error::success(); } @@ -979,7 +981,7 @@ template Error ELFSectionWriter::visit(const RelocationSection &Sec) { - uint8_t *Buf = Out.getBufferStart() + Sec.Offset; + uint8_t *Buf = reinterpret_cast(Out.getBufferStart()) + Sec.Offset; if (Sec.Type == SHT_REL) writeRel(Sec.Relocations, reinterpret_cast(Buf)); else @@ -1160,7 +1162,8 @@ template Error ELFSectionWriter::visit(const GnuDebugLinkSection &Sec) { - unsigned char *Buf = Out.getBufferStart() + Sec.Offset; + unsigned char *Buf = + reinterpret_cast(Out.getBufferStart()) + Sec.Offset; Elf_Word *CRC = reinterpret_cast(Buf + Sec.Size - sizeof(Elf_Word)); *CRC = Sec.CRC32; @@ -1971,7 +1974,7 @@ } template void ELFWriter::writeEhdr() { - Elf_Ehdr &Ehdr = *reinterpret_cast(Buf.getBufferStart()); + Elf_Ehdr &Ehdr = *reinterpret_cast(Buf->getBufferStart()); std::fill(Ehdr.e_ident, Ehdr.e_ident + 16, 0); Ehdr.e_ident[EI_MAG0] = 0x7f; Ehdr.e_ident[EI_MAG1] = 'E'; @@ -2036,7 +2039,7 @@ // 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(Buf.getBufferStart() + Obj.SHOff); + *reinterpret_cast(Buf->getBufferStart() + Obj.SHOff); Shdr.sh_name = 0; Shdr.sh_type = SHT_NULL; Shdr.sh_flags = 0; @@ -2076,7 +2079,7 @@ template void ELFWriter::writeSegmentData() { for (Segment &Seg : Obj.segments()) { size_t Size = std::min(Seg.FileSize, Seg.getContents().size()); - std::memcpy(Buf.getBufferStart() + Seg.Offset, Seg.getContents().data(), + std::memcpy(Buf->getBufferStart() + Seg.Offset, Seg.getContents().data(), Size); } @@ -2087,12 +2090,12 @@ 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 -ELFWriter::ELFWriter(Object &Obj, Buffer &Buf, bool WSH, +ELFWriter::ELFWriter(Object &Obj, raw_ostream &Buf, bool WSH, bool OnlyKeepDebug) : Writer(Obj, Buf), WriteSectionHeaders(WSH && Obj.HadShdrs), OnlyKeepDebug(OnlyKeepDebug) {} @@ -2409,7 +2412,11 @@ 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) { @@ -2531,9 +2538,14 @@ Sec.finalize(); } - if (Error E = Buf.allocate(totalSize())) - return E; - SecWriter = std::make_unique>(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>(*Buf); return Error::success(); } @@ -2542,7 +2554,10 @@ 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() { @@ -2570,9 +2585,12 @@ TotalSize = std::max(TotalSize, Sec.Offset + Sec.Size); } - if (Error E = Buf.allocate(TotalSize)) - return E; - SecWriter = std::make_unique(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(*Buf); return Error::success(); } @@ -2610,7 +2628,7 @@ } Error IHexWriter::write() { - IHexSectionWriter Writer(Buf); + IHexSectionWriter Writer(*Buf); // Write sections. for (const SectionBase *Sec : Sections) if (Error Err = Sec->accept(Writer)) @@ -2618,11 +2636,17 @@ uint64_t Offset = Writer.getBufferOffset(); // Write entry point address. - Offset += writeEntryPointRecord(Buf.getBufferStart() + Offset); + Offset += writeEntryPointRecord( + reinterpret_cast(Buf->getBufferStart()) + Offset); // Write EOF. - Offset += writeEndOfFileRecord(Buf.getBufferStart() + Offset); + Offset += writeEndOfFileRecord( + reinterpret_cast(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) { @@ -2647,7 +2671,7 @@ // 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 @@ -2666,7 +2690,13 @@ Sections.insert(&Sec); } - IHexSectionWriterBase LengthCalc(Buf); + std::unique_ptr 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; @@ -2676,8 +2706,13 @@ 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(); } diff --git a/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.h b/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.h --- a/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.h +++ b/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.h @@ -11,6 +11,7 @@ namespace llvm { class Error; +class raw_ostream; namespace object { class MachOObjectFile; @@ -23,10 +24,11 @@ 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 diff --git a/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.cpp b/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.cpp --- a/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.cpp +++ b/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.cpp @@ -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 { @@ -384,7 +386,7 @@ } Error executeObjcopyOnBinary(const CopyConfig &Config, - object::MachOObjectFile &In, Buffer &Out) { + object::MachOObjectFile &In, raw_ostream &Out) { MachOReader Reader(In); Expected> O = Reader.create(); if (!O) @@ -414,7 +416,7 @@ Error executeObjcopyOnMachOUniversalBinary(CopyConfig &Config, const MachOUniversalBinary &In, - Buffer &Out) { + raw_ostream &Out) { SmallVector, 2> Binaries; SmallVector Slices; for (const auto &O : In.objects()) { @@ -458,27 +460,28 @@ Config.InputFilename.str().c_str()); } std::string ArchFlagName = O.getArchFlagName(); - MemBuffer MB(ArchFlagName); - if (Error E = executeObjcopyOnBinary(Config, **ObjOrErr, MB)) + + SmallVector Buffer; + raw_svector_ostream MemStream(Buffer); + + if (Error E = executeObjcopyOnBinary(Config, **ObjOrErr, MemStream)) return E; - std::unique_ptr OutputBuffer = - MB.releaseMemoryBuffer(); - Expected> BinaryOrErr = - object::createBinary(*OutputBuffer); + + std::unique_ptr MB = + std::make_unique(std::move(Buffer), + ArchFlagName); + Expected> 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(Binaries.back().getBinary()), O.getAlign()); } - Expected> 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 diff --git a/llvm/tools/llvm-objcopy/MachO/MachOWriter.h b/llvm/tools/llvm-objcopy/MachO/MachOWriter.h --- a/llvm/tools/llvm-objcopy/MachO/MachOWriter.h +++ b/llvm/tools/llvm-objcopy/MachO/MachOWriter.h @@ -6,7 +6,6 @@ // //===----------------------------------------------------------------------===// -#include "../Buffer.h" #include "MachOLayoutBuilder.h" #include "MachOObjcopy.h" #include "Object.h" @@ -24,7 +23,8 @@ bool Is64Bit; bool IsLittleEndian; uint64_t PageSize; - Buffer &B; + std::unique_ptr Buf; + raw_ostream &Out; MachOLayoutBuilder LayoutBuilder; size_t headerSize() const; @@ -53,9 +53,9 @@ 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(); diff --git a/llvm/tools/llvm-objcopy/MachO/MachOWriter.cpp b/llvm/tools/llvm-objcopy/MachO/MachOWriter.cpp --- a/llvm/tools/llvm-objcopy/MachO/MachOWriter.cpp +++ b/llvm/tools/llvm-objcopy/MachO/MachOWriter.cpp @@ -159,11 +159,12 @@ 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(Buf->getBufferStart()) + headerSize(); for (const LoadCommand &LC : O.LoadCommands) { // Construct a load command. MachO::macho_load_command MLC = LC.MachOLoadCommand; @@ -257,7 +258,7 @@ 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 @@ if (IsLittleEndian != sys::IsLittleEndianHost) MachO::swapStruct( reinterpret_cast(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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ .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 @@ 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 @@ 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 diff --git a/llvm/tools/llvm-objcopy/llvm-objcopy.h b/llvm/tools/llvm-objcopy/llvm-objcopy.h --- a/llvm/tools/llvm-objcopy/llvm-objcopy.h +++ b/llvm/tools/llvm-objcopy/llvm-objcopy.h @@ -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 @@ Expected> 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 Write, + bool KeepOwnership = false, unsigned UserID = 0, + unsigned GroupID = 0); + } // end namespace objcopy } // end namespace llvm diff --git a/llvm/tools/llvm-objcopy/llvm-objcopy.cpp b/llvm/tools/llvm-objcopy/llvm-objcopy.cpp --- a/llvm/tools/llvm-objcopy/llvm-objcopy.cpp +++ b/llvm/tools/llvm-objcopy/llvm-objcopy.cpp @@ -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 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 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 @@ 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> 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 @@ /// 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 @@ /// 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 @@ /// 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(&In)) { if (Error E = Config.parseELFConfig()) return E; @@ -197,15 +239,19 @@ return createFileError(Ar.getFileName() + "(" + *ChildNameOrErr + ")", ChildOrErr.takeError()); - MemBuffer MB(ChildNameOrErr.get()); - if (Error E = executeObjcopyOnBinary(Config, *ChildOrErr->get(), MB)) + SmallVector Buffer; + raw_svector_ostream MemStream(Buffer); + + if (Error E = executeObjcopyOnBinary(Config, *ChildOrErr->get(), MemStream)) return std::move(E); Expected Member = NewArchiveMember::getOldMember(Child, Config.DeterministicArchives); if (!Member) return createFileError(Ar.getFileName(), Member.takeError()); - Member->Buf = MB.releaseMemoryBuffer(); + + Member->Buf = std::make_unique( + std::move(Buffer), ChildNameOrErr.get()); Member->MemberName = Member->Buf->getBufferIdentifier(); NewArchiveMembers.push_back(std::move(*Member)); } @@ -280,7 +326,7 @@ Stat.permissions(static_cast(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 @@ 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> BinaryOrErr = @@ -310,12 +359,15 @@ 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; } } diff --git a/llvm/tools/llvm-objcopy/wasm/WasmObjcopy.h b/llvm/tools/llvm-objcopy/wasm/WasmObjcopy.h --- a/llvm/tools/llvm-objcopy/wasm/WasmObjcopy.h +++ b/llvm/tools/llvm-objcopy/wasm/WasmObjcopy.h @@ -11,6 +11,7 @@ namespace llvm { class Error; +class raw_ostream; namespace object { class WasmObjectFile; @@ -18,11 +19,10 @@ 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 diff --git a/llvm/tools/llvm-objcopy/wasm/WasmObjcopy.cpp b/llvm/tools/llvm-objcopy/wasm/WasmObjcopy.cpp --- a/llvm/tools/llvm-objcopy/wasm/WasmObjcopy.cpp +++ b/llvm/tools/llvm-objcopy/wasm/WasmObjcopy.cpp @@ -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 @@ } Error executeObjcopyOnBinary(const CopyConfig &Config, - object::WasmObjectFile &In, Buffer &Out) { + object::WasmObjectFile &In, raw_ostream &Out) { Reader TheReader(In); Expected> ObjOrErr = TheReader.create(); if (!ObjOrErr) diff --git a/llvm/tools/llvm-objcopy/wasm/Writer.h b/llvm/tools/llvm-objcopy/wasm/Writer.h --- a/llvm/tools/llvm-objcopy/wasm/Writer.h +++ b/llvm/tools/llvm-objcopy/wasm/Writer.h @@ -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 #include @@ -20,13 +19,13 @@ 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; Object &Obj; - Buffer &Buf; + raw_ostream &Out; std::vector SectionHeaders; /// Generate a wasm section section header for S. diff --git a/llvm/tools/llvm-objcopy/wasm/Writer.cpp b/llvm/tools/llvm-objcopy/wasm/Writer.cpp --- a/llvm/tools/llvm-objcopy/wasm/Writer.cpp +++ b/llvm/tools/llvm-objcopy/wasm/Writer.cpp @@ -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 @@ } Error Writer::write() { - size_t FileSize = finalize(); - if (Error E = Buf.allocate(FileSize)) - return E; + size_t TotalSize = finalize(); + std::unique_ptr 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(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 @@ ArrayRef 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