xref: /llvm-project/llvm/lib/ObjCopy/MachO/MachOLayoutBuilder.cpp (revision 1a830aa1fe1e88749b563fefe18382842e0cff90)
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