Skip to content

Commit d20c602

Browse files
author
Alexander Shaposhnikov
committed
[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
1 parent 0a35232 commit d20c602

File tree

2 files changed

+55
-31
lines changed

2 files changed

+55
-31
lines changed

llvm/include/llvm/Object/MachOUniversalWriter.h

+3
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,9 @@ class Slice {
8686

8787
Error writeUniversalBinary(ArrayRef<Slice> Slices, StringRef OutputFileName);
8888

89+
Expected<std::unique_ptr<MemoryBuffer>>
90+
writeUniversalBinaryToBuffer(ArrayRef<Slice> Slices);
91+
8992
} // end namespace object
9093

9194
} // end namespace llvm

llvm/lib/Object/MachOUniversalWriter.cpp

+52-31
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
#include "llvm/Object/IRObjectFile.h"
2020
#include "llvm/Object/MachO.h"
2121
#include "llvm/Object/MachOUniversal.h"
22-
#include "llvm/Support/FileOutputBuffer.h"
22+
#include "llvm/Support/SmallVectorMemoryBuffer.h"
2323

2424
using namespace llvm;
2525
using namespace object;
@@ -258,8 +258,8 @@ buildFatArchList(ArrayRef<Slice> Slices) {
258258
return FatArchList;
259259
}
260260

261-
Error object::writeUniversalBinary(ArrayRef<Slice> Slices,
262-
StringRef OutputFileName) {
261+
static Error writeUniversalBinaryToStream(ArrayRef<Slice> Slices,
262+
raw_ostream &Out) {
263263
MachO::fat_header FatHeader;
264264
FatHeader.magic = MachO::FAT_MAGIC;
265265
FatHeader.nfat_arch = Slices.size();
@@ -270,42 +270,63 @@ Error object::writeUniversalBinary(ArrayRef<Slice> Slices,
270270
return FatArchListOrErr.takeError();
271271
SmallVector<MachO::fat_arch, 2> FatArchList = *FatArchListOrErr;
272272

273-
const bool IsExecutable = any_of(Slices, [](Slice S) {
274-
return sys::fs::can_execute(S.getBinary()->getFileName());
275-
});
276-
const uint64_t OutputFileSize =
277-
static_cast<uint64_t>(FatArchList.back().offset) +
278-
FatArchList.back().size;
279-
Expected<std::unique_ptr<FileOutputBuffer>> OutFileOrError =
280-
FileOutputBuffer::create(OutputFileName, OutputFileSize,
281-
IsExecutable ? FileOutputBuffer::F_executable
282-
: 0);
283-
if (!OutFileOrError)
284-
return createFileError(OutputFileName, OutFileOrError.takeError());
285-
std::unique_ptr<FileOutputBuffer> OutFile = std::move(OutFileOrError.get());
286-
std::memset(OutFile->getBufferStart(), 0, OutputFileSize);
287-
288273
if (sys::IsLittleEndianHost)
289274
MachO::swapStruct(FatHeader);
290-
std::memcpy(OutFile->getBufferStart(), &FatHeader, sizeof(MachO::fat_header));
275+
Out.write(reinterpret_cast<const char *>(&FatHeader),
276+
sizeof(MachO::fat_header));
291277

292-
for (size_t Index = 0, Size = Slices.size(); Index < Size; ++Index) {
293-
MemoryBufferRef BufferRef = Slices[Index].getBinary()->getMemoryBufferRef();
294-
std::copy(BufferRef.getBufferStart(), BufferRef.getBufferEnd(),
295-
OutFile->getBufferStart() + FatArchList[Index].offset);
296-
}
278+
if (sys::IsLittleEndianHost)
279+
for (MachO::fat_arch &FA : FatArchList)
280+
MachO::swapStruct(FA);
281+
Out.write(reinterpret_cast<const char *>(FatArchList.data()),
282+
sizeof(MachO::fat_arch) * FatArchList.size());
297283

298-
// FatArchs written after Slices in order to reduce the number of swaps for
299-
// the LittleEndian case
300284
if (sys::IsLittleEndianHost)
301285
for (MachO::fat_arch &FA : FatArchList)
302286
MachO::swapStruct(FA);
303-
std::memcpy(OutFile->getBufferStart() + sizeof(MachO::fat_header),
304-
FatArchList.begin(),
305-
sizeof(MachO::fat_arch) * FatArchList.size());
306287

307-
if (Error E = OutFile->commit())
308-
return createFileError(OutputFileName, std::move(E));
288+
size_t Offset =
289+
sizeof(MachO::fat_header) + sizeof(MachO::fat_arch) * FatArchList.size();
290+
for (size_t Index = 0, Size = Slices.size(); Index < Size; ++Index) {
291+
MemoryBufferRef BufferRef = Slices[Index].getBinary()->getMemoryBufferRef();
292+
assert((Offset <= FatArchList[Index].offset) && "Incorrect slice offset");
293+
Out.write_zeros(FatArchList[Index].offset - Offset);
294+
Out.write(BufferRef.getBufferStart(), BufferRef.getBufferSize());
295+
Offset = FatArchList[Index].offset + BufferRef.getBufferSize();
296+
}
309297

298+
Out.flush();
310299
return Error::success();
311300
}
301+
302+
Error object::writeUniversalBinary(ArrayRef<Slice> Slices,
303+
StringRef OutputFileName) {
304+
const bool IsExecutable = any_of(Slices, [](Slice S) {
305+
return sys::fs::can_execute(S.getBinary()->getFileName());
306+
});
307+
unsigned Mode = sys::fs::all_read | sys::fs::all_write;
308+
if (IsExecutable)
309+
Mode |= sys::fs::all_exe;
310+
Expected<sys::fs::TempFile> Temp = sys::fs::TempFile::create(
311+
OutputFileName + ".temp-universal-%%%%%%", Mode);
312+
if (!Temp)
313+
return Temp.takeError();
314+
raw_fd_ostream Out(Temp->FD, false);
315+
if (Error E = writeUniversalBinaryToStream(Slices, Out)) {
316+
if (Error DiscardError = Temp->discard())
317+
return joinErrors(std::move(E), std::move(DiscardError));
318+
return E;
319+
}
320+
return Temp->keep(OutputFileName);
321+
}
322+
323+
Expected<std::unique_ptr<MemoryBuffer>>
324+
object::writeUniversalBinaryToBuffer(ArrayRef<Slice> Slices) {
325+
SmallVector<char, 0> Buffer;
326+
raw_svector_ostream Out(Buffer);
327+
328+
if (Error E = writeUniversalBinaryToStream(Slices, Out))
329+
return std::move(E);
330+
331+
return std::make_unique<SmallVectorMemoryBuffer>(std::move(Buffer));
332+
}

0 commit comments

Comments
 (0)