1f75da0c8SAlexey Lapshin //===- MachOWriter.cpp ------------------------------------------*- C++ -*-===// 2f75da0c8SAlexey Lapshin // 3f75da0c8SAlexey Lapshin // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4f75da0c8SAlexey Lapshin // See https://llvm.org/LICENSE.txt for license information. 5f75da0c8SAlexey Lapshin // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6f75da0c8SAlexey Lapshin // 7f75da0c8SAlexey Lapshin //===----------------------------------------------------------------------===// 8f75da0c8SAlexey Lapshin 9f75da0c8SAlexey Lapshin #include "MachOWriter.h" 10f75da0c8SAlexey Lapshin #include "MachOLayoutBuilder.h" 1125d7b4fbSAlexey Lapshin #include "MachOObject.h" 12f75da0c8SAlexey Lapshin #include "llvm/ADT/STLExtras.h" 13f75da0c8SAlexey Lapshin #include "llvm/BinaryFormat/MachO.h" 14f75da0c8SAlexey Lapshin #include "llvm/Support/Errc.h" 15f75da0c8SAlexey Lapshin #include "llvm/Support/ErrorHandling.h" 16f75da0c8SAlexey Lapshin #include "llvm/Support/SHA256.h" 17f75da0c8SAlexey Lapshin #include <memory> 18f75da0c8SAlexey Lapshin 19f75da0c8SAlexey Lapshin #if defined(__APPLE__) 20f75da0c8SAlexey Lapshin #include <sys/mman.h> 21f75da0c8SAlexey Lapshin #endif 22f75da0c8SAlexey Lapshin 23f75da0c8SAlexey Lapshin using namespace llvm; 24f75da0c8SAlexey Lapshin using namespace llvm::objcopy::macho; 25f75da0c8SAlexey Lapshin using namespace llvm::support::endian; 26f75da0c8SAlexey Lapshin 27f75da0c8SAlexey Lapshin size_t MachOWriter::headerSize() const { 28f75da0c8SAlexey Lapshin return Is64Bit ? sizeof(MachO::mach_header_64) : sizeof(MachO::mach_header); 29f75da0c8SAlexey Lapshin } 30f75da0c8SAlexey Lapshin 31f75da0c8SAlexey Lapshin size_t MachOWriter::loadCommandsSize() const { return O.Header.SizeOfCmds; } 32f75da0c8SAlexey Lapshin 33f75da0c8SAlexey Lapshin size_t MachOWriter::symTableSize() const { 34f75da0c8SAlexey Lapshin return O.SymTable.Symbols.size() * 35f75da0c8SAlexey Lapshin (Is64Bit ? sizeof(MachO::nlist_64) : sizeof(MachO::nlist)); 36f75da0c8SAlexey Lapshin } 37f75da0c8SAlexey Lapshin 38f75da0c8SAlexey Lapshin size_t MachOWriter::totalSize() const { 39f75da0c8SAlexey Lapshin // Going from tail to head and looking for an appropriate "anchor" to 40f75da0c8SAlexey Lapshin // calculate the total size assuming that all the offsets are either valid 41f75da0c8SAlexey Lapshin // ("true") or 0 (0 indicates that the corresponding part is missing). 42f75da0c8SAlexey Lapshin 43f75da0c8SAlexey Lapshin SmallVector<size_t, 7> Ends; 44f75da0c8SAlexey Lapshin if (O.SymTabCommandIndex) { 45f75da0c8SAlexey Lapshin const MachO::symtab_command &SymTabCommand = 46f75da0c8SAlexey Lapshin O.LoadCommands[*O.SymTabCommandIndex] 47f75da0c8SAlexey Lapshin .MachOLoadCommand.symtab_command_data; 48f75da0c8SAlexey Lapshin if (SymTabCommand.symoff) 49f75da0c8SAlexey Lapshin Ends.push_back(SymTabCommand.symoff + symTableSize()); 50f75da0c8SAlexey Lapshin if (SymTabCommand.stroff) 51f75da0c8SAlexey Lapshin Ends.push_back(SymTabCommand.stroff + SymTabCommand.strsize); 52f75da0c8SAlexey Lapshin } 53f75da0c8SAlexey Lapshin if (O.DyLdInfoCommandIndex) { 54f75da0c8SAlexey Lapshin const MachO::dyld_info_command &DyLdInfoCommand = 55f75da0c8SAlexey Lapshin O.LoadCommands[*O.DyLdInfoCommandIndex] 56f75da0c8SAlexey Lapshin .MachOLoadCommand.dyld_info_command_data; 57f75da0c8SAlexey Lapshin if (DyLdInfoCommand.rebase_off) { 58f75da0c8SAlexey Lapshin assert((DyLdInfoCommand.rebase_size == O.Rebases.Opcodes.size()) && 59f75da0c8SAlexey Lapshin "Incorrect rebase opcodes size"); 60f75da0c8SAlexey Lapshin Ends.push_back(DyLdInfoCommand.rebase_off + DyLdInfoCommand.rebase_size); 61f75da0c8SAlexey Lapshin } 62f75da0c8SAlexey Lapshin if (DyLdInfoCommand.bind_off) { 63f75da0c8SAlexey Lapshin assert((DyLdInfoCommand.bind_size == O.Binds.Opcodes.size()) && 64f75da0c8SAlexey Lapshin "Incorrect bind opcodes size"); 65f75da0c8SAlexey Lapshin Ends.push_back(DyLdInfoCommand.bind_off + DyLdInfoCommand.bind_size); 66f75da0c8SAlexey Lapshin } 67f75da0c8SAlexey Lapshin if (DyLdInfoCommand.weak_bind_off) { 68f75da0c8SAlexey Lapshin assert((DyLdInfoCommand.weak_bind_size == O.WeakBinds.Opcodes.size()) && 69f75da0c8SAlexey Lapshin "Incorrect weak bind opcodes size"); 70f75da0c8SAlexey Lapshin Ends.push_back(DyLdInfoCommand.weak_bind_off + 71f75da0c8SAlexey Lapshin DyLdInfoCommand.weak_bind_size); 72f75da0c8SAlexey Lapshin } 73f75da0c8SAlexey Lapshin if (DyLdInfoCommand.lazy_bind_off) { 74f75da0c8SAlexey Lapshin assert((DyLdInfoCommand.lazy_bind_size == O.LazyBinds.Opcodes.size()) && 75f75da0c8SAlexey Lapshin "Incorrect lazy bind opcodes size"); 76f75da0c8SAlexey Lapshin Ends.push_back(DyLdInfoCommand.lazy_bind_off + 77f75da0c8SAlexey Lapshin DyLdInfoCommand.lazy_bind_size); 78f75da0c8SAlexey Lapshin } 79f75da0c8SAlexey Lapshin if (DyLdInfoCommand.export_off) { 80f75da0c8SAlexey Lapshin assert((DyLdInfoCommand.export_size == O.Exports.Trie.size()) && 81f75da0c8SAlexey Lapshin "Incorrect trie size"); 82f75da0c8SAlexey Lapshin Ends.push_back(DyLdInfoCommand.export_off + DyLdInfoCommand.export_size); 83f75da0c8SAlexey Lapshin } 84f75da0c8SAlexey Lapshin } 85f75da0c8SAlexey Lapshin 86f75da0c8SAlexey Lapshin if (O.DySymTabCommandIndex) { 87f75da0c8SAlexey Lapshin const MachO::dysymtab_command &DySymTabCommand = 88f75da0c8SAlexey Lapshin O.LoadCommands[*O.DySymTabCommandIndex] 89f75da0c8SAlexey Lapshin .MachOLoadCommand.dysymtab_command_data; 90f75da0c8SAlexey Lapshin 91f75da0c8SAlexey Lapshin if (DySymTabCommand.indirectsymoff) 92f75da0c8SAlexey Lapshin Ends.push_back(DySymTabCommand.indirectsymoff + 93f75da0c8SAlexey Lapshin sizeof(uint32_t) * O.IndirectSymTable.Symbols.size()); 94f75da0c8SAlexey Lapshin } 95f75da0c8SAlexey Lapshin 96ec941432SFangrui Song for (std::optional<size_t> LinkEditDataCommandIndex : 97c2d20947SKeith Smiley {O.CodeSignatureCommandIndex, O.DylibCodeSignDRsIndex, 98c2d20947SKeith Smiley O.DataInCodeCommandIndex, O.LinkerOptimizationHintCommandIndex, 99c2d20947SKeith Smiley O.FunctionStartsCommandIndex, O.ChainedFixupsCommandIndex, 100c2d20947SKeith Smiley O.ExportsTrieCommandIndex}) 101ddc09089SAlexander Shaposhnikov if (LinkEditDataCommandIndex) { 102f75da0c8SAlexey Lapshin const MachO::linkedit_data_command &LinkEditDataCommand = 103ddc09089SAlexander Shaposhnikov O.LoadCommands[*LinkEditDataCommandIndex] 104f75da0c8SAlexey Lapshin .MachOLoadCommand.linkedit_data_command_data; 105f75da0c8SAlexey Lapshin if (LinkEditDataCommand.dataoff) 106f75da0c8SAlexey Lapshin Ends.push_back(LinkEditDataCommand.dataoff + 107f75da0c8SAlexey Lapshin LinkEditDataCommand.datasize); 108f75da0c8SAlexey Lapshin } 109f75da0c8SAlexey Lapshin 110f75da0c8SAlexey Lapshin // Otherwise, use the last section / reloction. 111f75da0c8SAlexey Lapshin for (const LoadCommand &LC : O.LoadCommands) 112f75da0c8SAlexey Lapshin for (const std::unique_ptr<Section> &S : LC.Sections) { 113f75da0c8SAlexey Lapshin if (!S->hasValidOffset()) { 114f75da0c8SAlexey Lapshin assert((S->Offset == 0) && "Skipped section's offset must be zero"); 115f75da0c8SAlexey Lapshin assert((S->isVirtualSection() || S->Size == 0) && 116f75da0c8SAlexey Lapshin "Non-zero-fill sections with zero offset must have zero size"); 117f75da0c8SAlexey Lapshin continue; 118f75da0c8SAlexey Lapshin } 119f75da0c8SAlexey Lapshin assert((S->Offset != 0) && 120f75da0c8SAlexey Lapshin "Non-zero-fill section's offset cannot be zero"); 121f75da0c8SAlexey Lapshin Ends.push_back(S->Offset + S->Size); 122f75da0c8SAlexey Lapshin if (S->RelOff) 123f75da0c8SAlexey Lapshin Ends.push_back(S->RelOff + 124f75da0c8SAlexey Lapshin S->NReloc * sizeof(MachO::any_relocation_info)); 125f75da0c8SAlexey Lapshin } 126f75da0c8SAlexey Lapshin 127f75da0c8SAlexey Lapshin if (!Ends.empty()) 128*fab2bb8bSJustin Lebar return *llvm::max_element(Ends); 129f75da0c8SAlexey Lapshin 130f75da0c8SAlexey Lapshin // Otherwise, we have only Mach header and load commands. 131f75da0c8SAlexey Lapshin return headerSize() + loadCommandsSize(); 132f75da0c8SAlexey Lapshin } 133f75da0c8SAlexey Lapshin 134f75da0c8SAlexey Lapshin void MachOWriter::writeHeader() { 135f75da0c8SAlexey Lapshin MachO::mach_header_64 Header; 136f75da0c8SAlexey Lapshin 137f75da0c8SAlexey Lapshin Header.magic = O.Header.Magic; 138f75da0c8SAlexey Lapshin Header.cputype = O.Header.CPUType; 139f75da0c8SAlexey Lapshin Header.cpusubtype = O.Header.CPUSubType; 140f75da0c8SAlexey Lapshin Header.filetype = O.Header.FileType; 141f75da0c8SAlexey Lapshin Header.ncmds = O.Header.NCmds; 142f75da0c8SAlexey Lapshin Header.sizeofcmds = O.Header.SizeOfCmds; 143f75da0c8SAlexey Lapshin Header.flags = O.Header.Flags; 144f75da0c8SAlexey Lapshin Header.reserved = O.Header.Reserved; 145f75da0c8SAlexey Lapshin 146f75da0c8SAlexey Lapshin if (IsLittleEndian != sys::IsLittleEndianHost) 147f75da0c8SAlexey Lapshin MachO::swapStruct(Header); 148f75da0c8SAlexey Lapshin 149f75da0c8SAlexey Lapshin auto HeaderSize = 150f75da0c8SAlexey Lapshin Is64Bit ? sizeof(MachO::mach_header_64) : sizeof(MachO::mach_header); 151f75da0c8SAlexey Lapshin memcpy(Buf->getBufferStart(), &Header, HeaderSize); 152f75da0c8SAlexey Lapshin } 153f75da0c8SAlexey Lapshin 154f75da0c8SAlexey Lapshin void MachOWriter::writeLoadCommands() { 155f75da0c8SAlexey Lapshin uint8_t *Begin = 156f75da0c8SAlexey Lapshin reinterpret_cast<uint8_t *>(Buf->getBufferStart()) + headerSize(); 157f75da0c8SAlexey Lapshin for (const LoadCommand &LC : O.LoadCommands) { 158f75da0c8SAlexey Lapshin // Construct a load command. 159f75da0c8SAlexey Lapshin MachO::macho_load_command MLC = LC.MachOLoadCommand; 160f75da0c8SAlexey Lapshin switch (MLC.load_command_data.cmd) { 161f75da0c8SAlexey Lapshin case MachO::LC_SEGMENT: 162f75da0c8SAlexey Lapshin if (IsLittleEndian != sys::IsLittleEndianHost) 163f75da0c8SAlexey Lapshin MachO::swapStruct(MLC.segment_command_data); 164f75da0c8SAlexey Lapshin memcpy(Begin, &MLC.segment_command_data, sizeof(MachO::segment_command)); 165f75da0c8SAlexey Lapshin Begin += sizeof(MachO::segment_command); 166f75da0c8SAlexey Lapshin 167f75da0c8SAlexey Lapshin for (const std::unique_ptr<Section> &Sec : LC.Sections) 168f75da0c8SAlexey Lapshin writeSectionInLoadCommand<MachO::section>(*Sec, Begin); 169f75da0c8SAlexey Lapshin continue; 170f75da0c8SAlexey Lapshin case MachO::LC_SEGMENT_64: 171f75da0c8SAlexey Lapshin if (IsLittleEndian != sys::IsLittleEndianHost) 172f75da0c8SAlexey Lapshin MachO::swapStruct(MLC.segment_command_64_data); 173f75da0c8SAlexey Lapshin memcpy(Begin, &MLC.segment_command_64_data, 174f75da0c8SAlexey Lapshin sizeof(MachO::segment_command_64)); 175f75da0c8SAlexey Lapshin Begin += sizeof(MachO::segment_command_64); 176f75da0c8SAlexey Lapshin 177f75da0c8SAlexey Lapshin for (const std::unique_ptr<Section> &Sec : LC.Sections) 178f75da0c8SAlexey Lapshin writeSectionInLoadCommand<MachO::section_64>(*Sec, Begin); 179f75da0c8SAlexey Lapshin continue; 180f75da0c8SAlexey Lapshin } 181f75da0c8SAlexey Lapshin 182f75da0c8SAlexey Lapshin #define HANDLE_LOAD_COMMAND(LCName, LCValue, LCStruct) \ 183f75da0c8SAlexey Lapshin case MachO::LCName: \ 184f75da0c8SAlexey Lapshin assert(sizeof(MachO::LCStruct) + LC.Payload.size() == \ 185f75da0c8SAlexey Lapshin MLC.load_command_data.cmdsize); \ 186f75da0c8SAlexey Lapshin if (IsLittleEndian != sys::IsLittleEndianHost) \ 187f75da0c8SAlexey Lapshin MachO::swapStruct(MLC.LCStruct##_data); \ 188f75da0c8SAlexey Lapshin memcpy(Begin, &MLC.LCStruct##_data, sizeof(MachO::LCStruct)); \ 189f75da0c8SAlexey Lapshin Begin += sizeof(MachO::LCStruct); \ 190f75da0c8SAlexey Lapshin if (!LC.Payload.empty()) \ 191f75da0c8SAlexey Lapshin memcpy(Begin, LC.Payload.data(), LC.Payload.size()); \ 192f75da0c8SAlexey Lapshin Begin += LC.Payload.size(); \ 193f75da0c8SAlexey Lapshin break; 194f75da0c8SAlexey Lapshin 195f75da0c8SAlexey Lapshin // Copy the load command as it is. 196f75da0c8SAlexey Lapshin switch (MLC.load_command_data.cmd) { 197f75da0c8SAlexey Lapshin default: 198f75da0c8SAlexey Lapshin assert(sizeof(MachO::load_command) + LC.Payload.size() == 199f75da0c8SAlexey Lapshin MLC.load_command_data.cmdsize); 200f75da0c8SAlexey Lapshin if (IsLittleEndian != sys::IsLittleEndianHost) 201f75da0c8SAlexey Lapshin MachO::swapStruct(MLC.load_command_data); 202f75da0c8SAlexey Lapshin memcpy(Begin, &MLC.load_command_data, sizeof(MachO::load_command)); 203f75da0c8SAlexey Lapshin Begin += sizeof(MachO::load_command); 204f75da0c8SAlexey Lapshin if (!LC.Payload.empty()) 205f75da0c8SAlexey Lapshin memcpy(Begin, LC.Payload.data(), LC.Payload.size()); 206f75da0c8SAlexey Lapshin Begin += LC.Payload.size(); 207f75da0c8SAlexey Lapshin break; 208f75da0c8SAlexey Lapshin #include "llvm/BinaryFormat/MachO.def" 209f75da0c8SAlexey Lapshin } 210f75da0c8SAlexey Lapshin } 211f75da0c8SAlexey Lapshin } 212f75da0c8SAlexey Lapshin 213f75da0c8SAlexey Lapshin template <typename StructType> 214f75da0c8SAlexey Lapshin void MachOWriter::writeSectionInLoadCommand(const Section &Sec, uint8_t *&Out) { 215f75da0c8SAlexey Lapshin StructType Temp; 216f75da0c8SAlexey Lapshin assert(Sec.Segname.size() <= sizeof(Temp.segname) && "too long segment name"); 217f75da0c8SAlexey Lapshin assert(Sec.Sectname.size() <= sizeof(Temp.sectname) && 218f75da0c8SAlexey Lapshin "too long section name"); 219f75da0c8SAlexey Lapshin memset(&Temp, 0, sizeof(StructType)); 220f75da0c8SAlexey Lapshin memcpy(Temp.segname, Sec.Segname.data(), Sec.Segname.size()); 221f75da0c8SAlexey Lapshin memcpy(Temp.sectname, Sec.Sectname.data(), Sec.Sectname.size()); 222f75da0c8SAlexey Lapshin Temp.addr = Sec.Addr; 223f75da0c8SAlexey Lapshin Temp.size = Sec.Size; 224f75da0c8SAlexey Lapshin Temp.offset = Sec.Offset; 225f75da0c8SAlexey Lapshin Temp.align = Sec.Align; 226f75da0c8SAlexey Lapshin Temp.reloff = Sec.RelOff; 227f75da0c8SAlexey Lapshin Temp.nreloc = Sec.NReloc; 228f75da0c8SAlexey Lapshin Temp.flags = Sec.Flags; 229f75da0c8SAlexey Lapshin Temp.reserved1 = Sec.Reserved1; 230f75da0c8SAlexey Lapshin Temp.reserved2 = Sec.Reserved2; 231f75da0c8SAlexey Lapshin 232f75da0c8SAlexey Lapshin if (IsLittleEndian != sys::IsLittleEndianHost) 233f75da0c8SAlexey Lapshin MachO::swapStruct(Temp); 234f75da0c8SAlexey Lapshin memcpy(Out, &Temp, sizeof(StructType)); 235f75da0c8SAlexey Lapshin Out += sizeof(StructType); 236f75da0c8SAlexey Lapshin } 237f75da0c8SAlexey Lapshin 238f75da0c8SAlexey Lapshin void MachOWriter::writeSections() { 239f75da0c8SAlexey Lapshin for (const LoadCommand &LC : O.LoadCommands) 240f75da0c8SAlexey Lapshin for (const std::unique_ptr<Section> &Sec : LC.Sections) { 241f75da0c8SAlexey Lapshin if (!Sec->hasValidOffset()) { 242f75da0c8SAlexey Lapshin assert((Sec->Offset == 0) && "Skipped section's offset must be zero"); 243f75da0c8SAlexey Lapshin assert((Sec->isVirtualSection() || Sec->Size == 0) && 244f75da0c8SAlexey Lapshin "Non-zero-fill sections with zero offset must have zero size"); 245f75da0c8SAlexey Lapshin continue; 246f75da0c8SAlexey Lapshin } 247f75da0c8SAlexey Lapshin 248f75da0c8SAlexey Lapshin assert(Sec->Offset && "Section offset can not be zero"); 249f75da0c8SAlexey Lapshin assert((Sec->Size == Sec->Content.size()) && "Incorrect section size"); 250f75da0c8SAlexey Lapshin memcpy(Buf->getBufferStart() + Sec->Offset, Sec->Content.data(), 251f75da0c8SAlexey Lapshin Sec->Content.size()); 252f75da0c8SAlexey Lapshin for (size_t Index = 0; Index < Sec->Relocations.size(); ++Index) { 253f75da0c8SAlexey Lapshin RelocationInfo RelocInfo = Sec->Relocations[Index]; 254f75da0c8SAlexey Lapshin if (!RelocInfo.Scattered && !RelocInfo.IsAddend) { 255f75da0c8SAlexey Lapshin const uint32_t SymbolNum = RelocInfo.Extern 256f75da0c8SAlexey Lapshin ? (*RelocInfo.Symbol)->Index 257f75da0c8SAlexey Lapshin : (*RelocInfo.Sec)->Index; 258f75da0c8SAlexey Lapshin RelocInfo.setPlainRelocationSymbolNum(SymbolNum, IsLittleEndian); 259f75da0c8SAlexey Lapshin } 260f75da0c8SAlexey Lapshin if (IsLittleEndian != sys::IsLittleEndianHost) 261f75da0c8SAlexey Lapshin MachO::swapStruct( 262f75da0c8SAlexey Lapshin reinterpret_cast<MachO::any_relocation_info &>(RelocInfo.Info)); 263f75da0c8SAlexey Lapshin memcpy(Buf->getBufferStart() + Sec->RelOff + 264f75da0c8SAlexey Lapshin Index * sizeof(MachO::any_relocation_info), 265f75da0c8SAlexey Lapshin &RelocInfo.Info, sizeof(RelocInfo.Info)); 266f75da0c8SAlexey Lapshin } 267f75da0c8SAlexey Lapshin } 268f75da0c8SAlexey Lapshin } 269f75da0c8SAlexey Lapshin 270f75da0c8SAlexey Lapshin template <typename NListType> 271f75da0c8SAlexey Lapshin void writeNListEntry(const SymbolEntry &SE, bool IsLittleEndian, char *&Out, 272f75da0c8SAlexey Lapshin uint32_t Nstrx) { 273f75da0c8SAlexey Lapshin NListType ListEntry; 274f75da0c8SAlexey Lapshin ListEntry.n_strx = Nstrx; 275f75da0c8SAlexey Lapshin ListEntry.n_type = SE.n_type; 276f75da0c8SAlexey Lapshin ListEntry.n_sect = SE.n_sect; 277f75da0c8SAlexey Lapshin ListEntry.n_desc = SE.n_desc; 278f75da0c8SAlexey Lapshin ListEntry.n_value = SE.n_value; 279f75da0c8SAlexey Lapshin 280f75da0c8SAlexey Lapshin if (IsLittleEndian != sys::IsLittleEndianHost) 281f75da0c8SAlexey Lapshin MachO::swapStruct(ListEntry); 282f75da0c8SAlexey Lapshin memcpy(Out, reinterpret_cast<const char *>(&ListEntry), sizeof(NListType)); 283f75da0c8SAlexey Lapshin Out += sizeof(NListType); 284f75da0c8SAlexey Lapshin } 285f75da0c8SAlexey Lapshin 286f75da0c8SAlexey Lapshin void MachOWriter::writeStringTable() { 287f75da0c8SAlexey Lapshin if (!O.SymTabCommandIndex) 288f75da0c8SAlexey Lapshin return; 289f75da0c8SAlexey Lapshin const MachO::symtab_command &SymTabCommand = 290f75da0c8SAlexey Lapshin O.LoadCommands[*O.SymTabCommandIndex] 291f75da0c8SAlexey Lapshin .MachOLoadCommand.symtab_command_data; 292f75da0c8SAlexey Lapshin 293f75da0c8SAlexey Lapshin uint8_t *StrTable = (uint8_t *)Buf->getBufferStart() + SymTabCommand.stroff; 294f75da0c8SAlexey Lapshin LayoutBuilder.getStringTableBuilder().write(StrTable); 295f75da0c8SAlexey Lapshin } 296f75da0c8SAlexey Lapshin 297f75da0c8SAlexey Lapshin void MachOWriter::writeSymbolTable() { 298f75da0c8SAlexey Lapshin if (!O.SymTabCommandIndex) 299f75da0c8SAlexey Lapshin return; 300f75da0c8SAlexey Lapshin const MachO::symtab_command &SymTabCommand = 301f75da0c8SAlexey Lapshin O.LoadCommands[*O.SymTabCommandIndex] 302f75da0c8SAlexey Lapshin .MachOLoadCommand.symtab_command_data; 303f75da0c8SAlexey Lapshin 304f75da0c8SAlexey Lapshin char *SymTable = (char *)Buf->getBufferStart() + SymTabCommand.symoff; 305c63f8238SKazu Hirata for (auto &Symbol : O.SymTable.Symbols) { 306c63f8238SKazu Hirata SymbolEntry *Sym = Symbol.get(); 307f75da0c8SAlexey Lapshin uint32_t Nstrx = LayoutBuilder.getStringTableBuilder().getOffset(Sym->Name); 308f75da0c8SAlexey Lapshin 309f75da0c8SAlexey Lapshin if (Is64Bit) 310f75da0c8SAlexey Lapshin writeNListEntry<MachO::nlist_64>(*Sym, IsLittleEndian, SymTable, Nstrx); 311f75da0c8SAlexey Lapshin else 312f75da0c8SAlexey Lapshin writeNListEntry<MachO::nlist>(*Sym, IsLittleEndian, SymTable, Nstrx); 313f75da0c8SAlexey Lapshin } 314f75da0c8SAlexey Lapshin } 315f75da0c8SAlexey Lapshin 316f75da0c8SAlexey Lapshin void MachOWriter::writeRebaseInfo() { 317f75da0c8SAlexey Lapshin if (!O.DyLdInfoCommandIndex) 318f75da0c8SAlexey Lapshin return; 319f75da0c8SAlexey Lapshin const MachO::dyld_info_command &DyLdInfoCommand = 320f75da0c8SAlexey Lapshin O.LoadCommands[*O.DyLdInfoCommandIndex] 321f75da0c8SAlexey Lapshin .MachOLoadCommand.dyld_info_command_data; 322f75da0c8SAlexey Lapshin char *Out = (char *)Buf->getBufferStart() + DyLdInfoCommand.rebase_off; 323f75da0c8SAlexey Lapshin assert((DyLdInfoCommand.rebase_size == O.Rebases.Opcodes.size()) && 324f75da0c8SAlexey Lapshin "Incorrect rebase opcodes size"); 325f75da0c8SAlexey Lapshin memcpy(Out, O.Rebases.Opcodes.data(), O.Rebases.Opcodes.size()); 326f75da0c8SAlexey Lapshin } 327f75da0c8SAlexey Lapshin 328f75da0c8SAlexey Lapshin void MachOWriter::writeBindInfo() { 329f75da0c8SAlexey Lapshin if (!O.DyLdInfoCommandIndex) 330f75da0c8SAlexey Lapshin return; 331f75da0c8SAlexey Lapshin const MachO::dyld_info_command &DyLdInfoCommand = 332f75da0c8SAlexey Lapshin O.LoadCommands[*O.DyLdInfoCommandIndex] 333f75da0c8SAlexey Lapshin .MachOLoadCommand.dyld_info_command_data; 334f75da0c8SAlexey Lapshin char *Out = (char *)Buf->getBufferStart() + DyLdInfoCommand.bind_off; 335f75da0c8SAlexey Lapshin assert((DyLdInfoCommand.bind_size == O.Binds.Opcodes.size()) && 336f75da0c8SAlexey Lapshin "Incorrect bind opcodes size"); 337f75da0c8SAlexey Lapshin memcpy(Out, O.Binds.Opcodes.data(), O.Binds.Opcodes.size()); 338f75da0c8SAlexey Lapshin } 339f75da0c8SAlexey Lapshin 340f75da0c8SAlexey Lapshin void MachOWriter::writeWeakBindInfo() { 341f75da0c8SAlexey Lapshin if (!O.DyLdInfoCommandIndex) 342f75da0c8SAlexey Lapshin return; 343f75da0c8SAlexey Lapshin const MachO::dyld_info_command &DyLdInfoCommand = 344f75da0c8SAlexey Lapshin O.LoadCommands[*O.DyLdInfoCommandIndex] 345f75da0c8SAlexey Lapshin .MachOLoadCommand.dyld_info_command_data; 346f75da0c8SAlexey Lapshin char *Out = (char *)Buf->getBufferStart() + DyLdInfoCommand.weak_bind_off; 347f75da0c8SAlexey Lapshin assert((DyLdInfoCommand.weak_bind_size == O.WeakBinds.Opcodes.size()) && 348f75da0c8SAlexey Lapshin "Incorrect weak bind opcodes size"); 349f75da0c8SAlexey Lapshin memcpy(Out, O.WeakBinds.Opcodes.data(), O.WeakBinds.Opcodes.size()); 350f75da0c8SAlexey Lapshin } 351f75da0c8SAlexey Lapshin 352f75da0c8SAlexey Lapshin void MachOWriter::writeLazyBindInfo() { 353f75da0c8SAlexey Lapshin if (!O.DyLdInfoCommandIndex) 354f75da0c8SAlexey Lapshin return; 355f75da0c8SAlexey Lapshin const MachO::dyld_info_command &DyLdInfoCommand = 356f75da0c8SAlexey Lapshin O.LoadCommands[*O.DyLdInfoCommandIndex] 357f75da0c8SAlexey Lapshin .MachOLoadCommand.dyld_info_command_data; 358f75da0c8SAlexey Lapshin char *Out = (char *)Buf->getBufferStart() + DyLdInfoCommand.lazy_bind_off; 359f75da0c8SAlexey Lapshin assert((DyLdInfoCommand.lazy_bind_size == O.LazyBinds.Opcodes.size()) && 360f75da0c8SAlexey Lapshin "Incorrect lazy bind opcodes size"); 361f75da0c8SAlexey Lapshin memcpy(Out, O.LazyBinds.Opcodes.data(), O.LazyBinds.Opcodes.size()); 362f75da0c8SAlexey Lapshin } 363f75da0c8SAlexey Lapshin 364f75da0c8SAlexey Lapshin void MachOWriter::writeExportInfo() { 365f75da0c8SAlexey Lapshin if (!O.DyLdInfoCommandIndex) 366f75da0c8SAlexey Lapshin return; 367f75da0c8SAlexey Lapshin const MachO::dyld_info_command &DyLdInfoCommand = 368f75da0c8SAlexey Lapshin O.LoadCommands[*O.DyLdInfoCommandIndex] 369f75da0c8SAlexey Lapshin .MachOLoadCommand.dyld_info_command_data; 370f75da0c8SAlexey Lapshin char *Out = (char *)Buf->getBufferStart() + DyLdInfoCommand.export_off; 371f75da0c8SAlexey Lapshin assert((DyLdInfoCommand.export_size == O.Exports.Trie.size()) && 372f75da0c8SAlexey Lapshin "Incorrect export trie size"); 373f75da0c8SAlexey Lapshin memcpy(Out, O.Exports.Trie.data(), O.Exports.Trie.size()); 374f75da0c8SAlexey Lapshin } 375f75da0c8SAlexey Lapshin 376f75da0c8SAlexey Lapshin void MachOWriter::writeIndirectSymbolTable() { 377f75da0c8SAlexey Lapshin if (!O.DySymTabCommandIndex) 378f75da0c8SAlexey Lapshin return; 379f75da0c8SAlexey Lapshin 380f75da0c8SAlexey Lapshin const MachO::dysymtab_command &DySymTabCommand = 381f75da0c8SAlexey Lapshin O.LoadCommands[*O.DySymTabCommandIndex] 382f75da0c8SAlexey Lapshin .MachOLoadCommand.dysymtab_command_data; 383f75da0c8SAlexey Lapshin 384f75da0c8SAlexey Lapshin uint32_t *Out = 385f75da0c8SAlexey Lapshin (uint32_t *)(Buf->getBufferStart() + DySymTabCommand.indirectsymoff); 386f75da0c8SAlexey Lapshin for (const IndirectSymbolEntry &Sym : O.IndirectSymTable.Symbols) { 387f75da0c8SAlexey Lapshin uint32_t Entry = (Sym.Symbol) ? (*Sym.Symbol)->Index : Sym.OriginalIndex; 388f75da0c8SAlexey Lapshin if (IsLittleEndian != sys::IsLittleEndianHost) 389f75da0c8SAlexey Lapshin sys::swapByteOrder(Entry); 390f75da0c8SAlexey Lapshin *Out++ = Entry; 391f75da0c8SAlexey Lapshin } 392f75da0c8SAlexey Lapshin } 393f75da0c8SAlexey Lapshin 394ec941432SFangrui Song void MachOWriter::writeLinkData(std::optional<size_t> LCIndex, 395ec941432SFangrui Song const LinkData &LD) { 396f75da0c8SAlexey Lapshin if (!LCIndex) 397f75da0c8SAlexey Lapshin return; 398f75da0c8SAlexey Lapshin const MachO::linkedit_data_command &LinkEditDataCommand = 399f75da0c8SAlexey Lapshin O.LoadCommands[*LCIndex].MachOLoadCommand.linkedit_data_command_data; 400f75da0c8SAlexey Lapshin char *Out = (char *)Buf->getBufferStart() + LinkEditDataCommand.dataoff; 401f75da0c8SAlexey Lapshin assert((LinkEditDataCommand.datasize == LD.Data.size()) && 402f75da0c8SAlexey Lapshin "Incorrect data size"); 403f75da0c8SAlexey Lapshin memcpy(Out, LD.Data.data(), LD.Data.size()); 404f75da0c8SAlexey Lapshin } 405f75da0c8SAlexey Lapshin 406f75da0c8SAlexey Lapshin static uint64_t 407f75da0c8SAlexey Lapshin getSegmentFileOffset(const LoadCommand &TextSegmentLoadCommand) { 408f75da0c8SAlexey Lapshin const MachO::macho_load_command &MLC = 409f75da0c8SAlexey Lapshin TextSegmentLoadCommand.MachOLoadCommand; 410f75da0c8SAlexey Lapshin switch (MLC.load_command_data.cmd) { 411f75da0c8SAlexey Lapshin case MachO::LC_SEGMENT: 412f75da0c8SAlexey Lapshin return MLC.segment_command_data.fileoff; 413f75da0c8SAlexey Lapshin case MachO::LC_SEGMENT_64: 414f75da0c8SAlexey Lapshin return MLC.segment_command_64_data.fileoff; 415f75da0c8SAlexey Lapshin default: 416f75da0c8SAlexey Lapshin return 0; 417f75da0c8SAlexey Lapshin } 418f75da0c8SAlexey Lapshin } 419f75da0c8SAlexey Lapshin 420f75da0c8SAlexey Lapshin static uint64_t getSegmentFileSize(const LoadCommand &TextSegmentLoadCommand) { 421f75da0c8SAlexey Lapshin const MachO::macho_load_command &MLC = 422f75da0c8SAlexey Lapshin TextSegmentLoadCommand.MachOLoadCommand; 423f75da0c8SAlexey Lapshin switch (MLC.load_command_data.cmd) { 424f75da0c8SAlexey Lapshin case MachO::LC_SEGMENT: 425f75da0c8SAlexey Lapshin return MLC.segment_command_data.filesize; 426f75da0c8SAlexey Lapshin case MachO::LC_SEGMENT_64: 427f75da0c8SAlexey Lapshin return MLC.segment_command_64_data.filesize; 428f75da0c8SAlexey Lapshin default: 429f75da0c8SAlexey Lapshin return 0; 430f75da0c8SAlexey Lapshin } 431f75da0c8SAlexey Lapshin } 432f75da0c8SAlexey Lapshin 433f75da0c8SAlexey Lapshin void MachOWriter::writeCodeSignatureData() { 434f75da0c8SAlexey Lapshin // NOTE: This CodeSignature section behaviour must be kept in sync with that 435f75da0c8SAlexey Lapshin // performed in LLD's CodeSignatureSection::write / 436f75da0c8SAlexey Lapshin // CodeSignatureSection::writeHashes. Furthermore, this call must occur only 437f75da0c8SAlexey Lapshin // after the rest of the binary has already been written to the buffer. This 438f75da0c8SAlexey Lapshin // is because the buffer is read from to perform the necessary hashing. 439f75da0c8SAlexey Lapshin 440f75da0c8SAlexey Lapshin // The CodeSignature section is the last section in the MachO binary and 441f75da0c8SAlexey Lapshin // contains a hash of all content in the binary before it. Since llvm-objcopy 442f75da0c8SAlexey Lapshin // has likely modified the target binary, the hash must be regenerated 443f75da0c8SAlexey Lapshin // entirely. To generate this hash, we must read from the start of the binary 444f75da0c8SAlexey Lapshin // (HashReadStart) to just before the start of the CodeSignature section 445f75da0c8SAlexey Lapshin // (HashReadEnd). 446f75da0c8SAlexey Lapshin 447f75da0c8SAlexey Lapshin const CodeSignatureInfo &CodeSignature = LayoutBuilder.getCodeSignature(); 448f75da0c8SAlexey Lapshin 449f75da0c8SAlexey Lapshin uint8_t *BufferStart = reinterpret_cast<uint8_t *>(Buf->getBufferStart()); 450f75da0c8SAlexey Lapshin uint8_t *HashReadStart = BufferStart; 451f75da0c8SAlexey Lapshin uint8_t *HashReadEnd = BufferStart + CodeSignature.StartOffset; 452f75da0c8SAlexey Lapshin 453f75da0c8SAlexey Lapshin // The CodeSignature section begins with a header, after which the hashes 454f75da0c8SAlexey Lapshin // of each page of the binary are written. 455f75da0c8SAlexey Lapshin uint8_t *HashWriteStart = HashReadEnd + CodeSignature.AllHeadersSize; 456f75da0c8SAlexey Lapshin 457f75da0c8SAlexey Lapshin uint32_t TextSegmentFileOff = 0; 458f75da0c8SAlexey Lapshin uint32_t TextSegmentFileSize = 0; 459f75da0c8SAlexey Lapshin if (O.TextSegmentCommandIndex) { 460f75da0c8SAlexey Lapshin const LoadCommand &TextSegmentLoadCommand = 461f75da0c8SAlexey Lapshin O.LoadCommands[*O.TextSegmentCommandIndex]; 462f75da0c8SAlexey Lapshin assert(TextSegmentLoadCommand.MachOLoadCommand.load_command_data.cmd == 463f75da0c8SAlexey Lapshin MachO::LC_SEGMENT || 464f75da0c8SAlexey Lapshin TextSegmentLoadCommand.MachOLoadCommand.load_command_data.cmd == 465f75da0c8SAlexey Lapshin MachO::LC_SEGMENT_64); 466f75da0c8SAlexey Lapshin assert(StringRef(TextSegmentLoadCommand.MachOLoadCommand 467f75da0c8SAlexey Lapshin .segment_command_data.segname) == "__TEXT"); 468f75da0c8SAlexey Lapshin TextSegmentFileOff = getSegmentFileOffset(TextSegmentLoadCommand); 469f75da0c8SAlexey Lapshin TextSegmentFileSize = getSegmentFileSize(TextSegmentLoadCommand); 470f75da0c8SAlexey Lapshin } 471f75da0c8SAlexey Lapshin 472f75da0c8SAlexey Lapshin const uint32_t FileNamePad = CodeSignature.AllHeadersSize - 473f75da0c8SAlexey Lapshin CodeSignature.FixedHeadersSize - 474f75da0c8SAlexey Lapshin CodeSignature.OutputFileName.size(); 475f75da0c8SAlexey Lapshin 476f75da0c8SAlexey Lapshin // Write code section header. 477f75da0c8SAlexey Lapshin auto *SuperBlob = reinterpret_cast<MachO::CS_SuperBlob *>(HashReadEnd); 478f75da0c8SAlexey Lapshin write32be(&SuperBlob->magic, MachO::CSMAGIC_EMBEDDED_SIGNATURE); 479f75da0c8SAlexey Lapshin write32be(&SuperBlob->length, CodeSignature.Size); 480f75da0c8SAlexey Lapshin write32be(&SuperBlob->count, 1); 481f75da0c8SAlexey Lapshin auto *BlobIndex = reinterpret_cast<MachO::CS_BlobIndex *>(&SuperBlob[1]); 482f75da0c8SAlexey Lapshin write32be(&BlobIndex->type, MachO::CSSLOT_CODEDIRECTORY); 483f75da0c8SAlexey Lapshin write32be(&BlobIndex->offset, CodeSignature.BlobHeadersSize); 484f75da0c8SAlexey Lapshin auto *CodeDirectory = reinterpret_cast<MachO::CS_CodeDirectory *>( 485f75da0c8SAlexey Lapshin HashReadEnd + CodeSignature.BlobHeadersSize); 486f75da0c8SAlexey Lapshin write32be(&CodeDirectory->magic, MachO::CSMAGIC_CODEDIRECTORY); 487f75da0c8SAlexey Lapshin write32be(&CodeDirectory->length, 488f75da0c8SAlexey Lapshin CodeSignature.Size - CodeSignature.BlobHeadersSize); 489f75da0c8SAlexey Lapshin write32be(&CodeDirectory->version, MachO::CS_SUPPORTSEXECSEG); 490f75da0c8SAlexey Lapshin write32be(&CodeDirectory->flags, MachO::CS_ADHOC | MachO::CS_LINKER_SIGNED); 491f75da0c8SAlexey Lapshin write32be(&CodeDirectory->hashOffset, 492f75da0c8SAlexey Lapshin sizeof(MachO::CS_CodeDirectory) + 493f75da0c8SAlexey Lapshin CodeSignature.OutputFileName.size() + FileNamePad); 494f75da0c8SAlexey Lapshin write32be(&CodeDirectory->identOffset, sizeof(MachO::CS_CodeDirectory)); 495f75da0c8SAlexey Lapshin CodeDirectory->nSpecialSlots = 0; 496f75da0c8SAlexey Lapshin write32be(&CodeDirectory->nCodeSlots, CodeSignature.BlockCount); 497f75da0c8SAlexey Lapshin write32be(&CodeDirectory->codeLimit, CodeSignature.StartOffset); 498f75da0c8SAlexey Lapshin CodeDirectory->hashSize = static_cast<uint8_t>(CodeSignature.HashSize); 499f75da0c8SAlexey Lapshin CodeDirectory->hashType = MachO::kSecCodeSignatureHashSHA256; 500f75da0c8SAlexey Lapshin CodeDirectory->platform = 0; 501f75da0c8SAlexey Lapshin CodeDirectory->pageSize = CodeSignature.BlockSizeShift; 502f75da0c8SAlexey Lapshin CodeDirectory->spare2 = 0; 503f75da0c8SAlexey Lapshin CodeDirectory->scatterOffset = 0; 504f75da0c8SAlexey Lapshin CodeDirectory->teamOffset = 0; 505f75da0c8SAlexey Lapshin CodeDirectory->spare3 = 0; 506f75da0c8SAlexey Lapshin CodeDirectory->codeLimit64 = 0; 507f75da0c8SAlexey Lapshin write64be(&CodeDirectory->execSegBase, TextSegmentFileOff); 508f75da0c8SAlexey Lapshin write64be(&CodeDirectory->execSegLimit, TextSegmentFileSize); 509f75da0c8SAlexey Lapshin write64be(&CodeDirectory->execSegFlags, O.Header.FileType == MachO::MH_EXECUTE 510f75da0c8SAlexey Lapshin ? MachO::CS_EXECSEG_MAIN_BINARY 511f75da0c8SAlexey Lapshin : 0); 512f75da0c8SAlexey Lapshin 513f75da0c8SAlexey Lapshin auto *Id = reinterpret_cast<char *>(&CodeDirectory[1]); 514f75da0c8SAlexey Lapshin memcpy(Id, CodeSignature.OutputFileName.begin(), 515f75da0c8SAlexey Lapshin CodeSignature.OutputFileName.size()); 516f75da0c8SAlexey Lapshin memset(Id + CodeSignature.OutputFileName.size(), 0, FileNamePad); 517f75da0c8SAlexey Lapshin 518f75da0c8SAlexey Lapshin // Write the hashes. 519f75da0c8SAlexey Lapshin uint8_t *CurrHashReadPosition = HashReadStart; 520f75da0c8SAlexey Lapshin uint8_t *CurrHashWritePosition = HashWriteStart; 521f75da0c8SAlexey Lapshin while (CurrHashReadPosition < HashReadEnd) { 522f75da0c8SAlexey Lapshin StringRef Block(reinterpret_cast<char *>(CurrHashReadPosition), 523146f486bSJoshua Root std::min(static_cast<size_t>(HashReadEnd 524146f486bSJoshua Root - CurrHashReadPosition), 525146f486bSJoshua Root static_cast<size_t>(CodeSignature.BlockSize))); 526f75da0c8SAlexey Lapshin SHA256 Hasher; 527f75da0c8SAlexey Lapshin Hasher.update(Block); 528330268baSArgyrios Kyrtzidis std::array<uint8_t, 32> Hash = Hasher.final(); 529f75da0c8SAlexey Lapshin assert(Hash.size() == CodeSignature.HashSize); 530f75da0c8SAlexey Lapshin memcpy(CurrHashWritePosition, Hash.data(), CodeSignature.HashSize); 531f75da0c8SAlexey Lapshin CurrHashReadPosition += CodeSignature.BlockSize; 532f75da0c8SAlexey Lapshin CurrHashWritePosition += CodeSignature.HashSize; 533f75da0c8SAlexey Lapshin } 534f75da0c8SAlexey Lapshin #if defined(__APPLE__) 535f75da0c8SAlexey Lapshin // This is macOS-specific work-around and makes no sense for any 536f75da0c8SAlexey Lapshin // other host OS. See https://openradar.appspot.com/FB8914231 537f75da0c8SAlexey Lapshin // 538f75da0c8SAlexey Lapshin // The macOS kernel maintains a signature-verification cache to 539f75da0c8SAlexey Lapshin // quickly validate applications at time of execve(2). The trouble 540f75da0c8SAlexey Lapshin // is that for the kernel creates the cache entry at the time of the 541f75da0c8SAlexey Lapshin // mmap(2) call, before we have a chance to write either the code to 542f75da0c8SAlexey Lapshin // sign or the signature header+hashes. The fix is to invalidate 543f75da0c8SAlexey Lapshin // all cached data associated with the output file, thus discarding 544f75da0c8SAlexey Lapshin // the bogus prematurely-cached signature. 545f75da0c8SAlexey Lapshin msync(BufferStart, CodeSignature.StartOffset + CodeSignature.Size, 546f75da0c8SAlexey Lapshin MS_INVALIDATE); 547f75da0c8SAlexey Lapshin #endif 548f75da0c8SAlexey Lapshin } 549f75da0c8SAlexey Lapshin 550f75da0c8SAlexey Lapshin void MachOWriter::writeDataInCodeData() { 551f75da0c8SAlexey Lapshin return writeLinkData(O.DataInCodeCommandIndex, O.DataInCode); 552f75da0c8SAlexey Lapshin } 553f75da0c8SAlexey Lapshin 554f75da0c8SAlexey Lapshin void MachOWriter::writeLinkerOptimizationHint() { 555f75da0c8SAlexey Lapshin return writeLinkData(O.LinkerOptimizationHintCommandIndex, 556f75da0c8SAlexey Lapshin O.LinkerOptimizationHint); 557f75da0c8SAlexey Lapshin } 558f75da0c8SAlexey Lapshin 559f75da0c8SAlexey Lapshin void MachOWriter::writeFunctionStartsData() { 560f75da0c8SAlexey Lapshin return writeLinkData(O.FunctionStartsCommandIndex, O.FunctionStarts); 561f75da0c8SAlexey Lapshin } 562f75da0c8SAlexey Lapshin 563c2d20947SKeith Smiley void MachOWriter::writeDylibCodeSignDRsData() { 564c2d20947SKeith Smiley return writeLinkData(O.DylibCodeSignDRsIndex, O.DylibCodeSignDRs); 565c2d20947SKeith Smiley } 566c2d20947SKeith Smiley 567f75da0c8SAlexey Lapshin void MachOWriter::writeChainedFixupsData() { 568f75da0c8SAlexey Lapshin return writeLinkData(O.ChainedFixupsCommandIndex, O.ChainedFixups); 569f75da0c8SAlexey Lapshin } 570f75da0c8SAlexey Lapshin 571f75da0c8SAlexey Lapshin void MachOWriter::writeExportsTrieData() { 572652713e2SDaniel Rodríguez Troitiño if (!O.ExportsTrieCommandIndex) 573652713e2SDaniel Rodríguez Troitiño return; 574652713e2SDaniel Rodríguez Troitiño const MachO::linkedit_data_command &ExportsTrieCmd = 575652713e2SDaniel Rodríguez Troitiño O.LoadCommands[*O.ExportsTrieCommandIndex] 576652713e2SDaniel Rodríguez Troitiño .MachOLoadCommand.linkedit_data_command_data; 577652713e2SDaniel Rodríguez Troitiño char *Out = (char *)Buf->getBufferStart() + ExportsTrieCmd.dataoff; 578652713e2SDaniel Rodríguez Troitiño assert((ExportsTrieCmd.datasize == O.Exports.Trie.size()) && 579652713e2SDaniel Rodríguez Troitiño "Incorrect export trie size"); 580652713e2SDaniel Rodríguez Troitiño memcpy(Out, O.Exports.Trie.data(), O.Exports.Trie.size()); 581f75da0c8SAlexey Lapshin } 582f75da0c8SAlexey Lapshin 583f75da0c8SAlexey Lapshin void MachOWriter::writeTail() { 584f75da0c8SAlexey Lapshin typedef void (MachOWriter::*WriteHandlerType)(); 585f75da0c8SAlexey Lapshin typedef std::pair<uint64_t, WriteHandlerType> WriteOperation; 586f75da0c8SAlexey Lapshin SmallVector<WriteOperation, 7> Queue; 587f75da0c8SAlexey Lapshin 588f75da0c8SAlexey Lapshin if (O.SymTabCommandIndex) { 589f75da0c8SAlexey Lapshin const MachO::symtab_command &SymTabCommand = 590f75da0c8SAlexey Lapshin O.LoadCommands[*O.SymTabCommandIndex] 591f75da0c8SAlexey Lapshin .MachOLoadCommand.symtab_command_data; 592f75da0c8SAlexey Lapshin if (SymTabCommand.symoff) 593f75da0c8SAlexey Lapshin Queue.push_back({SymTabCommand.symoff, &MachOWriter::writeSymbolTable}); 594f75da0c8SAlexey Lapshin if (SymTabCommand.stroff) 595f75da0c8SAlexey Lapshin Queue.push_back({SymTabCommand.stroff, &MachOWriter::writeStringTable}); 596f75da0c8SAlexey Lapshin } 597f75da0c8SAlexey Lapshin 598f75da0c8SAlexey Lapshin if (O.DyLdInfoCommandIndex) { 599f75da0c8SAlexey Lapshin const MachO::dyld_info_command &DyLdInfoCommand = 600f75da0c8SAlexey Lapshin O.LoadCommands[*O.DyLdInfoCommandIndex] 601f75da0c8SAlexey Lapshin .MachOLoadCommand.dyld_info_command_data; 602f75da0c8SAlexey Lapshin if (DyLdInfoCommand.rebase_off) 603f75da0c8SAlexey Lapshin Queue.push_back( 604f75da0c8SAlexey Lapshin {DyLdInfoCommand.rebase_off, &MachOWriter::writeRebaseInfo}); 605f75da0c8SAlexey Lapshin if (DyLdInfoCommand.bind_off) 606f75da0c8SAlexey Lapshin Queue.push_back({DyLdInfoCommand.bind_off, &MachOWriter::writeBindInfo}); 607f75da0c8SAlexey Lapshin if (DyLdInfoCommand.weak_bind_off) 608f75da0c8SAlexey Lapshin Queue.push_back( 609f75da0c8SAlexey Lapshin {DyLdInfoCommand.weak_bind_off, &MachOWriter::writeWeakBindInfo}); 610f75da0c8SAlexey Lapshin if (DyLdInfoCommand.lazy_bind_off) 611f75da0c8SAlexey Lapshin Queue.push_back( 612f75da0c8SAlexey Lapshin {DyLdInfoCommand.lazy_bind_off, &MachOWriter::writeLazyBindInfo}); 613f75da0c8SAlexey Lapshin if (DyLdInfoCommand.export_off) 614f75da0c8SAlexey Lapshin Queue.push_back( 615f75da0c8SAlexey Lapshin {DyLdInfoCommand.export_off, &MachOWriter::writeExportInfo}); 616f75da0c8SAlexey Lapshin } 617f75da0c8SAlexey Lapshin 618f75da0c8SAlexey Lapshin if (O.DySymTabCommandIndex) { 619f75da0c8SAlexey Lapshin const MachO::dysymtab_command &DySymTabCommand = 620f75da0c8SAlexey Lapshin O.LoadCommands[*O.DySymTabCommandIndex] 621f75da0c8SAlexey Lapshin .MachOLoadCommand.dysymtab_command_data; 622f75da0c8SAlexey Lapshin 623f75da0c8SAlexey Lapshin if (DySymTabCommand.indirectsymoff) 624f75da0c8SAlexey Lapshin Queue.emplace_back(DySymTabCommand.indirectsymoff, 625f75da0c8SAlexey Lapshin &MachOWriter::writeIndirectSymbolTable); 626f75da0c8SAlexey Lapshin } 627f75da0c8SAlexey Lapshin 628ec941432SFangrui Song std::initializer_list<std::pair<std::optional<size_t>, WriteHandlerType>> 6294d87344eSAlexander Shaposhnikov LinkEditDataCommandWriters = { 6304d87344eSAlexander Shaposhnikov {O.CodeSignatureCommandIndex, &MachOWriter::writeCodeSignatureData}, 631c2d20947SKeith Smiley {O.DylibCodeSignDRsIndex, &MachOWriter::writeDylibCodeSignDRsData}, 6324d87344eSAlexander Shaposhnikov {O.DataInCodeCommandIndex, &MachOWriter::writeDataInCodeData}, 6334d87344eSAlexander Shaposhnikov {O.LinkerOptimizationHintCommandIndex, 6344d87344eSAlexander Shaposhnikov &MachOWriter::writeLinkerOptimizationHint}, 6354d87344eSAlexander Shaposhnikov {O.FunctionStartsCommandIndex, &MachOWriter::writeFunctionStartsData}, 6364d87344eSAlexander Shaposhnikov {O.ChainedFixupsCommandIndex, &MachOWriter::writeChainedFixupsData}, 6374d87344eSAlexander Shaposhnikov {O.ExportsTrieCommandIndex, &MachOWriter::writeExportsTrieData}}; 6384d87344eSAlexander Shaposhnikov for (const auto &W : LinkEditDataCommandWriters) { 639ec941432SFangrui Song std::optional<size_t> LinkEditDataCommandIndex; 6404d87344eSAlexander Shaposhnikov WriteHandlerType WriteHandler; 6414d87344eSAlexander Shaposhnikov std::tie(LinkEditDataCommandIndex, WriteHandler) = W; 6424d87344eSAlexander Shaposhnikov if (LinkEditDataCommandIndex) { 643f75da0c8SAlexey Lapshin const MachO::linkedit_data_command &LinkEditDataCommand = 6444d87344eSAlexander Shaposhnikov O.LoadCommands[*LinkEditDataCommandIndex] 645f75da0c8SAlexey Lapshin .MachOLoadCommand.linkedit_data_command_data; 646f75da0c8SAlexey Lapshin if (LinkEditDataCommand.dataoff) 6474d87344eSAlexander Shaposhnikov Queue.emplace_back(LinkEditDataCommand.dataoff, WriteHandler); 648f75da0c8SAlexey Lapshin } 649f75da0c8SAlexey Lapshin } 650f75da0c8SAlexey Lapshin 6514969a692SKazu Hirata llvm::sort(Queue, llvm::less_first()); 652f75da0c8SAlexey Lapshin 653f75da0c8SAlexey Lapshin for (auto WriteOp : Queue) 654f75da0c8SAlexey Lapshin (this->*WriteOp.second)(); 655f75da0c8SAlexey Lapshin } 656f75da0c8SAlexey Lapshin 657f75da0c8SAlexey Lapshin Error MachOWriter::finalize() { return LayoutBuilder.layout(); } 658f75da0c8SAlexey Lapshin 659f75da0c8SAlexey Lapshin Error MachOWriter::write() { 660f75da0c8SAlexey Lapshin size_t TotalSize = totalSize(); 661f75da0c8SAlexey Lapshin Buf = WritableMemoryBuffer::getNewMemBuffer(TotalSize); 662f75da0c8SAlexey Lapshin if (!Buf) 663f75da0c8SAlexey Lapshin return createStringError(errc::not_enough_memory, 664f75da0c8SAlexey Lapshin "failed to allocate memory buffer of " + 665f75da0c8SAlexey Lapshin Twine::utohexstr(TotalSize) + " bytes"); 666f75da0c8SAlexey Lapshin writeHeader(); 667f75da0c8SAlexey Lapshin writeLoadCommands(); 668f75da0c8SAlexey Lapshin writeSections(); 669f75da0c8SAlexey Lapshin writeTail(); 670f75da0c8SAlexey Lapshin 671f75da0c8SAlexey Lapshin // TODO: Implement direct writing to the output stream (without intermediate 672f75da0c8SAlexey Lapshin // memory buffer Buf). 673f75da0c8SAlexey Lapshin Out.write(Buf->getBufferStart(), Buf->getBufferSize()); 674f75da0c8SAlexey Lapshin return Error::success(); 675f75da0c8SAlexey Lapshin } 676