1f75da0c8SAlexey Lapshin //===- MachOLayoutBuilder.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 "MachOLayoutBuilder.h" 10f75da0c8SAlexey Lapshin #include "llvm/Support/Alignment.h" 11f75da0c8SAlexey Lapshin #include "llvm/Support/Errc.h" 12f75da0c8SAlexey Lapshin #include "llvm/Support/ErrorHandling.h" 13ec41462dSAbhina Sree #include "llvm/Support/SystemZ/zOSSupport.h" 14f75da0c8SAlexey Lapshin 15f75da0c8SAlexey Lapshin using namespace llvm; 16f75da0c8SAlexey Lapshin using namespace llvm::objcopy::macho; 17f75da0c8SAlexey Lapshin 18f75da0c8SAlexey Lapshin StringTableBuilder::Kind 19f75da0c8SAlexey Lapshin MachOLayoutBuilder::getStringTableBuilderKind(const Object &O, bool Is64Bit) { 20f75da0c8SAlexey Lapshin if (O.Header.FileType == MachO::HeaderFileType::MH_OBJECT) 21f75da0c8SAlexey Lapshin return Is64Bit ? StringTableBuilder::MachO64 : StringTableBuilder::MachO; 22f75da0c8SAlexey Lapshin return Is64Bit ? StringTableBuilder::MachO64Linked 23f75da0c8SAlexey Lapshin : StringTableBuilder::MachOLinked; 24f75da0c8SAlexey Lapshin } 25f75da0c8SAlexey Lapshin 26f75da0c8SAlexey Lapshin uint32_t MachOLayoutBuilder::computeSizeOfCmds() const { 27f75da0c8SAlexey Lapshin uint32_t Size = 0; 28f75da0c8SAlexey Lapshin for (const LoadCommand &LC : O.LoadCommands) { 29f75da0c8SAlexey Lapshin const MachO::macho_load_command &MLC = LC.MachOLoadCommand; 30f75da0c8SAlexey Lapshin auto cmd = MLC.load_command_data.cmd; 31f75da0c8SAlexey Lapshin switch (cmd) { 32f75da0c8SAlexey Lapshin case MachO::LC_SEGMENT: 33f75da0c8SAlexey Lapshin Size += sizeof(MachO::segment_command) + 34f75da0c8SAlexey Lapshin sizeof(MachO::section) * LC.Sections.size(); 35f75da0c8SAlexey Lapshin continue; 36f75da0c8SAlexey Lapshin case MachO::LC_SEGMENT_64: 37f75da0c8SAlexey Lapshin Size += sizeof(MachO::segment_command_64) + 38f75da0c8SAlexey Lapshin sizeof(MachO::section_64) * LC.Sections.size(); 39f75da0c8SAlexey Lapshin continue; 40f75da0c8SAlexey Lapshin } 41f75da0c8SAlexey Lapshin 42f75da0c8SAlexey Lapshin switch (cmd) { 43f75da0c8SAlexey Lapshin #define HANDLE_LOAD_COMMAND(LCName, LCValue, LCStruct) \ 44f75da0c8SAlexey Lapshin case MachO::LCName: \ 45f75da0c8SAlexey Lapshin Size += sizeof(MachO::LCStruct) + LC.Payload.size(); \ 46f75da0c8SAlexey Lapshin break; 47f75da0c8SAlexey Lapshin #include "llvm/BinaryFormat/MachO.def" 48f75da0c8SAlexey Lapshin #undef HANDLE_LOAD_COMMAND 49f75da0c8SAlexey Lapshin } 50f75da0c8SAlexey Lapshin } 51f75da0c8SAlexey Lapshin 52f75da0c8SAlexey Lapshin return Size; 53f75da0c8SAlexey Lapshin } 54f75da0c8SAlexey Lapshin 55f75da0c8SAlexey Lapshin void MachOLayoutBuilder::constructStringTable() { 56f75da0c8SAlexey Lapshin for (std::unique_ptr<SymbolEntry> &Sym : O.SymTable.Symbols) 57f75da0c8SAlexey Lapshin StrTableBuilder.add(Sym->Name); 58f75da0c8SAlexey Lapshin StrTableBuilder.finalize(); 59f75da0c8SAlexey Lapshin } 60f75da0c8SAlexey Lapshin 61f75da0c8SAlexey Lapshin void MachOLayoutBuilder::updateSymbolIndexes() { 62f75da0c8SAlexey Lapshin uint32_t Index = 0; 63f75da0c8SAlexey Lapshin for (auto &Symbol : O.SymTable.Symbols) 64f75da0c8SAlexey Lapshin Symbol->Index = Index++; 65f75da0c8SAlexey Lapshin } 66f75da0c8SAlexey Lapshin 67f75da0c8SAlexey Lapshin // Updates the index and the number of local/external/undefined symbols. 68f75da0c8SAlexey Lapshin void MachOLayoutBuilder::updateDySymTab(MachO::macho_load_command &MLC) { 69f75da0c8SAlexey Lapshin assert(MLC.load_command_data.cmd == MachO::LC_DYSYMTAB); 70f75da0c8SAlexey Lapshin // Make sure that nlist entries in the symbol table are sorted by the those 71f75da0c8SAlexey Lapshin // types. The order is: local < defined external < undefined external. 72f75da0c8SAlexey Lapshin assert(llvm::is_sorted(O.SymTable.Symbols, 73f75da0c8SAlexey Lapshin [](const std::unique_ptr<SymbolEntry> &A, 74f75da0c8SAlexey Lapshin const std::unique_ptr<SymbolEntry> &B) { 75f75da0c8SAlexey Lapshin bool AL = A->isLocalSymbol(), 76f75da0c8SAlexey Lapshin BL = B->isLocalSymbol(); 77f75da0c8SAlexey Lapshin if (AL != BL) 78f75da0c8SAlexey Lapshin return AL; 79f75da0c8SAlexey Lapshin return !AL && !A->isUndefinedSymbol() && 80f75da0c8SAlexey Lapshin B->isUndefinedSymbol(); 81f75da0c8SAlexey Lapshin }) && 82f75da0c8SAlexey Lapshin "Symbols are not sorted by their types."); 83f75da0c8SAlexey Lapshin 84f75da0c8SAlexey Lapshin uint32_t NumLocalSymbols = 0; 85f75da0c8SAlexey Lapshin auto Iter = O.SymTable.Symbols.begin(); 86f75da0c8SAlexey Lapshin auto End = O.SymTable.Symbols.end(); 87f75da0c8SAlexey Lapshin for (; Iter != End; ++Iter) { 88f75da0c8SAlexey Lapshin if ((*Iter)->isExternalSymbol()) 89f75da0c8SAlexey Lapshin break; 90f75da0c8SAlexey Lapshin 91f75da0c8SAlexey Lapshin ++NumLocalSymbols; 92f75da0c8SAlexey Lapshin } 93f75da0c8SAlexey Lapshin 94f75da0c8SAlexey Lapshin uint32_t NumExtDefSymbols = 0; 95f75da0c8SAlexey Lapshin for (; Iter != End; ++Iter) { 96f75da0c8SAlexey Lapshin if ((*Iter)->isUndefinedSymbol()) 97f75da0c8SAlexey Lapshin break; 98f75da0c8SAlexey Lapshin 99f75da0c8SAlexey Lapshin ++NumExtDefSymbols; 100f75da0c8SAlexey Lapshin } 101f75da0c8SAlexey Lapshin 102f75da0c8SAlexey Lapshin MLC.dysymtab_command_data.ilocalsym = 0; 103f75da0c8SAlexey Lapshin MLC.dysymtab_command_data.nlocalsym = NumLocalSymbols; 104f75da0c8SAlexey Lapshin MLC.dysymtab_command_data.iextdefsym = NumLocalSymbols; 105f75da0c8SAlexey Lapshin MLC.dysymtab_command_data.nextdefsym = NumExtDefSymbols; 106f75da0c8SAlexey Lapshin MLC.dysymtab_command_data.iundefsym = NumLocalSymbols + NumExtDefSymbols; 107f75da0c8SAlexey Lapshin MLC.dysymtab_command_data.nundefsym = 108f75da0c8SAlexey Lapshin O.SymTable.Symbols.size() - (NumLocalSymbols + NumExtDefSymbols); 109f75da0c8SAlexey Lapshin } 110f75da0c8SAlexey Lapshin 111f75da0c8SAlexey Lapshin // Recomputes and updates offset and size fields in load commands and sections 112f75da0c8SAlexey Lapshin // since they could be modified. 113f75da0c8SAlexey Lapshin uint64_t MachOLayoutBuilder::layoutSegments() { 114f75da0c8SAlexey Lapshin auto HeaderSize = 115f75da0c8SAlexey Lapshin Is64Bit ? sizeof(MachO::mach_header_64) : sizeof(MachO::mach_header); 116f75da0c8SAlexey Lapshin const bool IsObjectFile = 117f75da0c8SAlexey Lapshin O.Header.FileType == MachO::HeaderFileType::MH_OBJECT; 118f75da0c8SAlexey Lapshin uint64_t Offset = IsObjectFile ? (HeaderSize + O.Header.SizeOfCmds) : 0; 119*1a830aa1SDaniel Rodríguez Troitiño if (O.EncryptionInfoCommandIndex) { 120*1a830aa1SDaniel Rodríguez Troitiño // If we are emitting an encryptable binary, our load commands must have a 121*1a830aa1SDaniel Rodríguez Troitiño // separate (non-encrypted) page to themselves. 122*1a830aa1SDaniel Rodríguez Troitiño Offset = alignToPowerOf2(HeaderSize + O.Header.SizeOfCmds, PageSize); 123*1a830aa1SDaniel Rodríguez Troitiño } 124f75da0c8SAlexey Lapshin for (LoadCommand &LC : O.LoadCommands) { 125f75da0c8SAlexey Lapshin auto &MLC = LC.MachOLoadCommand; 126f75da0c8SAlexey Lapshin StringRef Segname; 127f75da0c8SAlexey Lapshin uint64_t SegmentVmAddr; 128f75da0c8SAlexey Lapshin uint64_t SegmentVmSize; 129f75da0c8SAlexey Lapshin switch (MLC.load_command_data.cmd) { 130f75da0c8SAlexey Lapshin case MachO::LC_SEGMENT: 131f75da0c8SAlexey Lapshin SegmentVmAddr = MLC.segment_command_data.vmaddr; 132f75da0c8SAlexey Lapshin SegmentVmSize = MLC.segment_command_data.vmsize; 133f75da0c8SAlexey Lapshin Segname = StringRef(MLC.segment_command_data.segname, 134f75da0c8SAlexey Lapshin strnlen(MLC.segment_command_data.segname, 135f75da0c8SAlexey Lapshin sizeof(MLC.segment_command_data.segname))); 136f75da0c8SAlexey Lapshin break; 137f75da0c8SAlexey Lapshin case MachO::LC_SEGMENT_64: 138f75da0c8SAlexey Lapshin SegmentVmAddr = MLC.segment_command_64_data.vmaddr; 139f75da0c8SAlexey Lapshin SegmentVmSize = MLC.segment_command_64_data.vmsize; 140f75da0c8SAlexey Lapshin Segname = StringRef(MLC.segment_command_64_data.segname, 141f75da0c8SAlexey Lapshin strnlen(MLC.segment_command_64_data.segname, 142f75da0c8SAlexey Lapshin sizeof(MLC.segment_command_64_data.segname))); 143f75da0c8SAlexey Lapshin break; 144f75da0c8SAlexey Lapshin default: 145f75da0c8SAlexey Lapshin continue; 146f75da0c8SAlexey Lapshin } 147f75da0c8SAlexey Lapshin 148f75da0c8SAlexey Lapshin if (Segname == "__LINKEDIT") { 149f75da0c8SAlexey Lapshin // We update the __LINKEDIT segment later (in layoutTail). 150f75da0c8SAlexey Lapshin assert(LC.Sections.empty() && "__LINKEDIT segment has sections"); 151f75da0c8SAlexey Lapshin LinkEditLoadCommand = &MLC; 152f75da0c8SAlexey Lapshin continue; 153f75da0c8SAlexey Lapshin } 154f75da0c8SAlexey Lapshin 155f75da0c8SAlexey Lapshin // Update file offsets and sizes of sections. 156f75da0c8SAlexey Lapshin uint64_t SegOffset = Offset; 157f75da0c8SAlexey Lapshin uint64_t SegFileSize = 0; 158f75da0c8SAlexey Lapshin uint64_t VMSize = 0; 159f75da0c8SAlexey Lapshin for (std::unique_ptr<Section> &Sec : LC.Sections) { 160f75da0c8SAlexey Lapshin assert(SegmentVmAddr <= Sec->Addr && 161f75da0c8SAlexey Lapshin "Section's address cannot be smaller than Segment's one"); 162f75da0c8SAlexey Lapshin uint32_t SectOffset = Sec->Addr - SegmentVmAddr; 163f75da0c8SAlexey Lapshin if (IsObjectFile) { 164f75da0c8SAlexey Lapshin if (!Sec->hasValidOffset()) { 165f75da0c8SAlexey Lapshin Sec->Offset = 0; 166f75da0c8SAlexey Lapshin } else { 167f75da0c8SAlexey Lapshin uint64_t PaddingSize = 168f75da0c8SAlexey Lapshin offsetToAlignment(SegFileSize, Align(1ull << Sec->Align)); 169f75da0c8SAlexey Lapshin Sec->Offset = SegOffset + SegFileSize + PaddingSize; 170f75da0c8SAlexey Lapshin Sec->Size = Sec->Content.size(); 171f75da0c8SAlexey Lapshin SegFileSize += PaddingSize + Sec->Size; 172f75da0c8SAlexey Lapshin } 173f75da0c8SAlexey Lapshin } else { 174f75da0c8SAlexey Lapshin if (!Sec->hasValidOffset()) { 175f75da0c8SAlexey Lapshin Sec->Offset = 0; 176f75da0c8SAlexey Lapshin } else { 177f75da0c8SAlexey Lapshin Sec->Offset = SegOffset + SectOffset; 178f75da0c8SAlexey Lapshin Sec->Size = Sec->Content.size(); 179f75da0c8SAlexey Lapshin SegFileSize = std::max(SegFileSize, SectOffset + Sec->Size); 180f75da0c8SAlexey Lapshin } 181f75da0c8SAlexey Lapshin } 182f75da0c8SAlexey Lapshin VMSize = std::max(VMSize, SectOffset + Sec->Size); 183f75da0c8SAlexey Lapshin } 184f75da0c8SAlexey Lapshin 185f75da0c8SAlexey Lapshin if (IsObjectFile) { 186f75da0c8SAlexey Lapshin Offset += SegFileSize; 187f75da0c8SAlexey Lapshin } else { 188f75da0c8SAlexey Lapshin Offset = alignTo(Offset + SegFileSize, PageSize); 189f75da0c8SAlexey Lapshin SegFileSize = alignTo(SegFileSize, PageSize); 190f75da0c8SAlexey Lapshin // Use the original vmsize if the segment is __PAGEZERO. 191f75da0c8SAlexey Lapshin VMSize = 192f75da0c8SAlexey Lapshin Segname == "__PAGEZERO" ? SegmentVmSize : alignTo(VMSize, PageSize); 193f75da0c8SAlexey Lapshin } 194f75da0c8SAlexey Lapshin 195f75da0c8SAlexey Lapshin switch (MLC.load_command_data.cmd) { 196f75da0c8SAlexey Lapshin case MachO::LC_SEGMENT: 197f75da0c8SAlexey Lapshin MLC.segment_command_data.cmdsize = 198f75da0c8SAlexey Lapshin sizeof(MachO::segment_command) + 199f75da0c8SAlexey Lapshin sizeof(MachO::section) * LC.Sections.size(); 200f75da0c8SAlexey Lapshin MLC.segment_command_data.nsects = LC.Sections.size(); 201f75da0c8SAlexey Lapshin MLC.segment_command_data.fileoff = SegOffset; 202f75da0c8SAlexey Lapshin MLC.segment_command_data.vmsize = VMSize; 203f75da0c8SAlexey Lapshin MLC.segment_command_data.filesize = SegFileSize; 204f75da0c8SAlexey Lapshin break; 205f75da0c8SAlexey Lapshin case MachO::LC_SEGMENT_64: 206f75da0c8SAlexey Lapshin MLC.segment_command_64_data.cmdsize = 207f75da0c8SAlexey Lapshin sizeof(MachO::segment_command_64) + 208f75da0c8SAlexey Lapshin sizeof(MachO::section_64) * LC.Sections.size(); 209f75da0c8SAlexey Lapshin MLC.segment_command_64_data.nsects = LC.Sections.size(); 210f75da0c8SAlexey Lapshin MLC.segment_command_64_data.fileoff = SegOffset; 211f75da0c8SAlexey Lapshin MLC.segment_command_64_data.vmsize = VMSize; 212f75da0c8SAlexey Lapshin MLC.segment_command_64_data.filesize = SegFileSize; 213f75da0c8SAlexey Lapshin break; 214f75da0c8SAlexey Lapshin } 215f75da0c8SAlexey Lapshin } 216f75da0c8SAlexey Lapshin 217f75da0c8SAlexey Lapshin return Offset; 218f75da0c8SAlexey Lapshin } 219f75da0c8SAlexey Lapshin 220f75da0c8SAlexey Lapshin uint64_t MachOLayoutBuilder::layoutRelocations(uint64_t Offset) { 221f75da0c8SAlexey Lapshin for (LoadCommand &LC : O.LoadCommands) 222f75da0c8SAlexey Lapshin for (std::unique_ptr<Section> &Sec : LC.Sections) { 223f75da0c8SAlexey Lapshin Sec->RelOff = Sec->Relocations.empty() ? 0 : Offset; 224f75da0c8SAlexey Lapshin Sec->NReloc = Sec->Relocations.size(); 225f75da0c8SAlexey Lapshin Offset += sizeof(MachO::any_relocation_info) * Sec->NReloc; 226f75da0c8SAlexey Lapshin } 227f75da0c8SAlexey Lapshin 228f75da0c8SAlexey Lapshin return Offset; 229f75da0c8SAlexey Lapshin } 230f75da0c8SAlexey Lapshin 231f75da0c8SAlexey Lapshin Error MachOLayoutBuilder::layoutTail(uint64_t Offset) { 232f75da0c8SAlexey Lapshin // If we are building the layout of an executable or dynamic library 233f75da0c8SAlexey Lapshin // which does not have any segments other than __LINKEDIT, 234f75da0c8SAlexey Lapshin // the Offset can be equal to zero by this time. It happens because of the 235f75da0c8SAlexey Lapshin // convention that in such cases the file offsets specified by LC_SEGMENT 236f75da0c8SAlexey Lapshin // start with zero (unlike the case of a relocatable object file). 237f75da0c8SAlexey Lapshin const uint64_t HeaderSize = 238f75da0c8SAlexey Lapshin Is64Bit ? sizeof(MachO::mach_header_64) : sizeof(MachO::mach_header); 239f75da0c8SAlexey Lapshin assert((!(O.Header.FileType == MachO::HeaderFileType::MH_OBJECT) || 240f75da0c8SAlexey Lapshin Offset >= HeaderSize + O.Header.SizeOfCmds) && 241f75da0c8SAlexey Lapshin "Incorrect tail offset"); 242f75da0c8SAlexey Lapshin Offset = std::max(Offset, HeaderSize + O.Header.SizeOfCmds); 243f75da0c8SAlexey Lapshin 244652713e2SDaniel Rodríguez Troitiño // The exports trie can be in either LC_DYLD_INFO or in 245652713e2SDaniel Rodríguez Troitiño // LC_DYLD_EXPORTS_TRIE, but not both. 246652713e2SDaniel Rodríguez Troitiño size_t DyldInfoExportsTrieSize = 0; 247652713e2SDaniel Rodríguez Troitiño size_t DyldExportsTrieSize = 0; 248652713e2SDaniel Rodríguez Troitiño for (const auto &LC : O.LoadCommands) { 249652713e2SDaniel Rodríguez Troitiño switch (LC.MachOLoadCommand.load_command_data.cmd) { 250652713e2SDaniel Rodríguez Troitiño case MachO::LC_DYLD_INFO: 251652713e2SDaniel Rodríguez Troitiño case MachO::LC_DYLD_INFO_ONLY: 252652713e2SDaniel Rodríguez Troitiño DyldInfoExportsTrieSize = O.Exports.Trie.size(); 253652713e2SDaniel Rodríguez Troitiño break; 254652713e2SDaniel Rodríguez Troitiño case MachO::LC_DYLD_EXPORTS_TRIE: 255652713e2SDaniel Rodríguez Troitiño DyldExportsTrieSize = O.Exports.Trie.size(); 256652713e2SDaniel Rodríguez Troitiño break; 257652713e2SDaniel Rodríguez Troitiño default: 258652713e2SDaniel Rodríguez Troitiño break; 259652713e2SDaniel Rodríguez Troitiño } 260652713e2SDaniel Rodríguez Troitiño } 261652713e2SDaniel Rodríguez Troitiño assert((DyldInfoExportsTrieSize == 0 || DyldExportsTrieSize == 0) && 262652713e2SDaniel Rodríguez Troitiño "Export trie in both LCs"); 263652713e2SDaniel Rodríguez Troitiño 264f75da0c8SAlexey Lapshin uint64_t NListSize = Is64Bit ? sizeof(MachO::nlist_64) : sizeof(MachO::nlist); 265f75da0c8SAlexey Lapshin uint64_t StartOfLinkEdit = Offset; 266dd2165efSDaniel Rodríguez Troitiño 267dd2165efSDaniel Rodríguez Troitiño // The order of LINKEDIT elements is as follows: 268dd2165efSDaniel Rodríguez Troitiño // rebase info, binding info, weak binding info, lazy binding info, export 269dd2165efSDaniel Rodríguez Troitiño // trie, chained fixups, dyld exports trie, function starts, data-in-code, 270dd2165efSDaniel Rodríguez Troitiño // symbol table, indirect symbol table, symbol table strings, 271dd2165efSDaniel Rodríguez Troitiño // dylib codesign drs, and code signature. 272dd2165efSDaniel Rodríguez Troitiño auto updateOffset = [&Offset](size_t Size) { 273dd2165efSDaniel Rodríguez Troitiño uint64_t PreviousOffset = Offset; 274dd2165efSDaniel Rodríguez Troitiño Offset += Size; 275dd2165efSDaniel Rodríguez Troitiño return PreviousOffset; 276dd2165efSDaniel Rodríguez Troitiño }; 277dd2165efSDaniel Rodríguez Troitiño 278dd2165efSDaniel Rodríguez Troitiño uint64_t StartOfRebaseInfo = updateOffset(O.Rebases.Opcodes.size()); 279dd2165efSDaniel Rodríguez Troitiño uint64_t StartOfBindingInfo = updateOffset(O.Binds.Opcodes.size()); 280dd2165efSDaniel Rodríguez Troitiño uint64_t StartOfWeakBindingInfo = updateOffset(O.WeakBinds.Opcodes.size()); 281dd2165efSDaniel Rodríguez Troitiño uint64_t StartOfLazyBindingInfo = updateOffset(O.LazyBinds.Opcodes.size()); 282652713e2SDaniel Rodríguez Troitiño uint64_t StartOfExportTrie = updateOffset(DyldInfoExportsTrieSize); 283dd2165efSDaniel Rodríguez Troitiño uint64_t StartOfChainedFixups = updateOffset(O.ChainedFixups.Data.size()); 284652713e2SDaniel Rodríguez Troitiño uint64_t StartOfDyldExportsTrie = updateOffset(DyldExportsTrieSize); 285dd2165efSDaniel Rodríguez Troitiño uint64_t StartOfFunctionStarts = updateOffset(O.FunctionStarts.Data.size()); 286dd2165efSDaniel Rodríguez Troitiño uint64_t StartOfDataInCode = updateOffset(O.DataInCode.Data.size()); 287f75da0c8SAlexey Lapshin uint64_t StartOfLinkerOptimizationHint = 288dd2165efSDaniel Rodríguez Troitiño updateOffset(O.LinkerOptimizationHint.Data.size()); 289dd2165efSDaniel Rodríguez Troitiño uint64_t StartOfSymbols = updateOffset(NListSize * O.SymTable.Symbols.size()); 290f75da0c8SAlexey Lapshin uint64_t StartOfIndirectSymbols = 291dd2165efSDaniel Rodríguez Troitiño updateOffset(sizeof(uint32_t) * O.IndirectSymTable.Symbols.size()); 292dd2165efSDaniel Rodríguez Troitiño uint64_t StartOfSymbolStrings = updateOffset(StrTableBuilder.getSize()); 293dd2165efSDaniel Rodríguez Troitiño uint64_t StartOfDylibCodeSignDRs = updateOffset(O.DylibCodeSignDRs.Data.size()); 294dd2165efSDaniel Rodríguez Troitiño 295dd2165efSDaniel Rodríguez Troitiño uint64_t StartOfCodeSignature = Offset; 296f75da0c8SAlexey Lapshin uint32_t CodeSignatureSize = 0; 297f75da0c8SAlexey Lapshin if (O.CodeSignatureCommandIndex) { 298f75da0c8SAlexey Lapshin StartOfCodeSignature = alignTo(StartOfCodeSignature, 16); 299f75da0c8SAlexey Lapshin 300f75da0c8SAlexey Lapshin // Note: These calculations are to be kept in sync with the same 301f75da0c8SAlexey Lapshin // calculations performed in LLD's CodeSignatureSection. 302f75da0c8SAlexey Lapshin const uint32_t AllHeadersSize = 303f75da0c8SAlexey Lapshin alignTo(CodeSignature.FixedHeadersSize + OutputFileName.size() + 1, 304f75da0c8SAlexey Lapshin CodeSignature.Align); 305f75da0c8SAlexey Lapshin const uint32_t BlockCount = 306f75da0c8SAlexey Lapshin (StartOfCodeSignature + CodeSignature.BlockSize - 1) / 307f75da0c8SAlexey Lapshin CodeSignature.BlockSize; 308f75da0c8SAlexey Lapshin const uint32_t Size = 309f75da0c8SAlexey Lapshin alignTo(AllHeadersSize + BlockCount * CodeSignature.HashSize, 310f75da0c8SAlexey Lapshin CodeSignature.Align); 311f75da0c8SAlexey Lapshin 312f75da0c8SAlexey Lapshin CodeSignature.StartOffset = StartOfCodeSignature; 313f75da0c8SAlexey Lapshin CodeSignature.AllHeadersSize = AllHeadersSize; 314f75da0c8SAlexey Lapshin CodeSignature.BlockCount = BlockCount; 315f75da0c8SAlexey Lapshin CodeSignature.OutputFileName = OutputFileName; 316f75da0c8SAlexey Lapshin CodeSignature.Size = Size; 317f75da0c8SAlexey Lapshin CodeSignatureSize = Size; 318f75da0c8SAlexey Lapshin } 319f75da0c8SAlexey Lapshin uint64_t LinkEditSize = 320f75da0c8SAlexey Lapshin StartOfCodeSignature + CodeSignatureSize - StartOfLinkEdit; 321f75da0c8SAlexey Lapshin 322f75da0c8SAlexey Lapshin // Now we have determined the layout of the contents of the __LINKEDIT 323f75da0c8SAlexey Lapshin // segment. Update its load command. 324f75da0c8SAlexey Lapshin if (LinkEditLoadCommand) { 325f75da0c8SAlexey Lapshin MachO::macho_load_command *MLC = LinkEditLoadCommand; 326f75da0c8SAlexey Lapshin switch (LinkEditLoadCommand->load_command_data.cmd) { 327f75da0c8SAlexey Lapshin case MachO::LC_SEGMENT: 328f75da0c8SAlexey Lapshin MLC->segment_command_data.cmdsize = sizeof(MachO::segment_command); 329f75da0c8SAlexey Lapshin MLC->segment_command_data.fileoff = StartOfLinkEdit; 330f75da0c8SAlexey Lapshin MLC->segment_command_data.vmsize = alignTo(LinkEditSize, PageSize); 331f75da0c8SAlexey Lapshin MLC->segment_command_data.filesize = LinkEditSize; 332f75da0c8SAlexey Lapshin break; 333f75da0c8SAlexey Lapshin case MachO::LC_SEGMENT_64: 334f75da0c8SAlexey Lapshin MLC->segment_command_64_data.cmdsize = sizeof(MachO::segment_command_64); 335f75da0c8SAlexey Lapshin MLC->segment_command_64_data.fileoff = StartOfLinkEdit; 336f75da0c8SAlexey Lapshin MLC->segment_command_64_data.vmsize = alignTo(LinkEditSize, PageSize); 337f75da0c8SAlexey Lapshin MLC->segment_command_64_data.filesize = LinkEditSize; 338f75da0c8SAlexey Lapshin break; 339f75da0c8SAlexey Lapshin } 340f75da0c8SAlexey Lapshin } 341f75da0c8SAlexey Lapshin 342f75da0c8SAlexey Lapshin for (LoadCommand &LC : O.LoadCommands) { 343f75da0c8SAlexey Lapshin auto &MLC = LC.MachOLoadCommand; 344f75da0c8SAlexey Lapshin auto cmd = MLC.load_command_data.cmd; 345f75da0c8SAlexey Lapshin switch (cmd) { 346f75da0c8SAlexey Lapshin case MachO::LC_CODE_SIGNATURE: 347f75da0c8SAlexey Lapshin MLC.linkedit_data_command_data.dataoff = StartOfCodeSignature; 348f75da0c8SAlexey Lapshin MLC.linkedit_data_command_data.datasize = CodeSignatureSize; 349f75da0c8SAlexey Lapshin break; 350c2d20947SKeith Smiley case MachO::LC_DYLIB_CODE_SIGN_DRS: 351c2d20947SKeith Smiley MLC.linkedit_data_command_data.dataoff = StartOfDylibCodeSignDRs; 352c2d20947SKeith Smiley MLC.linkedit_data_command_data.datasize = O.DylibCodeSignDRs.Data.size(); 353c2d20947SKeith Smiley break; 354f75da0c8SAlexey Lapshin case MachO::LC_SYMTAB: 355f75da0c8SAlexey Lapshin MLC.symtab_command_data.symoff = StartOfSymbols; 356f75da0c8SAlexey Lapshin MLC.symtab_command_data.nsyms = O.SymTable.Symbols.size(); 357f75da0c8SAlexey Lapshin MLC.symtab_command_data.stroff = StartOfSymbolStrings; 358f75da0c8SAlexey Lapshin MLC.symtab_command_data.strsize = StrTableBuilder.getSize(); 359f75da0c8SAlexey Lapshin break; 360f75da0c8SAlexey Lapshin case MachO::LC_DYSYMTAB: { 361f75da0c8SAlexey Lapshin if (MLC.dysymtab_command_data.ntoc != 0 || 362f75da0c8SAlexey Lapshin MLC.dysymtab_command_data.nmodtab != 0 || 363f75da0c8SAlexey Lapshin MLC.dysymtab_command_data.nextrefsyms != 0 || 364f75da0c8SAlexey Lapshin MLC.dysymtab_command_data.nlocrel != 0 || 365f75da0c8SAlexey Lapshin MLC.dysymtab_command_data.nextrel != 0) 366f75da0c8SAlexey Lapshin return createStringError(llvm::errc::not_supported, 367f75da0c8SAlexey Lapshin "shared library is not yet supported"); 3689c97aa5aSRichard Dzenis MLC.dysymtab_command_data.indirectsymoff = 3699c97aa5aSRichard Dzenis O.IndirectSymTable.Symbols.size() ? StartOfIndirectSymbols : 0; 370f75da0c8SAlexey Lapshin MLC.dysymtab_command_data.nindirectsyms = 371f75da0c8SAlexey Lapshin O.IndirectSymTable.Symbols.size(); 372f75da0c8SAlexey Lapshin updateDySymTab(MLC); 373f75da0c8SAlexey Lapshin break; 374f75da0c8SAlexey Lapshin } 375f75da0c8SAlexey Lapshin case MachO::LC_DATA_IN_CODE: 376f75da0c8SAlexey Lapshin MLC.linkedit_data_command_data.dataoff = StartOfDataInCode; 377f75da0c8SAlexey Lapshin MLC.linkedit_data_command_data.datasize = O.DataInCode.Data.size(); 378f75da0c8SAlexey Lapshin break; 379f75da0c8SAlexey Lapshin case MachO::LC_LINKER_OPTIMIZATION_HINT: 380f75da0c8SAlexey Lapshin MLC.linkedit_data_command_data.dataoff = StartOfLinkerOptimizationHint; 381f75da0c8SAlexey Lapshin MLC.linkedit_data_command_data.datasize = 382f75da0c8SAlexey Lapshin O.LinkerOptimizationHint.Data.size(); 383f75da0c8SAlexey Lapshin break; 384f75da0c8SAlexey Lapshin case MachO::LC_FUNCTION_STARTS: 385f75da0c8SAlexey Lapshin MLC.linkedit_data_command_data.dataoff = StartOfFunctionStarts; 386f75da0c8SAlexey Lapshin MLC.linkedit_data_command_data.datasize = O.FunctionStarts.Data.size(); 387f75da0c8SAlexey Lapshin break; 388f75da0c8SAlexey Lapshin case MachO::LC_DYLD_CHAINED_FIXUPS: 389f75da0c8SAlexey Lapshin MLC.linkedit_data_command_data.dataoff = StartOfChainedFixups; 390f75da0c8SAlexey Lapshin MLC.linkedit_data_command_data.datasize = O.ChainedFixups.Data.size(); 391f75da0c8SAlexey Lapshin break; 392f75da0c8SAlexey Lapshin case MachO::LC_DYLD_EXPORTS_TRIE: 393f75da0c8SAlexey Lapshin MLC.linkedit_data_command_data.dataoff = StartOfDyldExportsTrie; 394652713e2SDaniel Rodríguez Troitiño MLC.linkedit_data_command_data.datasize = DyldExportsTrieSize; 395f75da0c8SAlexey Lapshin break; 396f75da0c8SAlexey Lapshin case MachO::LC_DYLD_INFO: 397f75da0c8SAlexey Lapshin case MachO::LC_DYLD_INFO_ONLY: 398f75da0c8SAlexey Lapshin MLC.dyld_info_command_data.rebase_off = 399f75da0c8SAlexey Lapshin O.Rebases.Opcodes.empty() ? 0 : StartOfRebaseInfo; 400f75da0c8SAlexey Lapshin MLC.dyld_info_command_data.rebase_size = O.Rebases.Opcodes.size(); 401f75da0c8SAlexey Lapshin MLC.dyld_info_command_data.bind_off = 402f75da0c8SAlexey Lapshin O.Binds.Opcodes.empty() ? 0 : StartOfBindingInfo; 403f75da0c8SAlexey Lapshin MLC.dyld_info_command_data.bind_size = O.Binds.Opcodes.size(); 404f75da0c8SAlexey Lapshin MLC.dyld_info_command_data.weak_bind_off = 405f75da0c8SAlexey Lapshin O.WeakBinds.Opcodes.empty() ? 0 : StartOfWeakBindingInfo; 406f75da0c8SAlexey Lapshin MLC.dyld_info_command_data.weak_bind_size = O.WeakBinds.Opcodes.size(); 407f75da0c8SAlexey Lapshin MLC.dyld_info_command_data.lazy_bind_off = 408f75da0c8SAlexey Lapshin O.LazyBinds.Opcodes.empty() ? 0 : StartOfLazyBindingInfo; 409f75da0c8SAlexey Lapshin MLC.dyld_info_command_data.lazy_bind_size = O.LazyBinds.Opcodes.size(); 410f75da0c8SAlexey Lapshin MLC.dyld_info_command_data.export_off = 411f75da0c8SAlexey Lapshin O.Exports.Trie.empty() ? 0 : StartOfExportTrie; 412652713e2SDaniel Rodríguez Troitiño MLC.dyld_info_command_data.export_size = DyldInfoExportsTrieSize; 413f75da0c8SAlexey Lapshin break; 414f75da0c8SAlexey Lapshin // Note that LC_ENCRYPTION_INFO.cryptoff despite its name and the comment in 415f75da0c8SAlexey Lapshin // <mach-o/loader.h> is not an offset in the binary file, instead, it is a 416f75da0c8SAlexey Lapshin // relative virtual address. At the moment modification of the __TEXT 417f75da0c8SAlexey Lapshin // segment of executables isn't supported anyway (e.g. data in code entries 418f75da0c8SAlexey Lapshin // are not recalculated). Moreover, in general 419f75da0c8SAlexey Lapshin // LC_ENCRYPT_INFO/LC_ENCRYPTION_INFO_64 are nontrivial to update because 420f75da0c8SAlexey Lapshin // without making additional assumptions (e.g. that the entire __TEXT 421f75da0c8SAlexey Lapshin // segment should be encrypted) we do not know how to recalculate the 422f75da0c8SAlexey Lapshin // boundaries of the encrypted part. For now just copy over these load 423f75da0c8SAlexey Lapshin // commands until we encounter a real world usecase where 424f75da0c8SAlexey Lapshin // LC_ENCRYPT_INFO/LC_ENCRYPTION_INFO_64 need to be adjusted. 425f75da0c8SAlexey Lapshin case MachO::LC_ENCRYPTION_INFO: 426f75da0c8SAlexey Lapshin case MachO::LC_ENCRYPTION_INFO_64: 427f75da0c8SAlexey Lapshin case MachO::LC_LOAD_DYLINKER: 428f75da0c8SAlexey Lapshin case MachO::LC_MAIN: 429f75da0c8SAlexey Lapshin case MachO::LC_RPATH: 430f75da0c8SAlexey Lapshin case MachO::LC_SEGMENT: 431f75da0c8SAlexey Lapshin case MachO::LC_SEGMENT_64: 432f75da0c8SAlexey Lapshin case MachO::LC_VERSION_MIN_MACOSX: 433f75da0c8SAlexey Lapshin case MachO::LC_VERSION_MIN_IPHONEOS: 434f75da0c8SAlexey Lapshin case MachO::LC_VERSION_MIN_TVOS: 435f75da0c8SAlexey Lapshin case MachO::LC_VERSION_MIN_WATCHOS: 436f75da0c8SAlexey Lapshin case MachO::LC_BUILD_VERSION: 437f75da0c8SAlexey Lapshin case MachO::LC_ID_DYLIB: 438f75da0c8SAlexey Lapshin case MachO::LC_LOAD_DYLIB: 439f75da0c8SAlexey Lapshin case MachO::LC_LOAD_WEAK_DYLIB: 440f75da0c8SAlexey Lapshin case MachO::LC_UUID: 441f75da0c8SAlexey Lapshin case MachO::LC_SOURCE_VERSION: 442f75da0c8SAlexey Lapshin case MachO::LC_THREAD: 443f75da0c8SAlexey Lapshin case MachO::LC_UNIXTHREAD: 444f75da0c8SAlexey Lapshin case MachO::LC_SUB_FRAMEWORK: 445f75da0c8SAlexey Lapshin case MachO::LC_SUB_UMBRELLA: 446f75da0c8SAlexey Lapshin case MachO::LC_SUB_CLIENT: 447f75da0c8SAlexey Lapshin case MachO::LC_SUB_LIBRARY: 448f75da0c8SAlexey Lapshin case MachO::LC_LINKER_OPTION: 449f75da0c8SAlexey Lapshin // Nothing to update. 450f75da0c8SAlexey Lapshin break; 451f75da0c8SAlexey Lapshin default: 452f75da0c8SAlexey Lapshin // Abort if it's unsupported in order to prevent corrupting the object. 453f75da0c8SAlexey Lapshin return createStringError(llvm::errc::not_supported, 454f75da0c8SAlexey Lapshin "unsupported load command (cmd=0x%x)", cmd); 455f75da0c8SAlexey Lapshin } 456f75da0c8SAlexey Lapshin } 457f75da0c8SAlexey Lapshin 458f75da0c8SAlexey Lapshin return Error::success(); 459f75da0c8SAlexey Lapshin } 460f75da0c8SAlexey Lapshin 461f75da0c8SAlexey Lapshin Error MachOLayoutBuilder::layout() { 462f75da0c8SAlexey Lapshin O.Header.NCmds = O.LoadCommands.size(); 463f75da0c8SAlexey Lapshin O.Header.SizeOfCmds = computeSizeOfCmds(); 464f75da0c8SAlexey Lapshin constructStringTable(); 465f75da0c8SAlexey Lapshin updateSymbolIndexes(); 466f75da0c8SAlexey Lapshin uint64_t Offset = layoutSegments(); 467f75da0c8SAlexey Lapshin Offset = layoutRelocations(Offset); 468f75da0c8SAlexey Lapshin return layoutTail(Offset); 469f75da0c8SAlexey Lapshin } 470