| 1 | const std = @import("std"); |
| 2 | const builtin = @import("builtin"); |
| 3 | const assert = std.debug.assert; |
| 4 | const mem = std.mem; |
| 5 | const meta = std.meta; |
| 6 | const testing = std.testing; |
| 7 | |
| 8 | const Allocator = mem.Allocator; |
| 9 | |
| 10 | pub const cpu_type_t = c_int; |
| 11 | pub const cpu_subtype_t = c_int; |
| 12 | pub 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 | |
| 26 | pub 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 | |
| 36 | pub 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 | |
| 47 | pub const fat_header = extern struct { |
| 48 | magic: u32, |
| 49 | nfat_arch: u32, |
| 50 | }; |
| 51 | |
| 52 | pub 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 | |
| 60 | pub 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. |
| 67 | pub 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. |
| 80 | pub 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. |
| 96 | pub 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. |
| 110 | pub 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 | |
| 131 | pub 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 | |
| 139 | pub 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 | |
| 157 | pub 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. |
| 170 | pub 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>. |
| 187 | pub 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. |
| 244 | pub 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. |
| 384 | pub 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. |
| 404 | pub 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. |
| 525 | pub 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. |
| 546 | pub 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. |
| 564 | pub 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. |
| 580 | pub 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 | |
| 591 | pub 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 | |
| 600 | pub 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. |
| 620 | pub 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. |
| 657 | pub 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 | |
| 700 | pub 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>. |
| 742 | pub 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 | |
| 777 | pub 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 | |
| 858 | fn 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 | |
| 863 | pub 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 | |
| 871 | pub 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. |
| 951 | pub 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. |
| 978 | pub const LC_REQ_DYLD = 0x80000000; |
| 979 | |
| 980 | pub 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 |
| 1148 | pub const MH_MAGIC = 0xfeedface; |
| 1149 | |
| 1150 | /// NXSwapInt(MH_MAGIC) |
| 1151 | pub const MH_CIGAM = 0xcefaedfe; |
| 1152 | |
| 1153 | /// the 64-bit mach magic number |
| 1154 | pub const MH_MAGIC_64 = 0xfeedfacf; |
| 1155 | |
| 1156 | /// NXSwapInt(MH_MAGIC_64) |
| 1157 | pub const MH_CIGAM_64 = 0xcffaedfe; |
| 1158 | |
| 1159 | /// relocatable object file |
| 1160 | pub const MH_OBJECT = 0x1; |
| 1161 | |
| 1162 | /// demand paged executable file |
| 1163 | pub const MH_EXECUTE = 0x2; |
| 1164 | |
| 1165 | /// fixed VM shared library file |
| 1166 | pub const MH_FVMLIB = 0x3; |
| 1167 | |
| 1168 | /// core file |
| 1169 | pub const MH_CORE = 0x4; |
| 1170 | |
| 1171 | /// preloaded executable file |
| 1172 | pub const MH_PRELOAD = 0x5; |
| 1173 | |
| 1174 | /// dynamically bound shared library |
| 1175 | pub const MH_DYLIB = 0x6; |
| 1176 | |
| 1177 | /// dynamic link editor |
| 1178 | pub const MH_DYLINKER = 0x7; |
| 1179 | |
| 1180 | /// dynamically bound bundle file |
| 1181 | pub const MH_BUNDLE = 0x8; |
| 1182 | |
| 1183 | /// shared library stub for static linking only, no section contents |
| 1184 | pub const MH_DYLIB_STUB = 0x9; |
| 1185 | |
| 1186 | /// companion file with only debug sections |
| 1187 | pub const MH_DSYM = 0xa; |
| 1188 | |
| 1189 | /// x86_64 kexts |
| 1190 | pub 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 |
| 1195 | pub 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 |
| 1198 | pub const MH_INCRLINK = 0x2; |
| 1199 | |
| 1200 | /// the object file is input for the dynamic linker and can't be statically link edited again |
| 1201 | pub const MH_DYLDLINK = 0x4; |
| 1202 | |
| 1203 | /// the object file's undefined references are bound by the dynamic linker when loaded. |
| 1204 | pub const MH_BINDATLOAD = 0x8; |
| 1205 | |
| 1206 | /// the file has its dynamic undefined references prebound. |
| 1207 | pub const MH_PREBOUND = 0x10; |
| 1208 | |
| 1209 | /// the file has its read-only and read-write segments split |
| 1210 | pub 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) |
| 1213 | pub const MH_LAZY_INIT = 0x40; |
| 1214 | |
| 1215 | /// the image is using two-level name space bindings |
| 1216 | pub const MH_TWOLEVEL = 0x80; |
| 1217 | |
| 1218 | /// the executable is forcing all images to use flat name space bindings |
| 1219 | pub 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. |
| 1222 | pub const MH_NOMULTIDEFS = 0x200; |
| 1223 | |
| 1224 | /// do not have dyld notify the prebinding agent about this executable |
| 1225 | pub 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. |
| 1228 | pub 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. |
| 1231 | pub const MH_ALLMODSBOUND = 0x1000; |
| 1232 | |
| 1233 | /// safe to divide up the sections into sub-sections via symbols for dead code stripping |
| 1234 | pub const MH_SUBSECTIONS_VIA_SYMBOLS = 0x2000; |
| 1235 | |
| 1236 | /// the binary has been canonicalized via the unprebind operation |
| 1237 | pub const MH_CANONICAL = 0x4000; |
| 1238 | |
| 1239 | /// the final linked image contains external weak symbols |
| 1240 | pub const MH_WEAK_DEFINES = 0x8000; |
| 1241 | |
| 1242 | /// the final linked image uses weak symbols |
| 1243 | pub 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. |
| 1246 | pub 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 |
| 1249 | pub 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 |
| 1252 | pub 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 |
| 1255 | pub 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. |
| 1258 | pub 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. |
| 1261 | pub const MH_DEAD_STRIPPABLE_DYLIB = 0x400000; |
| 1262 | |
| 1263 | /// Contains a section of type S_THREAD_LOCAL_VARIABLES |
| 1264 | pub 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. |
| 1267 | pub const MH_NO_HEAP_EXECUTION = 0x1000000; |
| 1268 | |
| 1269 | /// The code was linked for use in an application extension. |
| 1270 | pub 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. |
| 1273 | pub 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. |
| 1276 | pub 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. |
| 1279 | pub const MH_DYLIB_IN_CACHE = 0x80000000; |
| 1280 | |
| 1281 | // Constants for the flags field of the fat_header |
| 1282 | |
| 1283 | /// the fat magic number |
| 1284 | pub const FAT_MAGIC = 0xcafebabe; |
| 1285 | |
| 1286 | /// NXSwapLong(FAT_MAGIC) |
| 1287 | pub const FAT_CIGAM = 0xbebafeca; |
| 1288 | |
| 1289 | /// the 64-bit fat magic number |
| 1290 | pub const FAT_MAGIC_64 = 0xcafebabf; |
| 1291 | |
| 1292 | /// NXSwapLong(FAT_MAGIC_64) |
| 1293 | pub 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). |
| 1298 | pub 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. |
| 1301 | pub 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. |
| 1304 | pub 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. |
| 1307 | pub const SG_PROTECTED_VERSION_1 = 0x8; |
| 1308 | /// This segment is made read-only after fixups |
| 1309 | pub 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 |
| 1316 | pub const SECTION_TYPE = 0x000000ff; |
| 1317 | |
| 1318 | /// 24 section attributes |
| 1319 | pub const SECTION_ATTRIBUTES = 0xffffff00; |
| 1320 | |
| 1321 | /// regular section |
| 1322 | pub const S_REGULAR = 0x0; |
| 1323 | |
| 1324 | /// zero fill on demand section |
| 1325 | pub const S_ZEROFILL = 0x1; |
| 1326 | |
| 1327 | /// section with only literal C string |
| 1328 | pub const S_CSTRING_LITERALS = 0x2; |
| 1329 | |
| 1330 | /// section with only 4 byte literals |
| 1331 | pub const S_4BYTE_LITERALS = 0x3; |
| 1332 | |
| 1333 | /// section with only 8 byte literals |
| 1334 | pub const S_8BYTE_LITERALS = 0x4; |
| 1335 | |
| 1336 | /// section with only pointers to |
| 1337 | pub const S_LITERAL_POINTERS = 0x5; |
| 1338 | |
| 1339 | /// if any of these bits set, a symbolic debugging entry |
| 1340 | pub const N_STAB = 0xe0; |
| 1341 | |
| 1342 | /// private external symbol bit |
| 1343 | pub const N_PEXT = 0x10; |
| 1344 | |
| 1345 | /// mask for the type bits |
| 1346 | pub const N_TYPE = 0x0e; |
| 1347 | |
| 1348 | /// external symbol bit, set for external symbols |
| 1349 | pub const N_EXT = 0x01; |
| 1350 | |
| 1351 | /// symbol is undefined |
| 1352 | pub const N_UNDF = 0x0; |
| 1353 | |
| 1354 | /// symbol is absolute |
| 1355 | pub const N_ABS = 0x2; |
| 1356 | |
| 1357 | /// symbol is defined in the section number given in n_sect |
| 1358 | pub const N_SECT = 0xe; |
| 1359 | |
| 1360 | /// symbol is undefined and the image is using a prebound |
| 1361 | /// value for the symbol |
| 1362 | pub 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 |
| 1367 | pub const N_INDR = 0xa; |
| 1368 | |
| 1369 | /// global symbol: name,,NO_SECT,type,0 |
| 1370 | pub const N_GSYM = 0x20; |
| 1371 | |
| 1372 | /// procedure name (f77 kludge): name,,NO_SECT,0,0 |
| 1373 | pub const N_FNAME = 0x22; |
| 1374 | |
| 1375 | /// procedure: name,,n_sect,linenumber,address |
| 1376 | pub const N_FUN = 0x24; |
| 1377 | |
| 1378 | /// static symbol: name,,n_sect,type,address |
| 1379 | pub const N_STSYM = 0x26; |
| 1380 | |
| 1381 | /// .lcomm symbol: name,,n_sect,type,address |
| 1382 | pub const N_LCSYM = 0x28; |
| 1383 | |
| 1384 | /// begin nsect sym: 0,,n_sect,0,address |
| 1385 | pub const N_BNSYM = 0x2e; |
| 1386 | |
| 1387 | /// AST file path: name,,NO_SECT,0,0 |
| 1388 | pub const N_AST = 0x32; |
| 1389 | |
| 1390 | /// emitted with gcc2_compiled and in gcc source |
| 1391 | pub const N_OPT = 0x3c; |
| 1392 | |
| 1393 | /// register sym: name,,NO_SECT,type,register |
| 1394 | pub const N_RSYM = 0x40; |
| 1395 | |
| 1396 | /// src line: 0,,n_sect,linenumber,address |
| 1397 | pub const N_SLINE = 0x44; |
| 1398 | |
| 1399 | /// end nsect sym: 0,,n_sect,0,address |
| 1400 | pub const N_ENSYM = 0x4e; |
| 1401 | |
| 1402 | /// structure elt: name,,NO_SECT,type,struct_offset |
| 1403 | pub const N_SSYM = 0x60; |
| 1404 | |
| 1405 | /// source file name: name,,n_sect,0,address |
| 1406 | pub const N_SO = 0x64; |
| 1407 | |
| 1408 | /// object file name: name,,0,0,st_mtime |
| 1409 | pub const N_OSO = 0x66; |
| 1410 | |
| 1411 | /// local sym: name,,NO_SECT,type,offset |
| 1412 | pub const N_LSYM = 0x80; |
| 1413 | |
| 1414 | /// include file beginning: name,,NO_SECT,0,sum |
| 1415 | pub const N_BINCL = 0x82; |
| 1416 | |
| 1417 | /// #included file name: name,,n_sect,0,address |
| 1418 | pub const N_SOL = 0x84; |
| 1419 | |
| 1420 | /// compiler parameters: name,,NO_SECT,0,0 |
| 1421 | pub const N_PARAMS = 0x86; |
| 1422 | |
| 1423 | /// compiler version: name,,NO_SECT,0,0 |
| 1424 | pub const N_VERSION = 0x88; |
| 1425 | |
| 1426 | /// compiler -O level: name,,NO_SECT,0,0 |
| 1427 | pub const N_OLEVEL = 0x8A; |
| 1428 | |
| 1429 | /// parameter: name,,NO_SECT,type,offset |
| 1430 | pub const N_PSYM = 0xa0; |
| 1431 | |
| 1432 | /// include file end: name,,NO_SECT,0,0 |
| 1433 | pub const N_EINCL = 0xa2; |
| 1434 | |
| 1435 | /// alternate entry: name,,n_sect,linenumber,address |
| 1436 | pub const N_ENTRY = 0xa4; |
| 1437 | |
| 1438 | /// left bracket: 0,,NO_SECT,nesting level,address |
| 1439 | pub const N_LBRAC = 0xc0; |
| 1440 | |
| 1441 | /// deleted include file: name,,NO_SECT,0,sum |
| 1442 | pub const N_EXCL = 0xc2; |
| 1443 | |
| 1444 | /// right bracket: 0,,NO_SECT,nesting level,address |
| 1445 | pub const N_RBRAC = 0xe0; |
| 1446 | |
| 1447 | /// begin common: name,,NO_SECT,0,0 |
| 1448 | pub const N_BCOMM = 0xe2; |
| 1449 | |
| 1450 | /// end common: name,,n_sect,0,0 |
| 1451 | pub const N_ECOMM = 0xe4; |
| 1452 | |
| 1453 | /// end common (local name): 0,,n_sect,0,address |
| 1454 | pub const N_ECOML = 0xe8; |
| 1455 | |
| 1456 | /// second stab entry with length information |
| 1457 | pub 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 |
| 1471 | pub const S_NON_LAZY_SYMBOL_POINTERS = 0x6; |
| 1472 | |
| 1473 | /// section with only lazy symbol pointers |
| 1474 | pub const S_LAZY_SYMBOL_POINTERS = 0x7; |
| 1475 | |
| 1476 | /// section with only symbol stubs, byte size of stub in the reserved2 field |
| 1477 | pub const S_SYMBOL_STUBS = 0x8; |
| 1478 | |
| 1479 | /// section with only function pointers for initialization |
| 1480 | pub const S_MOD_INIT_FUNC_POINTERS = 0x9; |
| 1481 | |
| 1482 | /// section with only function pointers for termination |
| 1483 | pub const S_MOD_TERM_FUNC_POINTERS = 0xa; |
| 1484 | |
| 1485 | /// section contains symbols that are to be coalesced |
| 1486 | pub const S_COALESCED = 0xb; |
| 1487 | |
| 1488 | /// zero fill on demand section (that can be larger than 4 gigabytes) |
| 1489 | pub const S_GB_ZEROFILL = 0xc; |
| 1490 | |
| 1491 | /// section with only pairs of function pointers for interposing |
| 1492 | pub const S_INTERPOSING = 0xd; |
| 1493 | |
| 1494 | /// section with only 16 byte literals |
| 1495 | pub const S_16BYTE_LITERALS = 0xe; |
| 1496 | |
| 1497 | /// section contains DTrace Object Format |
| 1498 | pub const S_DTRACE_DOF = 0xf; |
| 1499 | |
| 1500 | /// section with only lazy symbol pointers to lazy loaded dylibs |
| 1501 | pub 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 |
| 1512 | pub const S_ATTR_DEBUG = 0x02000000; |
| 1513 | |
| 1514 | /// section contains only true machine instructions |
| 1515 | pub const S_ATTR_PURE_INSTRUCTIONS = 0x80000000; |
| 1516 | |
| 1517 | /// section contains coalesced symbols that are not to be in a ranlib |
| 1518 | /// table of contents |
| 1519 | pub const S_ATTR_NO_TOC = 0x40000000; |
| 1520 | |
| 1521 | /// ok to strip static symbols in this section in files with the |
| 1522 | /// MH_DYLDLINK flag |
| 1523 | pub const S_ATTR_STRIP_STATIC_SYMS = 0x20000000; |
| 1524 | |
| 1525 | /// no dead stripping |
| 1526 | pub const S_ATTR_NO_DEAD_STRIP = 0x10000000; |
| 1527 | |
| 1528 | /// blocks are live if they reference live blocks |
| 1529 | pub const S_ATTR_LIVE_SUPPORT = 0x8000000; |
| 1530 | |
| 1531 | /// used with x86 code stubs written on by dyld |
| 1532 | pub const S_ATTR_SELF_MODIFYING_CODE = 0x4000000; |
| 1533 | |
| 1534 | /// section contains some machine instructions |
| 1535 | pub const S_ATTR_SOME_INSTRUCTIONS = 0x400; |
| 1536 | |
| 1537 | /// section has external relocation entries |
| 1538 | pub const S_ATTR_EXT_RELOC = 0x200; |
| 1539 | |
| 1540 | /// section has local relocation entries |
| 1541 | pub const S_ATTR_LOC_RELOC = 0x100; |
| 1542 | |
| 1543 | /// template of initial values for TLVs |
| 1544 | pub const S_THREAD_LOCAL_REGULAR = 0x11; |
| 1545 | |
| 1546 | /// template of initial values for TLVs |
| 1547 | pub const S_THREAD_LOCAL_ZEROFILL = 0x12; |
| 1548 | |
| 1549 | /// TLV descriptors |
| 1550 | pub const S_THREAD_LOCAL_VARIABLES = 0x13; |
| 1551 | |
| 1552 | /// pointers to TLV descriptors |
| 1553 | pub const S_THREAD_LOCAL_VARIABLE_POINTERS = 0x14; |
| 1554 | |
| 1555 | /// functions to call to initialize TLV values |
| 1556 | pub const S_THREAD_LOCAL_INIT_FUNCTION_POINTERS = 0x15; |
| 1557 | |
| 1558 | /// 32-bit offsets to initializers |
| 1559 | pub const S_INIT_FUNC_OFFSETS = 0x16; |
| 1560 | |
| 1561 | /// CPU type targeting 64-bit Intel-based Macs |
| 1562 | pub const CPU_TYPE_X86_64: cpu_type_t = 0x01000007; |
| 1563 | |
| 1564 | /// CPU type targeting 64-bit ARM-based Macs |
| 1565 | pub const CPU_TYPE_ARM64: cpu_type_t = 0x0100000C; |
| 1566 | |
| 1567 | /// All Intel-based Macs |
| 1568 | pub const CPU_SUBTYPE_X86_64_ALL: cpu_subtype_t = 0x3; |
| 1569 | |
| 1570 | /// All ARM-based Macs |
| 1571 | pub const CPU_SUBTYPE_ARM_ALL: cpu_subtype_t = 0x0; |
| 1572 | |
| 1573 | // The following are used to encode rebasing information |
| 1574 | pub const REBASE_TYPE_POINTER: u8 = 1; |
| 1575 | pub const REBASE_TYPE_TEXT_ABSOLUTE32: u8 = 2; |
| 1576 | pub const REBASE_TYPE_TEXT_PCREL32: u8 = 3; |
| 1577 | |
| 1578 | pub const REBASE_OPCODE_MASK: u8 = 0xF0; |
| 1579 | pub const REBASE_IMMEDIATE_MASK: u8 = 0x0F; |
| 1580 | pub const REBASE_OPCODE_DONE: u8 = 0x00; |
| 1581 | pub const REBASE_OPCODE_SET_TYPE_IMM: u8 = 0x10; |
| 1582 | pub const REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB: u8 = 0x20; |
| 1583 | pub const REBASE_OPCODE_ADD_ADDR_ULEB: u8 = 0x30; |
| 1584 | pub const REBASE_OPCODE_ADD_ADDR_IMM_SCALED: u8 = 0x40; |
| 1585 | pub const REBASE_OPCODE_DO_REBASE_IMM_TIMES: u8 = 0x50; |
| 1586 | pub const REBASE_OPCODE_DO_REBASE_ULEB_TIMES: u8 = 0x60; |
| 1587 | pub const REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB: u8 = 0x70; |
| 1588 | pub const REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB: u8 = 0x80; |
| 1589 | |
| 1590 | // The following are used to encode binding information |
| 1591 | pub const BIND_TYPE_POINTER: u8 = 1; |
| 1592 | pub const BIND_TYPE_TEXT_ABSOLUTE32: u8 = 2; |
| 1593 | pub const BIND_TYPE_TEXT_PCREL32: u8 = 3; |
| 1594 | |
| 1595 | pub const BIND_SPECIAL_DYLIB_SELF: i8 = 0; |
| 1596 | pub const BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE: i8 = -1; |
| 1597 | pub const BIND_SPECIAL_DYLIB_FLAT_LOOKUP: i8 = -2; |
| 1598 | |
| 1599 | pub const BIND_SYMBOL_FLAGS_WEAK_IMPORT: u8 = 0x1; |
| 1600 | pub const BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION: u8 = 0x8; |
| 1601 | |
| 1602 | pub const BIND_OPCODE_MASK: u8 = 0xf0; |
| 1603 | pub const BIND_IMMEDIATE_MASK: u8 = 0x0f; |
| 1604 | pub const BIND_OPCODE_DONE: u8 = 0x00; |
| 1605 | pub const BIND_OPCODE_SET_DYLIB_ORDINAL_IMM: u8 = 0x10; |
| 1606 | pub const BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB: u8 = 0x20; |
| 1607 | pub const BIND_OPCODE_SET_DYLIB_SPECIAL_IMM: u8 = 0x30; |
| 1608 | pub const BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM: u8 = 0x40; |
| 1609 | pub const BIND_OPCODE_SET_TYPE_IMM: u8 = 0x50; |
| 1610 | pub const BIND_OPCODE_SET_ADDEND_SLEB: u8 = 0x60; |
| 1611 | pub const BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB: u8 = 0x70; |
| 1612 | pub const BIND_OPCODE_ADD_ADDR_ULEB: u8 = 0x80; |
| 1613 | pub const BIND_OPCODE_DO_BIND: u8 = 0x90; |
| 1614 | pub const BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB: u8 = 0xa0; |
| 1615 | pub const BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED: u8 = 0xb0; |
| 1616 | pub const BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB: u8 = 0xc0; |
| 1617 | |
| 1618 | pub 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 | |
| 1650 | pub 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. |
| 1686 | pub 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. |
| 1689 | pub const REFERENCE_FLAG_UNDEFINED_LAZY: u16 = 0x1; |
| 1690 | |
| 1691 | /// This symbol is defined in this module. |
| 1692 | pub 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. |
| 1695 | pub 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. |
| 1699 | pub 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. |
| 1703 | pub 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. |
| 1708 | pub 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. |
| 1713 | pub const N_NO_DEAD_STRIP: u16 = 0x20; |
| 1714 | |
| 1715 | /// Used by the dynamic linker at runtime. Do not set this bit. |
| 1716 | pub 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. |
| 1721 | pub 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. |
| 1726 | pub 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) |
| 1732 | pub const N_SYMBOL_RESOLVER: u16 = 0x100; |
| 1733 | |
| 1734 | // The following are used on the flags byte of a terminal node in the export information. |
| 1735 | pub const EXPORT_SYMBOL_FLAGS_KIND_MASK: u8 = 0x03; |
| 1736 | pub const EXPORT_SYMBOL_FLAGS_KIND_REGULAR: u8 = 0x00; |
| 1737 | pub const EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL: u8 = 0x01; |
| 1738 | pub const EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE: u8 = 0x02; |
| 1739 | pub const EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION: u8 = 0x04; |
| 1740 | pub const EXPORT_SYMBOL_FLAGS_REEXPORT: u8 = 0x08; |
| 1741 | pub 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. |
| 1748 | pub const INDIRECT_SYMBOL_LOCAL: u32 = 0x80000000; |
| 1749 | pub 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 |
| 1755 | pub const CSMAGIC_REQUIREMENT: u32 = 0xfade0c00; |
| 1756 | /// Requirements vector (internal requirements) |
| 1757 | pub const CSMAGIC_REQUIREMENTS: u32 = 0xfade0c01; |
| 1758 | /// CodeDirectory blob |
| 1759 | pub const CSMAGIC_CODEDIRECTORY: u32 = 0xfade0c02; |
| 1760 | /// embedded form of signature data |
| 1761 | pub const CSMAGIC_EMBEDDED_SIGNATURE: u32 = 0xfade0cc0; |
| 1762 | /// XXX |
| 1763 | pub const CSMAGIC_EMBEDDED_SIGNATURE_OLD: u32 = 0xfade0b02; |
| 1764 | /// Embedded entitlements |
| 1765 | pub const CSMAGIC_EMBEDDED_ENTITLEMENTS: u32 = 0xfade7171; |
| 1766 | /// Embedded DER encoded entitlements |
| 1767 | pub const CSMAGIC_EMBEDDED_DER_ENTITLEMENTS: u32 = 0xfade7172; |
| 1768 | /// Multi-arch collection of embedded signatures |
| 1769 | pub const CSMAGIC_DETACHED_SIGNATURE: u32 = 0xfade0cc1; |
| 1770 | /// CMS Signature, among other things |
| 1771 | pub const CSMAGIC_BLOBWRAPPER: u32 = 0xfade0b01; |
| 1772 | |
| 1773 | pub const CS_SUPPORTSSCATTER: u32 = 0x20100; |
| 1774 | pub const CS_SUPPORTSTEAMID: u32 = 0x20200; |
| 1775 | pub const CS_SUPPORTSCODELIMIT64: u32 = 0x20300; |
| 1776 | pub const CS_SUPPORTSEXECSEG: u32 = 0x20400; |
| 1777 | |
| 1778 | /// Slot index for CodeDirectory |
| 1779 | pub const CSSLOT_CODEDIRECTORY: u32 = 0; |
| 1780 | pub const CSSLOT_INFOSLOT: u32 = 1; |
| 1781 | pub const CSSLOT_REQUIREMENTS: u32 = 2; |
| 1782 | pub const CSSLOT_RESOURCEDIR: u32 = 3; |
| 1783 | pub const CSSLOT_APPLICATION: u32 = 4; |
| 1784 | pub const CSSLOT_ENTITLEMENTS: u32 = 5; |
| 1785 | pub const CSSLOT_DER_ENTITLEMENTS: u32 = 7; |
| 1786 | |
| 1787 | /// first alternate CodeDirectory, if any |
| 1788 | pub const CSSLOT_ALTERNATE_CODEDIRECTORIES: u32 = 0x1000; |
| 1789 | /// Max number of alternate CD slots |
| 1790 | pub const CSSLOT_ALTERNATE_CODEDIRECTORY_MAX: u32 = 5; |
| 1791 | /// One past the last |
| 1792 | pub const CSSLOT_ALTERNATE_CODEDIRECTORY_LIMIT: u32 = CSSLOT_ALTERNATE_CODEDIRECTORIES + CSSLOT_ALTERNATE_CODEDIRECTORY_MAX; |
| 1793 | |
| 1794 | /// CMS Signature |
| 1795 | pub const CSSLOT_SIGNATURESLOT: u32 = 0x10000; |
| 1796 | pub const CSSLOT_IDENTIFICATIONSLOT: u32 = 0x10001; |
| 1797 | pub const CSSLOT_TICKETSLOT: u32 = 0x10002; |
| 1798 | |
| 1799 | /// Compat with amfi |
| 1800 | pub const CSTYPE_INDEX_REQUIREMENTS: u32 = 0x00000002; |
| 1801 | /// Compat with amfi |
| 1802 | pub const CSTYPE_INDEX_ENTITLEMENTS: u32 = 0x00000005; |
| 1803 | |
| 1804 | pub const CS_HASHTYPE_SHA1: u8 = 1; |
| 1805 | pub const CS_HASHTYPE_SHA256: u8 = 2; |
| 1806 | pub const CS_HASHTYPE_SHA256_TRUNCATED: u8 = 3; |
| 1807 | pub const CS_HASHTYPE_SHA384: u8 = 4; |
| 1808 | |
| 1809 | pub const CS_SHA1_LEN: u32 = 20; |
| 1810 | pub const CS_SHA256_LEN: u32 = 32; |
| 1811 | pub const CS_SHA256_TRUNCATED_LEN: u32 = 20; |
| 1812 | |
| 1813 | /// Always - larger hashes are truncated |
| 1814 | pub const CS_CDHASH_LEN: u32 = 20; |
| 1815 | /// Max size of the hash we'll support |
| 1816 | pub const CS_HASH_MAX_SIZE: u32 = 48; |
| 1817 | |
| 1818 | pub const CS_SIGNER_TYPE_UNKNOWN: u32 = 0; |
| 1819 | pub const CS_SIGNER_TYPE_LEGACYVPN: u32 = 5; |
| 1820 | pub const CS_SIGNER_TYPE_MAC_APP_STORE: u32 = 6; |
| 1821 | |
| 1822 | pub const CS_ADHOC: u32 = 0x2; |
| 1823 | pub const CS_LINKER_SIGNED: u32 = 0x20000; |
| 1824 | |
| 1825 | pub const CS_EXECSEG_MAIN_BINARY: u32 = 0x1; |
| 1826 | |
| 1827 | /// This CodeDirectory is tailored specifically at version 0x20400. |
| 1828 | pub 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 |
| 1894 | pub 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 |
| 1904 | pub 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 | |
| 1915 | pub 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. |
| 1926 | pub 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 | |
| 1935 | pub 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 | |
| 2009 | pub const compact_unwind_encoding_t = u32; |
| 2010 | |
| 2011 | // Relocatable object files: __LD,__compact_unwind |
| 2012 | |
| 2013 | pub 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 | |
| 2026 | pub const UNWIND_SECTION_VERSION = 1; |
| 2027 | |
| 2028 | pub 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 | |
| 2043 | pub 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 | |
| 2053 | pub 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 | |
| 2063 | pub const unwind_info_regular_second_level_entry = extern struct { |
| 2064 | functionOffset: u32, |
| 2065 | encoding: compact_unwind_encoding_t, |
| 2066 | }; |
| 2067 | |
| 2068 | pub const UNWIND_SECOND_LEVEL = enum(u32) { |
| 2069 | REGULAR = 2, |
| 2070 | COMPRESSED = 3, |
| 2071 | _, |
| 2072 | }; |
| 2073 | |
| 2074 | pub 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 | |
| 2083 | pub 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 | |
| 2095 | pub const UnwindInfoCompressedEntry = packed struct(u32) { |
| 2096 | funcOffset: u24, |
| 2097 | encodingIndex: u8, |
| 2098 | }; |
| 2099 | |
| 2100 | pub const UNWIND_IS_NOT_FUNCTION_START: u32 = 0x80000000; |
| 2101 | pub const UNWIND_HAS_LSDA: u32 = 0x40000000; |
| 2102 | pub const UNWIND_PERSONALITY_MASK: u32 = 0x30000000; |
| 2103 | |
| 2104 | // x86_64 |
| 2105 | pub const UNWIND_X86_64_MODE_MASK: u32 = 0x0F000000; |
| 2106 | pub 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 | }; |
| 2113 | pub const UNWIND_X86_64_RBP_FRAME_REGISTERS: u32 = 0x00007FFF; |
| 2114 | pub const UNWIND_X86_64_RBP_FRAME_OFFSET: u32 = 0x00FF0000; |
| 2115 | |
| 2116 | pub const UNWIND_X86_64_FRAMELESS_STACK_SIZE: u32 = 0x00FF0000; |
| 2117 | pub const UNWIND_X86_64_FRAMELESS_STACK_ADJUST: u32 = 0x0000E000; |
| 2118 | pub const UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT: u32 = 0x00001C00; |
| 2119 | pub const UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION: u32 = 0x000003FF; |
| 2120 | |
| 2121 | pub const UNWIND_X86_64_DWARF_SECTION_OFFSET: u32 = 0x00FFFFFF; |
| 2122 | |
| 2123 | pub 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 |
| 2134 | pub const UNWIND_ARM64_MODE_MASK: u32 = 0x0F000000; |
| 2135 | pub const UNWIND_ARM64_MODE = enum(u4) { |
| 2136 | OLD = 0, |
| 2137 | FRAMELESS = 2, |
| 2138 | DWARF = 3, |
| 2139 | FRAME = 4, |
| 2140 | }; |
| 2141 | |
| 2142 | pub const UNWIND_ARM64_FRAME_X19_X20_PAIR: u32 = 0x00000001; |
| 2143 | pub const UNWIND_ARM64_FRAME_X21_X22_PAIR: u32 = 0x00000002; |
| 2144 | pub const UNWIND_ARM64_FRAME_X23_X24_PAIR: u32 = 0x00000004; |
| 2145 | pub const UNWIND_ARM64_FRAME_X25_X26_PAIR: u32 = 0x00000008; |
| 2146 | pub const UNWIND_ARM64_FRAME_X27_X28_PAIR: u32 = 0x00000010; |
| 2147 | pub const UNWIND_ARM64_FRAME_D8_D9_PAIR: u32 = 0x00000100; |
| 2148 | pub const UNWIND_ARM64_FRAME_D10_D11_PAIR: u32 = 0x00000200; |
| 2149 | pub const UNWIND_ARM64_FRAME_D12_D13_PAIR: u32 = 0x00000400; |
| 2150 | pub const UNWIND_ARM64_FRAME_D14_D15_PAIR: u32 = 0x00000800; |
| 2151 | |
| 2152 | pub const UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK: u32 = 0x00FFF000; |
| 2153 | pub const UNWIND_ARM64_DWARF_SECTION_OFFSET: u32 = 0x00FFFFFF; |
| 2154 | |
| 2155 | pub 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 | }; |