LLVM 23.0.0git
MachOLayoutBuilder.cpp
Go to the documentation of this file.
1//===- MachOLayoutBuilder.cpp -----------------------------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
10#include "llvm/Support/Errc.h"
13
14using namespace llvm;
15using namespace llvm::objcopy::macho;
16
18MachOLayoutBuilder::getStringTableBuilderKind(const Object &O, bool Is64Bit) {
19 if (O.Header.FileType == MachO::HeaderFileType::MH_OBJECT)
23}
24
25uint32_t MachOLayoutBuilder::computeSizeOfCmds() const {
26 uint32_t Size = 0;
27 for (const LoadCommand &LC : O.LoadCommands) {
28 const MachO::macho_load_command &MLC = LC.MachOLoadCommand;
29 auto cmd = MLC.load_command_data.cmd;
30 switch (cmd) {
31 case MachO::LC_SEGMENT:
32 Size += sizeof(MachO::segment_command) +
33 sizeof(MachO::section) * LC.Sections.size();
34 continue;
35 case MachO::LC_SEGMENT_64:
36 Size += sizeof(MachO::segment_command_64) +
37 sizeof(MachO::section_64) * LC.Sections.size();
38 continue;
39 }
40
41 switch (cmd) {
42#define HANDLE_LOAD_COMMAND(LCName, LCValue, LCStruct) \
43 case MachO::LCName: \
44 Size += sizeof(MachO::LCStruct) + LC.Payload.size(); \
45 break;
46#include "llvm/BinaryFormat/MachO.def"
47#undef HANDLE_LOAD_COMMAND
48 }
49 }
50
51 return Size;
52}
53
54void MachOLayoutBuilder::constructStringTable() {
55 for (std::unique_ptr<SymbolEntry> &Sym : O.SymTable.Symbols)
56 StrTableBuilder.add(Sym->Name);
57 StrTableBuilder.finalize();
58}
59
60void MachOLayoutBuilder::updateSymbolIndexes() {
61 uint32_t Index = 0;
62 for (auto &Symbol : O.SymTable.Symbols)
63 Symbol->Index = Index++;
64}
65
66// Updates the index and the number of local/external/undefined symbols.
67void MachOLayoutBuilder::updateDySymTab(MachO::macho_load_command &MLC) {
68 assert(MLC.load_command_data.cmd == MachO::LC_DYSYMTAB);
69 // Make sure that nlist entries in the symbol table are sorted by the those
70 // types. The order is: local < defined external < undefined external.
71 assert(llvm::is_sorted(O.SymTable.Symbols,
72 [](const std::unique_ptr<SymbolEntry> &A,
73 const std::unique_ptr<SymbolEntry> &B) {
74 bool AL = A->isLocalSymbol(),
75 BL = B->isLocalSymbol();
76 if (AL != BL)
77 return AL;
78 return !AL && !A->isUndefinedSymbol() &&
79 B->isUndefinedSymbol();
80 }) &&
81 "Symbols are not sorted by their types.");
82
83 uint32_t NumLocalSymbols = 0;
84 auto Iter = O.SymTable.Symbols.begin();
85 auto End = O.SymTable.Symbols.end();
86 for (; Iter != End; ++Iter) {
87 if ((*Iter)->isExternalSymbol())
88 break;
89
90 ++NumLocalSymbols;
91 }
92
93 uint32_t NumExtDefSymbols = 0;
94 for (; Iter != End; ++Iter) {
95 if ((*Iter)->isUndefinedSymbol())
96 break;
97
98 ++NumExtDefSymbols;
99 }
100
101 MLC.dysymtab_command_data.ilocalsym = 0;
102 MLC.dysymtab_command_data.nlocalsym = NumLocalSymbols;
103 MLC.dysymtab_command_data.iextdefsym = NumLocalSymbols;
104 MLC.dysymtab_command_data.nextdefsym = NumExtDefSymbols;
105 MLC.dysymtab_command_data.iundefsym = NumLocalSymbols + NumExtDefSymbols;
106 MLC.dysymtab_command_data.nundefsym =
107 O.SymTable.Symbols.size() - (NumLocalSymbols + NumExtDefSymbols);
108}
109
110// Recomputes and updates offset and size fields in load commands and sections
111// since they could be modified.
112uint64_t MachOLayoutBuilder::layoutSegments() {
113 auto HeaderSize =
114 Is64Bit ? sizeof(MachO::mach_header_64) : sizeof(MachO::mach_header);
115 const bool IsObjectFile =
116 O.Header.FileType == MachO::HeaderFileType::MH_OBJECT;
117 uint64_t Offset = IsObjectFile ? (HeaderSize + O.Header.SizeOfCmds) : 0;
118 for (LoadCommand &LC : O.LoadCommands) {
119 auto &MLC = LC.MachOLoadCommand;
120 StringRef Segname;
121 uint64_t SegmentVmAddr;
122 uint64_t SegmentVmSize;
123 switch (MLC.load_command_data.cmd) {
124 case MachO::LC_SEGMENT:
125 SegmentVmAddr = MLC.segment_command_data.vmaddr;
126 SegmentVmSize = MLC.segment_command_data.vmsize;
127 Segname = StringRef(MLC.segment_command_data.segname,
128 strnlen(MLC.segment_command_data.segname,
129 sizeof(MLC.segment_command_data.segname)));
130 break;
131 case MachO::LC_SEGMENT_64:
132 SegmentVmAddr = MLC.segment_command_64_data.vmaddr;
133 SegmentVmSize = MLC.segment_command_64_data.vmsize;
134 Segname = StringRef(MLC.segment_command_64_data.segname,
135 strnlen(MLC.segment_command_64_data.segname,
136 sizeof(MLC.segment_command_64_data.segname)));
137 break;
138 default:
139 continue;
140 }
141
142 if (Segname == "__LINKEDIT") {
143 // We update the __LINKEDIT segment later (in layoutTail).
144 assert(LC.Sections.empty() && "__LINKEDIT segment has sections");
145 LinkEditLoadCommand = &MLC;
146 continue;
147 }
148
149 // Update file offsets and sizes of sections.
150 uint64_t SegOffset = Offset;
151 uint64_t SegFileSize = 0;
152 uint64_t VMSize = 0;
153 for (std::unique_ptr<Section> &Sec : LC.Sections) {
154 assert(SegmentVmAddr <= Sec->Addr &&
155 "Section's address cannot be smaller than Segment's one");
156 uint32_t SectOffset = Sec->Addr - SegmentVmAddr;
157 if (IsObjectFile) {
158 if (!Sec->hasValidOffset()) {
159 Sec->Offset = 0;
160 } else {
161 uint64_t PaddingSize =
162 offsetToAlignment(SegFileSize, Align(1ull << Sec->Align));
163 Sec->Offset = SegOffset + SegFileSize + PaddingSize;
164 Sec->Size = Sec->Content.size();
165 SegFileSize += PaddingSize + Sec->Size;
166 }
167 } else {
168 if (!Sec->hasValidOffset()) {
169 Sec->Offset = 0;
170 } else {
171 Sec->Offset = SegOffset + SectOffset;
172 Sec->Size = Sec->Content.size();
173 SegFileSize = std::max(SegFileSize, SectOffset + Sec->Size);
174 }
175 }
176 VMSize = std::max(VMSize, SectOffset + Sec->Size);
177 }
178
179 if (IsObjectFile) {
180 Offset += SegFileSize;
181 } else {
182 Offset = alignToPowerOf2(Offset + SegFileSize, PageSize);
183 SegFileSize = alignToPowerOf2(SegFileSize, PageSize);
184 // Use the original vmsize if the segment is __PAGEZERO.
185 VMSize = Segname == "__PAGEZERO" ? SegmentVmSize
186 : alignToPowerOf2(VMSize, PageSize);
187 }
188
189 switch (MLC.load_command_data.cmd) {
190 case MachO::LC_SEGMENT:
191 MLC.segment_command_data.cmdsize =
192 sizeof(MachO::segment_command) +
193 sizeof(MachO::section) * LC.Sections.size();
194 MLC.segment_command_data.nsects = LC.Sections.size();
195 MLC.segment_command_data.fileoff = SegOffset;
196 MLC.segment_command_data.vmsize = VMSize;
197 MLC.segment_command_data.filesize = SegFileSize;
198 break;
199 case MachO::LC_SEGMENT_64:
200 MLC.segment_command_64_data.cmdsize =
201 sizeof(MachO::segment_command_64) +
202 sizeof(MachO::section_64) * LC.Sections.size();
203 MLC.segment_command_64_data.nsects = LC.Sections.size();
204 MLC.segment_command_64_data.fileoff = SegOffset;
205 MLC.segment_command_64_data.vmsize = VMSize;
206 MLC.segment_command_64_data.filesize = SegFileSize;
207 break;
208 }
209 }
210
211 return Offset;
212}
213
214uint64_t MachOLayoutBuilder::layoutRelocations(uint64_t Offset) {
215 for (LoadCommand &LC : O.LoadCommands)
216 for (std::unique_ptr<Section> &Sec : LC.Sections) {
217 Sec->RelOff = Sec->Relocations.empty() ? 0 : Offset;
218 Sec->NReloc = Sec->Relocations.size();
219 Offset += sizeof(MachO::any_relocation_info) * Sec->NReloc;
220 }
221
222 return Offset;
223}
224
225Error MachOLayoutBuilder::layoutTail(uint64_t Offset) {
226 // If we are building the layout of an executable or dynamic library
227 // which does not have any segments other than __LINKEDIT,
228 // the Offset can be equal to zero by this time. It happens because of the
229 // convention that in such cases the file offsets specified by LC_SEGMENT
230 // start with zero (unlike the case of a relocatable object file).
231 const uint64_t HeaderSize =
232 Is64Bit ? sizeof(MachO::mach_header_64) : sizeof(MachO::mach_header);
233 assert((!(O.Header.FileType == MachO::HeaderFileType::MH_OBJECT) ||
234 Offset >= HeaderSize + O.Header.SizeOfCmds) &&
235 "Incorrect tail offset");
236 Offset = std::max(Offset, HeaderSize + O.Header.SizeOfCmds);
237
238 const uint64_t LinkEditAlign = Is64Bit ? 8 : 4;
239 Offset = alignToPowerOf2(Offset, LinkEditAlign);
240
241 // The exports trie can be in either LC_DYLD_INFO or in
242 // LC_DYLD_EXPORTS_TRIE, but not both.
243 uint64_t DyldInfoExportsTrieRawSize = 0;
244 uint64_t DyldExportsTrieRawSize = 0;
245 for (const auto &LC : O.LoadCommands) {
246 switch (LC.MachOLoadCommand.load_command_data.cmd) {
247 case MachO::LC_DYLD_INFO:
248 case MachO::LC_DYLD_INFO_ONLY:
249 DyldInfoExportsTrieRawSize = O.Exports.Trie.size();
250 break;
251 case MachO::LC_DYLD_EXPORTS_TRIE:
252 DyldExportsTrieRawSize = O.Exports.Trie.size();
253 break;
254 default:
255 break;
256 }
257 }
258 assert((DyldInfoExportsTrieRawSize == 0 || DyldExportsTrieRawSize == 0) &&
259 "Export trie in both LCs");
260
261 uint64_t NListSize = Is64Bit ? sizeof(MachO::nlist_64) : sizeof(MachO::nlist);
262 uint64_t StartOfLinkEdit = Offset;
263
264 // The order of LINKEDIT elements is as follows:
265 // rebase info, binding info, weak binding info, lazy binding info, export
266 // trie, chained fixups, dyld exports trie, function starts, data-in-code,
267 // symbol table, indirect symbol table, symbol table strings,
268 // dylib codesign drs, and code signature.
269 auto updateOffset = [&Offset, LinkEditAlign](uint64_t Size) {
270 uint64_t PreviousOffset = Offset;
271 // Match ld64 and lld-macho behavior by aligning all LINKEDIT entries to
272 // pointer size. This is safe because zero padding is valid for all entries.
273 uint64_t PaddedSize = alignToPowerOf2(Size, LinkEditAlign);
274 Offset += PaddedSize;
275 return std::make_pair(PreviousOffset, PaddedSize);
276 };
277
278 auto [StartOfRebaseInfo, RebaseInfoSize] =
279 updateOffset(O.Rebases.Opcodes.size());
280 auto [StartOfBindingInfo, BindingInfoSize] =
281 updateOffset(O.Binds.Opcodes.size());
282 auto [StartOfWeakBindingInfo, WeakBindingInfoSize] =
283 updateOffset(O.WeakBinds.Opcodes.size());
284 auto [StartOfLazyBindingInfo, LazyBindingInfoSize] =
285 updateOffset(O.LazyBinds.Opcodes.size());
286 auto [StartOfExportTrie, ExportTrieSize] =
287 updateOffset(DyldInfoExportsTrieRawSize);
288 auto [StartOfChainedFixups, ChainedFixupsSize] =
289 updateOffset(O.ChainedFixups.Data.size());
290 auto [StartOfDyldExportsTrie, DyldExportsTrieSize] =
291 updateOffset(DyldExportsTrieRawSize);
292 auto [StartOfFunctionStarts, FunctionStartsSize] =
293 updateOffset(O.FunctionStarts.Data.size());
294 auto [StartOfDataInCode, DataInCodeSize] =
295 updateOffset(O.DataInCode.Data.size());
296 auto [StartOfLinkerOptimizationHint, LinkerOptimizationHintSize] =
297 updateOffset(O.LinkerOptimizationHint.Data.size());
298 uint64_t StartOfSymbols =
299 updateOffset(NListSize * O.SymTable.Symbols.size()).first;
300 uint64_t StartOfIndirectSymbols =
301 updateOffset(sizeof(uint32_t) * O.IndirectSymTable.Symbols.size()).first;
302 auto [StartOfSymbolStrings, SymbolStringsSize] =
303 updateOffset(StrTableBuilder.getSize());
304 auto [StartOfDylibCodeSignDRs, DylibCodeSignDRsSize] =
305 updateOffset(O.DylibCodeSignDRs.Data.size());
306
307 uint64_t StartOfCodeSignature = Offset;
308 uint32_t CodeSignatureSize = 0;
309 if (O.CodeSignatureCommandIndex) {
310 StartOfCodeSignature = alignToPowerOf2(StartOfCodeSignature, 16);
311
312 // Note: These calculations are to be kept in sync with the same
313 // calculations performed in LLD's CodeSignatureSection.
314 const uint32_t AllHeadersSize = alignToPowerOf2(
315 CodeSignature.FixedHeadersSize + OutputFileName.size() + 1,
316 CodeSignature.Align);
317 const uint32_t BlockCount =
318 (StartOfCodeSignature + CodeSignature.BlockSize - 1) /
319 CodeSignature.BlockSize;
320 const uint32_t Size =
321 alignToPowerOf2(AllHeadersSize + BlockCount * CodeSignature.HashSize,
322 CodeSignature.Align);
323
324 CodeSignature.StartOffset = StartOfCodeSignature;
325 CodeSignature.AllHeadersSize = AllHeadersSize;
326 CodeSignature.BlockCount = BlockCount;
327 CodeSignature.OutputFileName = OutputFileName;
328 CodeSignature.Size = Size;
329 CodeSignatureSize = Size;
330 }
331 uint64_t LinkEditSize =
332 StartOfCodeSignature + CodeSignatureSize - StartOfLinkEdit;
333
334 // Now we have determined the layout of the contents of the __LINKEDIT
335 // segment. Update its load command.
336 if (LinkEditLoadCommand) {
337 MachO::macho_load_command *MLC = LinkEditLoadCommand;
338 switch (LinkEditLoadCommand->load_command_data.cmd) {
339 case MachO::LC_SEGMENT:
340 MLC->segment_command_data.cmdsize = sizeof(MachO::segment_command);
341 MLC->segment_command_data.fileoff = StartOfLinkEdit;
342 MLC->segment_command_data.vmsize =
343 alignToPowerOf2(LinkEditSize, PageSize);
344 MLC->segment_command_data.filesize = LinkEditSize;
345 break;
346 case MachO::LC_SEGMENT_64:
347 MLC->segment_command_64_data.cmdsize = sizeof(MachO::segment_command_64);
348 MLC->segment_command_64_data.fileoff = StartOfLinkEdit;
349 MLC->segment_command_64_data.vmsize =
350 alignToPowerOf2(LinkEditSize, PageSize);
351 MLC->segment_command_64_data.filesize = LinkEditSize;
352 break;
353 }
354 }
355
356 for (LoadCommand &LC : O.LoadCommands) {
357 auto &MLC = LC.MachOLoadCommand;
358 auto cmd = MLC.load_command_data.cmd;
359 switch (cmd) {
360 case MachO::LC_CODE_SIGNATURE:
361 MLC.linkedit_data_command_data.dataoff = StartOfCodeSignature;
362 MLC.linkedit_data_command_data.datasize = CodeSignatureSize;
363 break;
364 case MachO::LC_DYLIB_CODE_SIGN_DRS:
365 MLC.linkedit_data_command_data.dataoff = StartOfDylibCodeSignDRs;
366 MLC.linkedit_data_command_data.datasize = DylibCodeSignDRsSize;
367 break;
368 case MachO::LC_SYMTAB:
369 MLC.symtab_command_data.symoff = StartOfSymbols;
370 MLC.symtab_command_data.nsyms = O.SymTable.Symbols.size();
371 MLC.symtab_command_data.stroff = StartOfSymbolStrings;
372 MLC.symtab_command_data.strsize = SymbolStringsSize;
373 break;
374 case MachO::LC_DYSYMTAB: {
375 if (MLC.dysymtab_command_data.ntoc != 0 ||
376 MLC.dysymtab_command_data.nmodtab != 0 ||
377 MLC.dysymtab_command_data.nextrefsyms != 0 ||
378 MLC.dysymtab_command_data.nlocrel != 0 ||
379 MLC.dysymtab_command_data.nextrel != 0)
381 "shared library is not yet supported");
382 MLC.dysymtab_command_data.indirectsymoff =
383 O.IndirectSymTable.Symbols.size() ? StartOfIndirectSymbols : 0;
384 MLC.dysymtab_command_data.nindirectsyms =
385 O.IndirectSymTable.Symbols.size();
386 updateDySymTab(MLC);
387 break;
388 }
389 case MachO::LC_DATA_IN_CODE:
390 MLC.linkedit_data_command_data.dataoff = StartOfDataInCode;
391 MLC.linkedit_data_command_data.datasize = DataInCodeSize;
392 break;
393 case MachO::LC_LINKER_OPTIMIZATION_HINT:
394 MLC.linkedit_data_command_data.dataoff = StartOfLinkerOptimizationHint;
395 MLC.linkedit_data_command_data.datasize = LinkerOptimizationHintSize;
396 break;
397 case MachO::LC_FUNCTION_STARTS:
398 MLC.linkedit_data_command_data.dataoff = StartOfFunctionStarts;
399 MLC.linkedit_data_command_data.datasize = FunctionStartsSize;
400 break;
401 case MachO::LC_DYLD_CHAINED_FIXUPS:
402 MLC.linkedit_data_command_data.dataoff = StartOfChainedFixups;
403 MLC.linkedit_data_command_data.datasize = ChainedFixupsSize;
404 break;
405 case MachO::LC_DYLD_EXPORTS_TRIE:
406 MLC.linkedit_data_command_data.dataoff = StartOfDyldExportsTrie;
407 MLC.linkedit_data_command_data.datasize = DyldExportsTrieSize;
408 break;
409 case MachO::LC_DYLD_INFO:
410 case MachO::LC_DYLD_INFO_ONLY:
411 MLC.dyld_info_command_data.rebase_off =
412 O.Rebases.Opcodes.empty() ? 0 : StartOfRebaseInfo;
413 MLC.dyld_info_command_data.rebase_size = RebaseInfoSize;
414 MLC.dyld_info_command_data.bind_off =
415 O.Binds.Opcodes.empty() ? 0 : StartOfBindingInfo;
416 MLC.dyld_info_command_data.bind_size = BindingInfoSize;
417 MLC.dyld_info_command_data.weak_bind_off =
418 O.WeakBinds.Opcodes.empty() ? 0 : StartOfWeakBindingInfo;
419 MLC.dyld_info_command_data.weak_bind_size = WeakBindingInfoSize;
420 MLC.dyld_info_command_data.lazy_bind_off =
421 O.LazyBinds.Opcodes.empty() ? 0 : StartOfLazyBindingInfo;
422 MLC.dyld_info_command_data.lazy_bind_size = LazyBindingInfoSize;
423 MLC.dyld_info_command_data.export_off =
424 O.Exports.Trie.empty() ? 0 : StartOfExportTrie;
425 MLC.dyld_info_command_data.export_size = ExportTrieSize;
426 break;
427 // Note that LC_ENCRYPTION_INFO.cryptoff despite its name and the comment in
428 // <mach-o/loader.h> is not an offset in the binary file, instead, it is a
429 // relative virtual address. At the moment modification of the __TEXT
430 // segment of executables isn't supported anyway (e.g. data in code entries
431 // are not recalculated). Moreover, in general
432 // LC_ENCRYPT_INFO/LC_ENCRYPTION_INFO_64 are nontrivial to update because
433 // without making additional assumptions (e.g. that the entire __TEXT
434 // segment should be encrypted) we do not know how to recalculate the
435 // boundaries of the encrypted part. For now just copy over these load
436 // commands until we encounter a real world usecase where
437 // LC_ENCRYPT_INFO/LC_ENCRYPTION_INFO_64 need to be adjusted.
438 case MachO::LC_ENCRYPTION_INFO:
439 case MachO::LC_ENCRYPTION_INFO_64:
440 case MachO::LC_LOAD_DYLINKER:
441 case MachO::LC_MAIN:
442 case MachO::LC_RPATH:
443 case MachO::LC_SEGMENT:
444 case MachO::LC_SEGMENT_64:
445 case MachO::LC_VERSION_MIN_MACOSX:
446 case MachO::LC_VERSION_MIN_IPHONEOS:
447 case MachO::LC_VERSION_MIN_TVOS:
448 case MachO::LC_VERSION_MIN_WATCHOS:
449 case MachO::LC_BUILD_VERSION:
450 case MachO::LC_ID_DYLIB:
451 case MachO::LC_LOAD_DYLIB:
452 case MachO::LC_LOAD_WEAK_DYLIB:
453 case MachO::LC_UUID:
454 case MachO::LC_SOURCE_VERSION:
455 case MachO::LC_THREAD:
456 case MachO::LC_UNIXTHREAD:
457 case MachO::LC_SUB_FRAMEWORK:
458 case MachO::LC_SUB_UMBRELLA:
459 case MachO::LC_SUB_CLIENT:
460 case MachO::LC_SUB_LIBRARY:
461 case MachO::LC_LINKER_OPTION:
462 // Nothing to update.
463 break;
464 default:
465 // Abort if it's unsupported in order to prevent corrupting the object.
467 "unsupported load command (cmd=0x%x)", cmd);
468 }
469 }
470
471 return Error::success();
472}
473
475 O.Header.NCmds = O.LoadCommands.size();
476 O.Header.SizeOfCmds = computeSizeOfCmds();
477 constructStringTable();
478 updateSymbolIndexes();
479 uint64_t Offset = layoutSegments();
480 Offset = layoutRelocations(Offset);
481 return layoutTail(Offset);
482}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static cl::opt< int > PageSize("imp-null-check-page-size", cl::desc("The page size of the target in bytes"), cl::init(4096), cl::Hidden)
if(PassOpts->AAPipeline)
Lightweight error class with error context and mandatory checking.
Definition Error.h:159
static ErrorSuccess success()
Create a success value.
Definition Error.h:336
@ HeaderSize
Definition BTF.h:61
@ MH_OBJECT
Definition MachO.h:43
This is an optimization pass for GlobalISel generic memory operations.
@ Offset
Definition DWP.cpp:558
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
Definition Error.h:1321
@ not_supported
Definition Errc.h:69
constexpr T alignToPowerOf2(U Value, V Align)
Will overflow only if result is not representable in T.
Definition MathExtras.h:493
bool is_sorted(R &&Range, Compare C)
Wrapper function around std::is_sorted to check if elements in a range R are sorted with respect to a...
Definition STLExtras.h:1969
MachO::macho_load_command MachOLoadCommand
Definition MachOObject.h:82
std::vector< std::unique_ptr< Section > > Sections
Definition MachOObject.h:93