1const std = @import("std");
2const builtin = @import("builtin");
3const assert = std.debug.assert;
4const mem = std.mem;
5const meta = std.meta;
6const testing = std.testing;
7
8const Allocator = mem.Allocator;
9
10pub const cpu_type_t = c_int;
11pub const cpu_subtype_t = c_int;
12pub const vm_prot_t = packed struct(u32) {
13 READ: bool = false,
14 WRITE: bool = false,
15 EXEC: bool = false,
16 _: u1 = 0,
17 /// When a caller finds that they cannot obtain write permission on a
18 /// mapped entry, the following flag can be used. The entry will be
19 /// made "needs copy" effectively copying the object (using COW),
20 /// and write permission will be added to the maximum protections for
21 /// the associated entry.
22 COPY: bool = false,
23 __: u27 = 0,
24};
25
26pub const mach_header = extern struct {
27 magic: u32,
28 cputype: cpu_type_t,
29 cpusubtype: cpu_subtype_t,
30 filetype: u32,
31 ncmds: u32,
32 sizeofcmds: u32,
33 flags: u32,
34};
35
36pub const mach_header_64 = extern struct {
37 magic: u32 = MH_MAGIC_64,
38 cputype: cpu_type_t = 0,
39 cpusubtype: cpu_subtype_t = 0,
40 filetype: u32 = 0,
41 ncmds: u32 = 0,
42 sizeofcmds: u32 = 0,
43 flags: u32 = 0,
44 reserved: u32 = 0,
45};
46
47pub const fat_header = extern struct {
48 magic: u32,
49 nfat_arch: u32,
50};
51
52pub const fat_arch = extern struct {
53 cputype: cpu_type_t,
54 cpusubtype: cpu_subtype_t,
55 offset: u32,
56 size: u32,
57 @"align": u32,
58};
59
60pub const load_command = extern struct {
61 cmd: LC,
62 cmdsize: u32,
63};
64
65/// The uuid load command contains a single 128-bit unique random number that
66/// identifies an object produced by the static link editor.
67pub const uuid_command = extern struct {
68 /// LC_UUID
69 cmd: LC = .UUID,
70
71 /// sizeof(struct uuid_command)
72 cmdsize: u32 = @sizeOf(uuid_command),
73
74 /// the 128-bit uuid
75 uuid: [16]u8 = undefined,
76};
77
78/// The version_min_command contains the min OS version on which this
79/// binary was built to run.
80pub const version_min_command = extern struct {
81 /// LC_VERSION_MIN_MACOSX or LC_VERSION_MIN_IPHONEOS or LC_VERSION_MIN_WATCHOS or LC_VERSION_MIN_TVOS
82 cmd: LC,
83
84 /// sizeof(struct version_min_command)
85 cmdsize: u32 = @sizeOf(version_min_command),
86
87 /// X.Y.Z is encoded in nibbles xxxx.yy.zz
88 version: u32,
89
90 /// X.Y.Z is encoded in nibbles xxxx.yy.zz
91 sdk: u32,
92};
93
94/// The source_version_command is an optional load command containing
95/// the version of the sources used to build the binary.
96pub const source_version_command = extern struct {
97 /// LC_SOURCE_VERSION
98 cmd: LC = .SOURCE_VERSION,
99
100 /// sizeof(source_version_command)
101 cmdsize: u32 = @sizeOf(source_version_command),
102
103 /// A.B.C.D.E packed as a24.b10.c10.d10.e10
104 version: u64,
105};
106
107/// The build_version_command contains the min OS version on which this
108/// binary was built to run for its platform. The list of known platforms and
109/// tool values following it.
110pub const build_version_command = extern struct {
111 /// LC_BUILD_VERSION
112 cmd: LC = .BUILD_VERSION,
113
114 /// sizeof(struct build_version_command) plus
115 /// ntools * sizeof(struct build_version_command)
116 cmdsize: u32,
117
118 /// platform
119 platform: PLATFORM,
120
121 /// X.Y.Z is encoded in nibbles xxxx.yy.zz
122 minos: u32,
123
124 /// X.Y.Z is encoded in nibbles xxxx.yy.zz
125 sdk: u32,
126
127 /// number of tool entries following this
128 ntools: u32,
129};
130
131pub const build_tool_version = extern struct {
132 /// enum for the tool
133 tool: TOOL,
134
135 /// version number of the tool
136 version: u32,
137};
138
139pub const PLATFORM = enum(u32) {
140 UNKNOWN = 0,
141 ANY = 0xffffffff,
142 MACOS = 1,
143 IOS = 2,
144 TVOS = 3,
145 WATCHOS = 4,
146 BRIDGEOS = 5,
147 MACCATALYST = 6,
148 IOSSIMULATOR = 7,
149 TVOSSIMULATOR = 8,
150 WATCHOSSIMULATOR = 9,
151 DRIVERKIT = 10,
152 VISIONOS = 11,
153 VISIONOSSIMULATOR = 12,
154 _,
155};
156
157pub const TOOL = enum(u32) {
158 CLANG = 0x1,
159 SWIFT = 0x2,
160 LD = 0x3,
161 LLD = 0x4, // LLVM's stock LLD linker
162 ZIG = 0x5, // Unofficially Zig
163 _,
164};
165
166/// The entry_point_command is a replacement for thread_command.
167/// It is used for main executables to specify the location (file offset)
168/// of main(). If -stack_size was used at link time, the stacksize
169/// field will contain the stack size needed for the main thread.
170pub const entry_point_command = extern struct {
171 /// LC_MAIN only used in MH_EXECUTE filetypes
172 cmd: LC = .MAIN,
173
174 /// sizeof(struct entry_point_command)
175 cmdsize: u32 = @sizeOf(entry_point_command),
176
177 /// file (__TEXT) offset of main()
178 entryoff: u64 = 0,
179
180 /// if not zero, initial stack size
181 stacksize: u64 = 0,
182};
183
184/// The symtab_command contains the offsets and sizes of the link-edit 4.3BSD
185/// "stab" style symbol table information as described in the header files
186/// <nlist.h> and <stab.h>.
187pub const symtab_command = extern struct {
188 /// LC_SYMTAB
189 cmd: LC = .SYMTAB,
190
191 /// sizeof(struct symtab_command)
192 cmdsize: u32 = @sizeOf(symtab_command),
193
194 /// symbol table offset
195 symoff: u32 = 0,
196
197 /// number of symbol table entries
198 nsyms: u32 = 0,
199
200 /// string table offset
201 stroff: u32 = 0,
202
203 /// string table size in bytes
204 strsize: u32 = 0,
205};
206
207/// This is the second set of the symbolic information which is used to support
208/// the data structures for the dynamically link editor.
209///
210/// The original set of symbolic information in the symtab_command which contains
211/// the symbol and string tables must also be present when this load command is
212/// present. When this load command is present the symbol table is organized
213/// into three groups of symbols:
214/// local symbols (static and debugging symbols) - grouped by module
215/// defined external symbols - grouped by module (sorted by name if not lib)
216/// undefined external symbols (sorted by name if MH_BINDATLOAD is not set,
217/// and in order the were seen by the static linker if MH_BINDATLOAD is set)
218/// In this load command there are offsets and counts to each of the three groups
219/// of symbols.
220///
221/// This load command contains a the offsets and sizes of the following new
222/// symbolic information tables:
223/// table of contents
224/// module table
225/// reference symbol table
226/// indirect symbol table
227/// The first three tables above (the table of contents, module table and
228/// reference symbol table) are only present if the file is a dynamically linked
229/// shared library. For executable and object modules, which are files
230/// containing only one module, the information that would be in these three
231/// tables is determined as follows:
232/// table of contents - the defined external symbols are sorted by name
233/// module table - the file contains only one module so everything in the file
234/// is part of the module.
235/// reference symbol table - is the defined and undefined external symbols
236///
237/// For dynamically linked shared library files this load command also contains
238/// offsets and sizes to the pool of relocation entries for all sections
239/// separated into two groups:
240/// external relocation entries
241/// local relocation entries
242/// For executable and object modules the relocation entries continue to hang
243/// off the section structures.
244pub const dysymtab_command = extern struct {
245 /// LC_DYSYMTAB
246 cmd: LC = .DYSYMTAB,
247
248 /// sizeof(struct dysymtab_command)
249 cmdsize: u32 = @sizeOf(dysymtab_command),
250
251 // The symbols indicated by symoff and nsyms of the LC_SYMTAB load command
252 // are grouped into the following three groups:
253 // local symbols (further grouped by the module they are from)
254 // defined external symbols (further grouped by the module they are from)
255 // undefined symbols
256 //
257 // The local symbols are used only for debugging. The dynamic binding
258 // process may have to use them to indicate to the debugger the local
259 // symbols for a module that is being bound.
260 //
261 // The last two groups are used by the dynamic binding process to do the
262 // binding (indirectly through the module table and the reference symbol
263 // table when this is a dynamically linked shared library file).
264
265 /// index of local symbols
266 ilocalsym: u32 = 0,
267
268 /// number of local symbols
269 nlocalsym: u32 = 0,
270
271 /// index to externally defined symbols
272 iextdefsym: u32 = 0,
273
274 /// number of externally defined symbols
275 nextdefsym: u32 = 0,
276
277 /// index to undefined symbols
278 iundefsym: u32 = 0,
279
280 /// number of undefined symbols
281 nundefsym: u32 = 0,
282
283 // For the for the dynamic binding process to find which module a symbol
284 // is defined in the table of contents is used (analogous to the ranlib
285 // structure in an archive) which maps defined external symbols to modules
286 // they are defined in. This exists only in a dynamically linked shared
287 // library file. For executable and object modules the defined external
288 // symbols are sorted by name and is use as the table of contents.
289
290 /// file offset to table of contents
291 tocoff: u32 = 0,
292
293 /// number of entries in table of contents
294 ntoc: u32 = 0,
295
296 // To support dynamic binding of "modules" (whole object files) the symbol
297 // table must reflect the modules that the file was created from. This is
298 // done by having a module table that has indexes and counts into the merged
299 // tables for each module. The module structure that these two entries
300 // refer to is described below. This exists only in a dynamically linked
301 // shared library file. For executable and object modules the file only
302 // contains one module so everything in the file belongs to the module.
303
304 /// file offset to module table
305 modtaboff: u32 = 0,
306
307 /// number of module table entries
308 nmodtab: u32 = 0,
309
310 // To support dynamic module binding the module structure for each module
311 // indicates the external references (defined and undefined) each module
312 // makes. For each module there is an offset and a count into the
313 // reference symbol table for the symbols that the module references.
314 // This exists only in a dynamically linked shared library file. For
315 // executable and object modules the defined external symbols and the
316 // undefined external symbols indicates the external references.
317
318 /// offset to referenced symbol table
319 extrefsymoff: u32 = 0,
320
321 /// number of referenced symbol table entries
322 nextrefsyms: u32 = 0,
323
324 // The sections that contain "symbol pointers" and "routine stubs" have
325 // indexes and (implied counts based on the size of the section and fixed
326 // size of the entry) into the "indirect symbol" table for each pointer
327 // and stub. For every section of these two types the index into the
328 // indirect symbol table is stored in the section header in the field
329 // reserved1. An indirect symbol table entry is simply a 32bit index into
330 // the symbol table to the symbol that the pointer or stub is referring to.
331 // The indirect symbol table is ordered to match the entries in the section.
332
333 /// file offset to the indirect symbol table
334 indirectsymoff: u32 = 0,
335
336 /// number of indirect symbol table entries
337 nindirectsyms: u32 = 0,
338
339 // To support relocating an individual module in a library file quickly the
340 // external relocation entries for each module in the library need to be
341 // accessed efficiently. Since the relocation entries can't be accessed
342 // through the section headers for a library file they are separated into
343 // groups of local and external entries further grouped by module. In this
344 // case the presents of this load command who's extreloff, nextrel,
345 // locreloff and nlocrel fields are non-zero indicates that the relocation
346 // entries of non-merged sections are not referenced through the section
347 // structures (and the reloff and nreloc fields in the section headers are
348 // set to zero).
349 //
350 // Since the relocation entries are not accessed through the section headers
351 // this requires the r_address field to be something other than a section
352 // offset to identify the item to be relocated. In this case r_address is
353 // set to the offset from the vmaddr of the first LC_SEGMENT command.
354 // For MH_SPLIT_SEGS images r_address is set to the the offset from the
355 // vmaddr of the first read-write LC_SEGMENT command.
356 //
357 // The relocation entries are grouped by module and the module table
358 // entries have indexes and counts into them for the group of external
359 // relocation entries for that the module.
360 //
361 // For sections that are merged across modules there must not be any
362 // remaining external relocation entries for them (for merged sections
363 // remaining relocation entries must be local).
364
365 /// offset to external relocation entries
366 extreloff: u32 = 0,
367
368 /// number of external relocation entries
369 nextrel: u32 = 0,
370
371 // All the local relocation entries are grouped together (they are not
372 // grouped by their module since they are only used if the object is moved
373 // from its statically link edited address).
374
375 /// offset to local relocation entries
376 locreloff: u32 = 0,
377
378 /// number of local relocation entries
379 nlocrel: u32 = 0,
380};
381
382/// The linkedit_data_command contains the offsets and sizes of a blob
383/// of data in the __LINKEDIT segment.
384pub const linkedit_data_command = extern struct {
385 /// LC_CODE_SIGNATURE, LC_SEGMENT_SPLIT_INFO, LC_FUNCTION_STARTS, LC_DATA_IN_CODE, LC_DYLIB_CODE_SIGN_DRS or LC_LINKER_OPTIMIZATION_HINT.
386 cmd: LC,
387
388 /// sizeof(struct linkedit_data_command)
389 cmdsize: u32 = @sizeOf(linkedit_data_command),
390
391 /// file offset of data in __LINKEDIT segment
392 dataoff: u32 = 0,
393
394 /// file size of data in __LINKEDIT segment
395 datasize: u32 = 0,
396};
397
398/// The dyld_info_command contains the file offsets and sizes of
399/// the new compressed form of the information dyld needs to
400/// load the image. This information is used by dyld on Mac OS X
401/// 10.6 and later. All information pointed to by this command
402/// is encoded using byte streams, so no endian swapping is needed
403/// to interpret it.
404pub const dyld_info_command = extern struct {
405 /// LC_DYLD_INFO or LC_DYLD_INFO_ONLY
406 cmd: LC = .DYLD_INFO_ONLY,
407
408 /// sizeof(struct dyld_info_command)
409 cmdsize: u32 = @sizeOf(dyld_info_command),
410
411 // Dyld rebases an image whenever dyld loads it at an address different
412 // from its preferred address. The rebase information is a stream
413 // of byte sized opcodes whose symbolic names start with REBASE_OPCODE_.
414 // Conceptually the rebase information is a table of tuples:
415 // <seg-index, seg-offset, type>
416 // The opcodes are a compressed way to encode the table by only
417 // encoding when a column changes. In addition simple patterns
418 // like "every n'th offset for m times" can be encoded in a few
419 // bytes.
420
421 /// file offset to rebase info
422 rebase_off: u32 = 0,
423
424 /// size of rebase info
425 rebase_size: u32 = 0,
426
427 // Dyld binds an image during the loading process, if the image
428 // requires any pointers to be initialized to symbols in other images.
429 // The bind information is a stream of byte sized
430 // opcodes whose symbolic names start with BIND_OPCODE_.
431 // Conceptually the bind information is a table of tuples:
432 // <seg-index, seg-offset, type, symbol-library-ordinal, symbol-name, addend>
433 // The opcodes are a compressed way to encode the table by only
434 // encoding when a column changes. In addition simple patterns
435 // like for runs of pointers initialized to the same value can be
436 // encoded in a few bytes.
437
438 /// file offset to binding info
439 bind_off: u32 = 0,
440
441 /// size of binding info
442 bind_size: u32 = 0,
443
444 // Some C++ programs require dyld to unique symbols so that all
445 // images in the process use the same copy of some code/data.
446 // This step is done after binding. The content of the weak_bind
447 // info is an opcode stream like the bind_info. But it is sorted
448 // alphabetically by symbol name. This enable dyld to walk
449 // all images with weak binding information in order and look
450 // for collisions. If there are no collisions, dyld does
451 // no updating. That means that some fixups are also encoded
452 // in the bind_info. For instance, all calls to "operator new"
453 // are first bound to libstdc++.dylib using the information
454 // in bind_info. Then if some image overrides operator new
455 // that is detected when the weak_bind information is processed
456 // and the call to operator new is then rebound.
457
458 /// file offset to weak binding info
459 weak_bind_off: u32 = 0,
460
461 /// size of weak binding info
462 weak_bind_size: u32 = 0,
463
464 // Some uses of external symbols do not need to be bound immediately.
465 // Instead they can be lazily bound on first use. The lazy_bind
466 // are contains a stream of BIND opcodes to bind all lazy symbols.
467 // Normal use is that dyld ignores the lazy_bind section when
468 // loading an image. Instead the static linker arranged for the
469 // lazy pointer to initially point to a helper function which
470 // pushes the offset into the lazy_bind area for the symbol
471 // needing to be bound, then jumps to dyld which simply adds
472 // the offset to lazy_bind_off to get the information on what
473 // to bind.
474
475 /// file offset to lazy binding info
476 lazy_bind_off: u32 = 0,
477
478 /// size of lazy binding info
479 lazy_bind_size: u32 = 0,
480
481 // The symbols exported by a dylib are encoded in a trie. This
482 // is a compact representation that factors out common prefixes.
483 // It also reduces LINKEDIT pages in RAM because it encodes all
484 // information (name, address, flags) in one small, contiguous range.
485 // The export area is a stream of nodes. The first node sequentially
486 // is the start node for the trie.
487 //
488 // Nodes for a symbol start with a uleb128 that is the length of
489 // the exported symbol information for the string so far.
490 // If there is no exported symbol, the node starts with a zero byte.
491 // If there is exported info, it follows the length.
492 //
493 // First is a uleb128 containing flags. Normally, it is followed by
494 // a uleb128 encoded offset which is location of the content named
495 // by the symbol from the mach_header for the image. If the flags
496 // is EXPORT_SYMBOL_FLAGS_REEXPORT, then following the flags is
497 // a uleb128 encoded library ordinal, then a zero terminated
498 // UTF8 string. If the string is zero length, then the symbol
499 // is re-export from the specified dylib with the same name.
500 // If the flags is EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER, then following
501 // the flags is two uleb128s: the stub offset and the resolver offset.
502 // The stub is used by non-lazy pointers. The resolver is used
503 // by lazy pointers and must be called to get the actual address to use.
504 //
505 // After the optional exported symbol information is a byte of
506 // how many edges (0-255) that this node has leaving it,
507 // followed by each edge.
508 // Each edge is a zero terminated UTF8 of the addition chars
509 // in the symbol, followed by a uleb128 offset for the node that
510 // edge points to.
511
512 /// file offset to lazy binding info
513 export_off: u32 = 0,
514
515 /// size of lazy binding info
516 export_size: u32 = 0,
517};
518
519/// A program that uses a dynamic linker contains a dylinker_command to identify
520/// the name of the dynamic linker (LC_LOAD_DYLINKER). And a dynamic linker
521/// contains a dylinker_command to identify the dynamic linker (LC_ID_DYLINKER).
522/// A file can have at most one of these.
523/// This struct is also used for the LC_DYLD_ENVIRONMENT load command and contains
524/// string for dyld to treat like an environment variable.
525pub const dylinker_command = extern struct {
526 /// LC_ID_DYLINKER, LC_LOAD_DYLINKER, or LC_DYLD_ENVIRONMENT
527 cmd: LC,
528
529 /// includes pathname string
530 cmdsize: u32,
531
532 /// A variable length string in a load command is represented by an lc_str
533 /// union. The strings are stored just after the load command structure and
534 /// the offset is from the start of the load command structure. The size
535 /// of the string is reflected in the cmdsize field of the load command.
536 /// Once again any padded bytes to bring the cmdsize field to a multiple
537 /// of 4 bytes must be zero.
538 name: u32,
539};
540
541/// A dynamically linked shared library (filetype == MH_DYLIB in the mach header)
542/// contains a dylib_command (cmd == LC_ID_DYLIB) to identify the library.
543/// An object that uses a dynamically linked shared library also contains a
544/// dylib_command (cmd == LC_LOAD_DYLIB, LC_LOAD_WEAK_DYLIB, or
545/// LC_REEXPORT_DYLIB) for each library it uses.
546pub const dylib_command = extern struct {
547 /// LC_ID_DYLIB, LC_LOAD_WEAK_DYLIB, LC_LOAD_DYLIB, LC_REEXPORT_DYLIB
548 cmd: LC,
549
550 /// includes pathname string
551 cmdsize: u32,
552
553 /// the library identification
554 dylib: dylib,
555};
556
557/// Dynamically linked shared libraries are identified by two things. The
558/// pathname (the name of the library as found for execution), and the
559/// compatibility version number. The pathname must match and the compatibility
560/// number in the user of the library must be greater than or equal to the
561/// library being used. The time stamp is used to record the time a library was
562/// built and copied into user so it can be use to determined if the library used
563/// at runtime is exactly the same as used to build the program.
564pub const dylib = extern struct {
565 /// library's pathname (offset pointing at the end of dylib_command)
566 name: u32,
567
568 /// library's build timestamp
569 timestamp: u32,
570
571 /// library's current version number
572 current_version: u32,
573
574 /// library's compatibility version number
575 compatibility_version: u32,
576};
577
578/// The rpath_command contains a path which at runtime should be added to the current
579/// run path used to find @rpath prefixed dylibs.
580pub const rpath_command = extern struct {
581 /// LC_RPATH
582 cmd: LC = .RPATH,
583
584 /// includes string
585 cmdsize: u32,
586
587 /// path to add to run path
588 path: u32,
589};
590
591pub const encryption_info_command = extern struct {
592 cmd: LC = .ENCRYPTION_INFO,
593 cmdsize: u32 = @sizeOf(encryption_info_command),
594
595 cryptoff: u32,
596 cryptsize: u32,
597 cryptid: u32 = 0,
598};
599
600pub const encryption_info_command_64 = extern struct {
601 cmd: LC = .ENCRYPTION_INFO_64,
602 cmdsize: u32 = @sizeOf(encryption_info_command_64),
603
604 cryptoff: u32,
605 cryptsize: u32,
606 cryptid: u32 = 0,
607 _pad: u32 = 0,
608};
609
610/// The segment load command indicates that a part of this file is to be
611/// mapped into the task's address space. The size of this segment in memory,
612/// vmsize, maybe equal to or larger than the amount to map from this file,
613/// filesize. The file is mapped starting at fileoff to the beginning of
614/// the segment in memory, vmaddr. The rest of the memory of the segment,
615/// if any, is allocated zero fill on demand. The segment's maximum virtual
616/// memory protection and initial virtual memory protection are specified
617/// by the maxprot and initprot fields. If the segment has sections then the
618/// section structures directly follow the segment command and their size is
619/// reflected in cmdsize.
620pub const segment_command = extern struct {
621 /// LC_SEGMENT
622 cmd: LC = .SEGMENT,
623
624 /// includes sizeof section structs
625 cmdsize: u32,
626
627 /// segment name
628 segname: [16]u8,
629
630 /// memory address of this segment
631 vmaddr: u32,
632
633 /// memory size of this segment
634 vmsize: u32,
635
636 /// file offset of this segment
637 fileoff: u32,
638
639 /// amount to map from the file
640 filesize: u32,
641
642 /// maximum VM protection
643 maxprot: vm_prot_t,
644
645 /// initial VM protection
646 initprot: vm_prot_t,
647
648 /// number of sections in segment
649 nsects: u32,
650 flags: u32,
651};
652
653/// The 64-bit segment load command indicates that a part of this file is to be
654/// mapped into a 64-bit task's address space. If the 64-bit segment has
655/// sections then section_64 structures directly follow the 64-bit segment
656/// command and their size is reflected in cmdsize.
657pub const segment_command_64 = extern struct {
658 /// LC_SEGMENT_64
659 cmd: LC = .SEGMENT_64,
660
661 /// includes sizeof section_64 structs
662 cmdsize: u32,
663 // TODO lazy values in stage2
664 // cmdsize: u32 = @sizeOf(segment_command_64),
665
666 /// segment name
667 segname: [16]u8,
668
669 /// memory address of this segment
670 vmaddr: u64 = 0,
671
672 /// memory size of this segment
673 vmsize: u64 = 0,
674
675 /// file offset of this segment
676 fileoff: u64 = 0,
677
678 /// amount to map from the file
679 filesize: u64 = 0,
680
681 /// maximum VM protection
682 maxprot: vm_prot_t = .{},
683
684 /// initial VM protection
685 initprot: vm_prot_t = .{},
686
687 /// number of sections in segment
688 nsects: u32 = 0,
689 flags: u32 = 0,
690
691 pub fn segName(seg: *const segment_command_64) []const u8 {
692 return parseName(&seg.segname);
693 }
694
695 pub fn isWriteable(seg: segment_command_64) bool {
696 return seg.initprot.write;
697 }
698};
699
700pub const PROT = struct {
701 /// [MC2] no permissions
702 pub const NONE: vm_prot_t = 0x00;
703 /// [MC2] pages can be read
704 pub const READ: vm_prot_t = 0x01;
705 /// [MC2] pages can be written
706 pub const WRITE: vm_prot_t = 0x02;
707 /// [MC2] pages can be executed
708 pub const EXEC: vm_prot_t = 0x04;
709 /// When a caller finds that they cannot obtain write permission on a
710 /// mapped entry, the following flag can be used. The entry will be
711 /// made "needs copy" effectively copying the object (using COW),
712 /// and write permission will be added to the maximum protections for
713 /// the associated entry.
714 pub const COPY: vm_prot_t = 0x10;
715};
716
717/// A segment is made up of zero or more sections. Non-MH_OBJECT files have
718/// all of their segments with the proper sections in each, and padded to the
719/// specified segment alignment when produced by the link editor. The first
720/// segment of a MH_EXECUTE and MH_FVMLIB format file contains the mach_header
721/// and load commands of the object file before its first section. The zero
722/// fill sections are always last in their segment (in all formats). This
723/// allows the zeroed segment padding to be mapped into memory where zero fill
724/// sections might be. The gigabyte zero fill sections, those with the section
725/// type S_GB_ZEROFILL, can only be in a segment with sections of this type.
726/// These segments are then placed after all other segments.
727///
728/// The MH_OBJECT format has all of its sections in one segment for
729/// compactness. There is no padding to a specified segment boundary and the
730/// mach_header and load commands are not part of the segment.
731///
732/// Sections with the same section name, sectname, going into the same segment,
733/// segname, are combined by the link editor. The resulting section is aligned
734/// to the maximum alignment of the combined sections and is the new section's
735/// alignment. The combined sections are aligned to their original alignment in
736/// the combined section. Any padded bytes to get the specified alignment are
737/// zeroed.
738///
739/// The format of the relocation entries referenced by the reloff and nreloc
740/// fields of the section structure for mach object files is described in the
741/// header file <reloc.h>.
742pub const section = extern struct {
743 /// name of this section
744 sectname: [16]u8,
745
746 /// segment this section goes in
747 segname: [16]u8,
748
749 /// memory address of this section
750 addr: u32,
751
752 /// size in bytes of this section
753 size: u32,
754
755 /// file offset of this section
756 offset: u32,
757
758 /// section alignment (power of 2)
759 @"align": u32,
760
761 /// file offset of relocation entries
762 reloff: u32,
763
764 /// number of relocation entries
765 nreloc: u32,
766
767 /// flags (section type and attributes
768 flags: u32,
769
770 /// reserved (for offset or index)
771 reserved1: u32,
772
773 /// reserved (for count or sizeof)
774 reserved2: u32,
775};
776
777pub const section_64 = extern struct {
778 /// name of this section
779 sectname: [16]u8,
780
781 /// segment this section goes in
782 segname: [16]u8,
783
784 /// memory address of this section
785 addr: u64 = 0,
786
787 /// size in bytes of this section
788 size: u64 = 0,
789
790 /// file offset of this section
791 offset: u32 = 0,
792
793 /// section alignment (power of 2)
794 @"align": u32 = 0,
795
796 /// file offset of relocation entries
797 reloff: u32 = 0,
798
799 /// number of relocation entries
800 nreloc: u32 = 0,
801
802 /// flags (section type and attributes
803 flags: u32 = S_REGULAR,
804
805 /// reserved (for offset or index)
806 reserved1: u32 = 0,
807
808 /// reserved (for count or sizeof)
809 reserved2: u32 = 0,
810
811 /// reserved
812 reserved3: u32 = 0,
813
814 pub fn sectName(sect: *const section_64) []const u8 {
815 return parseName(&sect.sectname);
816 }
817
818 pub fn segName(sect: *const section_64) []const u8 {
819 return parseName(&sect.segname);
820 }
821
822 pub fn @"type"(sect: section_64) u8 {
823 return @as(u8, @truncate(sect.flags & 0xff));
824 }
825
826 pub fn attrs(sect: section_64) u32 {
827 return sect.flags & 0xffffff00;
828 }
829
830 pub fn isCode(sect: section_64) bool {
831 const attr = sect.attrs();
832 return attr & S_ATTR_PURE_INSTRUCTIONS != 0 or attr & S_ATTR_SOME_INSTRUCTIONS != 0;
833 }
834
835 pub fn isZerofill(sect: section_64) bool {
836 const tt = sect.type();
837 return tt == S_ZEROFILL or tt == S_GB_ZEROFILL or tt == S_THREAD_LOCAL_ZEROFILL;
838 }
839
840 pub fn isSymbolStubs(sect: section_64) bool {
841 const tt = sect.type();
842 return tt == S_SYMBOL_STUBS;
843 }
844
845 pub fn isDebug(sect: section_64) bool {
846 return sect.attrs() & S_ATTR_DEBUG != 0;
847 }
848
849 pub fn isDontDeadStrip(sect: section_64) bool {
850 return sect.attrs() & S_ATTR_NO_DEAD_STRIP != 0;
851 }
852
853 pub fn isDontDeadStripIfReferencesLive(sect: section_64) bool {
854 return sect.attrs() & S_ATTR_LIVE_SUPPORT != 0;
855 }
856};
857
858fn parseName(name: *const [16]u8) []const u8 {
859 const len = mem.findScalar(u8, name, @as(u8, 0)) orelse name.len;
860 return name[0..len];
861}
862
863pub const nlist = extern struct {
864 n_strx: u32,
865 n_type: u8,
866 n_sect: u8,
867 n_desc: i16,
868 n_value: u32,
869};
870
871pub const nlist_64 = extern struct {
872 n_strx: u32,
873 n_type: packed union(u8) {
874 bits: packed struct(u8) {
875 ext: bool,
876 type: enum(u3) {
877 undf = 0,
878 abs = 1,
879 sect = 7,
880 pbud = 6,
881 indr = 5,
882 _,
883 },
884 pext: bool,
885 /// Any non-zero value indicates this is an stab, so the `stab` field should be used.
886 is_stab: u3,
887 },
888 stab: enum(u8) {
889 gsym = N_GSYM,
890 fname = N_FNAME,
891 fun = N_FUN,
892 stsym = N_STSYM,
893 lcsym = N_LCSYM,
894 bnsym = N_BNSYM,
895 ast = N_AST,
896 opt = N_OPT,
897 rsym = N_RSYM,
898 sline = N_SLINE,
899 ensym = N_ENSYM,
900 ssym = N_SSYM,
901 so = N_SO,
902 oso = N_OSO,
903 lsym = N_LSYM,
904 bincl = N_BINCL,
905 sol = N_SOL,
906 params = N_PARAMS,
907 version = N_VERSION,
908 olevel = N_OLEVEL,
909 psym = N_PSYM,
910 eincl = N_EINCL,
911 entry = N_ENTRY,
912 lbrac = N_LBRAC,
913 excl = N_EXCL,
914 rbrac = N_RBRAC,
915 bcomm = N_BCOMM,
916 ecomm = N_ECOMM,
917 ecoml = N_ECOML,
918 leng = N_LENG,
919 _,
920 },
921 },
922 n_sect: u8,
923 n_desc: packed struct(u16) {
924 _pad0: u3 = 0,
925 arm_thumb_def: bool,
926 referenced_dynamically: bool,
927 /// The meaning of this bit is contextual.
928 /// See `N_DESC_DISCARDED` and `N_NO_DEAD_STRIP`.
929 discarded_or_no_dead_strip: bool,
930 weak_ref: bool,
931 /// The meaning of this bit is contextual.
932 /// See `N_WEAK_DEF` and `N_REF_TO_WEAK`.
933 weak_def_or_ref_to_weak: bool,
934 symbol_resolver: bool,
935 alt_entry: bool,
936 _pad2: u6 = 0,
937 },
938 n_value: u64,
939
940 pub fn tentative(sym: nlist_64) bool {
941 return sym.n_type.bits.type == .undf and sym.n_value != 0;
942 }
943};
944
945/// Format of a relocation entry of a Mach-O file. Modified from the 4.3BSD
946/// format. The modifications from the original format were changing the value
947/// of the r_symbolnum field for "local" (r_extern == 0) relocation entries.
948/// This modification is required to support symbols in an arbitrary number of
949/// sections not just the three sections (text, data and bss) in a 4.3BSD file.
950/// Also the last 4 bits have had the r_type tag added to them.
951pub const relocation_info = packed struct {
952 /// offset in the section to what is being relocated
953 r_address: i32,
954
955 /// symbol index if r_extern == 1 or section ordinal if r_extern == 0
956 r_symbolnum: u24,
957
958 /// was relocated pc relative already
959 r_pcrel: u1,
960
961 /// 0=byte, 1=word, 2=long, 3=quad
962 r_length: u2,
963
964 /// does not include value of sym referenced
965 r_extern: u1,
966
967 /// if not 0, machine specific relocation type
968 r_type: u4,
969};
970
971/// After MacOS X 10.1 when a new load command is added that is required to be
972/// understood by the dynamic linker for the image to execute properly the
973/// LC_REQ_DYLD bit will be or'ed into the load command constant. If the dynamic
974/// linker sees such a load command it it does not understand will issue a
975/// "unknown load command required for execution" error and refuse to use the
976/// image. Other load commands without this bit that are not understood will
977/// simply be ignored.
978pub const LC_REQ_DYLD = 0x80000000;
979
980pub const LC = enum(u32) {
981 /// No load command - invalid
982 NONE = 0x0,
983
984 /// segment of this file to be mapped
985 SEGMENT = 0x1,
986
987 /// link-edit stab symbol table info
988 SYMTAB = 0x2,
989
990 /// link-edit gdb symbol table info (obsolete)
991 SYMSEG = 0x3,
992
993 /// thread
994 THREAD = 0x4,
995
996 /// unix thread (includes a stack)
997 UNIXTHREAD = 0x5,
998
999 /// load a specified fixed VM shared library
1000 LOADFVMLIB = 0x6,
1001
1002 /// fixed VM shared library identification
1003 IDFVMLIB = 0x7,
1004
1005 /// object identification info (obsolete)
1006 IDENT = 0x8,
1007
1008 /// fixed VM file inclusion (internal use)
1009 FVMFILE = 0x9,
1010
1011 /// prepage command (internal use)
1012 PREPAGE = 0xa,
1013
1014 /// dynamic link-edit symbol table info
1015 DYSYMTAB = 0xb,
1016
1017 /// load a dynamically linked shared library
1018 LOAD_DYLIB = 0xc,
1019
1020 /// dynamically linked shared lib ident
1021 ID_DYLIB = 0xd,
1022
1023 /// load a dynamic linker
1024 LOAD_DYLINKER = 0xe,
1025
1026 /// dynamic linker identification
1027 ID_DYLINKER = 0xf,
1028
1029 /// modules prebound for a dynamically
1030 PREBOUND_DYLIB = 0x10,
1031
1032 /// image routines
1033 ROUTINES = 0x11,
1034
1035 /// sub framework
1036 SUB_FRAMEWORK = 0x12,
1037
1038 /// sub umbrella
1039 SUB_UMBRELLA = 0x13,
1040
1041 /// sub client
1042 SUB_CLIENT = 0x14,
1043
1044 /// sub library
1045 SUB_LIBRARY = 0x15,
1046
1047 /// two-level namespace lookup hints
1048 TWOLEVEL_HINTS = 0x16,
1049
1050 /// prebind checksum
1051 PREBIND_CKSUM = 0x17,
1052
1053 /// load a dynamically linked shared library that is allowed to be missing
1054 /// (all symbols are weak imported).
1055 LOAD_WEAK_DYLIB = 0x18 | LC_REQ_DYLD,
1056
1057 /// 64-bit segment of this file to be mapped
1058 SEGMENT_64 = 0x19,
1059
1060 /// 64-bit image routines
1061 ROUTINES_64 = 0x1a,
1062
1063 /// the uuid
1064 UUID = 0x1b,
1065
1066 /// runpath additions
1067 RPATH = 0x1c | LC_REQ_DYLD,
1068
1069 /// local of code signature
1070 CODE_SIGNATURE = 0x1d,
1071
1072 /// local of info to split segments
1073 SEGMENT_SPLIT_INFO = 0x1e,
1074
1075 /// load and re-export dylib
1076 REEXPORT_DYLIB = 0x1f | LC_REQ_DYLD,
1077
1078 /// delay load of dylib until first use
1079 LAZY_LOAD_DYLIB = 0x20,
1080
1081 /// encrypted segment information
1082 ENCRYPTION_INFO = 0x21,
1083
1084 /// compressed dyld information
1085 DYLD_INFO = 0x22,
1086
1087 /// compressed dyld information only
1088 DYLD_INFO_ONLY = 0x22 | LC_REQ_DYLD,
1089
1090 /// load upward dylib
1091 LOAD_UPWARD_DYLIB = 0x23 | LC_REQ_DYLD,
1092
1093 /// build for MacOSX min OS version
1094 VERSION_MIN_MACOSX = 0x24,
1095
1096 /// build for iPhoneOS min OS version
1097 VERSION_MIN_IPHONEOS = 0x25,
1098
1099 /// compressed table of function start addresses
1100 FUNCTION_STARTS = 0x26,
1101
1102 /// string for dyld to treat like environment variable
1103 DYLD_ENVIRONMENT = 0x27,
1104
1105 /// replacement for LC_UNIXTHREAD
1106 MAIN = 0x28 | LC_REQ_DYLD,
1107
1108 /// table of non-instructions in __text
1109 DATA_IN_CODE = 0x29,
1110
1111 /// source version used to build binary
1112 SOURCE_VERSION = 0x2A,
1113
1114 /// Code signing DRs copied from linked dylibs
1115 DYLIB_CODE_SIGN_DRS = 0x2B,
1116
1117 /// 64-bit encrypted segment information
1118 ENCRYPTION_INFO_64 = 0x2C,
1119
1120 /// linker options in MH_OBJECT files
1121 LINKER_OPTION = 0x2D,
1122
1123 /// optimization hints in MH_OBJECT files
1124 LINKER_OPTIMIZATION_HINT = 0x2E,
1125
1126 /// build for AppleTV min OS version
1127 VERSION_MIN_TVOS = 0x2F,
1128
1129 /// build for Watch min OS version
1130 VERSION_MIN_WATCHOS = 0x30,
1131
1132 /// arbitrary data included within a Mach-O file
1133 NOTE = 0x31,
1134
1135 /// build for platform min OS version
1136 BUILD_VERSION = 0x32,
1137
1138 /// used with linkedit_data_command, payload is trie
1139 DYLD_EXPORTS_TRIE = 0x33 | LC_REQ_DYLD,
1140
1141 /// used with linkedit_data_command
1142 DYLD_CHAINED_FIXUPS = 0x34 | LC_REQ_DYLD,
1143
1144 _,
1145};
1146
1147/// the mach magic number
1148pub const MH_MAGIC = 0xfeedface;
1149
1150/// NXSwapInt(MH_MAGIC)
1151pub const MH_CIGAM = 0xcefaedfe;
1152
1153/// the 64-bit mach magic number
1154pub const MH_MAGIC_64 = 0xfeedfacf;
1155
1156/// NXSwapInt(MH_MAGIC_64)
1157pub const MH_CIGAM_64 = 0xcffaedfe;
1158
1159/// relocatable object file
1160pub const MH_OBJECT = 0x1;
1161
1162/// demand paged executable file
1163pub const MH_EXECUTE = 0x2;
1164
1165/// fixed VM shared library file
1166pub const MH_FVMLIB = 0x3;
1167
1168/// core file
1169pub const MH_CORE = 0x4;
1170
1171/// preloaded executable file
1172pub const MH_PRELOAD = 0x5;
1173
1174/// dynamically bound shared library
1175pub const MH_DYLIB = 0x6;
1176
1177/// dynamic link editor
1178pub const MH_DYLINKER = 0x7;
1179
1180/// dynamically bound bundle file
1181pub const MH_BUNDLE = 0x8;
1182
1183/// shared library stub for static linking only, no section contents
1184pub const MH_DYLIB_STUB = 0x9;
1185
1186/// companion file with only debug sections
1187pub const MH_DSYM = 0xa;
1188
1189/// x86_64 kexts
1190pub const MH_KEXT_BUNDLE = 0xb;
1191
1192// Constants for the flags field of the mach_header
1193
1194/// the object file has no undefined references
1195pub const MH_NOUNDEFS = 0x1;
1196
1197/// the object file is the output of an incremental link against a base file and can't be link edited again
1198pub const MH_INCRLINK = 0x2;
1199
1200/// the object file is input for the dynamic linker and can't be statically link edited again
1201pub const MH_DYLDLINK = 0x4;
1202
1203/// the object file's undefined references are bound by the dynamic linker when loaded.
1204pub const MH_BINDATLOAD = 0x8;
1205
1206/// the file has its dynamic undefined references prebound.
1207pub const MH_PREBOUND = 0x10;
1208
1209/// the file has its read-only and read-write segments split
1210pub const MH_SPLIT_SEGS = 0x20;
1211
1212/// the shared library init routine is to be run lazily via catching memory faults to its writeable segments (obsolete)
1213pub const MH_LAZY_INIT = 0x40;
1214
1215/// the image is using two-level name space bindings
1216pub const MH_TWOLEVEL = 0x80;
1217
1218/// the executable is forcing all images to use flat name space bindings
1219pub const MH_FORCE_FLAT = 0x100;
1220
1221/// this umbrella guarantees no multiple definitions of symbols in its sub-images so the two-level namespace hints can always be used.
1222pub const MH_NOMULTIDEFS = 0x200;
1223
1224/// do not have dyld notify the prebinding agent about this executable
1225pub const MH_NOFIXPREBINDING = 0x400;
1226
1227/// the binary is not prebound but can have its prebinding redone. only used when MH_PREBOUND is not set.
1228pub const MH_PREBINDABLE = 0x800;
1229
1230/// indicates that this binary binds to all two-level namespace modules of its dependent libraries. only used when MH_PREBINDABLE and MH_TWOLEVEL are both set.
1231pub const MH_ALLMODSBOUND = 0x1000;
1232
1233/// safe to divide up the sections into sub-sections via symbols for dead code stripping
1234pub const MH_SUBSECTIONS_VIA_SYMBOLS = 0x2000;
1235
1236/// the binary has been canonicalized via the unprebind operation
1237pub const MH_CANONICAL = 0x4000;
1238
1239/// the final linked image contains external weak symbols
1240pub const MH_WEAK_DEFINES = 0x8000;
1241
1242/// the final linked image uses weak symbols
1243pub const MH_BINDS_TO_WEAK = 0x10000;
1244
1245/// When this bit is set, all stacks in the task will be given stack execution privilege. Only used in MH_EXECUTE filetypes.
1246pub const MH_ALLOW_STACK_EXECUTION = 0x20000;
1247
1248/// When this bit is set, the binary declares it is safe for use in processes with uid zero
1249pub const MH_ROOT_SAFE = 0x40000;
1250
1251/// When this bit is set, the binary declares it is safe for use in processes when issetugid() is true
1252pub const MH_SETUID_SAFE = 0x80000;
1253
1254/// When this bit is set on a dylib, the static linker does not need to examine dependent dylibs to see if any are re-exported
1255pub const MH_NO_REEXPORTED_DYLIBS = 0x100000;
1256
1257/// When this bit is set, the OS will load the main executable at a random address. Only used in MH_EXECUTE filetypes.
1258pub const MH_PIE = 0x200000;
1259
1260/// Only for use on dylibs. When linking against a dylib that has this bit set, the static linker will automatically not create a LC_LOAD_DYLIB load command to the dylib if no symbols are being referenced from the dylib.
1261pub const MH_DEAD_STRIPPABLE_DYLIB = 0x400000;
1262
1263/// Contains a section of type S_THREAD_LOCAL_VARIABLES
1264pub const MH_HAS_TLV_DESCRIPTORS = 0x800000;
1265
1266/// When this bit is set, the OS will run the main executable with a non-executable heap even on platforms (e.g. x86) that don't require it. Only used in MH_EXECUTE filetypes.
1267pub const MH_NO_HEAP_EXECUTION = 0x1000000;
1268
1269/// The code was linked for use in an application extension.
1270pub const MH_APP_EXTENSION_SAFE = 0x02000000;
1271
1272/// The external symbols listed in the nlist symbol table do not include all the symbols listed in the dyld info.
1273pub const MH_NLIST_OUTOFSYNC_WITH_DYLDINFO = 0x04000000;
1274
1275/// Allow LC_MIN_VERSION_MACOS and LC_BUILD_VERSION load commands with the platforms macOS, iOSMac, iOSSimulator, tvOSSimulator and watchOSSimulator.
1276pub const MH_SIM_SUPPORT = 0x08000000;
1277
1278/// Only for use on dylibs. When this bit is set, the dylib is part of the dyld shared cache, rather than loose in the filesystem.
1279pub const MH_DYLIB_IN_CACHE = 0x80000000;
1280
1281// Constants for the flags field of the fat_header
1282
1283/// the fat magic number
1284pub const FAT_MAGIC = 0xcafebabe;
1285
1286/// NXSwapLong(FAT_MAGIC)
1287pub const FAT_CIGAM = 0xbebafeca;
1288
1289/// the 64-bit fat magic number
1290pub const FAT_MAGIC_64 = 0xcafebabf;
1291
1292/// NXSwapLong(FAT_MAGIC_64)
1293pub const FAT_CIGAM_64 = 0xbfbafeca;
1294
1295/// Segment flags
1296/// The file contents for this segment is for the high part of the VM space, the low part
1297/// is zero filled (for stacks in core files).
1298pub const SG_HIGHVM = 0x1;
1299/// This segment is the VM that is allocated by a fixed VM library, for overlap checking in
1300/// the link editor.
1301pub const SG_FVMLIB = 0x2;
1302/// This segment has nothing that was relocated in it and nothing relocated to it, that is
1303/// it maybe safely replaced without relocation.
1304pub const SG_NORELOC = 0x4;
1305/// This segment is protected. If the segment starts at file offset 0, the
1306/// first page of the segment is not protected. All other pages of the segment are protected.
1307pub const SG_PROTECTED_VERSION_1 = 0x8;
1308/// This segment is made read-only after fixups
1309pub const SG_READ_ONLY = 0x10;
1310
1311/// The flags field of a section structure is separated into two parts a section
1312/// type and section attributes. The section types are mutually exclusive (it
1313/// can only have one type) but the section attributes are not (it may have more
1314/// than one attribute).
1315/// 256 section types
1316pub const SECTION_TYPE = 0x000000ff;
1317
1318/// 24 section attributes
1319pub const SECTION_ATTRIBUTES = 0xffffff00;
1320
1321/// regular section
1322pub const S_REGULAR = 0x0;
1323
1324/// zero fill on demand section
1325pub const S_ZEROFILL = 0x1;
1326
1327/// section with only literal C string
1328pub const S_CSTRING_LITERALS = 0x2;
1329
1330/// section with only 4 byte literals
1331pub const S_4BYTE_LITERALS = 0x3;
1332
1333/// section with only 8 byte literals
1334pub const S_8BYTE_LITERALS = 0x4;
1335
1336/// section with only pointers to
1337pub const S_LITERAL_POINTERS = 0x5;
1338
1339/// if any of these bits set, a symbolic debugging entry
1340pub const N_STAB = 0xe0;
1341
1342/// private external symbol bit
1343pub const N_PEXT = 0x10;
1344
1345/// mask for the type bits
1346pub const N_TYPE = 0x0e;
1347
1348/// external symbol bit, set for external symbols
1349pub const N_EXT = 0x01;
1350
1351/// symbol is undefined
1352pub const N_UNDF = 0x0;
1353
1354/// symbol is absolute
1355pub const N_ABS = 0x2;
1356
1357/// symbol is defined in the section number given in n_sect
1358pub const N_SECT = 0xe;
1359
1360/// symbol is undefined and the image is using a prebound
1361/// value for the symbol
1362pub const N_PBUD = 0xc;
1363
1364/// symbol is defined to be the same as another symbol; the n_value
1365/// field is an index into the string table specifying the name of the
1366/// other symbol
1367pub const N_INDR = 0xa;
1368
1369/// global symbol: name,,NO_SECT,type,0
1370pub const N_GSYM = 0x20;
1371
1372/// procedure name (f77 kludge): name,,NO_SECT,0,0
1373pub const N_FNAME = 0x22;
1374
1375/// procedure: name,,n_sect,linenumber,address
1376pub const N_FUN = 0x24;
1377
1378/// static symbol: name,,n_sect,type,address
1379pub const N_STSYM = 0x26;
1380
1381/// .lcomm symbol: name,,n_sect,type,address
1382pub const N_LCSYM = 0x28;
1383
1384/// begin nsect sym: 0,,n_sect,0,address
1385pub const N_BNSYM = 0x2e;
1386
1387/// AST file path: name,,NO_SECT,0,0
1388pub const N_AST = 0x32;
1389
1390/// emitted with gcc2_compiled and in gcc source
1391pub const N_OPT = 0x3c;
1392
1393/// register sym: name,,NO_SECT,type,register
1394pub const N_RSYM = 0x40;
1395
1396/// src line: 0,,n_sect,linenumber,address
1397pub const N_SLINE = 0x44;
1398
1399/// end nsect sym: 0,,n_sect,0,address
1400pub const N_ENSYM = 0x4e;
1401
1402/// structure elt: name,,NO_SECT,type,struct_offset
1403pub const N_SSYM = 0x60;
1404
1405/// source file name: name,,n_sect,0,address
1406pub const N_SO = 0x64;
1407
1408/// object file name: name,,0,0,st_mtime
1409pub const N_OSO = 0x66;
1410
1411/// local sym: name,,NO_SECT,type,offset
1412pub const N_LSYM = 0x80;
1413
1414/// include file beginning: name,,NO_SECT,0,sum
1415pub const N_BINCL = 0x82;
1416
1417/// #included file name: name,,n_sect,0,address
1418pub const N_SOL = 0x84;
1419
1420/// compiler parameters: name,,NO_SECT,0,0
1421pub const N_PARAMS = 0x86;
1422
1423/// compiler version: name,,NO_SECT,0,0
1424pub const N_VERSION = 0x88;
1425
1426/// compiler -O level: name,,NO_SECT,0,0
1427pub const N_OLEVEL = 0x8A;
1428
1429/// parameter: name,,NO_SECT,type,offset
1430pub const N_PSYM = 0xa0;
1431
1432/// include file end: name,,NO_SECT,0,0
1433pub const N_EINCL = 0xa2;
1434
1435/// alternate entry: name,,n_sect,linenumber,address
1436pub const N_ENTRY = 0xa4;
1437
1438/// left bracket: 0,,NO_SECT,nesting level,address
1439pub const N_LBRAC = 0xc0;
1440
1441/// deleted include file: name,,NO_SECT,0,sum
1442pub const N_EXCL = 0xc2;
1443
1444/// right bracket: 0,,NO_SECT,nesting level,address
1445pub const N_RBRAC = 0xe0;
1446
1447/// begin common: name,,NO_SECT,0,0
1448pub const N_BCOMM = 0xe2;
1449
1450/// end common: name,,n_sect,0,0
1451pub const N_ECOMM = 0xe4;
1452
1453/// end common (local name): 0,,n_sect,0,address
1454pub const N_ECOML = 0xe8;
1455
1456/// second stab entry with length information
1457pub const N_LENG = 0xfe;
1458
1459// For the two types of symbol pointers sections and the symbol stubs section
1460// they have indirect symbol table entries. For each of the entries in the
1461// section the indirect symbol table entries, in corresponding order in the
1462// indirect symbol table, start at the index stored in the reserved1 field
1463// of the section structure. Since the indirect symbol table entries
1464// correspond to the entries in the section the number of indirect symbol table
1465// entries is inferred from the size of the section divided by the size of the
1466// entries in the section. For symbol pointers sections the size of the entries
1467// in the section is 4 bytes and for symbol stubs sections the byte size of the
1468// stubs is stored in the reserved2 field of the section structure.
1469
1470/// section with only non-lazy symbol pointers
1471pub const S_NON_LAZY_SYMBOL_POINTERS = 0x6;
1472
1473/// section with only lazy symbol pointers
1474pub const S_LAZY_SYMBOL_POINTERS = 0x7;
1475
1476/// section with only symbol stubs, byte size of stub in the reserved2 field
1477pub const S_SYMBOL_STUBS = 0x8;
1478
1479/// section with only function pointers for initialization
1480pub const S_MOD_INIT_FUNC_POINTERS = 0x9;
1481
1482/// section with only function pointers for termination
1483pub const S_MOD_TERM_FUNC_POINTERS = 0xa;
1484
1485/// section contains symbols that are to be coalesced
1486pub const S_COALESCED = 0xb;
1487
1488/// zero fill on demand section (that can be larger than 4 gigabytes)
1489pub const S_GB_ZEROFILL = 0xc;
1490
1491/// section with only pairs of function pointers for interposing
1492pub const S_INTERPOSING = 0xd;
1493
1494/// section with only 16 byte literals
1495pub const S_16BYTE_LITERALS = 0xe;
1496
1497/// section contains DTrace Object Format
1498pub const S_DTRACE_DOF = 0xf;
1499
1500/// section with only lazy symbol pointers to lazy loaded dylibs
1501pub const S_LAZY_DYLIB_SYMBOL_POINTERS = 0x10;
1502
1503// If a segment contains any sections marked with S_ATTR_DEBUG then all
1504// sections in that segment must have this attribute. No section other than
1505// a section marked with this attribute may reference the contents of this
1506// section. A section with this attribute may contain no symbols and must have
1507// a section type S_REGULAR. The static linker will not copy section contents
1508// from sections with this attribute into its output file. These sections
1509// generally contain DWARF debugging info.
1510
1511/// a debug section
1512pub const S_ATTR_DEBUG = 0x02000000;
1513
1514/// section contains only true machine instructions
1515pub const S_ATTR_PURE_INSTRUCTIONS = 0x80000000;
1516
1517/// section contains coalesced symbols that are not to be in a ranlib
1518/// table of contents
1519pub const S_ATTR_NO_TOC = 0x40000000;
1520
1521/// ok to strip static symbols in this section in files with the
1522/// MH_DYLDLINK flag
1523pub const S_ATTR_STRIP_STATIC_SYMS = 0x20000000;
1524
1525/// no dead stripping
1526pub const S_ATTR_NO_DEAD_STRIP = 0x10000000;
1527
1528/// blocks are live if they reference live blocks
1529pub const S_ATTR_LIVE_SUPPORT = 0x8000000;
1530
1531/// used with x86 code stubs written on by dyld
1532pub const S_ATTR_SELF_MODIFYING_CODE = 0x4000000;
1533
1534/// section contains some machine instructions
1535pub const S_ATTR_SOME_INSTRUCTIONS = 0x400;
1536
1537/// section has external relocation entries
1538pub const S_ATTR_EXT_RELOC = 0x200;
1539
1540/// section has local relocation entries
1541pub const S_ATTR_LOC_RELOC = 0x100;
1542
1543/// template of initial values for TLVs
1544pub const S_THREAD_LOCAL_REGULAR = 0x11;
1545
1546/// template of initial values for TLVs
1547pub const S_THREAD_LOCAL_ZEROFILL = 0x12;
1548
1549/// TLV descriptors
1550pub const S_THREAD_LOCAL_VARIABLES = 0x13;
1551
1552/// pointers to TLV descriptors
1553pub const S_THREAD_LOCAL_VARIABLE_POINTERS = 0x14;
1554
1555/// functions to call to initialize TLV values
1556pub const S_THREAD_LOCAL_INIT_FUNCTION_POINTERS = 0x15;
1557
1558/// 32-bit offsets to initializers
1559pub const S_INIT_FUNC_OFFSETS = 0x16;
1560
1561/// CPU type targeting 64-bit Intel-based Macs
1562pub const CPU_TYPE_X86_64: cpu_type_t = 0x01000007;
1563
1564/// CPU type targeting 64-bit ARM-based Macs
1565pub const CPU_TYPE_ARM64: cpu_type_t = 0x0100000C;
1566
1567/// All Intel-based Macs
1568pub const CPU_SUBTYPE_X86_64_ALL: cpu_subtype_t = 0x3;
1569
1570/// All ARM-based Macs
1571pub const CPU_SUBTYPE_ARM_ALL: cpu_subtype_t = 0x0;
1572
1573// The following are used to encode rebasing information
1574pub const REBASE_TYPE_POINTER: u8 = 1;
1575pub const REBASE_TYPE_TEXT_ABSOLUTE32: u8 = 2;
1576pub const REBASE_TYPE_TEXT_PCREL32: u8 = 3;
1577
1578pub const REBASE_OPCODE_MASK: u8 = 0xF0;
1579pub const REBASE_IMMEDIATE_MASK: u8 = 0x0F;
1580pub const REBASE_OPCODE_DONE: u8 = 0x00;
1581pub const REBASE_OPCODE_SET_TYPE_IMM: u8 = 0x10;
1582pub const REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB: u8 = 0x20;
1583pub const REBASE_OPCODE_ADD_ADDR_ULEB: u8 = 0x30;
1584pub const REBASE_OPCODE_ADD_ADDR_IMM_SCALED: u8 = 0x40;
1585pub const REBASE_OPCODE_DO_REBASE_IMM_TIMES: u8 = 0x50;
1586pub const REBASE_OPCODE_DO_REBASE_ULEB_TIMES: u8 = 0x60;
1587pub const REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB: u8 = 0x70;
1588pub const REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB: u8 = 0x80;
1589
1590// The following are used to encode binding information
1591pub const BIND_TYPE_POINTER: u8 = 1;
1592pub const BIND_TYPE_TEXT_ABSOLUTE32: u8 = 2;
1593pub const BIND_TYPE_TEXT_PCREL32: u8 = 3;
1594
1595pub const BIND_SPECIAL_DYLIB_SELF: i8 = 0;
1596pub const BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE: i8 = -1;
1597pub const BIND_SPECIAL_DYLIB_FLAT_LOOKUP: i8 = -2;
1598
1599pub const BIND_SYMBOL_FLAGS_WEAK_IMPORT: u8 = 0x1;
1600pub const BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION: u8 = 0x8;
1601
1602pub const BIND_OPCODE_MASK: u8 = 0xf0;
1603pub const BIND_IMMEDIATE_MASK: u8 = 0x0f;
1604pub const BIND_OPCODE_DONE: u8 = 0x00;
1605pub const BIND_OPCODE_SET_DYLIB_ORDINAL_IMM: u8 = 0x10;
1606pub const BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB: u8 = 0x20;
1607pub const BIND_OPCODE_SET_DYLIB_SPECIAL_IMM: u8 = 0x30;
1608pub const BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM: u8 = 0x40;
1609pub const BIND_OPCODE_SET_TYPE_IMM: u8 = 0x50;
1610pub const BIND_OPCODE_SET_ADDEND_SLEB: u8 = 0x60;
1611pub const BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB: u8 = 0x70;
1612pub const BIND_OPCODE_ADD_ADDR_ULEB: u8 = 0x80;
1613pub const BIND_OPCODE_DO_BIND: u8 = 0x90;
1614pub const BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB: u8 = 0xa0;
1615pub const BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED: u8 = 0xb0;
1616pub const BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB: u8 = 0xc0;
1617
1618pub const reloc_type_x86_64 = enum(u4) {
1619 /// for absolute addresses
1620 X86_64_RELOC_UNSIGNED = 0,
1621
1622 /// for signed 32-bit displacement
1623 X86_64_RELOC_SIGNED,
1624
1625 /// a CALL/JMP instruction with 32-bit displacement
1626 X86_64_RELOC_BRANCH,
1627
1628 /// a MOVQ load of a GOT entry
1629 X86_64_RELOC_GOT_LOAD,
1630
1631 /// other GOT references
1632 X86_64_RELOC_GOT,
1633
1634 /// must be followed by a X86_64_RELOC_UNSIGNED
1635 X86_64_RELOC_SUBTRACTOR,
1636
1637 /// for signed 32-bit displacement with a -1 addend
1638 X86_64_RELOC_SIGNED_1,
1639
1640 /// for signed 32-bit displacement with a -2 addend
1641 X86_64_RELOC_SIGNED_2,
1642
1643 /// for signed 32-bit displacement with a -4 addend
1644 X86_64_RELOC_SIGNED_4,
1645
1646 /// for thread local variables
1647 X86_64_RELOC_TLV,
1648};
1649
1650pub const reloc_type_arm64 = enum(u4) {
1651 /// For pointers.
1652 ARM64_RELOC_UNSIGNED = 0,
1653
1654 /// Must be followed by a ARM64_RELOC_UNSIGNED.
1655 ARM64_RELOC_SUBTRACTOR,
1656
1657 /// A B/BL instruction with 26-bit displacement.
1658 ARM64_RELOC_BRANCH26,
1659
1660 /// Pc-rel distance to page of target.
1661 ARM64_RELOC_PAGE21,
1662
1663 /// Offset within page, scaled by r_length.
1664 ARM64_RELOC_PAGEOFF12,
1665
1666 /// Pc-rel distance to page of GOT slot.
1667 ARM64_RELOC_GOT_LOAD_PAGE21,
1668
1669 /// Offset within page of GOT slot, scaled by r_length.
1670 ARM64_RELOC_GOT_LOAD_PAGEOFF12,
1671
1672 /// For pointers to GOT slots.
1673 ARM64_RELOC_POINTER_TO_GOT,
1674
1675 /// Pc-rel distance to page of TLVP slot.
1676 ARM64_RELOC_TLVP_LOAD_PAGE21,
1677
1678 /// Offset within page of TLVP slot, scaled by r_length.
1679 ARM64_RELOC_TLVP_LOAD_PAGEOFF12,
1680
1681 /// Must be followed by PAGE21 or PAGEOFF12.
1682 ARM64_RELOC_ADDEND,
1683};
1684
1685/// This symbol is a reference to an external non-lazy (data) symbol.
1686pub const REFERENCE_FLAG_UNDEFINED_NON_LAZY: u16 = 0x0;
1687
1688/// This symbol is a reference to an external lazy symbol—that is, to a function call.
1689pub const REFERENCE_FLAG_UNDEFINED_LAZY: u16 = 0x1;
1690
1691/// This symbol is defined in this module.
1692pub const REFERENCE_FLAG_DEFINED: u16 = 0x2;
1693
1694/// This symbol is defined in this module and is visible only to modules within this shared library.
1695pub const REFERENCE_FLAG_PRIVATE_DEFINED: u16 = 3;
1696
1697/// This symbol is defined in another module in this file, is a non-lazy (data) symbol, and is visible
1698/// only to modules within this shared library.
1699pub const REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY: u16 = 4;
1700
1701/// This symbol is defined in another module in this file, is a lazy (function) symbol, and is visible
1702/// only to modules within this shared library.
1703pub const REFERENCE_FLAG_PRIVATE_UNDEFINED_LAZY: u16 = 5;
1704
1705/// Must be set for any defined symbol that is referenced by dynamic-loader APIs (such as dlsym and
1706/// NSLookupSymbolInImage) and not ordinary undefined symbol references. The strip tool uses this bit
1707/// to avoid removing symbols that must exist: If the symbol has this bit set, strip does not strip it.
1708pub const REFERENCED_DYNAMICALLY: u16 = 0x10;
1709
1710/// The N_NO_DEAD_STRIP bit of the n_desc field only ever appears in a
1711/// relocatable .o file (MH_OBJECT filetype). And is used to indicate to the
1712/// static link editor it is never to dead strip the symbol.
1713pub const N_NO_DEAD_STRIP: u16 = 0x20;
1714
1715/// Used by the dynamic linker at runtime. Do not set this bit.
1716pub const N_DESC_DISCARDED: u16 = 0x20;
1717
1718/// Indicates that this symbol is a weak reference. If the dynamic linker cannot find a definition
1719/// for this symbol, it sets the address of this symbol to 0. The static linker sets this symbol given
1720/// the appropriate weak-linking flags.
1721pub const N_WEAK_REF: u16 = 0x40;
1722
1723/// Indicates that this symbol is a weak definition. If the static linker or the dynamic linker finds
1724/// another (non-weak) definition for this symbol, the weak definition is ignored. Only symbols in a
1725/// coalesced section (page 23) can be marked as a weak definition.
1726pub const N_WEAK_DEF: u16 = 0x80;
1727
1728/// The N_SYMBOL_RESOLVER bit of the n_desc field indicates that the
1729/// that the function is actually a resolver function and should
1730/// be called to get the address of the real function to use.
1731/// This bit is only available in .o files (MH_OBJECT filetype)
1732pub const N_SYMBOL_RESOLVER: u16 = 0x100;
1733
1734// The following are used on the flags byte of a terminal node in the export information.
1735pub const EXPORT_SYMBOL_FLAGS_KIND_MASK: u8 = 0x03;
1736pub const EXPORT_SYMBOL_FLAGS_KIND_REGULAR: u8 = 0x00;
1737pub const EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL: u8 = 0x01;
1738pub const EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE: u8 = 0x02;
1739pub const EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION: u8 = 0x04;
1740pub const EXPORT_SYMBOL_FLAGS_REEXPORT: u8 = 0x08;
1741pub const EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER: u8 = 0x10;
1742
1743// An indirect symbol table entry is simply a 32bit index into the symbol table
1744// to the symbol that the pointer or stub is referring to. Unless it is for a
1745// non-lazy symbol pointer section for a defined symbol which strip(1) as
1746// removed. In which case it has the value INDIRECT_SYMBOL_LOCAL. If the
1747// symbol was also absolute INDIRECT_SYMBOL_ABS is or'ed with that.
1748pub const INDIRECT_SYMBOL_LOCAL: u32 = 0x80000000;
1749pub const INDIRECT_SYMBOL_ABS: u32 = 0x40000000;
1750
1751// Codesign consts and structs taken from:
1752// https://opensource.apple.com/source/xnu/xnu-6153.81.5/osfmk/kern/cs_blobs.h.auto.html
1753
1754/// Single Requirement blob
1755pub const CSMAGIC_REQUIREMENT: u32 = 0xfade0c00;
1756/// Requirements vector (internal requirements)
1757pub const CSMAGIC_REQUIREMENTS: u32 = 0xfade0c01;
1758/// CodeDirectory blob
1759pub const CSMAGIC_CODEDIRECTORY: u32 = 0xfade0c02;
1760/// embedded form of signature data
1761pub const CSMAGIC_EMBEDDED_SIGNATURE: u32 = 0xfade0cc0;
1762/// XXX
1763pub const CSMAGIC_EMBEDDED_SIGNATURE_OLD: u32 = 0xfade0b02;
1764/// Embedded entitlements
1765pub const CSMAGIC_EMBEDDED_ENTITLEMENTS: u32 = 0xfade7171;
1766/// Embedded DER encoded entitlements
1767pub const CSMAGIC_EMBEDDED_DER_ENTITLEMENTS: u32 = 0xfade7172;
1768/// Multi-arch collection of embedded signatures
1769pub const CSMAGIC_DETACHED_SIGNATURE: u32 = 0xfade0cc1;
1770/// CMS Signature, among other things
1771pub const CSMAGIC_BLOBWRAPPER: u32 = 0xfade0b01;
1772
1773pub const CS_SUPPORTSSCATTER: u32 = 0x20100;
1774pub const CS_SUPPORTSTEAMID: u32 = 0x20200;
1775pub const CS_SUPPORTSCODELIMIT64: u32 = 0x20300;
1776pub const CS_SUPPORTSEXECSEG: u32 = 0x20400;
1777
1778/// Slot index for CodeDirectory
1779pub const CSSLOT_CODEDIRECTORY: u32 = 0;
1780pub const CSSLOT_INFOSLOT: u32 = 1;
1781pub const CSSLOT_REQUIREMENTS: u32 = 2;
1782pub const CSSLOT_RESOURCEDIR: u32 = 3;
1783pub const CSSLOT_APPLICATION: u32 = 4;
1784pub const CSSLOT_ENTITLEMENTS: u32 = 5;
1785pub const CSSLOT_DER_ENTITLEMENTS: u32 = 7;
1786
1787/// first alternate CodeDirectory, if any
1788pub const CSSLOT_ALTERNATE_CODEDIRECTORIES: u32 = 0x1000;
1789/// Max number of alternate CD slots
1790pub const CSSLOT_ALTERNATE_CODEDIRECTORY_MAX: u32 = 5;
1791/// One past the last
1792pub const CSSLOT_ALTERNATE_CODEDIRECTORY_LIMIT: u32 = CSSLOT_ALTERNATE_CODEDIRECTORIES + CSSLOT_ALTERNATE_CODEDIRECTORY_MAX;
1793
1794/// CMS Signature
1795pub const CSSLOT_SIGNATURESLOT: u32 = 0x10000;
1796pub const CSSLOT_IDENTIFICATIONSLOT: u32 = 0x10001;
1797pub const CSSLOT_TICKETSLOT: u32 = 0x10002;
1798
1799/// Compat with amfi
1800pub const CSTYPE_INDEX_REQUIREMENTS: u32 = 0x00000002;
1801/// Compat with amfi
1802pub const CSTYPE_INDEX_ENTITLEMENTS: u32 = 0x00000005;
1803
1804pub const CS_HASHTYPE_SHA1: u8 = 1;
1805pub const CS_HASHTYPE_SHA256: u8 = 2;
1806pub const CS_HASHTYPE_SHA256_TRUNCATED: u8 = 3;
1807pub const CS_HASHTYPE_SHA384: u8 = 4;
1808
1809pub const CS_SHA1_LEN: u32 = 20;
1810pub const CS_SHA256_LEN: u32 = 32;
1811pub const CS_SHA256_TRUNCATED_LEN: u32 = 20;
1812
1813/// Always - larger hashes are truncated
1814pub const CS_CDHASH_LEN: u32 = 20;
1815/// Max size of the hash we'll support
1816pub const CS_HASH_MAX_SIZE: u32 = 48;
1817
1818pub const CS_SIGNER_TYPE_UNKNOWN: u32 = 0;
1819pub const CS_SIGNER_TYPE_LEGACYVPN: u32 = 5;
1820pub const CS_SIGNER_TYPE_MAC_APP_STORE: u32 = 6;
1821
1822pub const CS_ADHOC: u32 = 0x2;
1823pub const CS_LINKER_SIGNED: u32 = 0x20000;
1824
1825pub const CS_EXECSEG_MAIN_BINARY: u32 = 0x1;
1826
1827/// This CodeDirectory is tailored specifically at version 0x20400.
1828pub const CodeDirectory = extern struct {
1829 /// Magic number (CSMAGIC_CODEDIRECTORY)
1830 magic: u32,
1831
1832 /// Total length of CodeDirectory blob
1833 length: u32,
1834
1835 /// Compatibility version
1836 version: u32,
1837
1838 /// Setup and mode flags
1839 flags: u32,
1840
1841 /// Offset of hash slot element at index zero
1842 hashOffset: u32,
1843
1844 /// Offset of identifier string
1845 identOffset: u32,
1846
1847 /// Number of special hash slots
1848 nSpecialSlots: u32,
1849
1850 /// Number of ordinary (code) hash slots
1851 nCodeSlots: u32,
1852
1853 /// Limit to main image signature range
1854 codeLimit: u32,
1855
1856 /// Size of each hash in bytes
1857 hashSize: u8,
1858
1859 /// Type of hash (cdHashType* constants)
1860 hashType: u8,
1861
1862 /// Platform identifier; zero if not platform binary
1863 platform: u8,
1864
1865 /// log2(page size in bytes); 0 => infinite
1866 pageSize: u8,
1867
1868 /// Unused (must be zero)
1869 spare2: u32,
1870
1871 ///
1872 scatterOffset: u32,
1873
1874 ///
1875 teamOffset: u32,
1876
1877 ///
1878 spare3: u32,
1879
1880 ///
1881 codeLimit64: u64,
1882
1883 /// Offset of executable segment
1884 execSegBase: u64,
1885
1886 /// Limit of executable segment
1887 execSegLimit: u64,
1888
1889 /// Executable segment flags
1890 execSegFlags: u64,
1891};
1892
1893/// Structure of an embedded-signature SuperBlob
1894pub const BlobIndex = extern struct {
1895 /// Type of entry
1896 type: u32,
1897
1898 /// Offset of entry
1899 offset: u32,
1900};
1901
1902/// This structure is followed by GenericBlobs in no particular
1903/// order as indicated by offsets in index
1904pub const SuperBlob = extern struct {
1905 /// Magic number
1906 magic: u32,
1907
1908 /// Total length of SuperBlob
1909 length: u32,
1910
1911 /// Number of index BlobIndex entries following this struct
1912 count: u32,
1913};
1914
1915pub const GenericBlob = extern struct {
1916 /// Magic number
1917 magic: u32,
1918
1919 /// Total length of blob
1920 length: u32,
1921};
1922
1923/// The LC_DATA_IN_CODE load commands uses a linkedit_data_command
1924/// to point to an array of data_in_code_entry entries. Each entry
1925/// describes a range of data in a code section.
1926pub const data_in_code_entry = extern struct {
1927 /// From mach_header to start of data range.
1928 offset: u32,
1929 /// Number of bytes in data range.
1930 length: u16,
1931 /// A DICE_KIND value.
1932 kind: u16,
1933};
1934
1935pub const LoadCommandIterator = struct {
1936 next_index: usize,
1937 ncmds: usize,
1938 r: std.Io.Reader,
1939
1940 pub const LoadCommand = struct {
1941 hdr: load_command,
1942 data: []const u8,
1943
1944 pub fn cast(lc: LoadCommand, comptime Cmd: type) ?Cmd {
1945 if (lc.data.len < @sizeOf(Cmd)) return null;
1946 const ptr: *align(1) const Cmd = @ptrCast(lc.data.ptr);
1947 var cmd = ptr.*;
1948 if (builtin.cpu.arch.endian() != .little) std.mem.byteSwapAllFields(Cmd, &cmd);
1949 return cmd;
1950 }
1951
1952 /// Asserts LoadCommand is of type segment_command_64.
1953 /// If the native endian is not `.little`, the `section_64` values must be byte-swapped by the caller.
1954 pub fn getSections(lc: LoadCommand) []align(1) const section_64 {
1955 const segment_lc = lc.cast(segment_command_64).?;
1956 const sects_ptr: [*]align(1) const section_64 = @ptrCast(lc.data[@sizeOf(segment_command_64)..]);
1957 return sects_ptr[0..segment_lc.nsects];
1958 }
1959
1960 /// Asserts LoadCommand is of type dylib_command.
1961 pub fn getDylibPathName(lc: LoadCommand) []const u8 {
1962 const dylib_lc = lc.cast(dylib_command).?;
1963 return mem.sliceTo(lc.data[dylib_lc.dylib.name..], 0);
1964 }
1965
1966 /// Asserts LoadCommand is of type rpath_command.
1967 pub fn getRpathPathName(lc: LoadCommand) []const u8 {
1968 const rpath_lc = lc.cast(rpath_command).?;
1969 return mem.sliceTo(lc.data[rpath_lc.path..], 0);
1970 }
1971
1972 /// Asserts LoadCommand is of type build_version_command.
1973 /// If the native endian is not `.little`, the `build_tool_version` values must be byte-swapped by the caller.
1974 pub fn getBuildVersionTools(lc: LoadCommand) []align(1) const build_tool_version {
1975 const build_lc = lc.cast(build_version_command).?;
1976 const tools_ptr: [*]align(1) const build_tool_version = @ptrCast(lc.data[@sizeOf(build_version_command)..]);
1977 return tools_ptr[0..build_lc.ntools];
1978 }
1979 };
1980
1981 pub fn next(it: *LoadCommandIterator) error{InvalidMachO}!?LoadCommand {
1982 if (it.next_index >= it.ncmds) return null;
1983
1984 const hdr = it.r.peekStruct(load_command, .little) catch |err| switch (err) {
1985 error.ReadFailed => unreachable,
1986 error.EndOfStream => return error.InvalidMachO,
1987 };
1988 const data = it.r.take(hdr.cmdsize) catch |err| switch (err) {
1989 error.ReadFailed => unreachable,
1990 error.EndOfStream => return error.InvalidMachO,
1991 };
1992
1993 it.next_index += 1;
1994 return .{ .hdr = hdr, .data = data };
1995 }
1996
1997 pub fn init(hdr: *const mach_header_64, cmds_buf_overlong: []const u8) error{InvalidMachO}!LoadCommandIterator {
1998 if (cmds_buf_overlong.len < hdr.sizeofcmds) return error.InvalidMachO;
1999 if (hdr.ncmds > 0 and hdr.sizeofcmds < @sizeOf(load_command)) return error.InvalidMachO;
2000 const cmds_buf = cmds_buf_overlong[0..hdr.sizeofcmds];
2001 return .{
2002 .next_index = 0,
2003 .ncmds = hdr.ncmds,
2004 .r = .fixed(cmds_buf),
2005 };
2006 }
2007};
2008
2009pub const compact_unwind_encoding_t = u32;
2010
2011// Relocatable object files: __LD,__compact_unwind
2012
2013pub const compact_unwind_entry = extern struct {
2014 rangeStart: u64,
2015 rangeLength: u32,
2016 compactUnwindEncoding: u32,
2017 personalityFunction: u64,
2018 lsda: u64,
2019};
2020
2021// Final linked images: __TEXT,__unwind_info
2022// The __TEXT,__unwind_info section is laid out for an efficient two level lookup.
2023// The header of the section contains a coarse index that maps function address
2024// to the page (4096 byte block) containing the unwind info for that function.
2025
2026pub const UNWIND_SECTION_VERSION = 1;
2027
2028pub const unwind_info_section_header = extern struct {
2029 /// UNWIND_SECTION_VERSION
2030 version: u32 = UNWIND_SECTION_VERSION,
2031 commonEncodingsArraySectionOffset: u32,
2032 commonEncodingsArrayCount: u32,
2033 personalityArraySectionOffset: u32,
2034 personalityArrayCount: u32,
2035 indexSectionOffset: u32,
2036 indexCount: u32,
2037 // compact_unwind_encoding_t[]
2038 // uint32_t personalities[]
2039 // unwind_info_section_header_index_entry[]
2040 // unwind_info_section_header_lsda_index_entry[]
2041};
2042
2043pub const unwind_info_section_header_index_entry = extern struct {
2044 functionOffset: u32,
2045
2046 /// section offset to start of regular or compress page
2047 secondLevelPagesSectionOffset: u32,
2048
2049 /// section offset to start of lsda_index array for this range
2050 lsdaIndexArraySectionOffset: u32,
2051};
2052
2053pub const unwind_info_section_header_lsda_index_entry = extern struct {
2054 functionOffset: u32,
2055 lsdaOffset: u32,
2056};
2057
2058// There are two kinds of second level index pages: regular and compressed.
2059// A compressed page can hold up to 1021 entries, but it cannot be used if
2060// too many different encoding types are used. The regular page holds 511
2061// entries.
2062
2063pub const unwind_info_regular_second_level_entry = extern struct {
2064 functionOffset: u32,
2065 encoding: compact_unwind_encoding_t,
2066};
2067
2068pub const UNWIND_SECOND_LEVEL = enum(u32) {
2069 REGULAR = 2,
2070 COMPRESSED = 3,
2071 _,
2072};
2073
2074pub const unwind_info_regular_second_level_page_header = extern struct {
2075 /// UNWIND_SECOND_LEVEL_REGULAR
2076 kind: UNWIND_SECOND_LEVEL = .REGULAR,
2077
2078 entryPageOffset: u16,
2079 entryCount: u16,
2080 // entry array
2081};
2082
2083pub const unwind_info_compressed_second_level_page_header = extern struct {
2084 /// UNWIND_SECOND_LEVEL_COMPRESSED
2085 kind: UNWIND_SECOND_LEVEL = .COMPRESSED,
2086
2087 entryPageOffset: u16,
2088 entryCount: u16,
2089 encodingsPageOffset: u16,
2090 encodingsCount: u16,
2091 // 32bit entry array
2092 // encodings array
2093};
2094
2095pub const UnwindInfoCompressedEntry = packed struct(u32) {
2096 funcOffset: u24,
2097 encodingIndex: u8,
2098};
2099
2100pub const UNWIND_IS_NOT_FUNCTION_START: u32 = 0x80000000;
2101pub const UNWIND_HAS_LSDA: u32 = 0x40000000;
2102pub const UNWIND_PERSONALITY_MASK: u32 = 0x30000000;
2103
2104// x86_64
2105pub const UNWIND_X86_64_MODE_MASK: u32 = 0x0F000000;
2106pub const UNWIND_X86_64_MODE = enum(u4) {
2107 OLD = 0,
2108 RBP_FRAME = 1,
2109 STACK_IMMD = 2,
2110 STACK_IND = 3,
2111 DWARF = 4,
2112};
2113pub const UNWIND_X86_64_RBP_FRAME_REGISTERS: u32 = 0x00007FFF;
2114pub const UNWIND_X86_64_RBP_FRAME_OFFSET: u32 = 0x00FF0000;
2115
2116pub const UNWIND_X86_64_FRAMELESS_STACK_SIZE: u32 = 0x00FF0000;
2117pub const UNWIND_X86_64_FRAMELESS_STACK_ADJUST: u32 = 0x0000E000;
2118pub const UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT: u32 = 0x00001C00;
2119pub const UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION: u32 = 0x000003FF;
2120
2121pub const UNWIND_X86_64_DWARF_SECTION_OFFSET: u32 = 0x00FFFFFF;
2122
2123pub const UNWIND_X86_64_REG = enum(u3) {
2124 NONE = 0,
2125 RBX = 1,
2126 R12 = 2,
2127 R13 = 3,
2128 R14 = 4,
2129 R15 = 5,
2130 RBP = 6,
2131};
2132
2133// arm64
2134pub const UNWIND_ARM64_MODE_MASK: u32 = 0x0F000000;
2135pub const UNWIND_ARM64_MODE = enum(u4) {
2136 OLD = 0,
2137 FRAMELESS = 2,
2138 DWARF = 3,
2139 FRAME = 4,
2140};
2141
2142pub const UNWIND_ARM64_FRAME_X19_X20_PAIR: u32 = 0x00000001;
2143pub const UNWIND_ARM64_FRAME_X21_X22_PAIR: u32 = 0x00000002;
2144pub const UNWIND_ARM64_FRAME_X23_X24_PAIR: u32 = 0x00000004;
2145pub const UNWIND_ARM64_FRAME_X25_X26_PAIR: u32 = 0x00000008;
2146pub const UNWIND_ARM64_FRAME_X27_X28_PAIR: u32 = 0x00000010;
2147pub const UNWIND_ARM64_FRAME_D8_D9_PAIR: u32 = 0x00000100;
2148pub const UNWIND_ARM64_FRAME_D10_D11_PAIR: u32 = 0x00000200;
2149pub const UNWIND_ARM64_FRAME_D12_D13_PAIR: u32 = 0x00000400;
2150pub const UNWIND_ARM64_FRAME_D14_D15_PAIR: u32 = 0x00000800;
2151
2152pub const UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK: u32 = 0x00FFF000;
2153pub const UNWIND_ARM64_DWARF_SECTION_OFFSET: u32 = 0x00FFFFFF;
2154
2155pub const CompactUnwindEncoding = packed struct(u32) {
2156 value: packed union {
2157 x86_64: packed union {
2158 frame: packed struct(u24) {
2159 reg4: u3,
2160 reg3: u3,
2161 reg2: u3,
2162 reg1: u3,
2163 reg0: u3,
2164 unused: u1 = 0,
2165 frame_offset: u8,
2166 },
2167 frameless: packed struct(u24) {
2168 stack_reg_permutation: u10,
2169 stack_reg_count: u3,
2170 stack: packed union {
2171 direct: packed struct(u11) {
2172 _: u3,
2173 stack_size: u8,
2174 },
2175 indirect: packed struct(u11) {
2176 stack_adjust: u3,
2177 sub_offset: u8,
2178 },
2179 },
2180 },
2181 dwarf: u24,
2182 },
2183 arm64: packed union {
2184 frame: packed struct(u24) {
2185 x_reg_pairs: packed struct(u5) {
2186 x19_x20: u1,
2187 x21_x22: u1,
2188 x23_x24: u1,
2189 x25_x26: u1,
2190 x27_x28: u1,
2191 },
2192 d_reg_pairs: packed struct(u4) {
2193 d8_d9: u1,
2194 d10_d11: u1,
2195 d12_d13: u1,
2196 d14_d15: u1,
2197 },
2198 _: u15,
2199 },
2200 frameless: packed struct(u24) {
2201 _: u12 = 0,
2202 stack_size: u12,
2203 },
2204 dwarf: u24,
2205 },
2206 },
2207 mode: packed union {
2208 x86_64: UNWIND_X86_64_MODE,
2209 arm64: UNWIND_ARM64_MODE,
2210 },
2211 personality_index: u2,
2212 has_lsda: u1,
2213 start: u1,
2214};