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 @@ -86,6 +86,9 @@ Error writeUniversalBinary(ArrayRef Slices, StringRef OutputFileName); +Expected> +writeUniversalBinaryToBuffer(ArrayRef Slices); + } // end namespace object } // end namespace llvm 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 @@ -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 @@ return FatArchList; } -Error object::writeUniversalBinary(ArrayRef Slices, - StringRef OutputFileName) { +static Error writeUniversalBinaryToStream(ArrayRef Slices, + raw_ostream &Out) { MachO::fat_header FatHeader; FatHeader.magic = MachO::FAT_MAGIC; FatHeader.nfat_arch = Slices.size(); @@ -270,42 +270,63 @@ return FatArchListOrErr.takeError(); SmallVector FatArchList = *FatArchListOrErr; - const bool IsExecutable = any_of(Slices, [](Slice S) { - return sys::fs::can_execute(S.getBinary()->getFileName()); - }); - const uint64_t OutputFileSize = - static_cast(FatArchList.back().offset) + - FatArchList.back().size; - Expected> OutFileOrError = - FileOutputBuffer::create(OutputFileName, OutputFileSize, - IsExecutable ? FileOutputBuffer::F_executable - : 0); - if (!OutFileOrError) - return createFileError(OutputFileName, OutFileOrError.takeError()); - std::unique_ptr 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(&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(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 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 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> +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)); +}