diff options
Diffstat (limited to 'third_party/rust/object/src/macho.rs')
-rw-r--r-- | third_party/rust/object/src/macho.rs | 3307 |
1 files changed, 3307 insertions, 0 deletions
diff --git a/third_party/rust/object/src/macho.rs b/third_party/rust/object/src/macho.rs new file mode 100644 index 0000000000..86a5bf6266 --- /dev/null +++ b/third_party/rust/object/src/macho.rs @@ -0,0 +1,3307 @@ +//! Mach-O definitions. +//! +//! These definitions are independent of read/write support, although we do implement +//! some traits useful for those. +//! +//! This module is based heavily on header files from MacOSX11.1.sdk. + +#![allow(missing_docs)] + +use crate::endian::{BigEndian, Endian, U64Bytes, U16, U32, U64}; +use crate::pod::Pod; + +// Definitions from "/usr/include/mach/machine.h". + +/* + * Capability bits used in the definition of cpu_type. + */ + +/// mask for architecture bits +pub const CPU_ARCH_MASK: u32 = 0xff00_0000; +/// 64 bit ABI +pub const CPU_ARCH_ABI64: u32 = 0x0100_0000; +/// ABI for 64-bit hardware with 32-bit types; LP32 +pub const CPU_ARCH_ABI64_32: u32 = 0x0200_0000; + +/* + * Machine types known by all. + */ + +pub const CPU_TYPE_ANY: u32 = !0; + +pub const CPU_TYPE_VAX: u32 = 1; +pub const CPU_TYPE_MC680X0: u32 = 6; +pub const CPU_TYPE_X86: u32 = 7; +pub const CPU_TYPE_X86_64: u32 = CPU_TYPE_X86 | CPU_ARCH_ABI64; +pub const CPU_TYPE_MIPS: u32 = 8; +pub const CPU_TYPE_MC98000: u32 = 10; +pub const CPU_TYPE_HPPA: u32 = 11; +pub const CPU_TYPE_ARM: u32 = 12; +pub const CPU_TYPE_ARM64: u32 = CPU_TYPE_ARM | CPU_ARCH_ABI64; +pub const CPU_TYPE_ARM64_32: u32 = CPU_TYPE_ARM | CPU_ARCH_ABI64_32; +pub const CPU_TYPE_MC88000: u32 = 13; +pub const CPU_TYPE_SPARC: u32 = 14; +pub const CPU_TYPE_I860: u32 = 15; +pub const CPU_TYPE_ALPHA: u32 = 16; +pub const CPU_TYPE_POWERPC: u32 = 18; +pub const CPU_TYPE_POWERPC64: u32 = CPU_TYPE_POWERPC | CPU_ARCH_ABI64; + +/* + * Capability bits used in the definition of cpu_subtype. + */ +/// mask for feature flags +pub const CPU_SUBTYPE_MASK: u32 = 0xff00_0000; +/// 64 bit libraries +pub const CPU_SUBTYPE_LIB64: u32 = 0x8000_0000; +/// pointer authentication with versioned ABI +pub const CPU_SUBTYPE_PTRAUTH_ABI: u32 = 0x8000_0000; + +/// When selecting a slice, ANY will pick the slice with the best +/// grading for the selected cpu_type_t, unlike the "ALL" subtypes, +/// which are the slices that can run on any hardware for that cpu type. +pub const CPU_SUBTYPE_ANY: u32 = !0; + +/* + * Object files that are hand-crafted to run on any + * implementation of an architecture are tagged with + * CPU_SUBTYPE_MULTIPLE. This functions essentially the same as + * the "ALL" subtype of an architecture except that it allows us + * to easily find object files that may need to be modified + * whenever a new implementation of an architecture comes out. + * + * It is the responsibility of the implementor to make sure the + * software handles unsupported implementations elegantly. + */ +pub const CPU_SUBTYPE_MULTIPLE: u32 = !0; +pub const CPU_SUBTYPE_LITTLE_ENDIAN: u32 = 0; +pub const CPU_SUBTYPE_BIG_ENDIAN: u32 = 1; + +/* + * VAX subtypes (these do *not* necessary conform to the actual cpu + * ID assigned by DEC available via the SID register). + */ + +pub const CPU_SUBTYPE_VAX_ALL: u32 = 0; +pub const CPU_SUBTYPE_VAX780: u32 = 1; +pub const CPU_SUBTYPE_VAX785: u32 = 2; +pub const CPU_SUBTYPE_VAX750: u32 = 3; +pub const CPU_SUBTYPE_VAX730: u32 = 4; +pub const CPU_SUBTYPE_UVAXI: u32 = 5; +pub const CPU_SUBTYPE_UVAXII: u32 = 6; +pub const CPU_SUBTYPE_VAX8200: u32 = 7; +pub const CPU_SUBTYPE_VAX8500: u32 = 8; +pub const CPU_SUBTYPE_VAX8600: u32 = 9; +pub const CPU_SUBTYPE_VAX8650: u32 = 10; +pub const CPU_SUBTYPE_VAX8800: u32 = 11; +pub const CPU_SUBTYPE_UVAXIII: u32 = 12; + +/* + * 680x0 subtypes + * + * The subtype definitions here are unusual for historical reasons. + * NeXT used to consider 68030 code as generic 68000 code. For + * backwards compatability: + * + * CPU_SUBTYPE_MC68030 symbol has been preserved for source code + * compatability. + * + * CPU_SUBTYPE_MC680x0_ALL has been defined to be the same + * subtype as CPU_SUBTYPE_MC68030 for binary comatability. + * + * CPU_SUBTYPE_MC68030_ONLY has been added to allow new object + * files to be tagged as containing 68030-specific instructions. + */ + +pub const CPU_SUBTYPE_MC680X0_ALL: u32 = 1; +// compat +pub const CPU_SUBTYPE_MC68030: u32 = 1; +pub const CPU_SUBTYPE_MC68040: u32 = 2; +pub const CPU_SUBTYPE_MC68030_ONLY: u32 = 3; + +/* + * I386 subtypes + */ + +#[inline] +pub const fn cpu_subtype_intel(f: u32, m: u32) -> u32 { + f + (m << 4) +} + +pub const CPU_SUBTYPE_I386_ALL: u32 = cpu_subtype_intel(3, 0); +pub const CPU_SUBTYPE_386: u32 = cpu_subtype_intel(3, 0); +pub const CPU_SUBTYPE_486: u32 = cpu_subtype_intel(4, 0); +pub const CPU_SUBTYPE_486SX: u32 = cpu_subtype_intel(4, 8); +pub const CPU_SUBTYPE_586: u32 = cpu_subtype_intel(5, 0); +pub const CPU_SUBTYPE_PENT: u32 = cpu_subtype_intel(5, 0); +pub const CPU_SUBTYPE_PENTPRO: u32 = cpu_subtype_intel(6, 1); +pub const CPU_SUBTYPE_PENTII_M3: u32 = cpu_subtype_intel(6, 3); +pub const CPU_SUBTYPE_PENTII_M5: u32 = cpu_subtype_intel(6, 5); +pub const CPU_SUBTYPE_CELERON: u32 = cpu_subtype_intel(7, 6); +pub const CPU_SUBTYPE_CELERON_MOBILE: u32 = cpu_subtype_intel(7, 7); +pub const CPU_SUBTYPE_PENTIUM_3: u32 = cpu_subtype_intel(8, 0); +pub const CPU_SUBTYPE_PENTIUM_3_M: u32 = cpu_subtype_intel(8, 1); +pub const CPU_SUBTYPE_PENTIUM_3_XEON: u32 = cpu_subtype_intel(8, 2); +pub const CPU_SUBTYPE_PENTIUM_M: u32 = cpu_subtype_intel(9, 0); +pub const CPU_SUBTYPE_PENTIUM_4: u32 = cpu_subtype_intel(10, 0); +pub const CPU_SUBTYPE_PENTIUM_4_M: u32 = cpu_subtype_intel(10, 1); +pub const CPU_SUBTYPE_ITANIUM: u32 = cpu_subtype_intel(11, 0); +pub const CPU_SUBTYPE_ITANIUM_2: u32 = cpu_subtype_intel(11, 1); +pub const CPU_SUBTYPE_XEON: u32 = cpu_subtype_intel(12, 0); +pub const CPU_SUBTYPE_XEON_MP: u32 = cpu_subtype_intel(12, 1); + +#[inline] +pub const fn cpu_subtype_intel_family(x: u32) -> u32 { + x & 15 +} +pub const CPU_SUBTYPE_INTEL_FAMILY_MAX: u32 = 15; + +#[inline] +pub const fn cpu_subtype_intel_model(x: u32) -> u32 { + x >> 4 +} +pub const CPU_SUBTYPE_INTEL_MODEL_ALL: u32 = 0; + +/* + * X86 subtypes. + */ + +pub const CPU_SUBTYPE_X86_ALL: u32 = 3; +pub const CPU_SUBTYPE_X86_64_ALL: u32 = 3; +pub const CPU_SUBTYPE_X86_ARCH1: u32 = 4; +/// Haswell feature subset +pub const CPU_SUBTYPE_X86_64_H: u32 = 8; + +/* + * Mips subtypes. + */ + +pub const CPU_SUBTYPE_MIPS_ALL: u32 = 0; +pub const CPU_SUBTYPE_MIPS_R2300: u32 = 1; +pub const CPU_SUBTYPE_MIPS_R2600: u32 = 2; +pub const CPU_SUBTYPE_MIPS_R2800: u32 = 3; +/// pmax +pub const CPU_SUBTYPE_MIPS_R2000A: u32 = 4; +pub const CPU_SUBTYPE_MIPS_R2000: u32 = 5; +/// 3max +pub const CPU_SUBTYPE_MIPS_R3000A: u32 = 6; +pub const CPU_SUBTYPE_MIPS_R3000: u32 = 7; + +/* + * MC98000 (PowerPC) subtypes + */ +pub const CPU_SUBTYPE_MC98000_ALL: u32 = 0; +pub const CPU_SUBTYPE_MC98601: u32 = 1; + +/* + * HPPA subtypes for Hewlett-Packard HP-PA family of + * risc processors. Port by NeXT to 700 series. + */ + +pub const CPU_SUBTYPE_HPPA_ALL: u32 = 0; +pub const CPU_SUBTYPE_HPPA_7100LC: u32 = 1; + +/* + * MC88000 subtypes. + */ +pub const CPU_SUBTYPE_MC88000_ALL: u32 = 0; +pub const CPU_SUBTYPE_MC88100: u32 = 1; +pub const CPU_SUBTYPE_MC88110: u32 = 2; + +/* + * SPARC subtypes + */ +pub const CPU_SUBTYPE_SPARC_ALL: u32 = 0; + +/* + * I860 subtypes + */ +pub const CPU_SUBTYPE_I860_ALL: u32 = 0; +pub const CPU_SUBTYPE_I860_860: u32 = 1; + +/* + * PowerPC subtypes + */ +pub const CPU_SUBTYPE_POWERPC_ALL: u32 = 0; +pub const CPU_SUBTYPE_POWERPC_601: u32 = 1; +pub const CPU_SUBTYPE_POWERPC_602: u32 = 2; +pub const CPU_SUBTYPE_POWERPC_603: u32 = 3; +pub const CPU_SUBTYPE_POWERPC_603E: u32 = 4; +pub const CPU_SUBTYPE_POWERPC_603EV: u32 = 5; +pub const CPU_SUBTYPE_POWERPC_604: u32 = 6; +pub const CPU_SUBTYPE_POWERPC_604E: u32 = 7; +pub const CPU_SUBTYPE_POWERPC_620: u32 = 8; +pub const CPU_SUBTYPE_POWERPC_750: u32 = 9; +pub const CPU_SUBTYPE_POWERPC_7400: u32 = 10; +pub const CPU_SUBTYPE_POWERPC_7450: u32 = 11; +pub const CPU_SUBTYPE_POWERPC_970: u32 = 100; + +/* + * ARM subtypes + */ +pub const CPU_SUBTYPE_ARM_ALL: u32 = 0; +pub const CPU_SUBTYPE_ARM_V4T: u32 = 5; +pub const CPU_SUBTYPE_ARM_V6: u32 = 6; +pub const CPU_SUBTYPE_ARM_V5TEJ: u32 = 7; +pub const CPU_SUBTYPE_ARM_XSCALE: u32 = 8; +/// ARMv7-A and ARMv7-R +pub const CPU_SUBTYPE_ARM_V7: u32 = 9; +/// Cortex A9 +pub const CPU_SUBTYPE_ARM_V7F: u32 = 10; +/// Swift +pub const CPU_SUBTYPE_ARM_V7S: u32 = 11; +pub const CPU_SUBTYPE_ARM_V7K: u32 = 12; +pub const CPU_SUBTYPE_ARM_V8: u32 = 13; +/// Not meant to be run under xnu +pub const CPU_SUBTYPE_ARM_V6M: u32 = 14; +/// Not meant to be run under xnu +pub const CPU_SUBTYPE_ARM_V7M: u32 = 15; +/// Not meant to be run under xnu +pub const CPU_SUBTYPE_ARM_V7EM: u32 = 16; +/// Not meant to be run under xnu +pub const CPU_SUBTYPE_ARM_V8M: u32 = 17; + +/* + * ARM64 subtypes + */ +pub const CPU_SUBTYPE_ARM64_ALL: u32 = 0; +pub const CPU_SUBTYPE_ARM64_V8: u32 = 1; +pub const CPU_SUBTYPE_ARM64E: u32 = 2; + +/* + * ARM64_32 subtypes + */ +pub const CPU_SUBTYPE_ARM64_32_ALL: u32 = 0; +pub const CPU_SUBTYPE_ARM64_32_V8: u32 = 1; + +// Definitions from "/usr/include/mach/vm_prot.h". + +/// read permission +pub const VM_PROT_READ: u32 = 0x01; +/// write permission +pub const VM_PROT_WRITE: u32 = 0x02; +/// execute permission +pub const VM_PROT_EXECUTE: u32 = 0x04; + +// Definitions from https://opensource.apple.com/source/dyld/dyld-210.2.3/launch-cache/dyld_cache_format.h.auto.html + +/// The dyld cache header. +/// Corresponds to struct dyld_cache_header from dyld_cache_format.h. +/// This header has grown over time. Only the fields up to and including dyld_base_address +/// are guaranteed to be present. For all other fields, check the header size before +/// accessing the field. The header size is stored in mapping_offset; the mappings start +/// right after the theader. +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct DyldCacheHeader<E: Endian> { + /// e.g. "dyld_v0 i386" + pub magic: [u8; 16], + /// file offset to first dyld_cache_mapping_info + pub mapping_offset: U32<E>, // offset: 0x10 + /// number of dyld_cache_mapping_info entries + pub mapping_count: U32<E>, // offset: 0x14 + /// file offset to first dyld_cache_image_info + pub images_offset: U32<E>, // offset: 0x18 + /// number of dyld_cache_image_info entries + pub images_count: U32<E>, // offset: 0x1c + /// base address of dyld when cache was built + pub dyld_base_address: U64<E>, // offset: 0x20 + /// + reserved1: [u8; 32], // offset: 0x28 + /// file offset of where local symbols are stored + pub local_symbols_offset: U64<E>, // offset: 0x48 + /// size of local symbols information + pub local_symbols_size: U64<E>, // offset: 0x50 + /// unique value for each shared cache file + pub uuid: [u8; 16], // offset: 0x58 + /// + reserved2: [u8; 32], // offset: 0x68 + /// + reserved3: [u8; 32], // offset: 0x88 + /// + reserved4: [u8; 32], // offset: 0xa8 + /// + reserved5: [u8; 32], // offset: 0xc8 + /// + reserved6: [u8; 32], // offset: 0xe8 + /// + reserved7: [u8; 32], // offset: 0x108 + /// + reserved8: [u8; 32], // offset: 0x128 + /// + reserved9: [u8; 32], // offset: 0x148 + /// + reserved10: [u8; 32], // offset: 0x168 + /// file offset to first dyld_subcache_info + pub subcaches_offset: U32<E>, // offset: 0x188 + /// number of dyld_subcache_info entries + pub subcaches_count: U32<E>, // offset: 0x18c + /// the UUID of the .symbols subcache + pub symbols_subcache_uuid: [u8; 16], // offset: 0x190 + /// + reserved11: [u8; 32], // offset: 0x1a0 + /// file offset to first dyld_cache_image_info + /// Use this instead of images_offset if mapping_offset is at least 0x1c4. + pub images_across_all_subcaches_offset: U32<E>, // offset: 0x1c0 + /// number of dyld_cache_image_info entries + /// Use this instead of images_count if mapping_offset is at least 0x1c4. + pub images_across_all_subcaches_count: U32<E>, // offset: 0x1c4 +} + +/// Corresponds to struct dyld_cache_mapping_info from dyld_cache_format.h. +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct DyldCacheMappingInfo<E: Endian> { + /// + pub address: U64<E>, + /// + pub size: U64<E>, + /// + pub file_offset: U64<E>, + /// + pub max_prot: U32<E>, + /// + pub init_prot: U32<E>, +} + +/// Corresponds to struct dyld_cache_image_info from dyld_cache_format.h. +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct DyldCacheImageInfo<E: Endian> { + /// + pub address: U64<E>, + /// + pub mod_time: U64<E>, + /// + pub inode: U64<E>, + /// + pub path_file_offset: U32<E>, + /// + pub pad: U32<E>, +} + +/// Corresponds to a struct whose source code has not been published as of Nov 2021. +/// Added in the dyld cache version which shipped with macOS 12 / iOS 15. +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct DyldSubCacheInfo<E: Endian> { + /// The UUID of this subcache. + pub uuid: [u8; 16], + /// The size of this subcache plus all previous subcaches. + pub cumulative_size: U64<E>, +} + +// Definitions from "/usr/include/mach-o/loader.h". + +/* + * This header file describes the structures of the file format for "fat" + * architecture specific file (wrapper design). At the begining of the file + * there is one `FatHeader` structure followed by a number of `FatArch*` + * structures. For each architecture in the file, specified by a pair of + * cputype and cpusubtype, the `FatHeader` describes the file offset, file + * size and alignment in the file of the architecture specific member. + * The padded bytes in the file to place each member on it's specific alignment + * are defined to be read as zeros and can be left as "holes" if the file system + * can support them as long as they read as zeros. + * + * All structures defined here are always written and read to/from disk + * in big-endian order. + */ + +pub const FAT_MAGIC: u32 = 0xcafe_babe; +/// NXSwapLong(FAT_MAGIC) +pub const FAT_CIGAM: u32 = 0xbeba_feca; + +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct FatHeader { + /// FAT_MAGIC or FAT_MAGIC_64 + pub magic: U32<BigEndian>, + /// number of structs that follow + pub nfat_arch: U32<BigEndian>, +} + +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct FatArch32 { + /// cpu specifier (int) + pub cputype: U32<BigEndian>, + /// machine specifier (int) + pub cpusubtype: U32<BigEndian>, + /// file offset to this object file + pub offset: U32<BigEndian>, + /// size of this object file + pub size: U32<BigEndian>, + /// alignment as a power of 2 + pub align: U32<BigEndian>, +} + +/* + * The support for the 64-bit fat file format described here is a work in + * progress and not yet fully supported in all the Apple Developer Tools. + * + * When a slice is greater than 4mb or an offset to a slice is greater than 4mb + * then the 64-bit fat file format is used. + */ +pub const FAT_MAGIC_64: u32 = 0xcafe_babf; +/// NXSwapLong(FAT_MAGIC_64) +pub const FAT_CIGAM_64: u32 = 0xbfba_feca; + +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct FatArch64 { + /// cpu specifier (int) + pub cputype: U32<BigEndian>, + /// machine specifier (int) + pub cpusubtype: U32<BigEndian>, + /// file offset to this object file + pub offset: U64<BigEndian>, + /// size of this object file + pub size: U64<BigEndian>, + /// alignment as a power of 2 + pub align: U32<BigEndian>, + /// reserved + pub reserved: U32<BigEndian>, +} + +// Definitions from "/usr/include/mach-o/loader.h". + +/// The 32-bit mach header. +/// +/// Appears at the very beginning of the object file for 32-bit architectures. +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct MachHeader32<E: Endian> { + /// mach magic number identifier + pub magic: U32<BigEndian>, + /// cpu specifier + pub cputype: U32<E>, + /// machine specifier + pub cpusubtype: U32<E>, + /// type of file + pub filetype: U32<E>, + /// number of load commands + pub ncmds: U32<E>, + /// the size of all the load commands + pub sizeofcmds: U32<E>, + /// flags + pub flags: U32<E>, +} + +// Values for `MachHeader32::magic`. +/// the mach magic number +pub const MH_MAGIC: u32 = 0xfeed_face; +/// NXSwapInt(MH_MAGIC) +pub const MH_CIGAM: u32 = 0xcefa_edfe; + +/// The 64-bit mach header. +/// +/// Appears at the very beginning of object files for 64-bit architectures. +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct MachHeader64<E: Endian> { + /// mach magic number identifier + pub magic: U32<BigEndian>, + /// cpu specifier + pub cputype: U32<E>, + /// machine specifier + pub cpusubtype: U32<E>, + /// type of file + pub filetype: U32<E>, + /// number of load commands + pub ncmds: U32<E>, + /// the size of all the load commands + pub sizeofcmds: U32<E>, + /// flags + pub flags: U32<E>, + /// reserved + pub reserved: U32<E>, +} + +// Values for `MachHeader64::magic`. +/// the 64-bit mach magic number +pub const MH_MAGIC_64: u32 = 0xfeed_facf; +/// NXSwapInt(MH_MAGIC_64) +pub const MH_CIGAM_64: u32 = 0xcffa_edfe; + +/* + * The layout of the file depends on the filetype. For all but the MH_OBJECT + * file type the segments are padded out and aligned on a segment alignment + * boundary for efficient demand pageing. The MH_EXECUTE, MH_FVMLIB, MH_DYLIB, + * MH_DYLINKER and MH_BUNDLE file types also have the headers included as part + * of their first segment. + * + * The file type MH_OBJECT is a compact format intended as output of the + * assembler and input (and possibly output) of the link editor (the .o + * format). All sections are in one unnamed segment with no segment padding. + * This format is used as an executable format when the file is so small the + * segment padding greatly increases its size. + * + * The file type MH_PRELOAD is an executable format intended for things that + * are not executed under the kernel (proms, stand alones, kernels, etc). The + * format can be executed under the kernel but may demand paged it and not + * preload it before execution. + * + * A core file is in MH_CORE format and can be any in an arbritray legal + * Mach-O file. + */ + +// Values for `MachHeader*::filetype`. +/// relocatable object file +pub const MH_OBJECT: u32 = 0x1; +/// demand paged executable file +pub const MH_EXECUTE: u32 = 0x2; +/// fixed VM shared library file +pub const MH_FVMLIB: u32 = 0x3; +/// core file +pub const MH_CORE: u32 = 0x4; +/// preloaded executable file +pub const MH_PRELOAD: u32 = 0x5; +/// dynamically bound shared library +pub const MH_DYLIB: u32 = 0x6; +/// dynamic link editor +pub const MH_DYLINKER: u32 = 0x7; +/// dynamically bound bundle file +pub const MH_BUNDLE: u32 = 0x8; +/// shared library stub for static linking only, no section contents +pub const MH_DYLIB_STUB: u32 = 0x9; +/// companion file with only debug sections +pub const MH_DSYM: u32 = 0xa; +/// x86_64 kexts +pub const MH_KEXT_BUNDLE: u32 = 0xb; +/// set of mach-o's +pub const MH_FILESET: u32 = 0xc; + +// Values for `MachHeader*::flags`. +/// the object file has no undefined references +pub const MH_NOUNDEFS: u32 = 0x1; +/// the object file is the output of an incremental link against a base file and can't be link edited again +pub const MH_INCRLINK: u32 = 0x2; +/// the object file is input for the dynamic linker and can't be staticly link edited again +pub const MH_DYLDLINK: u32 = 0x4; +/// the object file's undefined references are bound by the dynamic linker when loaded. +pub const MH_BINDATLOAD: u32 = 0x8; +/// the file has its dynamic undefined references prebound. +pub const MH_PREBOUND: u32 = 0x10; +/// the file has its read-only and read-write segments split +pub const MH_SPLIT_SEGS: u32 = 0x20; +/// the shared library init routine is to be run lazily via catching memory faults to its writeable segments (obsolete) +pub const MH_LAZY_INIT: u32 = 0x40; +/// the image is using two-level name space bindings +pub const MH_TWOLEVEL: u32 = 0x80; +/// the executable is forcing all images to use flat name space bindings +pub const MH_FORCE_FLAT: u32 = 0x100; +/// this umbrella guarantees no multiple defintions of symbols in its sub-images so the two-level namespace hints can always be used. +pub const MH_NOMULTIDEFS: u32 = 0x200; +/// do not have dyld notify the prebinding agent about this executable +pub const MH_NOFIXPREBINDING: u32 = 0x400; +/// the binary is not prebound but can have its prebinding redone. only used when MH_PREBOUND is not set. +pub const MH_PREBINDABLE: u32 = 0x800; +/// 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. +pub const MH_ALLMODSBOUND: u32 = 0x1000; +/// safe to divide up the sections into sub-sections via symbols for dead code stripping +pub const MH_SUBSECTIONS_VIA_SYMBOLS: u32 = 0x2000; +/// the binary has been canonicalized via the unprebind operation +pub const MH_CANONICAL: u32 = 0x4000; +/// the final linked image contains external weak symbols +pub const MH_WEAK_DEFINES: u32 = 0x8000; +/// the final linked image uses weak symbols +pub const MH_BINDS_TO_WEAK: u32 = 0x10000; +/// When this bit is set, all stacks in the task will be given stack execution privilege. Only used in MH_EXECUTE filetypes. +pub const MH_ALLOW_STACK_EXECUTION: u32 = 0x20000; +/// When this bit is set, the binary declares it is safe for use in processes with uid zero +pub const MH_ROOT_SAFE: u32 = 0x40000; +/// When this bit is set, the binary declares it is safe for use in processes when issetugid() is true +pub const MH_SETUID_SAFE: u32 = 0x80000; +/// 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 +pub const MH_NO_REEXPORTED_DYLIBS: u32 = 0x10_0000; +/// When this bit is set, the OS will load the main executable at a random address. Only used in MH_EXECUTE filetypes. +pub const MH_PIE: u32 = 0x20_0000; +/// 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. +pub const MH_DEAD_STRIPPABLE_DYLIB: u32 = 0x40_0000; +/// Contains a section of type S_THREAD_LOCAL_VARIABLES +pub const MH_HAS_TLV_DESCRIPTORS: u32 = 0x80_0000; +/// When this bit is set, the OS will run the main executable with a non-executable heap even on platforms (e.g. i386) that don't require it. Only used in MH_EXECUTE filetypes. +pub const MH_NO_HEAP_EXECUTION: u32 = 0x100_0000; +/// The code was linked for use in an application extension. +pub const MH_APP_EXTENSION_SAFE: u32 = 0x0200_0000; +/// The external symbols listed in the nlist symbol table do not include all the symbols listed in the dyld info. +pub const MH_NLIST_OUTOFSYNC_WITH_DYLDINFO: u32 = 0x0400_0000; +/// Allow LC_MIN_VERSION_MACOS and LC_BUILD_VERSION load commands with +/// the platforms macOS, iOSMac, iOSSimulator, tvOSSimulator and watchOSSimulator. +pub const MH_SIM_SUPPORT: u32 = 0x0800_0000; +/// 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. +pub const MH_DYLIB_IN_CACHE: u32 = 0x8000_0000; + +/// Common fields at the start of every load command. +/// +/// The load commands directly follow the mach_header. The total size of all +/// of the commands is given by the sizeofcmds field in the mach_header. All +/// load commands must have as their first two fields `cmd` and `cmdsize`. The `cmd` +/// field is filled in with a constant for that command type. Each command type +/// has a structure specifically for it. The `cmdsize` field is the size in bytes +/// of the particular load command structure plus anything that follows it that +/// is a part of the load command (i.e. section structures, strings, etc.). To +/// advance to the next load command the `cmdsize` can be added to the offset or +/// pointer of the current load command. The `cmdsize` for 32-bit architectures +/// MUST be a multiple of 4 bytes and for 64-bit architectures MUST be a multiple +/// of 8 bytes (these are forever the maximum alignment of any load commands). +/// The padded bytes must be zero. All tables in the object file must also +/// follow these rules so the file can be memory mapped. Otherwise the pointers +/// to these tables will not work well or at all on some machines. With all +/// padding zeroed like objects will compare byte for byte. +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct LoadCommand<E: Endian> { + /// Type of load command. + /// + /// One of the `LC_*` constants. + pub cmd: U32<E>, + /// Total size of command in bytes. + pub cmdsize: U32<E>, +} + +/* + * After MacOS X 10.1 when a new load command is added that is required to be + * understood by the dynamic linker for the image to execute properly the + * LC_REQ_DYLD bit will be or'ed into the load command constant. If the dynamic + * linker sees such a load command it it does not understand will issue a + * "unknown load command required for execution" error and refuse to use the + * image. Other load commands without this bit that are not understood will + * simply be ignored. + */ +pub const LC_REQ_DYLD: u32 = 0x8000_0000; + +/* Constants for the cmd field of all load commands, the type */ +/// segment of this file to be mapped +pub const LC_SEGMENT: u32 = 0x1; +/// link-edit stab symbol table info +pub const LC_SYMTAB: u32 = 0x2; +/// link-edit gdb symbol table info (obsolete) +pub const LC_SYMSEG: u32 = 0x3; +/// thread +pub const LC_THREAD: u32 = 0x4; +/// unix thread (includes a stack) +pub const LC_UNIXTHREAD: u32 = 0x5; +/// load a specified fixed VM shared library +pub const LC_LOADFVMLIB: u32 = 0x6; +/// fixed VM shared library identification +pub const LC_IDFVMLIB: u32 = 0x7; +/// object identification info (obsolete) +pub const LC_IDENT: u32 = 0x8; +/// fixed VM file inclusion (internal use) +pub const LC_FVMFILE: u32 = 0x9; +/// prepage command (internal use) +pub const LC_PREPAGE: u32 = 0xa; +/// dynamic link-edit symbol table info +pub const LC_DYSYMTAB: u32 = 0xb; +/// load a dynamically linked shared library +pub const LC_LOAD_DYLIB: u32 = 0xc; +/// dynamically linked shared lib ident +pub const LC_ID_DYLIB: u32 = 0xd; +/// load a dynamic linker +pub const LC_LOAD_DYLINKER: u32 = 0xe; +/// dynamic linker identification +pub const LC_ID_DYLINKER: u32 = 0xf; +/// modules prebound for a dynamically linked shared library +pub const LC_PREBOUND_DYLIB: u32 = 0x10; +/// image routines +pub const LC_ROUTINES: u32 = 0x11; +/// sub framework +pub const LC_SUB_FRAMEWORK: u32 = 0x12; +/// sub umbrella +pub const LC_SUB_UMBRELLA: u32 = 0x13; +/// sub client +pub const LC_SUB_CLIENT: u32 = 0x14; +/// sub library +pub const LC_SUB_LIBRARY: u32 = 0x15; +/// two-level namespace lookup hints +pub const LC_TWOLEVEL_HINTS: u32 = 0x16; +/// prebind checksum +pub const LC_PREBIND_CKSUM: u32 = 0x17; +/// load a dynamically linked shared library that is allowed to be missing +/// (all symbols are weak imported). +pub const LC_LOAD_WEAK_DYLIB: u32 = 0x18 | LC_REQ_DYLD; +/// 64-bit segment of this file to be mapped +pub const LC_SEGMENT_64: u32 = 0x19; +/// 64-bit image routines +pub const LC_ROUTINES_64: u32 = 0x1a; +/// the uuid +pub const LC_UUID: u32 = 0x1b; +/// runpath additions +pub const LC_RPATH: u32 = 0x1c | LC_REQ_DYLD; +/// local of code signature +pub const LC_CODE_SIGNATURE: u32 = 0x1d; +/// local of info to split segments +pub const LC_SEGMENT_SPLIT_INFO: u32 = 0x1e; +/// load and re-export dylib +pub const LC_REEXPORT_DYLIB: u32 = 0x1f | LC_REQ_DYLD; +/// delay load of dylib until first use +pub const LC_LAZY_LOAD_DYLIB: u32 = 0x20; +/// encrypted segment information +pub const LC_ENCRYPTION_INFO: u32 = 0x21; +/// compressed dyld information +pub const LC_DYLD_INFO: u32 = 0x22; +/// compressed dyld information only +pub const LC_DYLD_INFO_ONLY: u32 = 0x22 | LC_REQ_DYLD; +/// load upward dylib +pub const LC_LOAD_UPWARD_DYLIB: u32 = 0x23 | LC_REQ_DYLD; +/// build for MacOSX min OS version +pub const LC_VERSION_MIN_MACOSX: u32 = 0x24; +/// build for iPhoneOS min OS version +pub const LC_VERSION_MIN_IPHONEOS: u32 = 0x25; +/// compressed table of function start addresses +pub const LC_FUNCTION_STARTS: u32 = 0x26; +/// string for dyld to treat like environment variable +pub const LC_DYLD_ENVIRONMENT: u32 = 0x27; +/// replacement for LC_UNIXTHREAD +pub const LC_MAIN: u32 = 0x28 | LC_REQ_DYLD; +/// table of non-instructions in __text +pub const LC_DATA_IN_CODE: u32 = 0x29; +/// source version used to build binary +pub const LC_SOURCE_VERSION: u32 = 0x2A; +/// Code signing DRs copied from linked dylibs +pub const LC_DYLIB_CODE_SIGN_DRS: u32 = 0x2B; +/// 64-bit encrypted segment information +pub const LC_ENCRYPTION_INFO_64: u32 = 0x2C; +/// linker options in MH_OBJECT files +pub const LC_LINKER_OPTION: u32 = 0x2D; +/// optimization hints in MH_OBJECT files +pub const LC_LINKER_OPTIMIZATION_HINT: u32 = 0x2E; +/// build for AppleTV min OS version +pub const LC_VERSION_MIN_TVOS: u32 = 0x2F; +/// build for Watch min OS version +pub const LC_VERSION_MIN_WATCHOS: u32 = 0x30; +/// arbitrary data included within a Mach-O file +pub const LC_NOTE: u32 = 0x31; +/// build for platform min OS version +pub const LC_BUILD_VERSION: u32 = 0x32; +/// used with `LinkeditDataCommand`, payload is trie +pub const LC_DYLD_EXPORTS_TRIE: u32 = 0x33 | LC_REQ_DYLD; +/// used with `LinkeditDataCommand` +pub const LC_DYLD_CHAINED_FIXUPS: u32 = 0x34 | LC_REQ_DYLD; +/// used with `FilesetEntryCommand` +pub const LC_FILESET_ENTRY: u32 = 0x35 | LC_REQ_DYLD; + +/// A variable length string in a load command. +/// +/// The strings are stored just after the load command structure and +/// the offset is from the start of the load command structure. The size +/// of the string is reflected in the `cmdsize` field of the load command. +/// Once again any padded bytes to bring the `cmdsize` field to a multiple +/// of 4 bytes must be zero. +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct LcStr<E: Endian> { + /// offset to the string + pub offset: U32<E>, +} + +/// 32-bit segment load command. +/// +/// The segment load command indicates that a part of this file is to be +/// mapped into the task's address space. The size of this segment in memory, +/// vmsize, maybe equal to or larger than the amount to map from this file, +/// filesize. The file is mapped starting at fileoff to the beginning of +/// the segment in memory, vmaddr. The rest of the memory of the segment, +/// if any, is allocated zero fill on demand. The segment's maximum virtual +/// memory protection and initial virtual memory protection are specified +/// by the maxprot and initprot fields. If the segment has sections then the +/// `Section32` structures directly follow the segment command and their size is +/// reflected in `cmdsize`. +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct SegmentCommand32<E: Endian> { + /// LC_SEGMENT + pub cmd: U32<E>, + /// includes sizeof section structs + pub cmdsize: U32<E>, + /// segment name + pub segname: [u8; 16], + /// memory address of this segment + pub vmaddr: U32<E>, + /// memory size of this segment + pub vmsize: U32<E>, + /// file offset of this segment + pub fileoff: U32<E>, + /// amount to map from the file + pub filesize: U32<E>, + /// maximum VM protection + pub maxprot: U32<E>, + /// initial VM protection + pub initprot: U32<E>, + /// number of sections in segment + pub nsects: U32<E>, + /// flags + pub flags: U32<E>, +} + +/// 64-bit segment load command. +/// +/// The 64-bit segment load command indicates that a part of this file is to be +/// mapped into a 64-bit task's address space. If the 64-bit segment has +/// sections then `Section64` structures directly follow the 64-bit segment +/// command and their size is reflected in `cmdsize`. +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct SegmentCommand64<E: Endian> { + /// LC_SEGMENT_64 + pub cmd: U32<E>, + /// includes sizeof section_64 structs + pub cmdsize: U32<E>, + /// segment name + pub segname: [u8; 16], + /// memory address of this segment + pub vmaddr: U64<E>, + /// memory size of this segment + pub vmsize: U64<E>, + /// file offset of this segment + pub fileoff: U64<E>, + /// amount to map from the file + pub filesize: U64<E>, + /// maximum VM protection + pub maxprot: U32<E>, + /// initial VM protection + pub initprot: U32<E>, + /// number of sections in segment + pub nsects: U32<E>, + /// flags + pub flags: U32<E>, +} + +// Values for `SegmentCommand*::flags`. +/// the file contents for this segment is for the high part of the VM space, the low part is zero filled (for stacks in core files) +pub const SG_HIGHVM: u32 = 0x1; +/// this segment is the VM that is allocated by a fixed VM library, for overlap checking in the link editor +pub const SG_FVMLIB: u32 = 0x2; +/// this segment has nothing that was relocated in it and nothing relocated to it, that is it maybe safely replaced without relocation +pub const SG_NORELOC: u32 = 0x4; +/// This segment is protected. If the segment starts at file offset 0, the first page of the segment is not protected. All other pages of the segment are protected. +pub const SG_PROTECTED_VERSION_1: u32 = 0x8; +/// This segment is made read-only after fixups +pub const SG_READ_ONLY: u32 = 0x10; + +/* + * A segment is made up of zero or more sections. Non-MH_OBJECT files have + * all of their segments with the proper sections in each, and padded to the + * specified segment alignment when produced by the link editor. The first + * segment of a MH_EXECUTE and MH_FVMLIB format file contains the mach_header + * and load commands of the object file before its first section. The zero + * fill sections are always last in their segment (in all formats). This + * allows the zeroed segment padding to be mapped into memory where zero fill + * sections might be. The gigabyte zero fill sections, those with the section + * type S_GB_ZEROFILL, can only be in a segment with sections of this type. + * These segments are then placed after all other segments. + * + * The MH_OBJECT format has all of its sections in one segment for + * compactness. There is no padding to a specified segment boundary and the + * mach_header and load commands are not part of the segment. + * + * Sections with the same section name, sectname, going into the same segment, + * segname, are combined by the link editor. The resulting section is aligned + * to the maximum alignment of the combined sections and is the new section's + * alignment. The combined sections are aligned to their original alignment in + * the combined section. Any padded bytes to get the specified alignment are + * zeroed. + * + * The format of the relocation entries referenced by the reloff and nreloc + * fields of the section structure for mach object files is described in the + * header file <reloc.h>. + */ +/// 32-bit section. +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct Section32<E: Endian> { + /// name of this section + pub sectname: [u8; 16], + /// segment this section goes in + pub segname: [u8; 16], + /// memory address of this section + pub addr: U32<E>, + /// size in bytes of this section + pub size: U32<E>, + /// file offset of this section + pub offset: U32<E>, + /// section alignment (power of 2) + pub align: U32<E>, + /// file offset of relocation entries + pub reloff: U32<E>, + /// number of relocation entries + pub nreloc: U32<E>, + /// flags (section type and attributes) + pub flags: U32<E>, + /// reserved (for offset or index) + pub reserved1: U32<E>, + /// reserved (for count or sizeof) + pub reserved2: U32<E>, +} + +/// 64-bit section. +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct Section64<E: Endian> { + /// name of this section + pub sectname: [u8; 16], + /// segment this section goes in + pub segname: [u8; 16], + /// memory address of this section + pub addr: U64<E>, + /// size in bytes of this section + pub size: U64<E>, + /// file offset of this section + pub offset: U32<E>, + /// section alignment (power of 2) + pub align: U32<E>, + /// file offset of relocation entries + pub reloff: U32<E>, + /// number of relocation entries + pub nreloc: U32<E>, + /// flags (section type and attributes) + pub flags: U32<E>, + /// reserved (for offset or index) + pub reserved1: U32<E>, + /// reserved (for count or sizeof) + pub reserved2: U32<E>, + /// reserved + pub reserved3: U32<E>, +} + +/* + * The flags field of a section structure is separated into two parts a section + * type and section attributes. The section types are mutually exclusive (it + * can only have one type) but the section attributes are not (it may have more + * than one attribute). + */ +/// 256 section types +pub const SECTION_TYPE: u32 = 0x0000_00ff; +/// 24 section attributes +pub const SECTION_ATTRIBUTES: u32 = 0xffff_ff00; + +/* Constants for the type of a section */ +/// regular section +pub const S_REGULAR: u32 = 0x0; +/// zero fill on demand section +pub const S_ZEROFILL: u32 = 0x1; +/// section with only literal C strings +pub const S_CSTRING_LITERALS: u32 = 0x2; +/// section with only 4 byte literals +pub const S_4BYTE_LITERALS: u32 = 0x3; +/// section with only 8 byte literals +pub const S_8BYTE_LITERALS: u32 = 0x4; +/// section with only pointers to literals +pub const S_LITERAL_POINTERS: u32 = 0x5; +/* + * For the two types of symbol pointers sections and the symbol stubs section + * they have indirect symbol table entries. For each of the entries in the + * section the indirect symbol table entries, in corresponding order in the + * indirect symbol table, start at the index stored in the reserved1 field + * of the section structure. Since the indirect symbol table entries + * correspond to the entries in the section the number of indirect symbol table + * entries is inferred from the size of the section divided by the size of the + * entries in the section. For symbol pointers sections the size of the entries + * in the section is 4 bytes and for symbol stubs sections the byte size of the + * stubs is stored in the reserved2 field of the section structure. + */ +/// section with only non-lazy symbol pointers +pub const S_NON_LAZY_SYMBOL_POINTERS: u32 = 0x6; +/// section with only lazy symbol pointers +pub const S_LAZY_SYMBOL_POINTERS: u32 = 0x7; +/// section with only symbol stubs, byte size of stub in the reserved2 field +pub const S_SYMBOL_STUBS: u32 = 0x8; +/// section with only function pointers for initialization +pub const S_MOD_INIT_FUNC_POINTERS: u32 = 0x9; +/// section with only function pointers for termination +pub const S_MOD_TERM_FUNC_POINTERS: u32 = 0xa; +/// section contains symbols that are to be coalesced +pub const S_COALESCED: u32 = 0xb; +/// zero fill on demand section (that can be larger than 4 gigabytes) +pub const S_GB_ZEROFILL: u32 = 0xc; +/// section with only pairs of function pointers for interposing +pub const S_INTERPOSING: u32 = 0xd; +/// section with only 16 byte literals +pub const S_16BYTE_LITERALS: u32 = 0xe; +/// section contains DTrace Object Format +pub const S_DTRACE_DOF: u32 = 0xf; +/// section with only lazy symbol pointers to lazy loaded dylibs +pub const S_LAZY_DYLIB_SYMBOL_POINTERS: u32 = 0x10; +/* + * Section types to support thread local variables + */ +/// template of initial values for TLVs +pub const S_THREAD_LOCAL_REGULAR: u32 = 0x11; +/// template of initial values for TLVs +pub const S_THREAD_LOCAL_ZEROFILL: u32 = 0x12; +/// TLV descriptors +pub const S_THREAD_LOCAL_VARIABLES: u32 = 0x13; +/// pointers to TLV descriptors +pub const S_THREAD_LOCAL_VARIABLE_POINTERS: u32 = 0x14; +/// functions to call to initialize TLV values +pub const S_THREAD_LOCAL_INIT_FUNCTION_POINTERS: u32 = 0x15; +/// 32-bit offsets to initializers +pub const S_INIT_FUNC_OFFSETS: u32 = 0x16; + +/* + * Constants for the section attributes part of the flags field of a section + * structure. + */ +/// User setable attributes +pub const SECTION_ATTRIBUTES_USR: u32 = 0xff00_0000; +/// section contains only true machine instructions +pub const S_ATTR_PURE_INSTRUCTIONS: u32 = 0x8000_0000; +/// section contains coalesced symbols that are not to be in a ranlib table of contents +pub const S_ATTR_NO_TOC: u32 = 0x4000_0000; +/// ok to strip static symbols in this section in files with the MH_DYLDLINK flag +pub const S_ATTR_STRIP_STATIC_SYMS: u32 = 0x2000_0000; +/// no dead stripping +pub const S_ATTR_NO_DEAD_STRIP: u32 = 0x1000_0000; +/// blocks are live if they reference live blocks +pub const S_ATTR_LIVE_SUPPORT: u32 = 0x0800_0000; +/// Used with i386 code stubs written on by dyld +pub const S_ATTR_SELF_MODIFYING_CODE: u32 = 0x0400_0000; +/* + * If a segment contains any sections marked with S_ATTR_DEBUG then all + * sections in that segment must have this attribute. No section other than + * a section marked with this attribute may reference the contents of this + * section. A section with this attribute may contain no symbols and must have + * a section type S_REGULAR. The static linker will not copy section contents + * from sections with this attribute into its output file. These sections + * generally contain DWARF debugging info. + */ +/// a debug section +pub const S_ATTR_DEBUG: u32 = 0x0200_0000; +/// system setable attributes +pub const SECTION_ATTRIBUTES_SYS: u32 = 0x00ff_ff00; +/// section contains some machine instructions +pub const S_ATTR_SOME_INSTRUCTIONS: u32 = 0x0000_0400; +/// section has external relocation entries +pub const S_ATTR_EXT_RELOC: u32 = 0x0000_0200; +/// section has local relocation entries +pub const S_ATTR_LOC_RELOC: u32 = 0x0000_0100; + +/* + * The names of segments and sections in them are mostly meaningless to the + * link-editor. But there are few things to support traditional UNIX + * executables that require the link-editor and assembler to use some names + * agreed upon by convention. + * + * The initial protection of the "__TEXT" segment has write protection turned + * off (not writeable). + * + * The link-editor will allocate common symbols at the end of the "__common" + * section in the "__DATA" segment. It will create the section and segment + * if needed. + */ + +/* The currently known segment names and the section names in those segments */ + +/// the pagezero segment which has no protections and catches NULL references for MH_EXECUTE files +pub const SEG_PAGEZERO: &str = "__PAGEZERO"; + +/// the tradition UNIX text segment +pub const SEG_TEXT: &str = "__TEXT"; +/// the real text part of the text section no headers, and no padding +pub const SECT_TEXT: &str = "__text"; +/// the fvmlib initialization section +pub const SECT_FVMLIB_INIT0: &str = "__fvmlib_init0"; +/// the section following the fvmlib initialization section +pub const SECT_FVMLIB_INIT1: &str = "__fvmlib_init1"; + +/// the tradition UNIX data segment +pub const SEG_DATA: &str = "__DATA"; +/// the real initialized data section no padding, no bss overlap +pub const SECT_DATA: &str = "__data"; +/// the real uninitialized data section no padding +pub const SECT_BSS: &str = "__bss"; +/// the section common symbols are allocated in by the link editor +pub const SECT_COMMON: &str = "__common"; + +/// objective-C runtime segment +pub const SEG_OBJC: &str = "__OBJC"; +/// symbol table +pub const SECT_OBJC_SYMBOLS: &str = "__symbol_table"; +/// module information +pub const SECT_OBJC_MODULES: &str = "__module_info"; +/// string table +pub const SECT_OBJC_STRINGS: &str = "__selector_strs"; +/// string table +pub const SECT_OBJC_REFS: &str = "__selector_refs"; + +/// the icon segment +pub const SEG_ICON: &str = "__ICON"; +/// the icon headers +pub const SECT_ICON_HEADER: &str = "__header"; +/// the icons in tiff format +pub const SECT_ICON_TIFF: &str = "__tiff"; + +/// the segment containing all structs created and maintained by the link editor. Created with -seglinkedit option to ld(1) for MH_EXECUTE and FVMLIB file types only +pub const SEG_LINKEDIT: &str = "__LINKEDIT"; + +/// the segment overlapping with linkedit containing linking information +pub const SEG_LINKINFO: &str = "__LINKINFO"; + +/// the unix stack segment +pub const SEG_UNIXSTACK: &str = "__UNIXSTACK"; + +/// the segment for the self (dyld) modifing code stubs that has read, write and execute permissions +pub const SEG_IMPORT: &str = "__IMPORT"; + +/* + * Fixed virtual memory shared libraries are identified by two things. The + * target pathname (the name of the library as found for execution), and the + * minor version number. The address of where the headers are loaded is in + * header_addr. (THIS IS OBSOLETE and no longer supported). + */ +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct Fvmlib<E: Endian> { + /// library's target pathname + pub name: LcStr<E>, + /// library's minor version number + pub minor_version: U32<E>, + /// library's header address + pub header_addr: U32<E>, +} + +/* + * A fixed virtual shared library (filetype == MH_FVMLIB in the mach header) + * contains a `FvmlibCommand` (cmd == LC_IDFVMLIB) to identify the library. + * An object that uses a fixed virtual shared library also contains a + * `FvmlibCommand` (cmd == LC_LOADFVMLIB) for each library it uses. + * (THIS IS OBSOLETE and no longer supported). + */ +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct FvmlibCommand<E: Endian> { + /// LC_IDFVMLIB or LC_LOADFVMLIB + pub cmd: U32<E>, + /// includes pathname string + pub cmdsize: U32<E>, + /// the library identification + pub fvmlib: Fvmlib<E>, +} + +/* + * Dynamicly linked shared libraries are identified by two things. The + * pathname (the name of the library as found for execution), and the + * compatibility version number. The pathname must match and the compatibility + * number in the user of the library must be greater than or equal to the + * library being used. The time stamp is used to record the time a library was + * built and copied into user so it can be use to determined if the library used + * at runtime is exactly the same as used to built the program. + */ +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct Dylib<E: Endian> { + /// library's path name + pub name: LcStr<E>, + /// library's build time stamp + pub timestamp: U32<E>, + /// library's current version number + pub current_version: U32<E>, + /// library's compatibility vers number + pub compatibility_version: U32<E>, +} + +/* + * A dynamically linked shared library (filetype == MH_DYLIB in the mach header) + * contains a `DylibCommand` (cmd == LC_ID_DYLIB) to identify the library. + * An object that uses a dynamically linked shared library also contains a + * `DylibCommand` (cmd == LC_LOAD_DYLIB, LC_LOAD_WEAK_DYLIB, or + * LC_REEXPORT_DYLIB) for each library it uses. + */ +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct DylibCommand<E: Endian> { + /// LC_ID_DYLIB, LC_LOAD_{,WEAK_}DYLIB, LC_REEXPORT_DYLIB + pub cmd: U32<E>, + /// includes pathname string + pub cmdsize: U32<E>, + /// the library identification + pub dylib: Dylib<E>, +} + +/* + * A dynamically linked shared library may be a subframework of an umbrella + * framework. If so it will be linked with "-umbrella umbrella_name" where + * Where "umbrella_name" is the name of the umbrella framework. A subframework + * can only be linked against by its umbrella framework or other subframeworks + * that are part of the same umbrella framework. Otherwise the static link + * editor produces an error and states to link against the umbrella framework. + * The name of the umbrella framework for subframeworks is recorded in the + * following structure. + */ +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct SubFrameworkCommand<E: Endian> { + /// LC_SUB_FRAMEWORK + pub cmd: U32<E>, + /// includes umbrella string + pub cmdsize: U32<E>, + /// the umbrella framework name + pub umbrella: LcStr<E>, +} + +/* + * For dynamically linked shared libraries that are subframework of an umbrella + * framework they can allow clients other than the umbrella framework or other + * subframeworks in the same umbrella framework. To do this the subframework + * is built with "-allowable_client client_name" and an LC_SUB_CLIENT load + * command is created for each -allowable_client flag. The client_name is + * usually a framework name. It can also be a name used for bundles clients + * where the bundle is built with "-client_name client_name". + */ +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct SubClientCommand<E: Endian> { + /// LC_SUB_CLIENT + pub cmd: U32<E>, + /// includes client string + pub cmdsize: U32<E>, + /// the client name + pub client: LcStr<E>, +} + +/* + * A dynamically linked shared library may be a sub_umbrella of an umbrella + * framework. If so it will be linked with "-sub_umbrella umbrella_name" where + * Where "umbrella_name" is the name of the sub_umbrella framework. When + * staticly linking when -twolevel_namespace is in effect a twolevel namespace + * umbrella framework will only cause its subframeworks and those frameworks + * listed as sub_umbrella frameworks to be implicited linked in. Any other + * dependent dynamic libraries will not be linked it when -twolevel_namespace + * is in effect. The primary library recorded by the static linker when + * resolving a symbol in these libraries will be the umbrella framework. + * Zero or more sub_umbrella frameworks may be use by an umbrella framework. + * The name of a sub_umbrella framework is recorded in the following structure. + */ +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct SubUmbrellaCommand<E: Endian> { + /// LC_SUB_UMBRELLA + pub cmd: U32<E>, + /// includes sub_umbrella string + pub cmdsize: U32<E>, + /// the sub_umbrella framework name + pub sub_umbrella: LcStr<E>, +} + +/* + * A dynamically linked shared library may be a sub_library of another shared + * library. If so it will be linked with "-sub_library library_name" where + * Where "library_name" is the name of the sub_library shared library. When + * staticly linking when -twolevel_namespace is in effect a twolevel namespace + * shared library will only cause its subframeworks and those frameworks + * listed as sub_umbrella frameworks and libraries listed as sub_libraries to + * be implicited linked in. Any other dependent dynamic libraries will not be + * linked it when -twolevel_namespace is in effect. The primary library + * recorded by the static linker when resolving a symbol in these libraries + * will be the umbrella framework (or dynamic library). Zero or more sub_library + * shared libraries may be use by an umbrella framework or (or dynamic library). + * The name of a sub_library framework is recorded in the following structure. + * For example /usr/lib/libobjc_profile.A.dylib would be recorded as "libobjc". + */ +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct SubLibraryCommand<E: Endian> { + /// LC_SUB_LIBRARY + pub cmd: U32<E>, + /// includes sub_library string + pub cmdsize: U32<E>, + /// the sub_library name + pub sub_library: LcStr<E>, +} + +/* + * A program (filetype == MH_EXECUTE) that is + * prebound to its dynamic libraries has one of these for each library that + * the static linker used in prebinding. It contains a bit vector for the + * modules in the library. The bits indicate which modules are bound (1) and + * which are not (0) from the library. The bit for module 0 is the low bit + * of the first byte. So the bit for the Nth module is: + * (linked_modules[N/8] >> N%8) & 1 + */ +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct PreboundDylibCommand<E: Endian> { + /// LC_PREBOUND_DYLIB + pub cmd: U32<E>, + /// includes strings + pub cmdsize: U32<E>, + /// library's path name + pub name: LcStr<E>, + /// number of modules in library + pub nmodules: U32<E>, + /// bit vector of linked modules + pub linked_modules: LcStr<E>, +} + +/* + * A program that uses a dynamic linker contains a `DylinkerCommand` to identify + * the name of the dynamic linker (LC_LOAD_DYLINKER). And a dynamic linker + * contains a `DylinkerCommand` to identify the dynamic linker (LC_ID_DYLINKER). + * A file can have at most one of these. + * This struct is also used for the LC_DYLD_ENVIRONMENT load command and + * contains string for dyld to treat like environment variable. + */ +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct DylinkerCommand<E: Endian> { + /// LC_ID_DYLINKER, LC_LOAD_DYLINKER or LC_DYLD_ENVIRONMENT + pub cmd: U32<E>, + /// includes pathname string + pub cmdsize: U32<E>, + /// dynamic linker's path name + pub name: LcStr<E>, +} + +/* + * Thread commands contain machine-specific data structures suitable for + * use in the thread state primitives. The machine specific data structures + * follow the struct `ThreadCommand` as follows. + * Each flavor of machine specific data structure is preceded by an uint32_t + * constant for the flavor of that data structure, an uint32_t that is the + * count of uint32_t's of the size of the state data structure and then + * the state data structure follows. This triple may be repeated for many + * flavors. The constants for the flavors, counts and state data structure + * definitions are expected to be in the header file <machine/thread_status.h>. + * These machine specific data structures sizes must be multiples of + * 4 bytes. The `cmdsize` reflects the total size of the `ThreadCommand` + * and all of the sizes of the constants for the flavors, counts and state + * data structures. + * + * For executable objects that are unix processes there will be one + * `ThreadCommand` (cmd == LC_UNIXTHREAD) created for it by the link-editor. + * This is the same as a LC_THREAD, except that a stack is automatically + * created (based on the shell's limit for the stack size). Command arguments + * and environment variables are copied onto that stack. + */ +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct ThreadCommand<E: Endian> { + /// LC_THREAD or LC_UNIXTHREAD + pub cmd: U32<E>, + /// total size of this command + pub cmdsize: U32<E>, + /* uint32_t flavor flavor of thread state */ + /* uint32_t count count of uint32_t's in thread state */ + /* struct XXX_thread_state state thread state for this flavor */ + /* ... */ +} + +/* + * The routines command contains the address of the dynamic shared library + * initialization routine and an index into the module table for the module + * that defines the routine. Before any modules are used from the library the + * dynamic linker fully binds the module that defines the initialization routine + * and then calls it. This gets called before any module initialization + * routines (used for C++ static constructors) in the library. + */ +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct RoutinesCommand32<E: Endian> { + /* for 32-bit architectures */ + /// LC_ROUTINES + pub cmd: U32<E>, + /// total size of this command + pub cmdsize: U32<E>, + /// address of initialization routine + pub init_address: U32<E>, + /// index into the module table that the init routine is defined in + pub init_module: U32<E>, + pub reserved1: U32<E>, + pub reserved2: U32<E>, + pub reserved3: U32<E>, + pub reserved4: U32<E>, + pub reserved5: U32<E>, + pub reserved6: U32<E>, +} + +/* + * The 64-bit routines command. Same use as above. + */ +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct RoutinesCommand64<E: Endian> { + /* for 64-bit architectures */ + /// LC_ROUTINES_64 + pub cmd: U32<E>, + /// total size of this command + pub cmdsize: U32<E>, + /// address of initialization routine + pub init_address: U64<E>, + /// index into the module table that the init routine is defined in + pub init_module: U64<E>, + pub reserved1: U64<E>, + pub reserved2: U64<E>, + pub reserved3: U64<E>, + pub reserved4: U64<E>, + pub reserved5: U64<E>, + pub reserved6: U64<E>, +} + +/* + * The `SymtabCommand` contains the offsets and sizes of the link-edit 4.3BSD + * "stab" style symbol table information as described in the header files + * <nlist.h> and <stab.h>. + */ +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct SymtabCommand<E: Endian> { + /// LC_SYMTAB + pub cmd: U32<E>, + /// sizeof(struct SymtabCommand) + pub cmdsize: U32<E>, + /// symbol table offset + pub symoff: U32<E>, + /// number of symbol table entries + pub nsyms: U32<E>, + /// string table offset + pub stroff: U32<E>, + /// string table size in bytes + pub strsize: U32<E>, +} + +/* + * This is the second set of the symbolic information which is used to support + * the data structures for the dynamically link editor. + * + * The original set of symbolic information in the `SymtabCommand` which contains + * the symbol and string tables must also be present when this load command is + * present. When this load command is present the symbol table is organized + * into three groups of symbols: + * local symbols (static and debugging symbols) - grouped by module + * defined external symbols - grouped by module (sorted by name if not lib) + * undefined external symbols (sorted by name if MH_BINDATLOAD is not set, + * and in order the were seen by the static + * linker if MH_BINDATLOAD is set) + * In this load command there are offsets and counts to each of the three groups + * of symbols. + * + * This load command contains a the offsets and sizes of the following new + * symbolic information tables: + * table of contents + * module table + * reference symbol table + * indirect symbol table + * The first three tables above (the table of contents, module table and + * reference symbol table) are only present if the file is a dynamically linked + * shared library. For executable and object modules, which are files + * containing only one module, the information that would be in these three + * tables is determined as follows: + * table of contents - the defined external symbols are sorted by name + * module table - the file contains only one module so everything in the + * file is part of the module. + * reference symbol table - is the defined and undefined external symbols + * + * For dynamically linked shared library files this load command also contains + * offsets and sizes to the pool of relocation entries for all sections + * separated into two groups: + * external relocation entries + * local relocation entries + * For executable and object modules the relocation entries continue to hang + * off the section structures. + */ +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct DysymtabCommand<E: Endian> { + /// LC_DYSYMTAB + pub cmd: U32<E>, + /// sizeof(struct DysymtabCommand) + pub cmdsize: U32<E>, + + /* + * The symbols indicated by symoff and nsyms of the LC_SYMTAB load command + * are grouped into the following three groups: + * local symbols (further grouped by the module they are from) + * defined external symbols (further grouped by the module they are from) + * undefined symbols + * + * The local symbols are used only for debugging. The dynamic binding + * process may have to use them to indicate to the debugger the local + * symbols for a module that is being bound. + * + * The last two groups are used by the dynamic binding process to do the + * binding (indirectly through the module table and the reference symbol + * table when this is a dynamically linked shared library file). + */ + /// index to local symbols + pub ilocalsym: U32<E>, + /// number of local symbols + pub nlocalsym: U32<E>, + + /// index to externally defined symbols + pub iextdefsym: U32<E>, + /// number of externally defined symbols + pub nextdefsym: U32<E>, + + /// index to undefined symbols + pub iundefsym: U32<E>, + /// number of undefined symbols + pub nundefsym: U32<E>, + + /* + * For the for the dynamic binding process to find which module a symbol + * is defined in the table of contents is used (analogous to the ranlib + * structure in an archive) which maps defined external symbols to modules + * they are defined in. This exists only in a dynamically linked shared + * library file. For executable and object modules the defined external + * symbols are sorted by name and is use as the table of contents. + */ + /// file offset to table of contents + pub tocoff: U32<E>, + /// number of entries in table of contents + pub ntoc: U32<E>, + + /* + * To support dynamic binding of "modules" (whole object files) the symbol + * table must reflect the modules that the file was created from. This is + * done by having a module table that has indexes and counts into the merged + * tables for each module. The module structure that these two entries + * refer to is described below. This exists only in a dynamically linked + * shared library file. For executable and object modules the file only + * contains one module so everything in the file belongs to the module. + */ + /// file offset to module table + pub modtaboff: U32<E>, + /// number of module table entries + pub nmodtab: U32<E>, + + /* + * To support dynamic module binding the module structure for each module + * indicates the external references (defined and undefined) each module + * makes. For each module there is an offset and a count into the + * reference symbol table for the symbols that the module references. + * This exists only in a dynamically linked shared library file. For + * executable and object modules the defined external symbols and the + * undefined external symbols indicates the external references. + */ + /// offset to referenced symbol table + pub extrefsymoff: U32<E>, + /// number of referenced symbol table entries + pub nextrefsyms: U32<E>, + + /* + * The sections that contain "symbol pointers" and "routine stubs" have + * indexes and (implied counts based on the size of the section and fixed + * size of the entry) into the "indirect symbol" table for each pointer + * and stub. For every section of these two types the index into the + * indirect symbol table is stored in the section header in the field + * reserved1. An indirect symbol table entry is simply a 32bit index into + * the symbol table to the symbol that the pointer or stub is referring to. + * The indirect symbol table is ordered to match the entries in the section. + */ + /// file offset to the indirect symbol table + pub indirectsymoff: U32<E>, + /// number of indirect symbol table entries + pub nindirectsyms: U32<E>, + + /* + * To support relocating an individual module in a library file quickly the + * external relocation entries for each module in the library need to be + * accessed efficiently. Since the relocation entries can't be accessed + * through the section headers for a library file they are separated into + * groups of local and external entries further grouped by module. In this + * case the presents of this load command who's extreloff, nextrel, + * locreloff and nlocrel fields are non-zero indicates that the relocation + * entries of non-merged sections are not referenced through the section + * structures (and the reloff and nreloc fields in the section headers are + * set to zero). + * + * Since the relocation entries are not accessed through the section headers + * this requires the r_address field to be something other than a section + * offset to identify the item to be relocated. In this case r_address is + * set to the offset from the vmaddr of the first LC_SEGMENT command. + * For MH_SPLIT_SEGS images r_address is set to the the offset from the + * vmaddr of the first read-write LC_SEGMENT command. + * + * The relocation entries are grouped by module and the module table + * entries have indexes and counts into them for the group of external + * relocation entries for that the module. + * + * For sections that are merged across modules there must not be any + * remaining external relocation entries for them (for merged sections + * remaining relocation entries must be local). + */ + /// offset to external relocation entries + pub extreloff: U32<E>, + /// number of external relocation entries + pub nextrel: U32<E>, + + /* + * All the local relocation entries are grouped together (they are not + * grouped by their module since they are only used if the object is moved + * from it staticly link edited address). + */ + /// offset to local relocation entries + pub locreloff: U32<E>, + /// number of local relocation entries + pub nlocrel: U32<E>, +} + +/* + * An indirect symbol table entry is simply a 32bit index into the symbol table + * to the symbol that the pointer or stub is refering to. Unless it is for a + * non-lazy symbol pointer section for a defined symbol which strip(1) as + * removed. In which case it has the value INDIRECT_SYMBOL_LOCAL. If the + * symbol was also absolute INDIRECT_SYMBOL_ABS is or'ed with that. + */ +pub const INDIRECT_SYMBOL_LOCAL: u32 = 0x8000_0000; +pub const INDIRECT_SYMBOL_ABS: u32 = 0x4000_0000; + +/* a table of contents entry */ +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct DylibTableOfContents<E: Endian> { + /// the defined external symbol (index into the symbol table) + pub symbol_index: U32<E>, + /// index into the module table this symbol is defined in + pub module_index: U32<E>, +} + +/* a module table entry */ +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct DylibModule32<E: Endian> { + /// the module name (index into string table) + pub module_name: U32<E>, + + /// index into externally defined symbols + pub iextdefsym: U32<E>, + /// number of externally defined symbols + pub nextdefsym: U32<E>, + /// index into reference symbol table + pub irefsym: U32<E>, + /// number of reference symbol table entries + pub nrefsym: U32<E>, + /// index into symbols for local symbols + pub ilocalsym: U32<E>, + /// number of local symbols + pub nlocalsym: U32<E>, + + /// index into external relocation entries + pub iextrel: U32<E>, + /// number of external relocation entries + pub nextrel: U32<E>, + + /// low 16 bits are the index into the init section, high 16 bits are the index into the term section + pub iinit_iterm: U32<E>, + /// low 16 bits are the number of init section entries, high 16 bits are the number of term section entries + pub ninit_nterm: U32<E>, + + /// for this module address of the start of the (__OBJC,__module_info) section + pub objc_module_info_addr: U32<E>, + /// for this module size of the (__OBJC,__module_info) section + pub objc_module_info_size: U32<E>, +} + +/* a 64-bit module table entry */ +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct DylibModule64<E: Endian> { + /// the module name (index into string table) + pub module_name: U32<E>, + + /// index into externally defined symbols + pub iextdefsym: U32<E>, + /// number of externally defined symbols + pub nextdefsym: U32<E>, + /// index into reference symbol table + pub irefsym: U32<E>, + /// number of reference symbol table entries + pub nrefsym: U32<E>, + /// index into symbols for local symbols + pub ilocalsym: U32<E>, + /// number of local symbols + pub nlocalsym: U32<E>, + + /// index into external relocation entries + pub iextrel: U32<E>, + /// number of external relocation entries + pub nextrel: U32<E>, + + /// low 16 bits are the index into the init section, high 16 bits are the index into the term section + pub iinit_iterm: U32<E>, + /// low 16 bits are the number of init section entries, high 16 bits are the number of term section entries + pub ninit_nterm: U32<E>, + + /// for this module size of the (__OBJC,__module_info) section + pub objc_module_info_size: U32<E>, + /// for this module address of the start of the (__OBJC,__module_info) section + pub objc_module_info_addr: U64<E>, +} + +/* + * The entries in the reference symbol table are used when loading the module + * (both by the static and dynamic link editors) and if the module is unloaded + * or replaced. Therefore all external symbols (defined and undefined) are + * listed in the module's reference table. The flags describe the type of + * reference that is being made. The constants for the flags are defined in + * <mach-o/nlist.h> as they are also used for symbol table entries. + */ +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct DylibReference<E: Endian> { + /* TODO: + uint32_t isym:24, /* index into the symbol table */ + flags:8; /* flags to indicate the type of reference */ + */ + pub bitfield: U32<E>, +} + +/* + * The TwolevelHintsCommand contains the offset and number of hints in the + * two-level namespace lookup hints table. + */ +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct TwolevelHintsCommand<E: Endian> { + /// LC_TWOLEVEL_HINTS + pub cmd: U32<E>, + /// sizeof(struct TwolevelHintsCommand) + pub cmdsize: U32<E>, + /// offset to the hint table + pub offset: U32<E>, + /// number of hints in the hint table + pub nhints: U32<E>, +} + +/* + * The entries in the two-level namespace lookup hints table are TwolevelHint + * structs. These provide hints to the dynamic link editor where to start + * looking for an undefined symbol in a two-level namespace image. The + * isub_image field is an index into the sub-images (sub-frameworks and + * sub-umbrellas list) that made up the two-level image that the undefined + * symbol was found in when it was built by the static link editor. If + * isub-image is 0 the the symbol is expected to be defined in library and not + * in the sub-images. If isub-image is non-zero it is an index into the array + * of sub-images for the umbrella with the first index in the sub-images being + * 1. The array of sub-images is the ordered list of sub-images of the umbrella + * that would be searched for a symbol that has the umbrella recorded as its + * primary library. The table of contents index is an index into the + * library's table of contents. This is used as the starting point of the + * binary search or a directed linear search. + */ +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct TwolevelHint<E: Endian> { + /* TODO: + uint32_t + isub_image:8, /* index into the sub images */ + itoc:24; /* index into the table of contents */ + */ + pub bitfield: U32<E>, +} + +/* + * The PrebindCksumCommand contains the value of the original check sum for + * prebound files or zero. When a prebound file is first created or modified + * for other than updating its prebinding information the value of the check sum + * is set to zero. When the file has it prebinding re-done and if the value of + * the check sum is zero the original check sum is calculated and stored in + * cksum field of this load command in the output file. If when the prebinding + * is re-done and the cksum field is non-zero it is left unchanged from the + * input file. + */ +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct PrebindCksumCommand<E: Endian> { + /// LC_PREBIND_CKSUM + pub cmd: U32<E>, + /// sizeof(struct PrebindCksumCommand) + pub cmdsize: U32<E>, + /// the check sum or zero + pub cksum: U32<E>, +} + +/* + * The uuid load command contains a single 128-bit unique random number that + * identifies an object produced by the static link editor. + */ +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct UuidCommand<E: Endian> { + /// LC_UUID + pub cmd: U32<E>, + /// sizeof(struct UuidCommand) + pub cmdsize: U32<E>, + /// the 128-bit uuid + pub uuid: [u8; 16], +} + +/* + * The RpathCommand contains a path which at runtime should be added to + * the current run path used to find @rpath prefixed dylibs. + */ +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct RpathCommand<E: Endian> { + /// LC_RPATH + pub cmd: U32<E>, + /// includes string + pub cmdsize: U32<E>, + /// path to add to run path + pub path: LcStr<E>, +} + +/* + * The LinkeditDataCommand contains the offsets and sizes of a blob + * of data in the __LINKEDIT segment. + */ +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct LinkeditDataCommand<E: Endian> { + /// `LC_CODE_SIGNATURE`, `LC_SEGMENT_SPLIT_INFO`, `LC_FUNCTION_STARTS`, + /// `LC_DATA_IN_CODE`, `LC_DYLIB_CODE_SIGN_DRS`, `LC_LINKER_OPTIMIZATION_HINT`, + /// `LC_DYLD_EXPORTS_TRIE`, or `LC_DYLD_CHAINED_FIXUPS`. + pub cmd: U32<E>, + /// sizeof(struct LinkeditDataCommand) + pub cmdsize: U32<E>, + /// file offset of data in __LINKEDIT segment + pub dataoff: U32<E>, + /// file size of data in __LINKEDIT segment + pub datasize: U32<E>, +} + +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct FilesetEntryCommand<E: Endian> { + // LC_FILESET_ENTRY + pub cmd: U32<E>, + /// includes id string + pub cmdsize: U32<E>, + /// memory address of the dylib + pub vmaddr: U64<E>, + /// file offset of the dylib + pub fileoff: U64<E>, + /// contained entry id + pub entry_id: LcStr<E>, + /// entry_id is 32-bits long, so this is the reserved padding + pub reserved: U32<E>, +} + +/* + * The EncryptionInfoCommand32 contains the file offset and size of an + * of an encrypted segment. + */ +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct EncryptionInfoCommand32<E: Endian> { + /// LC_ENCRYPTION_INFO + pub cmd: U32<E>, + /// sizeof(struct EncryptionInfoCommand32) + pub cmdsize: U32<E>, + /// file offset of encrypted range + pub cryptoff: U32<E>, + /// file size of encrypted range + pub cryptsize: U32<E>, + /// which enryption system, 0 means not-encrypted yet + pub cryptid: U32<E>, +} + +/* + * The EncryptionInfoCommand64 contains the file offset and size of an + * of an encrypted segment (for use in x86_64 targets). + */ +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct EncryptionInfoCommand64<E: Endian> { + /// LC_ENCRYPTION_INFO_64 + pub cmd: U32<E>, + /// sizeof(struct EncryptionInfoCommand64) + pub cmdsize: U32<E>, + /// file offset of encrypted range + pub cryptoff: U32<E>, + /// file size of encrypted range + pub cryptsize: U32<E>, + /// which enryption system, 0 means not-encrypted yet + pub cryptid: U32<E>, + /// padding to make this struct's size a multiple of 8 bytes + pub pad: U32<E>, +} + +/* + * The VersionMinCommand contains the min OS version on which this + * binary was built to run. + */ +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct VersionMinCommand<E: Endian> { + /// LC_VERSION_MIN_MACOSX or LC_VERSION_MIN_IPHONEOS or LC_VERSION_MIN_WATCHOS or LC_VERSION_MIN_TVOS + pub cmd: U32<E>, + /// sizeof(struct VersionMinCommand) + pub cmdsize: U32<E>, + /// X.Y.Z is encoded in nibbles xxxx.yy.zz + pub version: U32<E>, + /// X.Y.Z is encoded in nibbles xxxx.yy.zz + pub sdk: U32<E>, +} + +/* + * The BuildVersionCommand contains the min OS version on which this + * binary was built to run for its platform. The list of known platforms and + * tool values following it. + */ +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct BuildVersionCommand<E: Endian> { + /// LC_BUILD_VERSION + pub cmd: U32<E>, + /// sizeof(struct BuildVersionCommand) plus ntools * sizeof(struct BuildToolVersion) + pub cmdsize: U32<E>, + /// platform + pub platform: U32<E>, + /// X.Y.Z is encoded in nibbles xxxx.yy.zz + pub minos: U32<E>, + /// X.Y.Z is encoded in nibbles xxxx.yy.zz + pub sdk: U32<E>, + /// number of tool entries following this + pub ntools: U32<E>, +} + +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct BuildToolVersion<E: Endian> { + /// enum for the tool + pub tool: U32<E>, + /// version number of the tool + pub version: U32<E>, +} + +/* Known values for the platform field above. */ +pub const PLATFORM_MACOS: u32 = 1; +pub const PLATFORM_IOS: u32 = 2; +pub const PLATFORM_TVOS: u32 = 3; +pub const PLATFORM_WATCHOS: u32 = 4; +pub const PLATFORM_BRIDGEOS: u32 = 5; +pub const PLATFORM_MACCATALYST: u32 = 6; +pub const PLATFORM_IOSSIMULATOR: u32 = 7; +pub const PLATFORM_TVOSSIMULATOR: u32 = 8; +pub const PLATFORM_WATCHOSSIMULATOR: u32 = 9; +pub const PLATFORM_DRIVERKIT: u32 = 10; + +/* Known values for the tool field above. */ +pub const TOOL_CLANG: u32 = 1; +pub const TOOL_SWIFT: u32 = 2; +pub const TOOL_LD: u32 = 3; + +/* + * The DyldInfoCommand contains the file offsets and sizes of + * the new compressed form of the information dyld needs to + * load the image. This information is used by dyld on Mac OS X + * 10.6 and later. All information pointed to by this command + * is encoded using byte streams, so no endian swapping is needed + * to interpret it. + */ +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct DyldInfoCommand<E: Endian> { + /// LC_DYLD_INFO or LC_DYLD_INFO_ONLY + pub cmd: U32<E>, + /// sizeof(struct DyldInfoCommand) + pub cmdsize: U32<E>, + + /* + * Dyld rebases an image whenever dyld loads it at an address different + * from its preferred address. The rebase information is a stream + * of byte sized opcodes whose symbolic names start with REBASE_OPCODE_. + * Conceptually the rebase information is a table of tuples: + * <seg-index, seg-offset, type> + * The opcodes are a compressed way to encode the table by only + * encoding when a column changes. In addition simple patterns + * like "every n'th offset for m times" can be encoded in a few + * bytes. + */ + /// file offset to rebase info + pub rebase_off: U32<E>, + /// size of rebase info + pub rebase_size: U32<E>, + + /* + * Dyld binds an image during the loading process, if the image + * requires any pointers to be initialized to symbols in other images. + * The bind information is a stream of byte sized + * opcodes whose symbolic names start with BIND_OPCODE_. + * Conceptually the bind information is a table of tuples: + * <seg-index, seg-offset, type, symbol-library-ordinal, symbol-name, addend> + * The opcodes are a compressed way to encode the table by only + * encoding when a column changes. In addition simple patterns + * like for runs of pointers initialzed to the same value can be + * encoded in a few bytes. + */ + /// file offset to binding info + pub bind_off: U32<E>, + /// size of binding info + pub bind_size: U32<E>, + + /* + * Some C++ programs require dyld to unique symbols so that all + * images in the process use the same copy of some code/data. + * This step is done after binding. The content of the weak_bind + * info is an opcode stream like the bind_info. But it is sorted + * alphabetically by symbol name. This enable dyld to walk + * all images with weak binding information in order and look + * for collisions. If there are no collisions, dyld does + * no updating. That means that some fixups are also encoded + * in the bind_info. For instance, all calls to "operator new" + * are first bound to libstdc++.dylib using the information + * in bind_info. Then if some image overrides operator new + * that is detected when the weak_bind information is processed + * and the call to operator new is then rebound. + */ + /// file offset to weak binding info + pub weak_bind_off: U32<E>, + /// size of weak binding info + pub weak_bind_size: U32<E>, + + /* + * Some uses of external symbols do not need to be bound immediately. + * Instead they can be lazily bound on first use. The lazy_bind + * are contains a stream of BIND opcodes to bind all lazy symbols. + * Normal use is that dyld ignores the lazy_bind section when + * loading an image. Instead the static linker arranged for the + * lazy pointer to initially point to a helper function which + * pushes the offset into the lazy_bind area for the symbol + * needing to be bound, then jumps to dyld which simply adds + * the offset to lazy_bind_off to get the information on what + * to bind. + */ + /// file offset to lazy binding info + pub lazy_bind_off: U32<E>, + /// size of lazy binding infs + pub lazy_bind_size: U32<E>, + + /* + * The symbols exported by a dylib are encoded in a trie. This + * is a compact representation that factors out common prefixes. + * It also reduces LINKEDIT pages in RAM because it encodes all + * information (name, address, flags) in one small, contiguous range. + * The export area is a stream of nodes. The first node sequentially + * is the start node for the trie. + * + * Nodes for a symbol start with a uleb128 that is the length of + * the exported symbol information for the string so far. + * If there is no exported symbol, the node starts with a zero byte. + * If there is exported info, it follows the length. + * + * First is a uleb128 containing flags. Normally, it is followed by + * a uleb128 encoded offset which is location of the content named + * by the symbol from the mach_header for the image. If the flags + * is EXPORT_SYMBOL_FLAGS_REEXPORT, then following the flags is + * a uleb128 encoded library ordinal, then a zero terminated + * UTF8 string. If the string is zero length, then the symbol + * is re-export from the specified dylib with the same name. + * If the flags is EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER, then following + * the flags is two uleb128s: the stub offset and the resolver offset. + * The stub is used by non-lazy pointers. The resolver is used + * by lazy pointers and must be called to get the actual address to use. + * + * After the optional exported symbol information is a byte of + * how many edges (0-255) that this node has leaving it, + * followed by each edge. + * Each edge is a zero terminated UTF8 of the addition chars + * in the symbol, followed by a uleb128 offset for the node that + * edge points to. + * + */ + /// file offset to lazy binding info + pub export_off: U32<E>, + /// size of lazy binding infs + pub export_size: U32<E>, +} + +/* + * The following are used to encode rebasing information + */ +pub const REBASE_TYPE_POINTER: u8 = 1; +pub const REBASE_TYPE_TEXT_ABSOLUTE32: u8 = 2; +pub const REBASE_TYPE_TEXT_PCREL32: u8 = 3; + +pub const REBASE_OPCODE_MASK: u8 = 0xF0; +pub const REBASE_IMMEDIATE_MASK: u8 = 0x0F; +pub const REBASE_OPCODE_DONE: u8 = 0x00; +pub const REBASE_OPCODE_SET_TYPE_IMM: u8 = 0x10; +pub const REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB: u8 = 0x20; +pub const REBASE_OPCODE_ADD_ADDR_ULEB: u8 = 0x30; +pub const REBASE_OPCODE_ADD_ADDR_IMM_SCALED: u8 = 0x40; +pub const REBASE_OPCODE_DO_REBASE_IMM_TIMES: u8 = 0x50; +pub const REBASE_OPCODE_DO_REBASE_ULEB_TIMES: u8 = 0x60; +pub const REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB: u8 = 0x70; +pub const REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB: u8 = 0x80; + +/* + * The following are used to encode binding information + */ +pub const BIND_TYPE_POINTER: u8 = 1; +pub const BIND_TYPE_TEXT_ABSOLUTE32: u8 = 2; +pub const BIND_TYPE_TEXT_PCREL32: u8 = 3; + +pub const BIND_SPECIAL_DYLIB_SELF: i8 = 0; +pub const BIND_SPECIAL_DYLIB_MAIN_EXECUTABLE: i8 = -1; +pub const BIND_SPECIAL_DYLIB_FLAT_LOOKUP: i8 = -2; +pub const BIND_SPECIAL_DYLIB_WEAK_LOOKUP: i8 = -3; + +pub const BIND_SYMBOL_FLAGS_WEAK_IMPORT: u8 = 0x1; +pub const BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION: u8 = 0x8; + +pub const BIND_OPCODE_MASK: u8 = 0xF0; +pub const BIND_IMMEDIATE_MASK: u8 = 0x0F; +pub const BIND_OPCODE_DONE: u8 = 0x00; +pub const BIND_OPCODE_SET_DYLIB_ORDINAL_IMM: u8 = 0x10; +pub const BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB: u8 = 0x20; +pub const BIND_OPCODE_SET_DYLIB_SPECIAL_IMM: u8 = 0x30; +pub const BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM: u8 = 0x40; +pub const BIND_OPCODE_SET_TYPE_IMM: u8 = 0x50; +pub const BIND_OPCODE_SET_ADDEND_SLEB: u8 = 0x60; +pub const BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB: u8 = 0x70; +pub const BIND_OPCODE_ADD_ADDR_ULEB: u8 = 0x80; +pub const BIND_OPCODE_DO_BIND: u8 = 0x90; +pub const BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB: u8 = 0xA0; +pub const BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED: u8 = 0xB0; +pub const BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB: u8 = 0xC0; +pub const BIND_OPCODE_THREADED: u8 = 0xD0; +pub const BIND_SUBOPCODE_THREADED_SET_BIND_ORDINAL_TABLE_SIZE_ULEB: u8 = 0x00; +pub const BIND_SUBOPCODE_THREADED_APPLY: u8 = 0x01; + +/* + * The following are used on the flags byte of a terminal node + * in the export information. + */ +pub const EXPORT_SYMBOL_FLAGS_KIND_MASK: u32 = 0x03; +pub const EXPORT_SYMBOL_FLAGS_KIND_REGULAR: u32 = 0x00; +pub const EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL: u32 = 0x01; +pub const EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE: u32 = 0x02; +pub const EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION: u32 = 0x04; +pub const EXPORT_SYMBOL_FLAGS_REEXPORT: u32 = 0x08; +pub const EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER: u32 = 0x10; + +/* + * The LinkerOptionCommand contains linker options embedded in object files. + */ +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct LinkerOptionCommand<E: Endian> { + /// LC_LINKER_OPTION only used in MH_OBJECT filetypes + pub cmd: U32<E>, + pub cmdsize: U32<E>, + /// number of strings + pub count: U32<E>, + /* concatenation of zero terminated UTF8 strings. + Zero filled at end to align */ +} + +/* + * The SymsegCommand contains the offset and size of the GNU style + * symbol table information as described in the header file <symseg.h>. + * The symbol roots of the symbol segments must also be aligned properly + * in the file. So the requirement of keeping the offsets aligned to a + * multiple of a 4 bytes translates to the length field of the symbol + * roots also being a multiple of a long. Also the padding must again be + * zeroed. (THIS IS OBSOLETE and no longer supported). + */ +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct SymsegCommand<E: Endian> { + /// LC_SYMSEG + pub cmd: U32<E>, + /// sizeof(struct SymsegCommand) + pub cmdsize: U32<E>, + /// symbol segment offset + pub offset: U32<E>, + /// symbol segment size in bytes + pub size: U32<E>, +} + +/* + * The IdentCommand contains a free format string table following the + * IdentCommand structure. The strings are null terminated and the size of + * the command is padded out with zero bytes to a multiple of 4 bytes/ + * (THIS IS OBSOLETE and no longer supported). + */ +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct IdentCommand<E: Endian> { + /// LC_IDENT + pub cmd: U32<E>, + /// strings that follow this command + pub cmdsize: U32<E>, +} + +/* + * The FvmfileCommand contains a reference to a file to be loaded at the + * specified virtual address. (Presently, this command is reserved for + * internal use. The kernel ignores this command when loading a program into + * memory). + */ +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct FvmfileCommand<E: Endian> { + /// LC_FVMFILE + pub cmd: U32<E>, + /// includes pathname string + pub cmdsize: U32<E>, + /// files pathname + pub name: LcStr<E>, + /// files virtual address + pub header_addr: U32<E>, +} + +/* + * The EntryPointCommand is a replacement for thread_command. + * It is used for main executables to specify the location (file offset) + * of main(). If -stack_size was used at link time, the stacksize + * field will contain the stack size need for the main thread. + */ +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct EntryPointCommand<E: Endian> { + /// LC_MAIN only used in MH_EXECUTE filetypes + pub cmd: U32<E>, + /// 24 + pub cmdsize: U32<E>, + /// file (__TEXT) offset of main() + pub entryoff: U64<E>, + /// if not zero, initial stack size + pub stacksize: U64<E>, +} + +/* + * The SourceVersionCommand is an optional load command containing + * the version of the sources used to build the binary. + */ +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct SourceVersionCommand<E: Endian> { + /// LC_SOURCE_VERSION + pub cmd: U32<E>, + /// 16 + pub cmdsize: U32<E>, + /// A.B.C.D.E packed as a24.b10.c10.d10.e10 + pub version: U64<E>, +} + +/* + * The LC_DATA_IN_CODE load commands uses a LinkeditDataCommand + * to point to an array of DataInCodeEntry entries. Each entry + * describes a range of data in a code section. + */ +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct DataInCodeEntry<E: Endian> { + /// from mach_header to start of data range + pub offset: U32<E>, + /// number of bytes in data range + pub length: U16<E>, + /// a DICE_KIND_* value + pub kind: U16<E>, +} +pub const DICE_KIND_DATA: u32 = 0x0001; +pub const DICE_KIND_JUMP_TABLE8: u32 = 0x0002; +pub const DICE_KIND_JUMP_TABLE16: u32 = 0x0003; +pub const DICE_KIND_JUMP_TABLE32: u32 = 0x0004; +pub const DICE_KIND_ABS_JUMP_TABLE32: u32 = 0x0005; + +/* + * Sections of type S_THREAD_LOCAL_VARIABLES contain an array + * of TlvDescriptor structures. + */ +/* TODO: +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct TlvDescriptor<E: Endian> +{ + void* (*thunk)(struct TlvDescriptor*); + unsigned long key; + unsigned long offset; +} +*/ + +/* + * LC_NOTE commands describe a region of arbitrary data included in a Mach-O + * file. Its initial use is to record extra data in MH_CORE files. + */ +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct NoteCommand<E: Endian> { + /// LC_NOTE + pub cmd: U32<E>, + /// sizeof(struct NoteCommand) + pub cmdsize: U32<E>, + /// owner name for this LC_NOTE + pub data_owner: [u8; 16], + /// file offset of this data + pub offset: U64<E>, + /// length of data region + pub size: U64<E>, +} + +// Definitions from "/usr/include/mach-o/nlist.h". + +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct Nlist32<E: Endian> { + /// index into the string table + pub n_strx: U32<E>, + /// type flag, see below + pub n_type: u8, + /// section number or NO_SECT + pub n_sect: u8, + /// see <mach-o/stab.h> + pub n_desc: U16<E>, + /// value of this symbol (or stab offset) + pub n_value: U32<E>, +} + +/* + * This is the symbol table entry structure for 64-bit architectures. + */ +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct Nlist64<E: Endian> { + /// index into the string table + pub n_strx: U32<E>, + /// type flag, see below + pub n_type: u8, + /// section number or NO_SECT + pub n_sect: u8, + /// see <mach-o/stab.h> + pub n_desc: U16<E>, + /// value of this symbol (or stab offset) + // Note: 4 byte alignment has been observed in practice. + pub n_value: U64Bytes<E>, +} + +/* + * Symbols with a index into the string table of zero (n_un.n_strx == 0) are + * defined to have a null, "", name. Therefore all string indexes to non null + * names must not have a zero string index. This is bit historical information + * that has never been well documented. + */ + +/* + * The n_type field really contains four fields: + * unsigned char N_STAB:3, + * N_PEXT:1, + * N_TYPE:3, + * N_EXT:1; + * which are used via the following masks. + */ +/// if any of these bits set, a symbolic debugging entry +pub const N_STAB: u8 = 0xe0; +/// private external symbol bit +pub const N_PEXT: u8 = 0x10; +/// mask for the type bits +pub const N_TYPE: u8 = 0x0e; +/// external symbol bit, set for external symbols +pub const N_EXT: u8 = 0x01; + +/* + * Only symbolic debugging entries have some of the N_STAB bits set and if any + * of these bits are set then it is a symbolic debugging entry (a stab). In + * which case then the values of the n_type field (the entire field) are given + * in <mach-o/stab.h> + */ + +/* + * Values for N_TYPE bits of the n_type field. + */ +/// undefined, n_sect == NO_SECT +pub const N_UNDF: u8 = 0x0; +/// absolute, n_sect == NO_SECT +pub const N_ABS: u8 = 0x2; +/// defined in section number n_sect +pub const N_SECT: u8 = 0xe; +/// prebound undefined (defined in a dylib) +pub const N_PBUD: u8 = 0xc; +/// indirect +pub const N_INDR: u8 = 0xa; + +/* + * If the type is N_INDR then the symbol is defined to be the same as another + * symbol. In this case the n_value field is an index into the string table + * of the other symbol's name. When the other symbol is defined then they both + * take on the defined type and value. + */ + +/* + * If the type is N_SECT then the n_sect field contains an ordinal of the + * section the symbol is defined in. The sections are numbered from 1 and + * refer to sections in order they appear in the load commands for the file + * they are in. This means the same ordinal may very well refer to different + * sections in different files. + * + * The n_value field for all symbol table entries (including N_STAB's) gets + * updated by the link editor based on the value of it's n_sect field and where + * the section n_sect references gets relocated. If the value of the n_sect + * field is NO_SECT then it's n_value field is not changed by the link editor. + */ +/// symbol is not in any section +pub const NO_SECT: u8 = 0; +/// 1 thru 255 inclusive +pub const MAX_SECT: u8 = 255; + +/* + * Common symbols are represented by undefined (N_UNDF) external (N_EXT) types + * who's values (n_value) are non-zero. In which case the value of the n_value + * field is the size (in bytes) of the common symbol. The n_sect field is set + * to NO_SECT. The alignment of a common symbol may be set as a power of 2 + * between 2^1 and 2^15 as part of the n_desc field using the macros below. If + * the alignment is not set (a value of zero) then natural alignment based on + * the size is used. + */ +/* TODO: +#define GET_COMM_ALIGN(n_desc) (((n_desc) >> 8) & 0x0f) +#define SET_COMM_ALIGN(n_desc,align) \ + (n_desc) = (((n_desc) & 0xf0ff) | (((align) & 0x0f) << 8)) + */ + +/* + * To support the lazy binding of undefined symbols in the dynamic link-editor, + * the undefined symbols in the symbol table (the nlist structures) are marked + * with the indication if the undefined reference is a lazy reference or + * non-lazy reference. If both a non-lazy reference and a lazy reference is + * made to the same symbol the non-lazy reference takes precedence. A reference + * is lazy only when all references to that symbol are made through a symbol + * pointer in a lazy symbol pointer section. + * + * The implementation of marking nlist structures in the symbol table for + * undefined symbols will be to use some of the bits of the n_desc field as a + * reference type. The mask REFERENCE_TYPE will be applied to the n_desc field + * of an nlist structure for an undefined symbol to determine the type of + * undefined reference (lazy or non-lazy). + * + * The constants for the REFERENCE FLAGS are propagated to the reference table + * in a shared library file. In that case the constant for a defined symbol, + * REFERENCE_FLAG_DEFINED, is also used. + */ +/* Reference type bits of the n_desc field of undefined symbols */ +pub const REFERENCE_TYPE: u16 = 0x7; +/* types of references */ +pub const REFERENCE_FLAG_UNDEFINED_NON_LAZY: u16 = 0; +pub const REFERENCE_FLAG_UNDEFINED_LAZY: u16 = 1; +pub const REFERENCE_FLAG_DEFINED: u16 = 2; +pub const REFERENCE_FLAG_PRIVATE_DEFINED: u16 = 3; +pub const REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY: u16 = 4; +pub const REFERENCE_FLAG_PRIVATE_UNDEFINED_LAZY: u16 = 5; + +/* + * To simplify stripping of objects that use are used with the dynamic link + * editor, the static link editor marks the symbols defined an object that are + * referenced by a dynamicly bound object (dynamic shared libraries, bundles). + * With this marking strip knows not to strip these symbols. + */ +pub const REFERENCED_DYNAMICALLY: u16 = 0x0010; + +/* + * For images created by the static link editor with the -twolevel_namespace + * option in effect the flags field of the mach header is marked with + * MH_TWOLEVEL. And the binding of the undefined references of the image are + * determined by the static link editor. Which library an undefined symbol is + * bound to is recorded by the static linker in the high 8 bits of the n_desc + * field using the SET_LIBRARY_ORDINAL macro below. The ordinal recorded + * references the libraries listed in the Mach-O's LC_LOAD_DYLIB, + * LC_LOAD_WEAK_DYLIB, LC_REEXPORT_DYLIB, LC_LOAD_UPWARD_DYLIB, and + * LC_LAZY_LOAD_DYLIB, etc. load commands in the order they appear in the + * headers. The library ordinals start from 1. + * For a dynamic library that is built as a two-level namespace image the + * undefined references from module defined in another use the same nlist struct + * an in that case SELF_LIBRARY_ORDINAL is used as the library ordinal. For + * defined symbols in all images they also must have the library ordinal set to + * SELF_LIBRARY_ORDINAL. The EXECUTABLE_ORDINAL refers to the executable + * image for references from plugins that refer to the executable that loads + * them. + * + * The DYNAMIC_LOOKUP_ORDINAL is for undefined symbols in a two-level namespace + * image that are looked up by the dynamic linker with flat namespace semantics. + * This ordinal was added as a feature in Mac OS X 10.3 by reducing the + * value of MAX_LIBRARY_ORDINAL by one. So it is legal for existing binaries + * or binaries built with older tools to have 0xfe (254) dynamic libraries. In + * this case the ordinal value 0xfe (254) must be treated as a library ordinal + * for compatibility. + */ +/* TODO: +#define GET_LIBRARY_ORDINAL(n_desc) (((n_desc) >> 8) & 0xff) +#define SET_LIBRARY_ORDINAL(n_desc,ordinal) \ + (n_desc) = (((n_desc) & 0x00ff) | (((ordinal) & 0xff) << 8)) + */ +pub const SELF_LIBRARY_ORDINAL: u8 = 0x0; +pub const MAX_LIBRARY_ORDINAL: u8 = 0xfd; +pub const DYNAMIC_LOOKUP_ORDINAL: u8 = 0xfe; +pub const EXECUTABLE_ORDINAL: u8 = 0xff; + +/* + * The bit 0x0020 of the n_desc field is used for two non-overlapping purposes + * and has two different symbolic names, N_NO_DEAD_STRIP and N_DESC_DISCARDED. + */ + +/* + * The N_NO_DEAD_STRIP bit of the n_desc field only ever appears in a + * relocatable .o file (MH_OBJECT filetype). And is used to indicate to the + * static link editor it is never to dead strip the symbol. + */ +/// symbol is not to be dead stripped +pub const N_NO_DEAD_STRIP: u16 = 0x0020; + +/* + * The N_DESC_DISCARDED bit of the n_desc field never appears in linked image. + * But is used in very rare cases by the dynamic link editor to mark an in + * memory symbol as discared and longer used for linking. + */ +/// symbol is discarded +pub const N_DESC_DISCARDED: u16 = 0x0020; + +/* + * The N_WEAK_REF bit of the n_desc field indicates to the dynamic linker that + * the undefined symbol is allowed to be missing and is to have the address of + * zero when missing. + */ +/// symbol is weak referenced +pub const N_WEAK_REF: u16 = 0x0040; + +/* + * The N_WEAK_DEF bit of the n_desc field indicates to the static and dynamic + * linkers that the symbol definition is weak, allowing a non-weak symbol to + * also be used which causes the weak definition to be discared. Currently this + * is only supported for symbols in coalesed sections. + */ +/// coalesed symbol is a weak definition +pub const N_WEAK_DEF: u16 = 0x0080; + +/* + * The N_REF_TO_WEAK bit of the n_desc field indicates to the dynamic linker + * that the undefined symbol should be resolved using flat namespace searching. + */ +/// reference to a weak symbol +pub const N_REF_TO_WEAK: u16 = 0x0080; + +/* + * The N_ARM_THUMB_DEF bit of the n_desc field indicates that the symbol is + * a defintion of a Thumb function. + */ +/// symbol is a Thumb function (ARM) +pub const N_ARM_THUMB_DEF: u16 = 0x0008; + +/* + * The N_SYMBOL_RESOLVER bit of the n_desc field indicates that the + * that the function is actually a resolver function and should + * be called to get the address of the real function to use. + * This bit is only available in .o files (MH_OBJECT filetype) + */ +pub const N_SYMBOL_RESOLVER: u16 = 0x0100; + +/* + * The N_ALT_ENTRY bit of the n_desc field indicates that the + * symbol is pinned to the previous content. + */ +pub const N_ALT_ENTRY: u16 = 0x0200; + +// Definitions from "/usr/include/mach-o/stab.h". + +/* + * This file gives definitions supplementing <nlist.h> for permanent symbol + * table entries of Mach-O files. Modified from the BSD definitions. The + * modifications from the original definitions were changing what the values of + * what was the n_other field (an unused field) which is now the n_sect field. + * These modifications are required to support symbols in an arbitrary number of + * sections not just the three sections (text, data and bss) in a BSD file. + * The values of the defined constants have NOT been changed. + * + * These must have one of the N_STAB bits on. The n_value fields are subject + * to relocation according to the value of their n_sect field. So for types + * that refer to things in sections the n_sect field must be filled in with the + * proper section ordinal. For types that are not to have their n_value field + * relocatated the n_sect field must be NO_SECT. + */ + +/* + * Symbolic debugger symbols. The comments give the conventional use for + * + * .stabs "n_name", n_type, n_sect, n_desc, n_value + * + * where n_type is the defined constant and not listed in the comment. Other + * fields not listed are zero. n_sect is the section ordinal the entry is + * refering to. + */ +/// global symbol: name,,NO_SECT,type,0 +pub const N_GSYM: u8 = 0x20; +/// procedure name (f77 kludge): name,,NO_SECT,0,0 +pub const N_FNAME: u8 = 0x22; +/// procedure: name,,n_sect,linenumber,address +pub const N_FUN: u8 = 0x24; +/// static symbol: name,,n_sect,type,address +pub const N_STSYM: u8 = 0x26; +/// .lcomm symbol: name,,n_sect,type,address +pub const N_LCSYM: u8 = 0x28; +/// begin nsect sym: 0,,n_sect,0,address +pub const N_BNSYM: u8 = 0x2e; +/// AST file path: name,,NO_SECT,0,0 +pub const N_AST: u8 = 0x32; +/// emitted with gcc2_compiled and in gcc source +pub const N_OPT: u8 = 0x3c; +/// register sym: name,,NO_SECT,type,register +pub const N_RSYM: u8 = 0x40; +/// src line: 0,,n_sect,linenumber,address +pub const N_SLINE: u8 = 0x44; +/// end nsect sym: 0,,n_sect,0,address +pub const N_ENSYM: u8 = 0x4e; +/// structure elt: name,,NO_SECT,type,struct_offset +pub const N_SSYM: u8 = 0x60; +/// source file name: name,,n_sect,0,address +pub const N_SO: u8 = 0x64; +/// object file name: name,,0,0,st_mtime +pub const N_OSO: u8 = 0x66; +/// local sym: name,,NO_SECT,type,offset +pub const N_LSYM: u8 = 0x80; +/// include file beginning: name,,NO_SECT,0,sum +pub const N_BINCL: u8 = 0x82; +/// #included file name: name,,n_sect,0,address +pub const N_SOL: u8 = 0x84; +/// compiler parameters: name,,NO_SECT,0,0 +pub const N_PARAMS: u8 = 0x86; +/// compiler version: name,,NO_SECT,0,0 +pub const N_VERSION: u8 = 0x88; +/// compiler -O level: name,,NO_SECT,0,0 +pub const N_OLEVEL: u8 = 0x8A; +/// parameter: name,,NO_SECT,type,offset +pub const N_PSYM: u8 = 0xa0; +/// include file end: name,,NO_SECT,0,0 +pub const N_EINCL: u8 = 0xa2; +/// alternate entry: name,,n_sect,linenumber,address +pub const N_ENTRY: u8 = 0xa4; +/// left bracket: 0,,NO_SECT,nesting level,address +pub const N_LBRAC: u8 = 0xc0; +/// deleted include file: name,,NO_SECT,0,sum +pub const N_EXCL: u8 = 0xc2; +/// right bracket: 0,,NO_SECT,nesting level,address +pub const N_RBRAC: u8 = 0xe0; +/// begin common: name,,NO_SECT,0,0 +pub const N_BCOMM: u8 = 0xe2; +/// end common: name,,n_sect,0,0 +pub const N_ECOMM: u8 = 0xe4; +/// end common (local name): 0,,n_sect,0,address +pub const N_ECOML: u8 = 0xe8; +/// second stab entry with length information +pub const N_LENG: u8 = 0xfe; + +/* + * for the berkeley pascal compiler, pc(1): + */ +/// global pascal symbol: name,,NO_SECT,subtype,line +pub const N_PC: u8 = 0x30; + +// Definitions from "/usr/include/mach-o/reloc.h". + +/// A relocation entry. +/// +/// Mach-O relocations have plain and scattered variants, with the +/// meaning of the fields depending on the variant. +/// +/// This type provides functions for determining whether the relocation +/// is scattered, and for accessing the fields of each variant. +#[derive(Debug, Clone, Copy)] +#[repr(C)] +pub struct Relocation<E: Endian> { + pub r_word0: U32<E>, + pub r_word1: U32<E>, +} + +impl<E: Endian> Relocation<E> { + /// Determine whether this is a scattered relocation. + #[inline] + pub fn r_scattered(self, endian: E, cputype: u32) -> bool { + if cputype == CPU_TYPE_X86_64 { + false + } else { + self.r_word0.get(endian) & R_SCATTERED != 0 + } + } + + /// Return the fields of a plain relocation. + pub fn info(self, endian: E) -> RelocationInfo { + let r_address = self.r_word0.get(endian); + let r_word1 = self.r_word1.get(endian); + if endian.is_little_endian() { + RelocationInfo { + r_address, + r_symbolnum: r_word1 & 0x00ff_ffff, + r_pcrel: ((r_word1 >> 24) & 0x1) != 0, + r_length: ((r_word1 >> 25) & 0x3) as u8, + r_extern: ((r_word1 >> 27) & 0x1) != 0, + r_type: (r_word1 >> 28) as u8, + } + } else { + RelocationInfo { + r_address, + r_symbolnum: r_word1 >> 8, + r_pcrel: ((r_word1 >> 7) & 0x1) != 0, + r_length: ((r_word1 >> 5) & 0x3) as u8, + r_extern: ((r_word1 >> 4) & 0x1) != 0, + r_type: (r_word1 & 0xf) as u8, + } + } + } + + /// Return the fields of a scattered relocation. + pub fn scattered_info(self, endian: E) -> ScatteredRelocationInfo { + let r_word0 = self.r_word0.get(endian); + let r_value = self.r_word1.get(endian); + ScatteredRelocationInfo { + r_address: r_word0 & 0x00ff_ffff, + r_type: ((r_word0 >> 24) & 0xf) as u8, + r_length: ((r_word0 >> 28) & 0x3) as u8, + r_pcrel: ((r_word0 >> 30) & 0x1) != 0, + r_value, + } + } +} + +/* + * Format of a relocation entry of a Mach-O file. Modified from the 4.3BSD + * format. The modifications from the original format were changing the value + * of the r_symbolnum field for "local" (r_extern == 0) relocation entries. + * This modification is required to support symbols in an arbitrary number of + * sections not just the three sections (text, data and bss) in a 4.3BSD file. + * Also the last 4 bits have had the r_type tag added to them. + */ + +#[derive(Debug, Clone, Copy)] +pub struct RelocationInfo { + /// offset in the section to what is being relocated + pub r_address: u32, + /// symbol index if r_extern == 1 or section ordinal if r_extern == 0 + pub r_symbolnum: u32, + /// was relocated pc relative already + pub r_pcrel: bool, + /// 0=byte, 1=word, 2=long, 3=quad + pub r_length: u8, + /// does not include value of sym referenced + pub r_extern: bool, + /// if not 0, machine specific relocation type + pub r_type: u8, +} + +impl RelocationInfo { + /// Combine the fields into a `Relocation`. + pub fn relocation<E: Endian>(self, endian: E) -> Relocation<E> { + let r_word0 = U32::new(endian, self.r_address); + let r_word1 = U32::new( + endian, + if endian.is_little_endian() { + self.r_symbolnum & 0x00ff_ffff + | u32::from(self.r_pcrel) << 24 + | u32::from(self.r_length & 0x3) << 25 + | u32::from(self.r_extern) << 27 + | u32::from(self.r_type) << 28 + } else { + self.r_symbolnum >> 8 + | u32::from(self.r_pcrel) << 7 + | u32::from(self.r_length & 0x3) << 5 + | u32::from(self.r_extern) << 4 + | u32::from(self.r_type) & 0xf + }, + ); + Relocation { r_word0, r_word1 } + } +} + +/// absolute relocation type for Mach-O files +pub const R_ABS: u8 = 0; + +/* + * The r_address is not really the address as it's name indicates but an offset. + * In 4.3BSD a.out objects this offset is from the start of the "segment" for + * which relocation entry is for (text or data). For Mach-O object files it is + * also an offset but from the start of the "section" for which the relocation + * entry is for. See comments in <mach-o/loader.h> about the r_address feild + * in images for used with the dynamic linker. + * + * In 4.3BSD a.out objects if r_extern is zero then r_symbolnum is an ordinal + * for the segment the symbol being relocated is in. These ordinals are the + * symbol types N_TEXT, N_DATA, N_BSS or N_ABS. In Mach-O object files these + * ordinals refer to the sections in the object file in the order their section + * structures appear in the headers of the object file they are in. The first + * section has the ordinal 1, the second 2, and so on. This means that the + * same ordinal in two different object files could refer to two different + * sections. And further could have still different ordinals when combined + * by the link-editor. The value R_ABS is used for relocation entries for + * absolute symbols which need no further relocation. + */ + +/* + * For RISC machines some of the references are split across two instructions + * and the instruction does not contain the complete value of the reference. + * In these cases a second, or paired relocation entry, follows each of these + * relocation entries, using a PAIR r_type, which contains the other part of the + * reference not contained in the instruction. This other part is stored in the + * pair's r_address field. The exact number of bits of the other part of the + * reference store in the r_address field is dependent on the particular + * relocation type for the particular architecture. + */ + +/* + * To make scattered loading by the link editor work correctly "local" + * relocation entries can't be used when the item to be relocated is the value + * of a symbol plus an offset (where the resulting expresion is outside the + * block the link editor is moving, a blocks are divided at symbol addresses). + * In this case. where the item is a symbol value plus offset, the link editor + * needs to know more than just the section the symbol was defined. What is + * needed is the actual value of the symbol without the offset so it can do the + * relocation correctly based on where the value of the symbol got relocated to + * not the value of the expression (with the offset added to the symbol value). + * So for the NeXT 2.0 release no "local" relocation entries are ever used when + * there is a non-zero offset added to a symbol. The "external" and "local" + * relocation entries remain unchanged. + * + * The implemention is quite messy given the compatibility with the existing + * relocation entry format. The ASSUMPTION is that a section will never be + * bigger than 2**24 - 1 (0x00ffffff or 16,777,215) bytes. This assumption + * allows the r_address (which is really an offset) to fit in 24 bits and high + * bit of the r_address field in the relocation_info structure to indicate + * it is really a scattered_relocation_info structure. Since these are only + * used in places where "local" relocation entries are used and not where + * "external" relocation entries are used the r_extern field has been removed. + * + * For scattered loading to work on a RISC machine where some of the references + * are split across two instructions the link editor needs to be assured that + * each reference has a unique 32 bit reference (that more than one reference is + * NOT sharing the same high 16 bits for example) so it move each referenced + * item independent of each other. Some compilers guarantees this but the + * compilers don't so scattered loading can be done on those that do guarantee + * this. + */ + +/// Bit set in `Relocation::r_word0` for scattered relocations. +pub const R_SCATTERED: u32 = 0x8000_0000; + +#[derive(Debug, Clone, Copy)] +pub struct ScatteredRelocationInfo { + /// offset in the section to what is being relocated + pub r_address: u32, + /// if not 0, machine specific relocation type + pub r_type: u8, + /// 0=byte, 1=word, 2=long, 3=quad + pub r_length: u8, + /// was relocated pc relative already + pub r_pcrel: bool, + /// the value the item to be relocated is refering to (without any offset added) + pub r_value: u32, +} + +impl ScatteredRelocationInfo { + /// Combine the fields into a `Relocation`. + pub fn relocation<E: Endian>(self, endian: E) -> Relocation<E> { + let r_word0 = U32::new( + endian, + self.r_address & 0x00ff_ffff + | u32::from(self.r_type & 0xf) << 24 + | u32::from(self.r_length & 0x3) << 28 + | u32::from(self.r_pcrel) << 30 + | R_SCATTERED, + ); + let r_word1 = U32::new(endian, self.r_value); + Relocation { r_word0, r_word1 } + } +} + +/* + * Relocation types used in a generic implementation. Relocation entries for + * normal things use the generic relocation as discribed above and their r_type + * is GENERIC_RELOC_VANILLA (a value of zero). + * + * Another type of generic relocation, GENERIC_RELOC_SECTDIFF, is to support + * the difference of two symbols defined in different sections. That is the + * expression "symbol1 - symbol2 + constant" is a relocatable expression when + * both symbols are defined in some section. For this type of relocation the + * both relocations entries are scattered relocation entries. The value of + * symbol1 is stored in the first relocation entry's r_value field and the + * value of symbol2 is stored in the pair's r_value field. + * + * A special case for a prebound lazy pointer is needed to beable to set the + * value of the lazy pointer back to its non-prebound state. This is done + * using the GENERIC_RELOC_PB_LA_PTR r_type. This is a scattered relocation + * entry where the r_value feild is the value of the lazy pointer not prebound. + */ +/// generic relocation as discribed above +pub const GENERIC_RELOC_VANILLA: u8 = 0; +/// Only follows a GENERIC_RELOC_SECTDIFF +pub const GENERIC_RELOC_PAIR: u8 = 1; +pub const GENERIC_RELOC_SECTDIFF: u8 = 2; +/// prebound lazy pointer +pub const GENERIC_RELOC_PB_LA_PTR: u8 = 3; +pub const GENERIC_RELOC_LOCAL_SECTDIFF: u8 = 4; +/// thread local variables +pub const GENERIC_RELOC_TLV: u8 = 5; + +// Definitions from "/usr/include/mach-o/arm/reloc.h". + +/* + * Relocation types used in the arm implementation. Relocation entries for + * things other than instructions use the same generic relocation as discribed + * in <mach-o/reloc.h> and their r_type is ARM_RELOC_VANILLA, one of the + * *_SECTDIFF or the *_PB_LA_PTR types. The rest of the relocation types are + * for instructions. Since they are for instructions the r_address field + * indicates the 32 bit instruction that the relocation is to be preformed on. + */ +/// generic relocation as discribed above +pub const ARM_RELOC_VANILLA: u8 = 0; +/// the second relocation entry of a pair +pub const ARM_RELOC_PAIR: u8 = 1; +/// a PAIR follows with subtract symbol value +pub const ARM_RELOC_SECTDIFF: u8 = 2; +/// like ARM_RELOC_SECTDIFF, but the symbol referenced was local. +pub const ARM_RELOC_LOCAL_SECTDIFF: u8 = 3; +/// prebound lazy pointer +pub const ARM_RELOC_PB_LA_PTR: u8 = 4; +/// 24 bit branch displacement (to a word address) +pub const ARM_RELOC_BR24: u8 = 5; +/// 22 bit branch displacement (to a half-word address) +pub const ARM_THUMB_RELOC_BR22: u8 = 6; +/// obsolete - a thumb 32-bit branch instruction possibly needing page-spanning branch workaround +pub const ARM_THUMB_32BIT_BRANCH: u8 = 7; + +/* + * For these two r_type relocations they always have a pair following them + * and the r_length bits are used differently. The encoding of the + * r_length is as follows: + * low bit of r_length: + * 0 - :lower16: for movw instructions + * 1 - :upper16: for movt instructions + * high bit of r_length: + * 0 - arm instructions + * 1 - thumb instructions + * the other half of the relocated expression is in the following pair + * relocation entry in the the low 16 bits of r_address field. + */ +pub const ARM_RELOC_HALF: u8 = 8; +pub const ARM_RELOC_HALF_SECTDIFF: u8 = 9; + +// Definitions from "/usr/include/mach-o/arm64/reloc.h". + +/* + * Relocation types used in the arm64 implementation. + */ +/// for pointers +pub const ARM64_RELOC_UNSIGNED: u8 = 0; +/// must be followed by a ARM64_RELOC_UNSIGNED +pub const ARM64_RELOC_SUBTRACTOR: u8 = 1; +/// a B/BL instruction with 26-bit displacement +pub const ARM64_RELOC_BRANCH26: u8 = 2; +/// pc-rel distance to page of target +pub const ARM64_RELOC_PAGE21: u8 = 3; +/// offset within page, scaled by r_length +pub const ARM64_RELOC_PAGEOFF12: u8 = 4; +/// pc-rel distance to page of GOT slot +pub const ARM64_RELOC_GOT_LOAD_PAGE21: u8 = 5; +/// offset within page of GOT slot, scaled by r_length +pub const ARM64_RELOC_GOT_LOAD_PAGEOFF12: u8 = 6; +/// for pointers to GOT slots +pub const ARM64_RELOC_POINTER_TO_GOT: u8 = 7; +/// pc-rel distance to page of TLVP slot +pub const ARM64_RELOC_TLVP_LOAD_PAGE21: u8 = 8; +/// offset within page of TLVP slot, scaled by r_length +pub const ARM64_RELOC_TLVP_LOAD_PAGEOFF12: u8 = 9; +/// must be followed by PAGE21 or PAGEOFF12 +pub const ARM64_RELOC_ADDEND: u8 = 10; + +// An arm64e authenticated pointer. +// +// Represents a pointer to a symbol (like ARM64_RELOC_UNSIGNED). +// Additionally, the resulting pointer is signed. The signature is +// specified in the target location: the addend is restricted to the lower +// 32 bits (instead of the full 64 bits for ARM64_RELOC_UNSIGNED): +// +// |63|62|61-51|50-49| 48 |47 - 32|31 - 0| +// | 1| 0| 0 | key | addr | discriminator | addend | +// +// The key is one of: +// IA: 00 IB: 01 +// DA: 10 DB: 11 +// +// The discriminator field is used as extra signature diversification. +// +// The addr field indicates whether the target address should be blended +// into the discriminator. +// +pub const ARM64_RELOC_AUTHENTICATED_POINTER: u8 = 11; + +// Definitions from "/usr/include/mach-o/ppc/reloc.h". + +/* + * Relocation types used in the ppc implementation. Relocation entries for + * things other than instructions use the same generic relocation as discribed + * above and their r_type is RELOC_VANILLA. The rest of the relocation types + * are for instructions. Since they are for instructions the r_address field + * indicates the 32 bit instruction that the relocation is to be preformed on. + * The fields r_pcrel and r_length are ignored for non-RELOC_VANILLA r_types + * except for PPC_RELOC_BR14. + * + * For PPC_RELOC_BR14 if the r_length is the unused value 3, then the branch was + * statically predicted setting or clearing the Y-bit based on the sign of the + * displacement or the opcode. If this is the case the static linker must flip + * the value of the Y-bit if the sign of the displacement changes for non-branch + * always conditions. + */ +/// generic relocation as discribed above +pub const PPC_RELOC_VANILLA: u8 = 0; +/// the second relocation entry of a pair +pub const PPC_RELOC_PAIR: u8 = 1; +/// 14 bit branch displacement (to a word address) +pub const PPC_RELOC_BR14: u8 = 2; +/// 24 bit branch displacement (to a word address) +pub const PPC_RELOC_BR24: u8 = 3; +/// a PAIR follows with the low half +pub const PPC_RELOC_HI16: u8 = 4; +/// a PAIR follows with the high half +pub const PPC_RELOC_LO16: u8 = 5; +/// Same as the RELOC_HI16 except the low 16 bits and the high 16 bits are added together +/// with the low 16 bits sign extened first. This means if bit 15 of the low 16 bits is +/// set the high 16 bits stored in the instruction will be adjusted. +pub const PPC_RELOC_HA16: u8 = 6; +/// Same as the LO16 except that the low 2 bits are not stored in the instruction and are +/// always zero. This is used in double word load/store instructions. +pub const PPC_RELOC_LO14: u8 = 7; +/// a PAIR follows with subtract symbol value +pub const PPC_RELOC_SECTDIFF: u8 = 8; +/// prebound lazy pointer +pub const PPC_RELOC_PB_LA_PTR: u8 = 9; +/// section difference forms of above. a PAIR +pub const PPC_RELOC_HI16_SECTDIFF: u8 = 10; +/// follows these with subtract symbol value +pub const PPC_RELOC_LO16_SECTDIFF: u8 = 11; +pub const PPC_RELOC_HA16_SECTDIFF: u8 = 12; +pub const PPC_RELOC_JBSR: u8 = 13; +pub const PPC_RELOC_LO14_SECTDIFF: u8 = 14; +/// like PPC_RELOC_SECTDIFF, but the symbol referenced was local. +pub const PPC_RELOC_LOCAL_SECTDIFF: u8 = 15; + +// Definitions from "/usr/include/mach-o/x86_64/reloc.h". + +/* + * Relocations for x86_64 are a bit different than for other architectures in + * Mach-O: Scattered relocations are not used. Almost all relocations produced + * by the compiler are external relocations. An external relocation has the + * r_extern bit set to 1 and the r_symbolnum field contains the symbol table + * index of the target label. + * + * When the assembler is generating relocations, if the target label is a local + * label (begins with 'L'), then the previous non-local label in the same + * section is used as the target of the external relocation. An addend is used + * with the distance from that non-local label to the target label. Only when + * there is no previous non-local label in the section is an internal + * relocation used. + * + * The addend (i.e. the 4 in _foo+4) is encoded in the instruction (Mach-O does + * not have RELA relocations). For PC-relative relocations, the addend is + * stored directly in the instruction. This is different from other Mach-O + * architectures, which encode the addend minus the current section offset. + * + * The relocation types are: + * + * X86_64_RELOC_UNSIGNED // for absolute addresses + * X86_64_RELOC_SIGNED // for signed 32-bit displacement + * X86_64_RELOC_BRANCH // a CALL/JMP instruction with 32-bit displacement + * X86_64_RELOC_GOT_LOAD // a MOVQ load of a GOT entry + * X86_64_RELOC_GOT // other GOT references + * X86_64_RELOC_SUBTRACTOR // must be followed by a X86_64_RELOC_UNSIGNED + * + * The following are sample assembly instructions, followed by the relocation + * and section content they generate in an object file: + * + * call _foo + * r_type=X86_64_RELOC_BRANCH, r_length=2, r_extern=1, r_pcrel=1, r_symbolnum=_foo + * E8 00 00 00 00 + * + * call _foo+4 + * r_type=X86_64_RELOC_BRANCH, r_length=2, r_extern=1, r_pcrel=1, r_symbolnum=_foo + * E8 04 00 00 00 + * + * movq _foo@GOTPCREL(%rip), %rax + * r_type=X86_64_RELOC_GOT_LOAD, r_length=2, r_extern=1, r_pcrel=1, r_symbolnum=_foo + * 48 8B 05 00 00 00 00 + * + * pushq _foo@GOTPCREL(%rip) + * r_type=X86_64_RELOC_GOT, r_length=2, r_extern=1, r_pcrel=1, r_symbolnum=_foo + * FF 35 00 00 00 00 + * + * movl _foo(%rip), %eax + * r_type=X86_64_RELOC_SIGNED, r_length=2, r_extern=1, r_pcrel=1, r_symbolnum=_foo + * 8B 05 00 00 00 00 + * + * movl _foo+4(%rip), %eax + * r_type=X86_64_RELOC_SIGNED, r_length=2, r_extern=1, r_pcrel=1, r_symbolnum=_foo + * 8B 05 04 00 00 00 + * + * movb $0x12, _foo(%rip) + * r_type=X86_64_RELOC_SIGNED, r_length=2, r_extern=1, r_pcrel=1, r_symbolnum=_foo + * C6 05 FF FF FF FF 12 + * + * movl $0x12345678, _foo(%rip) + * r_type=X86_64_RELOC_SIGNED, r_length=2, r_extern=1, r_pcrel=1, r_symbolnum=_foo + * C7 05 FC FF FF FF 78 56 34 12 + * + * .quad _foo + * r_type=X86_64_RELOC_UNSIGNED, r_length=3, r_extern=1, r_pcrel=0, r_symbolnum=_foo + * 00 00 00 00 00 00 00 00 + * + * .quad _foo+4 + * r_type=X86_64_RELOC_UNSIGNED, r_length=3, r_extern=1, r_pcrel=0, r_symbolnum=_foo + * 04 00 00 00 00 00 00 00 + * + * .quad _foo - _bar + * r_type=X86_64_RELOC_SUBTRACTOR, r_length=3, r_extern=1, r_pcrel=0, r_symbolnum=_bar + * r_type=X86_64_RELOC_UNSIGNED, r_length=3, r_extern=1, r_pcrel=0, r_symbolnum=_foo + * 00 00 00 00 00 00 00 00 + * + * .quad _foo - _bar + 4 + * r_type=X86_64_RELOC_SUBTRACTOR, r_length=3, r_extern=1, r_pcrel=0, r_symbolnum=_bar + * r_type=X86_64_RELOC_UNSIGNED, r_length=3, r_extern=1, r_pcrel=0, r_symbolnum=_foo + * 04 00 00 00 00 00 00 00 + * + * .long _foo - _bar + * r_type=X86_64_RELOC_SUBTRACTOR, r_length=2, r_extern=1, r_pcrel=0, r_symbolnum=_bar + * r_type=X86_64_RELOC_UNSIGNED, r_length=2, r_extern=1, r_pcrel=0, r_symbolnum=_foo + * 00 00 00 00 + * + * lea L1(%rip), %rax + * r_type=X86_64_RELOC_SIGNED, r_length=2, r_extern=1, r_pcrel=1, r_symbolnum=_prev + * 48 8d 05 12 00 00 00 + * // assumes _prev is the first non-local label 0x12 bytes before L1 + * + * lea L0(%rip), %rax + * r_type=X86_64_RELOC_SIGNED, r_length=2, r_extern=0, r_pcrel=1, r_symbolnum=3 + * 48 8d 05 56 00 00 00 + * // assumes L0 is in third section and there is no previous non-local label. + * // The rip-relative-offset of 0x00000056 is L0-address_of_next_instruction. + * // address_of_next_instruction is the address of the relocation + 4. + * + * add $6,L0(%rip) + * r_type=X86_64_RELOC_SIGNED_1, r_length=2, r_extern=0, r_pcrel=1, r_symbolnum=3 + * 83 05 18 00 00 00 06 + * // assumes L0 is in third section and there is no previous non-local label. + * // The rip-relative-offset of 0x00000018 is L0-address_of_next_instruction. + * // address_of_next_instruction is the address of the relocation + 4 + 1. + * // The +1 comes from SIGNED_1. This is used because the relocation is not + * // at the end of the instruction. + * + * .quad L1 + * r_type=X86_64_RELOC_UNSIGNED, r_length=3, r_extern=1, r_pcrel=0, r_symbolnum=_prev + * 12 00 00 00 00 00 00 00 + * // assumes _prev is the first non-local label 0x12 bytes before L1 + * + * .quad L0 + * r_type=X86_64_RELOC_UNSIGNED, r_length=3, r_extern=0, r_pcrel=0, r_symbolnum=3 + * 56 00 00 00 00 00 00 00 + * // assumes L0 is in third section, has an address of 0x00000056 in .o + * // file, and there is no previous non-local label + * + * .quad _foo - . + * r_type=X86_64_RELOC_SUBTRACTOR, r_length=3, r_extern=1, r_pcrel=0, r_symbolnum=_prev + * r_type=X86_64_RELOC_UNSIGNED, r_length=3, r_extern=1, r_pcrel=0, r_symbolnum=_foo + * EE FF FF FF FF FF FF FF + * // assumes _prev is the first non-local label 0x12 bytes before this + * // .quad + * + * .quad _foo - L1 + * r_type=X86_64_RELOC_SUBTRACTOR, r_length=3, r_extern=1, r_pcrel=0, r_symbolnum=_prev + * r_type=X86_64_RELOC_UNSIGNED, r_length=3, r_extern=1, r_pcrel=0, r_symbolnum=_foo + * EE FF FF FF FF FF FF FF + * // assumes _prev is the first non-local label 0x12 bytes before L1 + * + * .quad L1 - _prev + * // No relocations. This is an assembly time constant. + * 12 00 00 00 00 00 00 00 + * // assumes _prev is the first non-local label 0x12 bytes before L1 + * + * + * + * In final linked images, there are only two valid relocation kinds: + * + * r_type=X86_64_RELOC_UNSIGNED, r_length=3, r_pcrel=0, r_extern=1, r_symbolnum=sym_index + * This tells dyld to add the address of a symbol to a pointer sized (8-byte) + * piece of data (i.e on disk the 8-byte piece of data contains the addend). The + * r_symbolnum contains the index into the symbol table of the target symbol. + * + * r_type=X86_64_RELOC_UNSIGNED, r_length=3, r_pcrel=0, r_extern=0, r_symbolnum=0 + * This tells dyld to adjust the pointer sized (8-byte) piece of data by the amount + * the containing image was loaded from its base address (e.g. slide). + * + */ +/// for absolute addresses +pub const X86_64_RELOC_UNSIGNED: u8 = 0; +/// for signed 32-bit displacement +pub const X86_64_RELOC_SIGNED: u8 = 1; +/// a CALL/JMP instruction with 32-bit displacement +pub const X86_64_RELOC_BRANCH: u8 = 2; +/// a MOVQ load of a GOT entry +pub const X86_64_RELOC_GOT_LOAD: u8 = 3; +/// other GOT references +pub const X86_64_RELOC_GOT: u8 = 4; +/// must be followed by a X86_64_RELOC_UNSIGNED +pub const X86_64_RELOC_SUBTRACTOR: u8 = 5; +/// for signed 32-bit displacement with a -1 addend +pub const X86_64_RELOC_SIGNED_1: u8 = 6; +/// for signed 32-bit displacement with a -2 addend +pub const X86_64_RELOC_SIGNED_2: u8 = 7; +/// for signed 32-bit displacement with a -4 addend +pub const X86_64_RELOC_SIGNED_4: u8 = 8; +/// for thread local variables +pub const X86_64_RELOC_TLV: u8 = 9; + +unsafe_impl_pod!(FatHeader, FatArch32, FatArch64,); +unsafe_impl_endian_pod!( + DyldCacheHeader, + DyldCacheMappingInfo, + DyldCacheImageInfo, + DyldSubCacheInfo, + MachHeader32, + MachHeader64, + LoadCommand, + LcStr, + SegmentCommand32, + SegmentCommand64, + Section32, + Section64, + Fvmlib, + FvmlibCommand, + Dylib, + DylibCommand, + SubFrameworkCommand, + SubClientCommand, + SubUmbrellaCommand, + SubLibraryCommand, + PreboundDylibCommand, + DylinkerCommand, + ThreadCommand, + RoutinesCommand32, + RoutinesCommand64, + SymtabCommand, + DysymtabCommand, + DylibTableOfContents, + DylibModule32, + DylibModule64, + DylibReference, + TwolevelHintsCommand, + TwolevelHint, + PrebindCksumCommand, + UuidCommand, + RpathCommand, + LinkeditDataCommand, + FilesetEntryCommand, + EncryptionInfoCommand32, + EncryptionInfoCommand64, + VersionMinCommand, + BuildVersionCommand, + BuildToolVersion, + DyldInfoCommand, + LinkerOptionCommand, + SymsegCommand, + IdentCommand, + FvmfileCommand, + EntryPointCommand, + SourceVersionCommand, + DataInCodeEntry, + //TlvDescriptor, + NoteCommand, + Nlist32, + Nlist64, + Relocation, +); |