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