1*e8d8bef9SDimitry Andric //===- MachOUniversalWriter.cpp - MachO universal binary writer---*- C++-*-===// 2*e8d8bef9SDimitry Andric // 3*e8d8bef9SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*e8d8bef9SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*e8d8bef9SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*e8d8bef9SDimitry Andric // 7*e8d8bef9SDimitry Andric //===----------------------------------------------------------------------===// 8*e8d8bef9SDimitry Andric // 9*e8d8bef9SDimitry Andric // Defines the Slice class and writeUniversalBinary function for writing a MachO 10*e8d8bef9SDimitry Andric // universal binary file. 11*e8d8bef9SDimitry Andric // 12*e8d8bef9SDimitry Andric //===----------------------------------------------------------------------===// 13*e8d8bef9SDimitry Andric 14*e8d8bef9SDimitry Andric #include "llvm/Object/MachOUniversalWriter.h" 15*e8d8bef9SDimitry Andric #include "llvm/ADT/Triple.h" 16*e8d8bef9SDimitry Andric #include "llvm/Object/Archive.h" 17*e8d8bef9SDimitry Andric #include "llvm/Object/Binary.h" 18*e8d8bef9SDimitry Andric #include "llvm/Object/Error.h" 19*e8d8bef9SDimitry Andric #include "llvm/Object/IRObjectFile.h" 20*e8d8bef9SDimitry Andric #include "llvm/Object/MachO.h" 21*e8d8bef9SDimitry Andric #include "llvm/Object/MachOUniversal.h" 22*e8d8bef9SDimitry Andric #include "llvm/Support/SmallVectorMemoryBuffer.h" 23*e8d8bef9SDimitry Andric 24*e8d8bef9SDimitry Andric using namespace llvm; 25*e8d8bef9SDimitry Andric using namespace object; 26*e8d8bef9SDimitry Andric 27*e8d8bef9SDimitry Andric // For compatibility with cctools lipo, a file's alignment is calculated as the 28*e8d8bef9SDimitry Andric // minimum aligment of all segments. For object files, the file's alignment is 29*e8d8bef9SDimitry Andric // the maximum alignment of its sections. 30*e8d8bef9SDimitry Andric static uint32_t calculateFileAlignment(const MachOObjectFile &O) { 31*e8d8bef9SDimitry Andric uint32_t P2CurrentAlignment; 32*e8d8bef9SDimitry Andric uint32_t P2MinAlignment = MachOUniversalBinary::MaxSectionAlignment; 33*e8d8bef9SDimitry Andric const bool Is64Bit = O.is64Bit(); 34*e8d8bef9SDimitry Andric 35*e8d8bef9SDimitry Andric for (const auto &LC : O.load_commands()) { 36*e8d8bef9SDimitry Andric if (LC.C.cmd != (Is64Bit ? MachO::LC_SEGMENT_64 : MachO::LC_SEGMENT)) 37*e8d8bef9SDimitry Andric continue; 38*e8d8bef9SDimitry Andric if (O.getHeader().filetype == MachO::MH_OBJECT) { 39*e8d8bef9SDimitry Andric unsigned NumberOfSections = 40*e8d8bef9SDimitry Andric (Is64Bit ? O.getSegment64LoadCommand(LC).nsects 41*e8d8bef9SDimitry Andric : O.getSegmentLoadCommand(LC).nsects); 42*e8d8bef9SDimitry Andric P2CurrentAlignment = NumberOfSections ? 2 : P2MinAlignment; 43*e8d8bef9SDimitry Andric for (unsigned SI = 0; SI < NumberOfSections; ++SI) { 44*e8d8bef9SDimitry Andric P2CurrentAlignment = std::max(P2CurrentAlignment, 45*e8d8bef9SDimitry Andric (Is64Bit ? O.getSection64(LC, SI).align 46*e8d8bef9SDimitry Andric : O.getSection(LC, SI).align)); 47*e8d8bef9SDimitry Andric } 48*e8d8bef9SDimitry Andric } else { 49*e8d8bef9SDimitry Andric P2CurrentAlignment = 50*e8d8bef9SDimitry Andric countTrailingZeros(Is64Bit ? O.getSegment64LoadCommand(LC).vmaddr 51*e8d8bef9SDimitry Andric : O.getSegmentLoadCommand(LC).vmaddr); 52*e8d8bef9SDimitry Andric } 53*e8d8bef9SDimitry Andric P2MinAlignment = std::min(P2MinAlignment, P2CurrentAlignment); 54*e8d8bef9SDimitry Andric } 55*e8d8bef9SDimitry Andric // return a value >= 4 byte aligned, and less than MachO MaxSectionAlignment 56*e8d8bef9SDimitry Andric return std::max( 57*e8d8bef9SDimitry Andric static_cast<uint32_t>(2), 58*e8d8bef9SDimitry Andric std::min(P2MinAlignment, static_cast<uint32_t>( 59*e8d8bef9SDimitry Andric MachOUniversalBinary::MaxSectionAlignment))); 60*e8d8bef9SDimitry Andric } 61*e8d8bef9SDimitry Andric 62*e8d8bef9SDimitry Andric static uint32_t calculateAlignment(const MachOObjectFile &ObjectFile) { 63*e8d8bef9SDimitry Andric switch (ObjectFile.getHeader().cputype) { 64*e8d8bef9SDimitry Andric case MachO::CPU_TYPE_I386: 65*e8d8bef9SDimitry Andric case MachO::CPU_TYPE_X86_64: 66*e8d8bef9SDimitry Andric case MachO::CPU_TYPE_POWERPC: 67*e8d8bef9SDimitry Andric case MachO::CPU_TYPE_POWERPC64: 68*e8d8bef9SDimitry Andric return 12; // log2 value of page size(4k) for x86 and PPC 69*e8d8bef9SDimitry Andric case MachO::CPU_TYPE_ARM: 70*e8d8bef9SDimitry Andric case MachO::CPU_TYPE_ARM64: 71*e8d8bef9SDimitry Andric case MachO::CPU_TYPE_ARM64_32: 72*e8d8bef9SDimitry Andric return 14; // log2 value of page size(16k) for Darwin ARM 73*e8d8bef9SDimitry Andric default: 74*e8d8bef9SDimitry Andric return calculateFileAlignment(ObjectFile); 75*e8d8bef9SDimitry Andric } 76*e8d8bef9SDimitry Andric } 77*e8d8bef9SDimitry Andric 78*e8d8bef9SDimitry Andric Slice::Slice(const Archive &A, uint32_t CPUType, uint32_t CPUSubType, 79*e8d8bef9SDimitry Andric std::string ArchName, uint32_t Align) 80*e8d8bef9SDimitry Andric : B(&A), CPUType(CPUType), CPUSubType(CPUSubType), 81*e8d8bef9SDimitry Andric ArchName(std::move(ArchName)), P2Alignment(Align) {} 82*e8d8bef9SDimitry Andric 83*e8d8bef9SDimitry Andric Slice::Slice(const MachOObjectFile &O, uint32_t Align) 84*e8d8bef9SDimitry Andric : B(&O), CPUType(O.getHeader().cputype), 85*e8d8bef9SDimitry Andric CPUSubType(O.getHeader().cpusubtype), 86*e8d8bef9SDimitry Andric ArchName(std::string(O.getArchTriple().getArchName())), 87*e8d8bef9SDimitry Andric P2Alignment(Align) {} 88*e8d8bef9SDimitry Andric 89*e8d8bef9SDimitry Andric Slice::Slice(const IRObjectFile &IRO, uint32_t CPUType, uint32_t CPUSubType, 90*e8d8bef9SDimitry Andric std::string ArchName, uint32_t Align) 91*e8d8bef9SDimitry Andric : B(&IRO), CPUType(CPUType), CPUSubType(CPUSubType), 92*e8d8bef9SDimitry Andric ArchName(std::move(ArchName)), P2Alignment(Align) {} 93*e8d8bef9SDimitry Andric 94*e8d8bef9SDimitry Andric Slice::Slice(const MachOObjectFile &O) : Slice(O, calculateAlignment(O)) {} 95*e8d8bef9SDimitry Andric 96*e8d8bef9SDimitry Andric using MachoCPUTy = std::pair<unsigned, unsigned>; 97*e8d8bef9SDimitry Andric 98*e8d8bef9SDimitry Andric static Expected<MachoCPUTy> getMachoCPUFromTriple(Triple TT) { 99*e8d8bef9SDimitry Andric auto CPU = std::make_pair(MachO::getCPUType(TT), MachO::getCPUSubType(TT)); 100*e8d8bef9SDimitry Andric if (!CPU.first) { 101*e8d8bef9SDimitry Andric return CPU.first.takeError(); 102*e8d8bef9SDimitry Andric } 103*e8d8bef9SDimitry Andric if (!CPU.second) { 104*e8d8bef9SDimitry Andric return CPU.second.takeError(); 105*e8d8bef9SDimitry Andric } 106*e8d8bef9SDimitry Andric return std::make_pair(*CPU.first, *CPU.second); 107*e8d8bef9SDimitry Andric } 108*e8d8bef9SDimitry Andric 109*e8d8bef9SDimitry Andric static Expected<MachoCPUTy> getMachoCPUFromTriple(StringRef TT) { 110*e8d8bef9SDimitry Andric return getMachoCPUFromTriple(Triple{TT}); 111*e8d8bef9SDimitry Andric } 112*e8d8bef9SDimitry Andric 113*e8d8bef9SDimitry Andric Expected<Slice> Slice::create(const Archive &A, LLVMContext *LLVMCtx) { 114*e8d8bef9SDimitry Andric Error Err = Error::success(); 115*e8d8bef9SDimitry Andric std::unique_ptr<MachOObjectFile> MFO = nullptr; 116*e8d8bef9SDimitry Andric std::unique_ptr<IRObjectFile> IRFO = nullptr; 117*e8d8bef9SDimitry Andric for (const Archive::Child &Child : A.children(Err)) { 118*e8d8bef9SDimitry Andric Expected<std::unique_ptr<Binary>> ChildOrErr = Child.getAsBinary(LLVMCtx); 119*e8d8bef9SDimitry Andric if (!ChildOrErr) 120*e8d8bef9SDimitry Andric return createFileError(A.getFileName(), ChildOrErr.takeError()); 121*e8d8bef9SDimitry Andric Binary *Bin = ChildOrErr.get().get(); 122*e8d8bef9SDimitry Andric if (Bin->isMachOUniversalBinary()) 123*e8d8bef9SDimitry Andric return createStringError(std::errc::invalid_argument, 124*e8d8bef9SDimitry Andric ("archive member " + Bin->getFileName() + 125*e8d8bef9SDimitry Andric " is a fat file (not allowed in an archive)") 126*e8d8bef9SDimitry Andric .str() 127*e8d8bef9SDimitry Andric .c_str()); 128*e8d8bef9SDimitry Andric if (Bin->isMachO()) { 129*e8d8bef9SDimitry Andric MachOObjectFile *O = cast<MachOObjectFile>(Bin); 130*e8d8bef9SDimitry Andric if (IRFO) { 131*e8d8bef9SDimitry Andric return createStringError( 132*e8d8bef9SDimitry Andric std::errc::invalid_argument, 133*e8d8bef9SDimitry Andric "archive member %s is a MachO, while previous archive member " 134*e8d8bef9SDimitry Andric "%s was an IR LLVM object", 135*e8d8bef9SDimitry Andric O->getFileName().str().c_str(), IRFO->getFileName().str().c_str()); 136*e8d8bef9SDimitry Andric } 137*e8d8bef9SDimitry Andric if (MFO && 138*e8d8bef9SDimitry Andric std::tie(MFO->getHeader().cputype, MFO->getHeader().cpusubtype) != 139*e8d8bef9SDimitry Andric std::tie(O->getHeader().cputype, O->getHeader().cpusubtype)) { 140*e8d8bef9SDimitry Andric return createStringError( 141*e8d8bef9SDimitry Andric std::errc::invalid_argument, 142*e8d8bef9SDimitry Andric ("archive member " + O->getFileName() + " cputype (" + 143*e8d8bef9SDimitry Andric Twine(O->getHeader().cputype) + ") and cpusubtype(" + 144*e8d8bef9SDimitry Andric Twine(O->getHeader().cpusubtype) + 145*e8d8bef9SDimitry Andric ") does not match previous archive members cputype (" + 146*e8d8bef9SDimitry Andric Twine(MFO->getHeader().cputype) + ") and cpusubtype(" + 147*e8d8bef9SDimitry Andric Twine(MFO->getHeader().cpusubtype) + 148*e8d8bef9SDimitry Andric ") (all members must match) " + MFO->getFileName()) 149*e8d8bef9SDimitry Andric .str() 150*e8d8bef9SDimitry Andric .c_str()); 151*e8d8bef9SDimitry Andric } 152*e8d8bef9SDimitry Andric if (!MFO) { 153*e8d8bef9SDimitry Andric ChildOrErr.get().release(); 154*e8d8bef9SDimitry Andric MFO.reset(O); 155*e8d8bef9SDimitry Andric } 156*e8d8bef9SDimitry Andric } else if (Bin->isIR()) { 157*e8d8bef9SDimitry Andric IRObjectFile *O = cast<IRObjectFile>(Bin); 158*e8d8bef9SDimitry Andric if (MFO) { 159*e8d8bef9SDimitry Andric return createStringError(std::errc::invalid_argument, 160*e8d8bef9SDimitry Andric "archive member '%s' is an LLVM IR object, " 161*e8d8bef9SDimitry Andric "while previous archive member " 162*e8d8bef9SDimitry Andric "'%s' was a MachO", 163*e8d8bef9SDimitry Andric O->getFileName().str().c_str(), 164*e8d8bef9SDimitry Andric MFO->getFileName().str().c_str()); 165*e8d8bef9SDimitry Andric } 166*e8d8bef9SDimitry Andric if (IRFO) { 167*e8d8bef9SDimitry Andric Expected<MachoCPUTy> CPUO = getMachoCPUFromTriple(O->getTargetTriple()); 168*e8d8bef9SDimitry Andric Expected<MachoCPUTy> CPUFO = 169*e8d8bef9SDimitry Andric getMachoCPUFromTriple(IRFO->getTargetTriple()); 170*e8d8bef9SDimitry Andric if (!CPUO) 171*e8d8bef9SDimitry Andric return CPUO.takeError(); 172*e8d8bef9SDimitry Andric if (!CPUFO) 173*e8d8bef9SDimitry Andric return CPUFO.takeError(); 174*e8d8bef9SDimitry Andric if (*CPUO != *CPUFO) { 175*e8d8bef9SDimitry Andric return createStringError( 176*e8d8bef9SDimitry Andric std::errc::invalid_argument, 177*e8d8bef9SDimitry Andric ("archive member " + O->getFileName() + " cputype (" + 178*e8d8bef9SDimitry Andric Twine(CPUO->first) + ") and cpusubtype(" + Twine(CPUO->second) + 179*e8d8bef9SDimitry Andric ") does not match previous archive members cputype (" + 180*e8d8bef9SDimitry Andric Twine(CPUFO->first) + ") and cpusubtype(" + 181*e8d8bef9SDimitry Andric Twine(CPUFO->second) + ") (all members must match) " + 182*e8d8bef9SDimitry Andric IRFO->getFileName()) 183*e8d8bef9SDimitry Andric .str() 184*e8d8bef9SDimitry Andric .c_str()); 185*e8d8bef9SDimitry Andric } 186*e8d8bef9SDimitry Andric } else { 187*e8d8bef9SDimitry Andric ChildOrErr.get().release(); 188*e8d8bef9SDimitry Andric IRFO.reset(O); 189*e8d8bef9SDimitry Andric } 190*e8d8bef9SDimitry Andric } else 191*e8d8bef9SDimitry Andric return createStringError(std::errc::invalid_argument, 192*e8d8bef9SDimitry Andric ("archive member " + Bin->getFileName() + 193*e8d8bef9SDimitry Andric " is neither a MachO file or an LLVM IR file " 194*e8d8bef9SDimitry Andric "(not allowed in an archive)") 195*e8d8bef9SDimitry Andric .str() 196*e8d8bef9SDimitry Andric .c_str()); 197*e8d8bef9SDimitry Andric } 198*e8d8bef9SDimitry Andric if (Err) 199*e8d8bef9SDimitry Andric return createFileError(A.getFileName(), std::move(Err)); 200*e8d8bef9SDimitry Andric if (!MFO && !IRFO) 201*e8d8bef9SDimitry Andric return createStringError( 202*e8d8bef9SDimitry Andric std::errc::invalid_argument, 203*e8d8bef9SDimitry Andric ("empty archive with no architecture specification: " + 204*e8d8bef9SDimitry Andric A.getFileName() + " (can't determine architecture for it)") 205*e8d8bef9SDimitry Andric .str() 206*e8d8bef9SDimitry Andric .c_str()); 207*e8d8bef9SDimitry Andric 208*e8d8bef9SDimitry Andric if (MFO) { 209*e8d8bef9SDimitry Andric Slice ArchiveSlice(*(MFO.get()), MFO->is64Bit() ? 3 : 2); 210*e8d8bef9SDimitry Andric ArchiveSlice.B = &A; 211*e8d8bef9SDimitry Andric return ArchiveSlice; 212*e8d8bef9SDimitry Andric } 213*e8d8bef9SDimitry Andric 214*e8d8bef9SDimitry Andric // For IR objects 215*e8d8bef9SDimitry Andric Expected<Slice> ArchiveSliceOrErr = Slice::create(*IRFO, 0); 216*e8d8bef9SDimitry Andric if (!ArchiveSliceOrErr) 217*e8d8bef9SDimitry Andric return createFileError(A.getFileName(), ArchiveSliceOrErr.takeError()); 218*e8d8bef9SDimitry Andric auto &ArchiveSlice = ArchiveSliceOrErr.get(); 219*e8d8bef9SDimitry Andric ArchiveSlice.B = &A; 220*e8d8bef9SDimitry Andric return std::move(ArchiveSlice); 221*e8d8bef9SDimitry Andric } 222*e8d8bef9SDimitry Andric 223*e8d8bef9SDimitry Andric Expected<Slice> Slice::create(const IRObjectFile &IRO, uint32_t Align) { 224*e8d8bef9SDimitry Andric Expected<MachoCPUTy> CPUOrErr = getMachoCPUFromTriple(IRO.getTargetTriple()); 225*e8d8bef9SDimitry Andric if (!CPUOrErr) 226*e8d8bef9SDimitry Andric return CPUOrErr.takeError(); 227*e8d8bef9SDimitry Andric unsigned CPUType, CPUSubType; 228*e8d8bef9SDimitry Andric std::tie(CPUType, CPUSubType) = CPUOrErr.get(); 229*e8d8bef9SDimitry Andric // We don't directly use the architecture name of the target triple T, as, 230*e8d8bef9SDimitry Andric // for instance, thumb is treated as ARM by the MachOUniversal object. 231*e8d8bef9SDimitry Andric std::string ArchName( 232*e8d8bef9SDimitry Andric MachOObjectFile::getArchTriple(CPUType, CPUSubType).getArchName()); 233*e8d8bef9SDimitry Andric return Slice{IRO, CPUType, CPUSubType, std::move(ArchName), Align}; 234*e8d8bef9SDimitry Andric } 235*e8d8bef9SDimitry Andric 236*e8d8bef9SDimitry Andric static Expected<SmallVector<MachO::fat_arch, 2>> 237*e8d8bef9SDimitry Andric buildFatArchList(ArrayRef<Slice> Slices) { 238*e8d8bef9SDimitry Andric SmallVector<MachO::fat_arch, 2> FatArchList; 239*e8d8bef9SDimitry Andric uint64_t Offset = 240*e8d8bef9SDimitry Andric sizeof(MachO::fat_header) + Slices.size() * sizeof(MachO::fat_arch); 241*e8d8bef9SDimitry Andric 242*e8d8bef9SDimitry Andric for (const auto &S : Slices) { 243*e8d8bef9SDimitry Andric Offset = alignTo(Offset, 1ull << S.getP2Alignment()); 244*e8d8bef9SDimitry Andric if (Offset > UINT32_MAX) 245*e8d8bef9SDimitry Andric return createStringError( 246*e8d8bef9SDimitry Andric std::errc::invalid_argument, 247*e8d8bef9SDimitry Andric ("fat file too large to be created because the offset " 248*e8d8bef9SDimitry Andric "field in struct fat_arch is only 32-bits and the offset " + 249*e8d8bef9SDimitry Andric Twine(Offset) + " for " + S.getBinary()->getFileName() + 250*e8d8bef9SDimitry Andric " for architecture " + S.getArchString() + "exceeds that.") 251*e8d8bef9SDimitry Andric .str() 252*e8d8bef9SDimitry Andric .c_str()); 253*e8d8bef9SDimitry Andric 254*e8d8bef9SDimitry Andric MachO::fat_arch FatArch; 255*e8d8bef9SDimitry Andric FatArch.cputype = S.getCPUType(); 256*e8d8bef9SDimitry Andric FatArch.cpusubtype = S.getCPUSubType(); 257*e8d8bef9SDimitry Andric FatArch.offset = Offset; 258*e8d8bef9SDimitry Andric FatArch.size = S.getBinary()->getMemoryBufferRef().getBufferSize(); 259*e8d8bef9SDimitry Andric FatArch.align = S.getP2Alignment(); 260*e8d8bef9SDimitry Andric Offset += FatArch.size; 261*e8d8bef9SDimitry Andric FatArchList.push_back(FatArch); 262*e8d8bef9SDimitry Andric } 263*e8d8bef9SDimitry Andric return FatArchList; 264*e8d8bef9SDimitry Andric } 265*e8d8bef9SDimitry Andric 266*e8d8bef9SDimitry Andric static Error writeUniversalBinaryToStream(ArrayRef<Slice> Slices, 267*e8d8bef9SDimitry Andric raw_ostream &Out) { 268*e8d8bef9SDimitry Andric MachO::fat_header FatHeader; 269*e8d8bef9SDimitry Andric FatHeader.magic = MachO::FAT_MAGIC; 270*e8d8bef9SDimitry Andric FatHeader.nfat_arch = Slices.size(); 271*e8d8bef9SDimitry Andric 272*e8d8bef9SDimitry Andric Expected<SmallVector<MachO::fat_arch, 2>> FatArchListOrErr = 273*e8d8bef9SDimitry Andric buildFatArchList(Slices); 274*e8d8bef9SDimitry Andric if (!FatArchListOrErr) 275*e8d8bef9SDimitry Andric return FatArchListOrErr.takeError(); 276*e8d8bef9SDimitry Andric SmallVector<MachO::fat_arch, 2> FatArchList = *FatArchListOrErr; 277*e8d8bef9SDimitry Andric 278*e8d8bef9SDimitry Andric if (sys::IsLittleEndianHost) 279*e8d8bef9SDimitry Andric MachO::swapStruct(FatHeader); 280*e8d8bef9SDimitry Andric Out.write(reinterpret_cast<const char *>(&FatHeader), 281*e8d8bef9SDimitry Andric sizeof(MachO::fat_header)); 282*e8d8bef9SDimitry Andric 283*e8d8bef9SDimitry Andric if (sys::IsLittleEndianHost) 284*e8d8bef9SDimitry Andric for (MachO::fat_arch &FA : FatArchList) 285*e8d8bef9SDimitry Andric MachO::swapStruct(FA); 286*e8d8bef9SDimitry Andric Out.write(reinterpret_cast<const char *>(FatArchList.data()), 287*e8d8bef9SDimitry Andric sizeof(MachO::fat_arch) * FatArchList.size()); 288*e8d8bef9SDimitry Andric 289*e8d8bef9SDimitry Andric if (sys::IsLittleEndianHost) 290*e8d8bef9SDimitry Andric for (MachO::fat_arch &FA : FatArchList) 291*e8d8bef9SDimitry Andric MachO::swapStruct(FA); 292*e8d8bef9SDimitry Andric 293*e8d8bef9SDimitry Andric size_t Offset = 294*e8d8bef9SDimitry Andric sizeof(MachO::fat_header) + sizeof(MachO::fat_arch) * FatArchList.size(); 295*e8d8bef9SDimitry Andric for (size_t Index = 0, Size = Slices.size(); Index < Size; ++Index) { 296*e8d8bef9SDimitry Andric MemoryBufferRef BufferRef = Slices[Index].getBinary()->getMemoryBufferRef(); 297*e8d8bef9SDimitry Andric assert((Offset <= FatArchList[Index].offset) && "Incorrect slice offset"); 298*e8d8bef9SDimitry Andric Out.write_zeros(FatArchList[Index].offset - Offset); 299*e8d8bef9SDimitry Andric Out.write(BufferRef.getBufferStart(), BufferRef.getBufferSize()); 300*e8d8bef9SDimitry Andric Offset = FatArchList[Index].offset + BufferRef.getBufferSize(); 301*e8d8bef9SDimitry Andric } 302*e8d8bef9SDimitry Andric 303*e8d8bef9SDimitry Andric Out.flush(); 304*e8d8bef9SDimitry Andric return Error::success(); 305*e8d8bef9SDimitry Andric } 306*e8d8bef9SDimitry Andric 307*e8d8bef9SDimitry Andric Error object::writeUniversalBinary(ArrayRef<Slice> Slices, 308*e8d8bef9SDimitry Andric StringRef OutputFileName) { 309*e8d8bef9SDimitry Andric const bool IsExecutable = any_of(Slices, [](Slice S) { 310*e8d8bef9SDimitry Andric return sys::fs::can_execute(S.getBinary()->getFileName()); 311*e8d8bef9SDimitry Andric }); 312*e8d8bef9SDimitry Andric unsigned Mode = sys::fs::all_read | sys::fs::all_write; 313*e8d8bef9SDimitry Andric if (IsExecutable) 314*e8d8bef9SDimitry Andric Mode |= sys::fs::all_exe; 315*e8d8bef9SDimitry Andric Expected<sys::fs::TempFile> Temp = sys::fs::TempFile::create( 316*e8d8bef9SDimitry Andric OutputFileName + ".temp-universal-%%%%%%", Mode); 317*e8d8bef9SDimitry Andric if (!Temp) 318*e8d8bef9SDimitry Andric return Temp.takeError(); 319*e8d8bef9SDimitry Andric raw_fd_ostream Out(Temp->FD, false); 320*e8d8bef9SDimitry Andric if (Error E = writeUniversalBinaryToStream(Slices, Out)) { 321*e8d8bef9SDimitry Andric if (Error DiscardError = Temp->discard()) 322*e8d8bef9SDimitry Andric return joinErrors(std::move(E), std::move(DiscardError)); 323*e8d8bef9SDimitry Andric return E; 324*e8d8bef9SDimitry Andric } 325*e8d8bef9SDimitry Andric return Temp->keep(OutputFileName); 326*e8d8bef9SDimitry Andric } 327*e8d8bef9SDimitry Andric 328*e8d8bef9SDimitry Andric Expected<std::unique_ptr<MemoryBuffer>> 329*e8d8bef9SDimitry Andric object::writeUniversalBinaryToBuffer(ArrayRef<Slice> Slices) { 330*e8d8bef9SDimitry Andric SmallVector<char, 0> Buffer; 331*e8d8bef9SDimitry Andric raw_svector_ostream Out(Buffer); 332*e8d8bef9SDimitry Andric 333*e8d8bef9SDimitry Andric if (Error E = writeUniversalBinaryToStream(Slices, Out)) 334*e8d8bef9SDimitry Andric return std::move(E); 335*e8d8bef9SDimitry Andric 336*e8d8bef9SDimitry Andric return std::make_unique<SmallVectorMemoryBuffer>(std::move(Buffer)); 337*e8d8bef9SDimitry Andric } 338