diff options
-rw-r--r-- | llvm/include/llvm/Object/MachOUniversalWriter.h | 3 | ||||
-rw-r--r-- | llvm/lib/Object/MachOUniversalWriter.cpp | 83 |
2 files changed, 55 insertions, 31 deletions
diff --git a/llvm/include/llvm/Object/MachOUniversalWriter.h b/llvm/include/llvm/Object/MachOUniversalWriter.h index 5a94edb..4935244 100644 --- a/llvm/include/llvm/Object/MachOUniversalWriter.h +++ b/llvm/include/llvm/Object/MachOUniversalWriter.h @@ -86,6 +86,9 @@ public: Error writeUniversalBinary(ArrayRef<Slice> Slices, StringRef OutputFileName); +Expected<std::unique_ptr<MemoryBuffer>> +writeUniversalBinaryToBuffer(ArrayRef<Slice> Slices); + } // end namespace object } // end namespace llvm diff --git a/llvm/lib/Object/MachOUniversalWriter.cpp b/llvm/lib/Object/MachOUniversalWriter.cpp index 2d7bb43..165964e 100644 --- a/llvm/lib/Object/MachOUniversalWriter.cpp +++ b/llvm/lib/Object/MachOUniversalWriter.cpp @@ -19,7 +19,7 @@ #include "llvm/Object/IRObjectFile.h" #include "llvm/Object/MachO.h" #include "llvm/Object/MachOUniversal.h" -#include "llvm/Support/FileOutputBuffer.h" +#include "llvm/Support/SmallVectorMemoryBuffer.h" using namespace llvm; using namespace object; @@ -258,8 +258,8 @@ buildFatArchList(ArrayRef<Slice> Slices) { return FatArchList; } -Error object::writeUniversalBinary(ArrayRef<Slice> Slices, - StringRef OutputFileName) { +static Error writeUniversalBinaryToStream(ArrayRef<Slice> Slices, + raw_ostream &Out) { MachO::fat_header FatHeader; FatHeader.magic = MachO::FAT_MAGIC; FatHeader.nfat_arch = Slices.size(); @@ -270,42 +270,63 @@ Error object::writeUniversalBinary(ArrayRef<Slice> Slices, return FatArchListOrErr.takeError(); SmallVector<MachO::fat_arch, 2> FatArchList = *FatArchListOrErr; - const bool IsExecutable = any_of(Slices, [](Slice S) { - return sys::fs::can_execute(S.getBinary()->getFileName()); - }); - const uint64_t OutputFileSize = - static_cast<uint64_t>(FatArchList.back().offset) + - FatArchList.back().size; - Expected<std::unique_ptr<FileOutputBuffer>> OutFileOrError = - FileOutputBuffer::create(OutputFileName, OutputFileSize, - IsExecutable ? FileOutputBuffer::F_executable - : 0); - if (!OutFileOrError) - return createFileError(OutputFileName, OutFileOrError.takeError()); - std::unique_ptr<FileOutputBuffer> OutFile = std::move(OutFileOrError.get()); - std::memset(OutFile->getBufferStart(), 0, OutputFileSize); - if (sys::IsLittleEndianHost) MachO::swapStruct(FatHeader); - std::memcpy(OutFile->getBufferStart(), &FatHeader, sizeof(MachO::fat_header)); + Out.write(reinterpret_cast<const char *>(&FatHeader), + sizeof(MachO::fat_header)); - for (size_t Index = 0, Size = Slices.size(); Index < Size; ++Index) { - MemoryBufferRef BufferRef = Slices[Index].getBinary()->getMemoryBufferRef(); - std::copy(BufferRef.getBufferStart(), BufferRef.getBufferEnd(), - OutFile->getBufferStart() + FatArchList[Index].offset); - } + if (sys::IsLittleEndianHost) + for (MachO::fat_arch &FA : FatArchList) + MachO::swapStruct(FA); + Out.write(reinterpret_cast<const char *>(FatArchList.data()), + sizeof(MachO::fat_arch) * FatArchList.size()); - // FatArchs written after Slices in order to reduce the number of swaps for - // the LittleEndian case if (sys::IsLittleEndianHost) for (MachO::fat_arch &FA : FatArchList) MachO::swapStruct(FA); - std::memcpy(OutFile->getBufferStart() + sizeof(MachO::fat_header), - FatArchList.begin(), - sizeof(MachO::fat_arch) * FatArchList.size()); - if (Error E = OutFile->commit()) - return createFileError(OutputFileName, std::move(E)); + size_t Offset = + sizeof(MachO::fat_header) + sizeof(MachO::fat_arch) * FatArchList.size(); + for (size_t Index = 0, Size = Slices.size(); Index < Size; ++Index) { + MemoryBufferRef BufferRef = Slices[Index].getBinary()->getMemoryBufferRef(); + assert((Offset <= FatArchList[Index].offset) && "Incorrect slice offset"); + Out.write_zeros(FatArchList[Index].offset - Offset); + Out.write(BufferRef.getBufferStart(), BufferRef.getBufferSize()); + Offset = FatArchList[Index].offset + BufferRef.getBufferSize(); + } + Out.flush(); return Error::success(); } + +Error object::writeUniversalBinary(ArrayRef<Slice> Slices, + StringRef OutputFileName) { + const bool IsExecutable = any_of(Slices, [](Slice S) { + return sys::fs::can_execute(S.getBinary()->getFileName()); + }); + unsigned Mode = sys::fs::all_read | sys::fs::all_write; + if (IsExecutable) + Mode |= sys::fs::all_exe; + Expected<sys::fs::TempFile> Temp = sys::fs::TempFile::create( + OutputFileName + ".temp-universal-%%%%%%", Mode); + if (!Temp) + return Temp.takeError(); + raw_fd_ostream Out(Temp->FD, false); + if (Error E = writeUniversalBinaryToStream(Slices, Out)) { + if (Error DiscardError = Temp->discard()) + return joinErrors(std::move(E), std::move(DiscardError)); + return E; + } + 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)); +} |