aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Shaposhnikov <alexshap@fb.com>2020-10-03 14:18:38 -0700
committerAlexander Shaposhnikov <alexshap@fb.com>2020-10-03 14:18:38 -0700
commitd20c602aad7cc7d116df3bf8c17c533ef361ee61 (patch)
tree2de6934ebb98d2298d8bb78f7f2aaf9ec7736fa5
parent0a3523299dec61f2e6eb2a28fdecd25360e8b6d8 (diff)
downloadllvm-d20c602aad7cc7d116df3bf8c17c533ef361ee61.zip
llvm-d20c602aad7cc7d116df3bf8c17c533ef361ee61.tar.gz
llvm-d20c602aad7cc7d116df3bf8c17c533ef361ee61.tar.bz2
[Object][MachO] Refactor MachOUniversalWriter
This diff refactors writeUniversalBinary and adds writeUniversalBinaryToBuffer. This is a preparation for adding support for universal binaries to llvm-objcopy. Test plan: make check-all Differential revision: https://reviews.llvm.org/D88372
-rw-r--r--llvm/include/llvm/Object/MachOUniversalWriter.h3
-rw-r--r--llvm/lib/Object/MachOUniversalWriter.cpp83
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));
+}