181ad6265SDimitry Andric //===- MachOWriter.cpp ------------------------------------------*- C++ -*-===// 281ad6265SDimitry Andric // 381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 681ad6265SDimitry Andric // 781ad6265SDimitry Andric //===----------------------------------------------------------------------===// 881ad6265SDimitry Andric 981ad6265SDimitry Andric #include "MachOWriter.h" 1081ad6265SDimitry Andric #include "MachOLayoutBuilder.h" 1181ad6265SDimitry Andric #include "MachOObject.h" 1281ad6265SDimitry Andric #include "llvm/ADT/STLExtras.h" 1381ad6265SDimitry Andric #include "llvm/BinaryFormat/MachO.h" 1481ad6265SDimitry Andric #include "llvm/Object/MachO.h" 1581ad6265SDimitry Andric #include "llvm/Support/Errc.h" 1681ad6265SDimitry Andric #include "llvm/Support/ErrorHandling.h" 1781ad6265SDimitry Andric #include "llvm/Support/SHA256.h" 1881ad6265SDimitry Andric #include <memory> 1981ad6265SDimitry Andric 2081ad6265SDimitry Andric #if defined(__APPLE__) 2181ad6265SDimitry Andric #include <sys/mman.h> 2281ad6265SDimitry Andric #endif 2381ad6265SDimitry Andric 2481ad6265SDimitry Andric using namespace llvm; 2581ad6265SDimitry Andric using namespace llvm::objcopy::macho; 2681ad6265SDimitry Andric using namespace llvm::support::endian; 2781ad6265SDimitry Andric 2881ad6265SDimitry Andric size_t MachOWriter::headerSize() const { 2981ad6265SDimitry Andric return Is64Bit ? sizeof(MachO::mach_header_64) : sizeof(MachO::mach_header); 3081ad6265SDimitry Andric } 3181ad6265SDimitry Andric 3281ad6265SDimitry Andric size_t MachOWriter::loadCommandsSize() const { return O.Header.SizeOfCmds; } 3381ad6265SDimitry Andric 3481ad6265SDimitry Andric size_t MachOWriter::symTableSize() const { 3581ad6265SDimitry Andric return O.SymTable.Symbols.size() * 3681ad6265SDimitry Andric (Is64Bit ? sizeof(MachO::nlist_64) : sizeof(MachO::nlist)); 3781ad6265SDimitry Andric } 3881ad6265SDimitry Andric 3981ad6265SDimitry Andric size_t MachOWriter::totalSize() const { 4081ad6265SDimitry Andric // Going from tail to head and looking for an appropriate "anchor" to 4181ad6265SDimitry Andric // calculate the total size assuming that all the offsets are either valid 4281ad6265SDimitry Andric // ("true") or 0 (0 indicates that the corresponding part is missing). 4381ad6265SDimitry Andric 4481ad6265SDimitry Andric SmallVector<size_t, 7> Ends; 4581ad6265SDimitry Andric if (O.SymTabCommandIndex) { 4681ad6265SDimitry Andric const MachO::symtab_command &SymTabCommand = 4781ad6265SDimitry Andric O.LoadCommands[*O.SymTabCommandIndex] 4881ad6265SDimitry Andric .MachOLoadCommand.symtab_command_data; 4981ad6265SDimitry Andric if (SymTabCommand.symoff) 5081ad6265SDimitry Andric Ends.push_back(SymTabCommand.symoff + symTableSize()); 5181ad6265SDimitry Andric if (SymTabCommand.stroff) 5281ad6265SDimitry Andric Ends.push_back(SymTabCommand.stroff + SymTabCommand.strsize); 5381ad6265SDimitry Andric } 5481ad6265SDimitry Andric if (O.DyLdInfoCommandIndex) { 5581ad6265SDimitry Andric const MachO::dyld_info_command &DyLdInfoCommand = 5681ad6265SDimitry Andric O.LoadCommands[*O.DyLdInfoCommandIndex] 5781ad6265SDimitry Andric .MachOLoadCommand.dyld_info_command_data; 5881ad6265SDimitry Andric if (DyLdInfoCommand.rebase_off) { 5981ad6265SDimitry Andric assert((DyLdInfoCommand.rebase_size == O.Rebases.Opcodes.size()) && 6081ad6265SDimitry Andric "Incorrect rebase opcodes size"); 6181ad6265SDimitry Andric Ends.push_back(DyLdInfoCommand.rebase_off + DyLdInfoCommand.rebase_size); 6281ad6265SDimitry Andric } 6381ad6265SDimitry Andric if (DyLdInfoCommand.bind_off) { 6481ad6265SDimitry Andric assert((DyLdInfoCommand.bind_size == O.Binds.Opcodes.size()) && 6581ad6265SDimitry Andric "Incorrect bind opcodes size"); 6681ad6265SDimitry Andric Ends.push_back(DyLdInfoCommand.bind_off + DyLdInfoCommand.bind_size); 6781ad6265SDimitry Andric } 6881ad6265SDimitry Andric if (DyLdInfoCommand.weak_bind_off) { 6981ad6265SDimitry Andric assert((DyLdInfoCommand.weak_bind_size == O.WeakBinds.Opcodes.size()) && 7081ad6265SDimitry Andric "Incorrect weak bind opcodes size"); 7181ad6265SDimitry Andric Ends.push_back(DyLdInfoCommand.weak_bind_off + 7281ad6265SDimitry Andric DyLdInfoCommand.weak_bind_size); 7381ad6265SDimitry Andric } 7481ad6265SDimitry Andric if (DyLdInfoCommand.lazy_bind_off) { 7581ad6265SDimitry Andric assert((DyLdInfoCommand.lazy_bind_size == O.LazyBinds.Opcodes.size()) && 7681ad6265SDimitry Andric "Incorrect lazy bind opcodes size"); 7781ad6265SDimitry Andric Ends.push_back(DyLdInfoCommand.lazy_bind_off + 7881ad6265SDimitry Andric DyLdInfoCommand.lazy_bind_size); 7981ad6265SDimitry Andric } 8081ad6265SDimitry Andric if (DyLdInfoCommand.export_off) { 8181ad6265SDimitry Andric assert((DyLdInfoCommand.export_size == O.Exports.Trie.size()) && 8281ad6265SDimitry Andric "Incorrect trie size"); 8381ad6265SDimitry Andric Ends.push_back(DyLdInfoCommand.export_off + DyLdInfoCommand.export_size); 8481ad6265SDimitry Andric } 8581ad6265SDimitry Andric } 8681ad6265SDimitry Andric 8781ad6265SDimitry Andric if (O.DySymTabCommandIndex) { 8881ad6265SDimitry Andric const MachO::dysymtab_command &DySymTabCommand = 8981ad6265SDimitry Andric O.LoadCommands[*O.DySymTabCommandIndex] 9081ad6265SDimitry Andric .MachOLoadCommand.dysymtab_command_data; 9181ad6265SDimitry Andric 9281ad6265SDimitry Andric if (DySymTabCommand.indirectsymoff) 9381ad6265SDimitry Andric Ends.push_back(DySymTabCommand.indirectsymoff + 9481ad6265SDimitry Andric sizeof(uint32_t) * O.IndirectSymTable.Symbols.size()); 9581ad6265SDimitry Andric } 9681ad6265SDimitry Andric 97bdd1243dSDimitry Andric for (std::optional<size_t> LinkEditDataCommandIndex : 98bdd1243dSDimitry Andric {O.CodeSignatureCommandIndex, O.DylibCodeSignDRsIndex, 99bdd1243dSDimitry Andric O.DataInCodeCommandIndex, O.LinkerOptimizationHintCommandIndex, 100bdd1243dSDimitry Andric O.FunctionStartsCommandIndex, O.ChainedFixupsCommandIndex, 101bdd1243dSDimitry Andric O.ExportsTrieCommandIndex}) 10281ad6265SDimitry Andric if (LinkEditDataCommandIndex) { 10381ad6265SDimitry Andric const MachO::linkedit_data_command &LinkEditDataCommand = 10481ad6265SDimitry Andric O.LoadCommands[*LinkEditDataCommandIndex] 10581ad6265SDimitry Andric .MachOLoadCommand.linkedit_data_command_data; 10681ad6265SDimitry Andric if (LinkEditDataCommand.dataoff) 10781ad6265SDimitry Andric Ends.push_back(LinkEditDataCommand.dataoff + 10881ad6265SDimitry Andric LinkEditDataCommand.datasize); 10981ad6265SDimitry Andric } 11081ad6265SDimitry Andric 11181ad6265SDimitry Andric // Otherwise, use the last section / reloction. 11281ad6265SDimitry Andric for (const LoadCommand &LC : O.LoadCommands) 11381ad6265SDimitry Andric for (const std::unique_ptr<Section> &S : LC.Sections) { 11481ad6265SDimitry Andric if (!S->hasValidOffset()) { 11581ad6265SDimitry Andric assert((S->Offset == 0) && "Skipped section's offset must be zero"); 11681ad6265SDimitry Andric assert((S->isVirtualSection() || S->Size == 0) && 11781ad6265SDimitry Andric "Non-zero-fill sections with zero offset must have zero size"); 11881ad6265SDimitry Andric continue; 11981ad6265SDimitry Andric } 12081ad6265SDimitry Andric assert((S->Offset != 0) && 12181ad6265SDimitry Andric "Non-zero-fill section's offset cannot be zero"); 12281ad6265SDimitry Andric Ends.push_back(S->Offset + S->Size); 12381ad6265SDimitry Andric if (S->RelOff) 12481ad6265SDimitry Andric Ends.push_back(S->RelOff + 12581ad6265SDimitry Andric S->NReloc * sizeof(MachO::any_relocation_info)); 12681ad6265SDimitry Andric } 12781ad6265SDimitry Andric 12881ad6265SDimitry Andric if (!Ends.empty()) 129*0fca6ea1SDimitry Andric return *llvm::max_element(Ends); 13081ad6265SDimitry Andric 13181ad6265SDimitry Andric // Otherwise, we have only Mach header and load commands. 13281ad6265SDimitry Andric return headerSize() + loadCommandsSize(); 13381ad6265SDimitry Andric } 13481ad6265SDimitry Andric 13581ad6265SDimitry Andric void MachOWriter::writeHeader() { 13681ad6265SDimitry Andric MachO::mach_header_64 Header; 13781ad6265SDimitry Andric 13881ad6265SDimitry Andric Header.magic = O.Header.Magic; 13981ad6265SDimitry Andric Header.cputype = O.Header.CPUType; 14081ad6265SDimitry Andric Header.cpusubtype = O.Header.CPUSubType; 14181ad6265SDimitry Andric Header.filetype = O.Header.FileType; 14281ad6265SDimitry Andric Header.ncmds = O.Header.NCmds; 14381ad6265SDimitry Andric Header.sizeofcmds = O.Header.SizeOfCmds; 14481ad6265SDimitry Andric Header.flags = O.Header.Flags; 14581ad6265SDimitry Andric Header.reserved = O.Header.Reserved; 14681ad6265SDimitry Andric 14781ad6265SDimitry Andric if (IsLittleEndian != sys::IsLittleEndianHost) 14881ad6265SDimitry Andric MachO::swapStruct(Header); 14981ad6265SDimitry Andric 15081ad6265SDimitry Andric auto HeaderSize = 15181ad6265SDimitry Andric Is64Bit ? sizeof(MachO::mach_header_64) : sizeof(MachO::mach_header); 15281ad6265SDimitry Andric memcpy(Buf->getBufferStart(), &Header, HeaderSize); 15381ad6265SDimitry Andric } 15481ad6265SDimitry Andric 15581ad6265SDimitry Andric void MachOWriter::writeLoadCommands() { 15681ad6265SDimitry Andric uint8_t *Begin = 15781ad6265SDimitry Andric reinterpret_cast<uint8_t *>(Buf->getBufferStart()) + headerSize(); 15881ad6265SDimitry Andric for (const LoadCommand &LC : O.LoadCommands) { 15981ad6265SDimitry Andric // Construct a load command. 16081ad6265SDimitry Andric MachO::macho_load_command MLC = LC.MachOLoadCommand; 16181ad6265SDimitry Andric switch (MLC.load_command_data.cmd) { 16281ad6265SDimitry Andric case MachO::LC_SEGMENT: 16381ad6265SDimitry Andric if (IsLittleEndian != sys::IsLittleEndianHost) 16481ad6265SDimitry Andric MachO::swapStruct(MLC.segment_command_data); 16581ad6265SDimitry Andric memcpy(Begin, &MLC.segment_command_data, sizeof(MachO::segment_command)); 16681ad6265SDimitry Andric Begin += sizeof(MachO::segment_command); 16781ad6265SDimitry Andric 16881ad6265SDimitry Andric for (const std::unique_ptr<Section> &Sec : LC.Sections) 16981ad6265SDimitry Andric writeSectionInLoadCommand<MachO::section>(*Sec, Begin); 17081ad6265SDimitry Andric continue; 17181ad6265SDimitry Andric case MachO::LC_SEGMENT_64: 17281ad6265SDimitry Andric if (IsLittleEndian != sys::IsLittleEndianHost) 17381ad6265SDimitry Andric MachO::swapStruct(MLC.segment_command_64_data); 17481ad6265SDimitry Andric memcpy(Begin, &MLC.segment_command_64_data, 17581ad6265SDimitry Andric sizeof(MachO::segment_command_64)); 17681ad6265SDimitry Andric Begin += sizeof(MachO::segment_command_64); 17781ad6265SDimitry Andric 17881ad6265SDimitry Andric for (const std::unique_ptr<Section> &Sec : LC.Sections) 17981ad6265SDimitry Andric writeSectionInLoadCommand<MachO::section_64>(*Sec, Begin); 18081ad6265SDimitry Andric continue; 18181ad6265SDimitry Andric } 18281ad6265SDimitry Andric 18381ad6265SDimitry Andric #define HANDLE_LOAD_COMMAND(LCName, LCValue, LCStruct) \ 18481ad6265SDimitry Andric case MachO::LCName: \ 18581ad6265SDimitry Andric assert(sizeof(MachO::LCStruct) + LC.Payload.size() == \ 18681ad6265SDimitry Andric MLC.load_command_data.cmdsize); \ 18781ad6265SDimitry Andric if (IsLittleEndian != sys::IsLittleEndianHost) \ 18881ad6265SDimitry Andric MachO::swapStruct(MLC.LCStruct##_data); \ 18981ad6265SDimitry Andric memcpy(Begin, &MLC.LCStruct##_data, sizeof(MachO::LCStruct)); \ 19081ad6265SDimitry Andric Begin += sizeof(MachO::LCStruct); \ 19181ad6265SDimitry Andric if (!LC.Payload.empty()) \ 19281ad6265SDimitry Andric memcpy(Begin, LC.Payload.data(), LC.Payload.size()); \ 19381ad6265SDimitry Andric Begin += LC.Payload.size(); \ 19481ad6265SDimitry Andric break; 19581ad6265SDimitry Andric 19681ad6265SDimitry Andric // Copy the load command as it is. 19781ad6265SDimitry Andric switch (MLC.load_command_data.cmd) { 19881ad6265SDimitry Andric default: 19981ad6265SDimitry Andric assert(sizeof(MachO::load_command) + LC.Payload.size() == 20081ad6265SDimitry Andric MLC.load_command_data.cmdsize); 20181ad6265SDimitry Andric if (IsLittleEndian != sys::IsLittleEndianHost) 20281ad6265SDimitry Andric MachO::swapStruct(MLC.load_command_data); 20381ad6265SDimitry Andric memcpy(Begin, &MLC.load_command_data, sizeof(MachO::load_command)); 20481ad6265SDimitry Andric Begin += sizeof(MachO::load_command); 20581ad6265SDimitry Andric if (!LC.Payload.empty()) 20681ad6265SDimitry Andric memcpy(Begin, LC.Payload.data(), LC.Payload.size()); 20781ad6265SDimitry Andric Begin += LC.Payload.size(); 20881ad6265SDimitry Andric break; 20981ad6265SDimitry Andric #include "llvm/BinaryFormat/MachO.def" 21081ad6265SDimitry Andric } 21181ad6265SDimitry Andric } 21281ad6265SDimitry Andric } 21381ad6265SDimitry Andric 21481ad6265SDimitry Andric template <typename StructType> 21581ad6265SDimitry Andric void MachOWriter::writeSectionInLoadCommand(const Section &Sec, uint8_t *&Out) { 21681ad6265SDimitry Andric StructType Temp; 21781ad6265SDimitry Andric assert(Sec.Segname.size() <= sizeof(Temp.segname) && "too long segment name"); 21881ad6265SDimitry Andric assert(Sec.Sectname.size() <= sizeof(Temp.sectname) && 21981ad6265SDimitry Andric "too long section name"); 22081ad6265SDimitry Andric memset(&Temp, 0, sizeof(StructType)); 22181ad6265SDimitry Andric memcpy(Temp.segname, Sec.Segname.data(), Sec.Segname.size()); 22281ad6265SDimitry Andric memcpy(Temp.sectname, Sec.Sectname.data(), Sec.Sectname.size()); 22381ad6265SDimitry Andric Temp.addr = Sec.Addr; 22481ad6265SDimitry Andric Temp.size = Sec.Size; 22581ad6265SDimitry Andric Temp.offset = Sec.Offset; 22681ad6265SDimitry Andric Temp.align = Sec.Align; 22781ad6265SDimitry Andric Temp.reloff = Sec.RelOff; 22881ad6265SDimitry Andric Temp.nreloc = Sec.NReloc; 22981ad6265SDimitry Andric Temp.flags = Sec.Flags; 23081ad6265SDimitry Andric Temp.reserved1 = Sec.Reserved1; 23181ad6265SDimitry Andric Temp.reserved2 = Sec.Reserved2; 23281ad6265SDimitry Andric 23381ad6265SDimitry Andric if (IsLittleEndian != sys::IsLittleEndianHost) 23481ad6265SDimitry Andric MachO::swapStruct(Temp); 23581ad6265SDimitry Andric memcpy(Out, &Temp, sizeof(StructType)); 23681ad6265SDimitry Andric Out += sizeof(StructType); 23781ad6265SDimitry Andric } 23881ad6265SDimitry Andric 23981ad6265SDimitry Andric void MachOWriter::writeSections() { 24081ad6265SDimitry Andric for (const LoadCommand &LC : O.LoadCommands) 24181ad6265SDimitry Andric for (const std::unique_ptr<Section> &Sec : LC.Sections) { 24281ad6265SDimitry Andric if (!Sec->hasValidOffset()) { 24381ad6265SDimitry Andric assert((Sec->Offset == 0) && "Skipped section's offset must be zero"); 24481ad6265SDimitry Andric assert((Sec->isVirtualSection() || Sec->Size == 0) && 24581ad6265SDimitry Andric "Non-zero-fill sections with zero offset must have zero size"); 24681ad6265SDimitry Andric continue; 24781ad6265SDimitry Andric } 24881ad6265SDimitry Andric 24981ad6265SDimitry Andric assert(Sec->Offset && "Section offset can not be zero"); 25081ad6265SDimitry Andric assert((Sec->Size == Sec->Content.size()) && "Incorrect section size"); 25181ad6265SDimitry Andric memcpy(Buf->getBufferStart() + Sec->Offset, Sec->Content.data(), 25281ad6265SDimitry Andric Sec->Content.size()); 25381ad6265SDimitry Andric for (size_t Index = 0; Index < Sec->Relocations.size(); ++Index) { 25481ad6265SDimitry Andric RelocationInfo RelocInfo = Sec->Relocations[Index]; 25581ad6265SDimitry Andric if (!RelocInfo.Scattered && !RelocInfo.IsAddend) { 25681ad6265SDimitry Andric const uint32_t SymbolNum = RelocInfo.Extern 25781ad6265SDimitry Andric ? (*RelocInfo.Symbol)->Index 25881ad6265SDimitry Andric : (*RelocInfo.Sec)->Index; 25981ad6265SDimitry Andric RelocInfo.setPlainRelocationSymbolNum(SymbolNum, IsLittleEndian); 26081ad6265SDimitry Andric } 26181ad6265SDimitry Andric if (IsLittleEndian != sys::IsLittleEndianHost) 26281ad6265SDimitry Andric MachO::swapStruct( 26381ad6265SDimitry Andric reinterpret_cast<MachO::any_relocation_info &>(RelocInfo.Info)); 26481ad6265SDimitry Andric memcpy(Buf->getBufferStart() + Sec->RelOff + 26581ad6265SDimitry Andric Index * sizeof(MachO::any_relocation_info), 26681ad6265SDimitry Andric &RelocInfo.Info, sizeof(RelocInfo.Info)); 26781ad6265SDimitry Andric } 26881ad6265SDimitry Andric } 26981ad6265SDimitry Andric } 27081ad6265SDimitry Andric 27181ad6265SDimitry Andric template <typename NListType> 27281ad6265SDimitry Andric void writeNListEntry(const SymbolEntry &SE, bool IsLittleEndian, char *&Out, 27381ad6265SDimitry Andric uint32_t Nstrx) { 27481ad6265SDimitry Andric NListType ListEntry; 27581ad6265SDimitry Andric ListEntry.n_strx = Nstrx; 27681ad6265SDimitry Andric ListEntry.n_type = SE.n_type; 27781ad6265SDimitry Andric ListEntry.n_sect = SE.n_sect; 27881ad6265SDimitry Andric ListEntry.n_desc = SE.n_desc; 27981ad6265SDimitry Andric ListEntry.n_value = SE.n_value; 28081ad6265SDimitry Andric 28181ad6265SDimitry Andric if (IsLittleEndian != sys::IsLittleEndianHost) 28281ad6265SDimitry Andric MachO::swapStruct(ListEntry); 28381ad6265SDimitry Andric memcpy(Out, reinterpret_cast<const char *>(&ListEntry), sizeof(NListType)); 28481ad6265SDimitry Andric Out += sizeof(NListType); 28581ad6265SDimitry Andric } 28681ad6265SDimitry Andric 28781ad6265SDimitry Andric void MachOWriter::writeStringTable() { 28881ad6265SDimitry Andric if (!O.SymTabCommandIndex) 28981ad6265SDimitry Andric return; 29081ad6265SDimitry Andric const MachO::symtab_command &SymTabCommand = 29181ad6265SDimitry Andric O.LoadCommands[*O.SymTabCommandIndex] 29281ad6265SDimitry Andric .MachOLoadCommand.symtab_command_data; 29381ad6265SDimitry Andric 29481ad6265SDimitry Andric uint8_t *StrTable = (uint8_t *)Buf->getBufferStart() + SymTabCommand.stroff; 29581ad6265SDimitry Andric LayoutBuilder.getStringTableBuilder().write(StrTable); 29681ad6265SDimitry Andric } 29781ad6265SDimitry Andric 29881ad6265SDimitry Andric void MachOWriter::writeSymbolTable() { 29981ad6265SDimitry Andric if (!O.SymTabCommandIndex) 30081ad6265SDimitry Andric return; 30181ad6265SDimitry Andric const MachO::symtab_command &SymTabCommand = 30281ad6265SDimitry Andric O.LoadCommands[*O.SymTabCommandIndex] 30381ad6265SDimitry Andric .MachOLoadCommand.symtab_command_data; 30481ad6265SDimitry Andric 30581ad6265SDimitry Andric char *SymTable = (char *)Buf->getBufferStart() + SymTabCommand.symoff; 306bdd1243dSDimitry Andric for (auto &Symbol : O.SymTable.Symbols) { 307bdd1243dSDimitry Andric SymbolEntry *Sym = Symbol.get(); 30881ad6265SDimitry Andric uint32_t Nstrx = LayoutBuilder.getStringTableBuilder().getOffset(Sym->Name); 30981ad6265SDimitry Andric 31081ad6265SDimitry Andric if (Is64Bit) 31181ad6265SDimitry Andric writeNListEntry<MachO::nlist_64>(*Sym, IsLittleEndian, SymTable, Nstrx); 31281ad6265SDimitry Andric else 31381ad6265SDimitry Andric writeNListEntry<MachO::nlist>(*Sym, IsLittleEndian, SymTable, Nstrx); 31481ad6265SDimitry Andric } 31581ad6265SDimitry Andric } 31681ad6265SDimitry Andric 31781ad6265SDimitry Andric void MachOWriter::writeRebaseInfo() { 31881ad6265SDimitry Andric if (!O.DyLdInfoCommandIndex) 31981ad6265SDimitry Andric return; 32081ad6265SDimitry Andric const MachO::dyld_info_command &DyLdInfoCommand = 32181ad6265SDimitry Andric O.LoadCommands[*O.DyLdInfoCommandIndex] 32281ad6265SDimitry Andric .MachOLoadCommand.dyld_info_command_data; 32381ad6265SDimitry Andric char *Out = (char *)Buf->getBufferStart() + DyLdInfoCommand.rebase_off; 32481ad6265SDimitry Andric assert((DyLdInfoCommand.rebase_size == O.Rebases.Opcodes.size()) && 32581ad6265SDimitry Andric "Incorrect rebase opcodes size"); 32681ad6265SDimitry Andric memcpy(Out, O.Rebases.Opcodes.data(), O.Rebases.Opcodes.size()); 32781ad6265SDimitry Andric } 32881ad6265SDimitry Andric 32981ad6265SDimitry Andric void MachOWriter::writeBindInfo() { 33081ad6265SDimitry Andric if (!O.DyLdInfoCommandIndex) 33181ad6265SDimitry Andric return; 33281ad6265SDimitry Andric const MachO::dyld_info_command &DyLdInfoCommand = 33381ad6265SDimitry Andric O.LoadCommands[*O.DyLdInfoCommandIndex] 33481ad6265SDimitry Andric .MachOLoadCommand.dyld_info_command_data; 33581ad6265SDimitry Andric char *Out = (char *)Buf->getBufferStart() + DyLdInfoCommand.bind_off; 33681ad6265SDimitry Andric assert((DyLdInfoCommand.bind_size == O.Binds.Opcodes.size()) && 33781ad6265SDimitry Andric "Incorrect bind opcodes size"); 33881ad6265SDimitry Andric memcpy(Out, O.Binds.Opcodes.data(), O.Binds.Opcodes.size()); 33981ad6265SDimitry Andric } 34081ad6265SDimitry Andric 34181ad6265SDimitry Andric void MachOWriter::writeWeakBindInfo() { 34281ad6265SDimitry Andric if (!O.DyLdInfoCommandIndex) 34381ad6265SDimitry Andric return; 34481ad6265SDimitry Andric const MachO::dyld_info_command &DyLdInfoCommand = 34581ad6265SDimitry Andric O.LoadCommands[*O.DyLdInfoCommandIndex] 34681ad6265SDimitry Andric .MachOLoadCommand.dyld_info_command_data; 34781ad6265SDimitry Andric char *Out = (char *)Buf->getBufferStart() + DyLdInfoCommand.weak_bind_off; 34881ad6265SDimitry Andric assert((DyLdInfoCommand.weak_bind_size == O.WeakBinds.Opcodes.size()) && 34981ad6265SDimitry Andric "Incorrect weak bind opcodes size"); 35081ad6265SDimitry Andric memcpy(Out, O.WeakBinds.Opcodes.data(), O.WeakBinds.Opcodes.size()); 35181ad6265SDimitry Andric } 35281ad6265SDimitry Andric 35381ad6265SDimitry Andric void MachOWriter::writeLazyBindInfo() { 35481ad6265SDimitry Andric if (!O.DyLdInfoCommandIndex) 35581ad6265SDimitry Andric return; 35681ad6265SDimitry Andric const MachO::dyld_info_command &DyLdInfoCommand = 35781ad6265SDimitry Andric O.LoadCommands[*O.DyLdInfoCommandIndex] 35881ad6265SDimitry Andric .MachOLoadCommand.dyld_info_command_data; 35981ad6265SDimitry Andric char *Out = (char *)Buf->getBufferStart() + DyLdInfoCommand.lazy_bind_off; 36081ad6265SDimitry Andric assert((DyLdInfoCommand.lazy_bind_size == O.LazyBinds.Opcodes.size()) && 36181ad6265SDimitry Andric "Incorrect lazy bind opcodes size"); 36281ad6265SDimitry Andric memcpy(Out, O.LazyBinds.Opcodes.data(), O.LazyBinds.Opcodes.size()); 36381ad6265SDimitry Andric } 36481ad6265SDimitry Andric 36581ad6265SDimitry Andric void MachOWriter::writeExportInfo() { 36681ad6265SDimitry Andric if (!O.DyLdInfoCommandIndex) 36781ad6265SDimitry Andric return; 36881ad6265SDimitry Andric const MachO::dyld_info_command &DyLdInfoCommand = 36981ad6265SDimitry Andric O.LoadCommands[*O.DyLdInfoCommandIndex] 37081ad6265SDimitry Andric .MachOLoadCommand.dyld_info_command_data; 37181ad6265SDimitry Andric char *Out = (char *)Buf->getBufferStart() + DyLdInfoCommand.export_off; 37281ad6265SDimitry Andric assert((DyLdInfoCommand.export_size == O.Exports.Trie.size()) && 37381ad6265SDimitry Andric "Incorrect export trie size"); 37481ad6265SDimitry Andric memcpy(Out, O.Exports.Trie.data(), O.Exports.Trie.size()); 37581ad6265SDimitry Andric } 37681ad6265SDimitry Andric 37781ad6265SDimitry Andric void MachOWriter::writeIndirectSymbolTable() { 37881ad6265SDimitry Andric if (!O.DySymTabCommandIndex) 37981ad6265SDimitry Andric return; 38081ad6265SDimitry Andric 38181ad6265SDimitry Andric const MachO::dysymtab_command &DySymTabCommand = 38281ad6265SDimitry Andric O.LoadCommands[*O.DySymTabCommandIndex] 38381ad6265SDimitry Andric .MachOLoadCommand.dysymtab_command_data; 38481ad6265SDimitry Andric 38581ad6265SDimitry Andric uint32_t *Out = 38681ad6265SDimitry Andric (uint32_t *)(Buf->getBufferStart() + DySymTabCommand.indirectsymoff); 38781ad6265SDimitry Andric for (const IndirectSymbolEntry &Sym : O.IndirectSymTable.Symbols) { 38881ad6265SDimitry Andric uint32_t Entry = (Sym.Symbol) ? (*Sym.Symbol)->Index : Sym.OriginalIndex; 38981ad6265SDimitry Andric if (IsLittleEndian != sys::IsLittleEndianHost) 39081ad6265SDimitry Andric sys::swapByteOrder(Entry); 39181ad6265SDimitry Andric *Out++ = Entry; 39281ad6265SDimitry Andric } 39381ad6265SDimitry Andric } 39481ad6265SDimitry Andric 395bdd1243dSDimitry Andric void MachOWriter::writeLinkData(std::optional<size_t> LCIndex, 396bdd1243dSDimitry Andric const LinkData &LD) { 39781ad6265SDimitry Andric if (!LCIndex) 39881ad6265SDimitry Andric return; 39981ad6265SDimitry Andric const MachO::linkedit_data_command &LinkEditDataCommand = 40081ad6265SDimitry Andric O.LoadCommands[*LCIndex].MachOLoadCommand.linkedit_data_command_data; 40181ad6265SDimitry Andric char *Out = (char *)Buf->getBufferStart() + LinkEditDataCommand.dataoff; 40281ad6265SDimitry Andric assert((LinkEditDataCommand.datasize == LD.Data.size()) && 40381ad6265SDimitry Andric "Incorrect data size"); 40481ad6265SDimitry Andric memcpy(Out, LD.Data.data(), LD.Data.size()); 40581ad6265SDimitry Andric } 40681ad6265SDimitry Andric 40781ad6265SDimitry Andric static uint64_t 40881ad6265SDimitry Andric getSegmentFileOffset(const LoadCommand &TextSegmentLoadCommand) { 40981ad6265SDimitry Andric const MachO::macho_load_command &MLC = 41081ad6265SDimitry Andric TextSegmentLoadCommand.MachOLoadCommand; 41181ad6265SDimitry Andric switch (MLC.load_command_data.cmd) { 41281ad6265SDimitry Andric case MachO::LC_SEGMENT: 41381ad6265SDimitry Andric return MLC.segment_command_data.fileoff; 41481ad6265SDimitry Andric case MachO::LC_SEGMENT_64: 41581ad6265SDimitry Andric return MLC.segment_command_64_data.fileoff; 41681ad6265SDimitry Andric default: 41781ad6265SDimitry Andric return 0; 41881ad6265SDimitry Andric } 41981ad6265SDimitry Andric } 42081ad6265SDimitry Andric 42181ad6265SDimitry Andric static uint64_t getSegmentFileSize(const LoadCommand &TextSegmentLoadCommand) { 42281ad6265SDimitry Andric const MachO::macho_load_command &MLC = 42381ad6265SDimitry Andric TextSegmentLoadCommand.MachOLoadCommand; 42481ad6265SDimitry Andric switch (MLC.load_command_data.cmd) { 42581ad6265SDimitry Andric case MachO::LC_SEGMENT: 42681ad6265SDimitry Andric return MLC.segment_command_data.filesize; 42781ad6265SDimitry Andric case MachO::LC_SEGMENT_64: 42881ad6265SDimitry Andric return MLC.segment_command_64_data.filesize; 42981ad6265SDimitry Andric default: 43081ad6265SDimitry Andric return 0; 43181ad6265SDimitry Andric } 43281ad6265SDimitry Andric } 43381ad6265SDimitry Andric 43481ad6265SDimitry Andric void MachOWriter::writeCodeSignatureData() { 43581ad6265SDimitry Andric // NOTE: This CodeSignature section behaviour must be kept in sync with that 43681ad6265SDimitry Andric // performed in LLD's CodeSignatureSection::write / 43781ad6265SDimitry Andric // CodeSignatureSection::writeHashes. Furthermore, this call must occur only 43881ad6265SDimitry Andric // after the rest of the binary has already been written to the buffer. This 43981ad6265SDimitry Andric // is because the buffer is read from to perform the necessary hashing. 44081ad6265SDimitry Andric 44181ad6265SDimitry Andric // The CodeSignature section is the last section in the MachO binary and 44281ad6265SDimitry Andric // contains a hash of all content in the binary before it. Since llvm-objcopy 44381ad6265SDimitry Andric // has likely modified the target binary, the hash must be regenerated 44481ad6265SDimitry Andric // entirely. To generate this hash, we must read from the start of the binary 44581ad6265SDimitry Andric // (HashReadStart) to just before the start of the CodeSignature section 44681ad6265SDimitry Andric // (HashReadEnd). 44781ad6265SDimitry Andric 44881ad6265SDimitry Andric const CodeSignatureInfo &CodeSignature = LayoutBuilder.getCodeSignature(); 44981ad6265SDimitry Andric 45081ad6265SDimitry Andric uint8_t *BufferStart = reinterpret_cast<uint8_t *>(Buf->getBufferStart()); 45181ad6265SDimitry Andric uint8_t *HashReadStart = BufferStart; 45281ad6265SDimitry Andric uint8_t *HashReadEnd = BufferStart + CodeSignature.StartOffset; 45381ad6265SDimitry Andric 45481ad6265SDimitry Andric // The CodeSignature section begins with a header, after which the hashes 45581ad6265SDimitry Andric // of each page of the binary are written. 45681ad6265SDimitry Andric uint8_t *HashWriteStart = HashReadEnd + CodeSignature.AllHeadersSize; 45781ad6265SDimitry Andric 45881ad6265SDimitry Andric uint32_t TextSegmentFileOff = 0; 45981ad6265SDimitry Andric uint32_t TextSegmentFileSize = 0; 46081ad6265SDimitry Andric if (O.TextSegmentCommandIndex) { 46181ad6265SDimitry Andric const LoadCommand &TextSegmentLoadCommand = 46281ad6265SDimitry Andric O.LoadCommands[*O.TextSegmentCommandIndex]; 46381ad6265SDimitry Andric assert(TextSegmentLoadCommand.MachOLoadCommand.load_command_data.cmd == 46481ad6265SDimitry Andric MachO::LC_SEGMENT || 46581ad6265SDimitry Andric TextSegmentLoadCommand.MachOLoadCommand.load_command_data.cmd == 46681ad6265SDimitry Andric MachO::LC_SEGMENT_64); 46781ad6265SDimitry Andric assert(StringRef(TextSegmentLoadCommand.MachOLoadCommand 46881ad6265SDimitry Andric .segment_command_data.segname) == "__TEXT"); 46981ad6265SDimitry Andric TextSegmentFileOff = getSegmentFileOffset(TextSegmentLoadCommand); 47081ad6265SDimitry Andric TextSegmentFileSize = getSegmentFileSize(TextSegmentLoadCommand); 47181ad6265SDimitry Andric } 47281ad6265SDimitry Andric 47381ad6265SDimitry Andric const uint32_t FileNamePad = CodeSignature.AllHeadersSize - 47481ad6265SDimitry Andric CodeSignature.FixedHeadersSize - 47581ad6265SDimitry Andric CodeSignature.OutputFileName.size(); 47681ad6265SDimitry Andric 47781ad6265SDimitry Andric // Write code section header. 47881ad6265SDimitry Andric auto *SuperBlob = reinterpret_cast<MachO::CS_SuperBlob *>(HashReadEnd); 47981ad6265SDimitry Andric write32be(&SuperBlob->magic, MachO::CSMAGIC_EMBEDDED_SIGNATURE); 48081ad6265SDimitry Andric write32be(&SuperBlob->length, CodeSignature.Size); 48181ad6265SDimitry Andric write32be(&SuperBlob->count, 1); 48281ad6265SDimitry Andric auto *BlobIndex = reinterpret_cast<MachO::CS_BlobIndex *>(&SuperBlob[1]); 48381ad6265SDimitry Andric write32be(&BlobIndex->type, MachO::CSSLOT_CODEDIRECTORY); 48481ad6265SDimitry Andric write32be(&BlobIndex->offset, CodeSignature.BlobHeadersSize); 48581ad6265SDimitry Andric auto *CodeDirectory = reinterpret_cast<MachO::CS_CodeDirectory *>( 48681ad6265SDimitry Andric HashReadEnd + CodeSignature.BlobHeadersSize); 48781ad6265SDimitry Andric write32be(&CodeDirectory->magic, MachO::CSMAGIC_CODEDIRECTORY); 48881ad6265SDimitry Andric write32be(&CodeDirectory->length, 48981ad6265SDimitry Andric CodeSignature.Size - CodeSignature.BlobHeadersSize); 49081ad6265SDimitry Andric write32be(&CodeDirectory->version, MachO::CS_SUPPORTSEXECSEG); 49181ad6265SDimitry Andric write32be(&CodeDirectory->flags, MachO::CS_ADHOC | MachO::CS_LINKER_SIGNED); 49281ad6265SDimitry Andric write32be(&CodeDirectory->hashOffset, 49381ad6265SDimitry Andric sizeof(MachO::CS_CodeDirectory) + 49481ad6265SDimitry Andric CodeSignature.OutputFileName.size() + FileNamePad); 49581ad6265SDimitry Andric write32be(&CodeDirectory->identOffset, sizeof(MachO::CS_CodeDirectory)); 49681ad6265SDimitry Andric CodeDirectory->nSpecialSlots = 0; 49781ad6265SDimitry Andric write32be(&CodeDirectory->nCodeSlots, CodeSignature.BlockCount); 49881ad6265SDimitry Andric write32be(&CodeDirectory->codeLimit, CodeSignature.StartOffset); 49981ad6265SDimitry Andric CodeDirectory->hashSize = static_cast<uint8_t>(CodeSignature.HashSize); 50081ad6265SDimitry Andric CodeDirectory->hashType = MachO::kSecCodeSignatureHashSHA256; 50181ad6265SDimitry Andric CodeDirectory->platform = 0; 50281ad6265SDimitry Andric CodeDirectory->pageSize = CodeSignature.BlockSizeShift; 50381ad6265SDimitry Andric CodeDirectory->spare2 = 0; 50481ad6265SDimitry Andric CodeDirectory->scatterOffset = 0; 50581ad6265SDimitry Andric CodeDirectory->teamOffset = 0; 50681ad6265SDimitry Andric CodeDirectory->spare3 = 0; 50781ad6265SDimitry Andric CodeDirectory->codeLimit64 = 0; 50881ad6265SDimitry Andric write64be(&CodeDirectory->execSegBase, TextSegmentFileOff); 50981ad6265SDimitry Andric write64be(&CodeDirectory->execSegLimit, TextSegmentFileSize); 51081ad6265SDimitry Andric write64be(&CodeDirectory->execSegFlags, O.Header.FileType == MachO::MH_EXECUTE 51181ad6265SDimitry Andric ? MachO::CS_EXECSEG_MAIN_BINARY 51281ad6265SDimitry Andric : 0); 51381ad6265SDimitry Andric 51481ad6265SDimitry Andric auto *Id = reinterpret_cast<char *>(&CodeDirectory[1]); 51581ad6265SDimitry Andric memcpy(Id, CodeSignature.OutputFileName.begin(), 51681ad6265SDimitry Andric CodeSignature.OutputFileName.size()); 51781ad6265SDimitry Andric memset(Id + CodeSignature.OutputFileName.size(), 0, FileNamePad); 51881ad6265SDimitry Andric 51981ad6265SDimitry Andric // Write the hashes. 52081ad6265SDimitry Andric uint8_t *CurrHashReadPosition = HashReadStart; 52181ad6265SDimitry Andric uint8_t *CurrHashWritePosition = HashWriteStart; 52281ad6265SDimitry Andric while (CurrHashReadPosition < HashReadEnd) { 52381ad6265SDimitry Andric StringRef Block(reinterpret_cast<char *>(CurrHashReadPosition), 52481ad6265SDimitry Andric std::min(static_cast<size_t>(HashReadEnd 52581ad6265SDimitry Andric - CurrHashReadPosition), 52681ad6265SDimitry Andric static_cast<size_t>(CodeSignature.BlockSize))); 52781ad6265SDimitry Andric SHA256 Hasher; 52881ad6265SDimitry Andric Hasher.update(Block); 52981ad6265SDimitry Andric std::array<uint8_t, 32> Hash = Hasher.final(); 53081ad6265SDimitry Andric assert(Hash.size() == CodeSignature.HashSize); 53181ad6265SDimitry Andric memcpy(CurrHashWritePosition, Hash.data(), CodeSignature.HashSize); 53281ad6265SDimitry Andric CurrHashReadPosition += CodeSignature.BlockSize; 53381ad6265SDimitry Andric CurrHashWritePosition += CodeSignature.HashSize; 53481ad6265SDimitry Andric } 53581ad6265SDimitry Andric #if defined(__APPLE__) 53681ad6265SDimitry Andric // This is macOS-specific work-around and makes no sense for any 53781ad6265SDimitry Andric // other host OS. See https://openradar.appspot.com/FB8914231 53881ad6265SDimitry Andric // 53981ad6265SDimitry Andric // The macOS kernel maintains a signature-verification cache to 54081ad6265SDimitry Andric // quickly validate applications at time of execve(2). The trouble 54181ad6265SDimitry Andric // is that for the kernel creates the cache entry at the time of the 54281ad6265SDimitry Andric // mmap(2) call, before we have a chance to write either the code to 54381ad6265SDimitry Andric // sign or the signature header+hashes. The fix is to invalidate 54481ad6265SDimitry Andric // all cached data associated with the output file, thus discarding 54581ad6265SDimitry Andric // the bogus prematurely-cached signature. 54681ad6265SDimitry Andric msync(BufferStart, CodeSignature.StartOffset + CodeSignature.Size, 54781ad6265SDimitry Andric MS_INVALIDATE); 54881ad6265SDimitry Andric #endif 54981ad6265SDimitry Andric } 55081ad6265SDimitry Andric 55181ad6265SDimitry Andric void MachOWriter::writeDataInCodeData() { 55281ad6265SDimitry Andric return writeLinkData(O.DataInCodeCommandIndex, O.DataInCode); 55381ad6265SDimitry Andric } 55481ad6265SDimitry Andric 55581ad6265SDimitry Andric void MachOWriter::writeLinkerOptimizationHint() { 55681ad6265SDimitry Andric return writeLinkData(O.LinkerOptimizationHintCommandIndex, 55781ad6265SDimitry Andric O.LinkerOptimizationHint); 55881ad6265SDimitry Andric } 55981ad6265SDimitry Andric 56081ad6265SDimitry Andric void MachOWriter::writeFunctionStartsData() { 56181ad6265SDimitry Andric return writeLinkData(O.FunctionStartsCommandIndex, O.FunctionStarts); 56281ad6265SDimitry Andric } 56381ad6265SDimitry Andric 564bdd1243dSDimitry Andric void MachOWriter::writeDylibCodeSignDRsData() { 565bdd1243dSDimitry Andric return writeLinkData(O.DylibCodeSignDRsIndex, O.DylibCodeSignDRs); 566bdd1243dSDimitry Andric } 567bdd1243dSDimitry Andric 56881ad6265SDimitry Andric void MachOWriter::writeChainedFixupsData() { 56981ad6265SDimitry Andric return writeLinkData(O.ChainedFixupsCommandIndex, O.ChainedFixups); 57081ad6265SDimitry Andric } 57181ad6265SDimitry Andric 57281ad6265SDimitry Andric void MachOWriter::writeExportsTrieData() { 573bdd1243dSDimitry Andric if (!O.ExportsTrieCommandIndex) 574bdd1243dSDimitry Andric return; 575bdd1243dSDimitry Andric const MachO::linkedit_data_command &ExportsTrieCmd = 576bdd1243dSDimitry Andric O.LoadCommands[*O.ExportsTrieCommandIndex] 577bdd1243dSDimitry Andric .MachOLoadCommand.linkedit_data_command_data; 578bdd1243dSDimitry Andric char *Out = (char *)Buf->getBufferStart() + ExportsTrieCmd.dataoff; 579bdd1243dSDimitry Andric assert((ExportsTrieCmd.datasize == O.Exports.Trie.size()) && 580bdd1243dSDimitry Andric "Incorrect export trie size"); 581bdd1243dSDimitry Andric memcpy(Out, O.Exports.Trie.data(), O.Exports.Trie.size()); 58281ad6265SDimitry Andric } 58381ad6265SDimitry Andric 58481ad6265SDimitry Andric void MachOWriter::writeTail() { 58581ad6265SDimitry Andric typedef void (MachOWriter::*WriteHandlerType)(); 58681ad6265SDimitry Andric typedef std::pair<uint64_t, WriteHandlerType> WriteOperation; 58781ad6265SDimitry Andric SmallVector<WriteOperation, 7> Queue; 58881ad6265SDimitry Andric 58981ad6265SDimitry Andric if (O.SymTabCommandIndex) { 59081ad6265SDimitry Andric const MachO::symtab_command &SymTabCommand = 59181ad6265SDimitry Andric O.LoadCommands[*O.SymTabCommandIndex] 59281ad6265SDimitry Andric .MachOLoadCommand.symtab_command_data; 59381ad6265SDimitry Andric if (SymTabCommand.symoff) 59481ad6265SDimitry Andric Queue.push_back({SymTabCommand.symoff, &MachOWriter::writeSymbolTable}); 59581ad6265SDimitry Andric if (SymTabCommand.stroff) 59681ad6265SDimitry Andric Queue.push_back({SymTabCommand.stroff, &MachOWriter::writeStringTable}); 59781ad6265SDimitry Andric } 59881ad6265SDimitry Andric 59981ad6265SDimitry Andric if (O.DyLdInfoCommandIndex) { 60081ad6265SDimitry Andric const MachO::dyld_info_command &DyLdInfoCommand = 60181ad6265SDimitry Andric O.LoadCommands[*O.DyLdInfoCommandIndex] 60281ad6265SDimitry Andric .MachOLoadCommand.dyld_info_command_data; 60381ad6265SDimitry Andric if (DyLdInfoCommand.rebase_off) 60481ad6265SDimitry Andric Queue.push_back( 60581ad6265SDimitry Andric {DyLdInfoCommand.rebase_off, &MachOWriter::writeRebaseInfo}); 60681ad6265SDimitry Andric if (DyLdInfoCommand.bind_off) 60781ad6265SDimitry Andric Queue.push_back({DyLdInfoCommand.bind_off, &MachOWriter::writeBindInfo}); 60881ad6265SDimitry Andric if (DyLdInfoCommand.weak_bind_off) 60981ad6265SDimitry Andric Queue.push_back( 61081ad6265SDimitry Andric {DyLdInfoCommand.weak_bind_off, &MachOWriter::writeWeakBindInfo}); 61181ad6265SDimitry Andric if (DyLdInfoCommand.lazy_bind_off) 61281ad6265SDimitry Andric Queue.push_back( 61381ad6265SDimitry Andric {DyLdInfoCommand.lazy_bind_off, &MachOWriter::writeLazyBindInfo}); 61481ad6265SDimitry Andric if (DyLdInfoCommand.export_off) 61581ad6265SDimitry Andric Queue.push_back( 61681ad6265SDimitry Andric {DyLdInfoCommand.export_off, &MachOWriter::writeExportInfo}); 61781ad6265SDimitry Andric } 61881ad6265SDimitry Andric 61981ad6265SDimitry Andric if (O.DySymTabCommandIndex) { 62081ad6265SDimitry Andric const MachO::dysymtab_command &DySymTabCommand = 62181ad6265SDimitry Andric O.LoadCommands[*O.DySymTabCommandIndex] 62281ad6265SDimitry Andric .MachOLoadCommand.dysymtab_command_data; 62381ad6265SDimitry Andric 62481ad6265SDimitry Andric if (DySymTabCommand.indirectsymoff) 62581ad6265SDimitry Andric Queue.emplace_back(DySymTabCommand.indirectsymoff, 62681ad6265SDimitry Andric &MachOWriter::writeIndirectSymbolTable); 62781ad6265SDimitry Andric } 62881ad6265SDimitry Andric 629bdd1243dSDimitry Andric std::initializer_list<std::pair<std::optional<size_t>, WriteHandlerType>> 63081ad6265SDimitry Andric LinkEditDataCommandWriters = { 63181ad6265SDimitry Andric {O.CodeSignatureCommandIndex, &MachOWriter::writeCodeSignatureData}, 632bdd1243dSDimitry Andric {O.DylibCodeSignDRsIndex, &MachOWriter::writeDylibCodeSignDRsData}, 63381ad6265SDimitry Andric {O.DataInCodeCommandIndex, &MachOWriter::writeDataInCodeData}, 63481ad6265SDimitry Andric {O.LinkerOptimizationHintCommandIndex, 63581ad6265SDimitry Andric &MachOWriter::writeLinkerOptimizationHint}, 63681ad6265SDimitry Andric {O.FunctionStartsCommandIndex, &MachOWriter::writeFunctionStartsData}, 63781ad6265SDimitry Andric {O.ChainedFixupsCommandIndex, &MachOWriter::writeChainedFixupsData}, 63881ad6265SDimitry Andric {O.ExportsTrieCommandIndex, &MachOWriter::writeExportsTrieData}}; 63981ad6265SDimitry Andric for (const auto &W : LinkEditDataCommandWriters) { 640bdd1243dSDimitry Andric std::optional<size_t> LinkEditDataCommandIndex; 64181ad6265SDimitry Andric WriteHandlerType WriteHandler; 64281ad6265SDimitry Andric std::tie(LinkEditDataCommandIndex, WriteHandler) = W; 64381ad6265SDimitry Andric if (LinkEditDataCommandIndex) { 64481ad6265SDimitry Andric const MachO::linkedit_data_command &LinkEditDataCommand = 64581ad6265SDimitry Andric O.LoadCommands[*LinkEditDataCommandIndex] 64681ad6265SDimitry Andric .MachOLoadCommand.linkedit_data_command_data; 64781ad6265SDimitry Andric if (LinkEditDataCommand.dataoff) 64881ad6265SDimitry Andric Queue.emplace_back(LinkEditDataCommand.dataoff, WriteHandler); 64981ad6265SDimitry Andric } 65081ad6265SDimitry Andric } 65181ad6265SDimitry Andric 65281ad6265SDimitry Andric llvm::sort(Queue, llvm::less_first()); 65381ad6265SDimitry Andric 65481ad6265SDimitry Andric for (auto WriteOp : Queue) 65581ad6265SDimitry Andric (this->*WriteOp.second)(); 65681ad6265SDimitry Andric } 65781ad6265SDimitry Andric 65881ad6265SDimitry Andric Error MachOWriter::finalize() { return LayoutBuilder.layout(); } 65981ad6265SDimitry Andric 66081ad6265SDimitry Andric Error MachOWriter::write() { 66181ad6265SDimitry Andric size_t TotalSize = totalSize(); 66281ad6265SDimitry Andric Buf = WritableMemoryBuffer::getNewMemBuffer(TotalSize); 66381ad6265SDimitry Andric if (!Buf) 66481ad6265SDimitry Andric return createStringError(errc::not_enough_memory, 66581ad6265SDimitry Andric "failed to allocate memory buffer of " + 66681ad6265SDimitry Andric Twine::utohexstr(TotalSize) + " bytes"); 66781ad6265SDimitry Andric writeHeader(); 66881ad6265SDimitry Andric writeLoadCommands(); 66981ad6265SDimitry Andric writeSections(); 67081ad6265SDimitry Andric writeTail(); 67181ad6265SDimitry Andric 67281ad6265SDimitry Andric // TODO: Implement direct writing to the output stream (without intermediate 67381ad6265SDimitry Andric // memory buffer Buf). 67481ad6265SDimitry Andric Out.write(Buf->getBufferStart(), Buf->getBufferSize()); 67581ad6265SDimitry Andric return Error::success(); 67681ad6265SDimitry Andric } 677