kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

macho.h (9555B)


      1 /* Mach-O wire-format constants, structs, and per-arch reloc translators
      2  * shared between obj/macho_emit.c, obj/macho_read.c, and link/link_macho.c
      3  * (none of which exist yet).
      4  *
      5  * Private to src/. The public ObjBuilder/Linker surface is format-neutral
      6  * (obj/obj.h, link/link.h); the Mach-O spelling of those abstractions only
      7  * exists inside libkit.
      8  *
      9  * Scope: 64-bit little-endian only (MH_MAGIC_64). The per-arch reloc
     10  * mapping is split across macho_reloc_<arch>.c, mirroring the ELF
     11  * arrangement; emit_macho and the linker dispatch to the right
     12  * translator by Compiler.target.arch. */
     13 
     14 #ifndef KIT_OBJ_MACHO_H
     15 #define KIT_OBJ_MACHO_H
     16 
     17 #include "core/core.h"
     18 #include "obj/format.h"
     19 #include "obj/obj.h"
     20 
     21 /* ---- magic ---- */
     22 #define MH_MAGIC_64 0xfeedfacfu
     23 #define MH_CIGAM_64                                        \
     24   0xcffaedfeu /* byte-swapped (big-endian host reading LE) \
     25                */
     26 
     27 /* ---- cputype / cpusubtype (subset kit cares about) ---- */
     28 #define CPU_TYPE_X86 0x00000007
     29 #define CPU_TYPE_X86_64 0x01000007
     30 #define CPU_TYPE_ARM 0x0000000C
     31 #define CPU_TYPE_ARM64 0x0100000C
     32 
     33 #define CPU_SUBTYPE_X86_64_ALL 3
     34 #define CPU_SUBTYPE_ARM64_ALL 0
     35 
     36 /* ---- filetype ---- */
     37 #define MH_OBJECT 0x1  /* relocatable .o (no segments split) */
     38 #define MH_EXECUTE 0x2 /* main executable */
     39 #define MH_DYLIB 0x6   /* dynamically bound shared library */
     40 #define MH_DYLINKER 0x7
     41 #define MH_BUNDLE 0x8
     42 
     43 /* ---- mach_header flags (subset) ---- */
     44 #define MH_NOUNDEFS 0x00000001u
     45 #define MH_DYLDLINK 0x00000004u
     46 #define MH_TWOLEVEL 0x00000080u
     47 #define MH_SUBSECTIONS_VIA_SYMBOLS 0x00002000u
     48 #define MH_PIE 0x00200000u
     49 #define MH_HAS_TLV_DESCRIPTORS 0x00800000u
     50 
     51 /* ---- load command IDs (subset kit will emit / consume) ---- */
     52 #define LC_REQ_DYLD 0x80000000u
     53 #define LC_SEGMENT_64 0x19u
     54 #define LC_SYMTAB 0x02u
     55 #define LC_UNIXTHREAD 0x05u
     56 #define LC_DYSYMTAB 0x0bu
     57 #define LC_LOAD_DYLIB 0x0cu
     58 #define LC_ID_DYLIB 0x0du
     59 #define LC_LOAD_DYLINKER 0x0eu
     60 #define LC_LOAD_WEAK_DYLIB (0x18u | LC_REQ_DYLD)
     61 #define LC_RPATH (0x1cu | LC_REQ_DYLD)
     62 #define LC_REEXPORT_DYLIB (0x1fu | LC_REQ_DYLD)
     63 #define LC_UUID 0x1bu
     64 #define LC_FUNCTION_STARTS 0x26u
     65 #define LC_DATA_IN_CODE 0x29u
     66 #define LC_SOURCE_VERSION 0x2au
     67 #define LC_BUILD_VERSION 0x32u
     68 #define LC_DYLD_EXPORTS_TRIE (0x33u | LC_REQ_DYLD)
     69 #define LC_DYLD_CHAINED_FIXUPS (0x34u | LC_REQ_DYLD)
     70 #define LC_MAIN (0x28u | LC_REQ_DYLD)
     71 
     72 /* ---- LC_BUILD_VERSION platform values ---- */
     73 #define PLATFORM_MACOS 1u
     74 #define PLATFORM_IOS 2u
     75 #define PLATFORM_IOSSIMULATOR 7u
     76 
     77 /* Single source of truth for the OS <-> LC_BUILD_VERSION platform mapping. The
     78  * first entry (macOS) is the fallback for both directions. */
     79 static const struct {
     80   KitOSKind os;
     81   u32 platform;
     82 } macho_os_platform_table[] = {
     83     {KIT_OS_MACOS, PLATFORM_MACOS},
     84     {KIT_OS_IOS, PLATFORM_IOS},
     85     {KIT_OS_IOS_SIMULATOR, PLATFORM_IOSSIMULATOR},
     86 };
     87 
     88 static inline u32 macho_platform_for_target(KitTargetSpec target) {
     89   size_t i;
     90   for (i = 1;
     91        i < sizeof macho_os_platform_table / sizeof macho_os_platform_table[0];
     92        ++i)
     93     if (macho_os_platform_table[i].os == target.os)
     94       return macho_os_platform_table[i].platform;
     95   return PLATFORM_MACOS;
     96 }
     97 
     98 static inline KitOSKind macho_os_for_platform(u32 platform) {
     99   size_t i;
    100   for (i = 1;
    101        i < sizeof macho_os_platform_table / sizeof macho_os_platform_table[0];
    102        ++i)
    103     if (macho_os_platform_table[i].platform == platform)
    104       return macho_os_platform_table[i].os;
    105   return KIT_OS_MACOS;
    106 }
    107 
    108 /* ---- VM protection bits (segment maxprot / initprot) ---- */
    109 #define VM_PROT_READ 0x1u
    110 #define VM_PROT_WRITE 0x2u
    111 #define VM_PROT_EXECUTE 0x4u
    112 
    113 /* ---- LC_DYLD_CHAINED_FIXUPS encodings (subset kit emits/reads) ---- */
    114 #define DYLD_CHAINED_PTR_64 2u /* pointer_format */
    115 #define DYLD_CHAINED_IMPORT 1u /* imports_format */
    116 
    117 /* ---- header sizes ---- */
    118 #define MACHO_HDR64_SIZE 32u
    119 #define MACHO_SEGCMD64_SIZE 72u
    120 #define MACHO_SECT64_SIZE 80u
    121 #define MACHO_SYMTAB_CMD_SIZE 24u
    122 #define MACHO_DYSYMTAB_CMD_SIZE 80u
    123 #define MACHO_NLIST64_SIZE 16u
    124 #define MACHO_RELOC_SIZE 8u
    125 
    126 /* ---- on-disk structures (LE) ---- */
    127 
    128 typedef struct MachHeader64 {
    129   u32 magic;      /* MH_MAGIC_64 */
    130   u32 cputype;    /* CPU_TYPE_*  */
    131   u32 cpusubtype; /* CPU_SUBTYPE_* (low 24 bits) | feature flags */
    132   u32 filetype;   /* MH_OBJECT / MH_EXECUTE / ... */
    133   u32 ncmds;      /* number of load commands */
    134   u32 sizeofcmds; /* total bytes of load commands */
    135   u32 flags;      /* MH_* */
    136   u32 reserved;
    137 } MachHeader64;
    138 
    139 typedef struct MachLoadCmd {
    140   u32 cmd;     /* LC_* */
    141   u32 cmdsize; /* size of this command including header */
    142 } MachLoadCmd;
    143 
    144 /* LC_SEGMENT_64: one per Mach-O segment.  Followed by `nsects`
    145  * MachSection64 records inline. */
    146 typedef struct MachSegmentCmd64 {
    147   u32 cmd;     /* LC_SEGMENT_64 */
    148   u32 cmdsize; /* sizeof(this) + nsects * sizeof(MachSection64) */
    149   char segname[16];
    150   u64 vmaddr;
    151   u64 vmsize;
    152   u64 fileoff;
    153   u64 filesize;
    154   u32 maxprot;
    155   u32 initprot;
    156   u32 nsects;
    157   u32 flags;
    158 } MachSegmentCmd64;
    159 
    160 /* Mach-O section descriptor, embedded inside an LC_SEGMENT_64. */
    161 typedef struct MachSection64 {
    162   char sectname[16];
    163   char segname[16];
    164   u64 addr;
    165   u64 size;
    166   u32 offset;
    167   u32 align; /* power of 2 (so 3 means 8-byte align) */
    168   u32 reloff;
    169   u32 nreloc;
    170   u32 flags;
    171   u32 reserved1;
    172   u32 reserved2;
    173   u32 reserved3;
    174 } MachSection64;
    175 
    176 typedef struct MachSymtabCmd {
    177   u32 cmd; /* LC_SYMTAB */
    178   u32 cmdsize;
    179   u32 symoff;
    180   u32 nsyms;
    181   u32 stroff;
    182   u32 strsize;
    183 } MachSymtabCmd;
    184 
    185 typedef struct MachDysymtabCmd {
    186   u32 cmd; /* LC_DYSYMTAB */
    187   u32 cmdsize;
    188   u32 ilocalsym;
    189   u32 nlocalsym;
    190   u32 iextdefsym;
    191   u32 nextdefsym;
    192   u32 iundefsym;
    193   u32 nundefsym;
    194   u32 tocoff;
    195   u32 ntoc;
    196   u32 modtaboff;
    197   u32 nmodtab;
    198   u32 extrefsymoff;
    199   u32 nextrefsyms;
    200   u32 indirectsymoff;
    201   u32 nindirectsyms;
    202   u32 extreloff;
    203   u32 nextrel;
    204   u32 locreloff;
    205   u32 nlocrel;
    206 } MachDysymtabCmd;
    207 
    208 /* nlist_64 entry. n_type packs N_STAB | N_PEXT | N_TYPE | N_EXT. */
    209 typedef struct MachNlist64 {
    210   u32 n_strx;
    211   u8 n_type;
    212   u8 n_sect; /* 1-based section index, 0 = NO_SECT */
    213   u16 n_desc;
    214   u64 n_value;
    215 } MachNlist64;
    216 
    217 /* ---- nlist n_type bits ---- */
    218 #define N_STAB 0xe0u
    219 #define N_PEXT 0x10u
    220 #define N_TYPE 0x0eu
    221 #define N_EXT 0x01u
    222 
    223 /* N_TYPE values */
    224 #define N_UNDF 0x0u
    225 #define N_ABS 0x2u
    226 #define N_SECT 0xeu
    227 #define N_PBUD 0xcu
    228 #define N_INDR 0xau
    229 
    230 #define NO_SECT 0u
    231 
    232 /* n_desc bits (subset) */
    233 #define N_NO_DEAD_STRIP 0x0020u
    234 #define N_WEAK_REF 0x0040u
    235 #define N_WEAK_DEF 0x0080u
    236 #define N_ALT_ENTRY 0x0200u
    237 #define REFERENCE_FLAG_UNDEFINED_NON_LAZY 0x0u
    238 #define REFERENCE_FLAG_UNDEFINED_LAZY 0x1u
    239 
    240 /* ---- section type / attributes (subset of section.flags) ---- */
    241 #define SECTION_TYPE 0x000000ffu
    242 #define SECTION_ATTRIBUTES 0xffffff00u
    243 
    244 #define S_REGULAR 0x0u
    245 #define S_ZEROFILL 0x1u
    246 #define S_CSTRING_LITERALS 0x2u
    247 #define S_NON_LAZY_SYMBOL_POINTERS 0x6u
    248 #define S_LAZY_SYMBOL_POINTERS 0x7u
    249 #define S_SYMBOL_STUBS 0x8u
    250 #define S_MOD_INIT_FUNC_POINTERS 0x9u
    251 #define S_MOD_TERM_FUNC_POINTERS 0xau
    252 #define S_COALESCED 0xbu
    253 #define S_INTERPOSING 0xdu
    254 #define S_THREAD_LOCAL_REGULAR 0x11u
    255 #define S_THREAD_LOCAL_ZEROFILL 0x12u
    256 #define S_THREAD_LOCAL_VARIABLES 0x13u
    257 #define S_THREAD_LOCAL_VARIABLE_POINTERS 0x14u
    258 #define S_THREAD_LOCAL_INIT_FUNCTION_POINTERS 0x15u
    259 
    260 #define S_ATTR_PURE_INSTRUCTIONS 0x80000000u
    261 #define S_ATTR_SOME_INSTRUCTIONS 0x00000400u
    262 #define S_ATTR_DEBUG 0x02000000u
    263 #define S_ATTR_NO_DEAD_STRIP 0x10000000u
    264 
    265 /* ---- relocation_info (external/scattered union; kit emits only the
    266  *      external form for arm64 / x86_64) ----
    267  *
    268  * Wire layout (little-endian):
    269  *   u32 r_address;       offset within the section the reloc patches
    270  *   u32 packed;          bitfield: r_symbolnum:24, r_pcrel:1, r_length:2,
    271  *                                  r_extern:1, r_type:4
    272  *
    273  * length encoding: 0=byte, 1=word, 2=long, 3=quad. */
    274 typedef struct MachRelocInfo {
    275   u32 r_address;
    276   u32 r_packed;
    277 } MachRelocInfo;
    278 
    279 /* ---- arm64 reloc types (r_type field) ---- */
    280 #define ARM64_RELOC_UNSIGNED 0u
    281 #define ARM64_RELOC_SUBTRACTOR 1u
    282 #define ARM64_RELOC_BRANCH26 2u
    283 #define ARM64_RELOC_PAGE21 3u
    284 #define ARM64_RELOC_PAGEOFF12 4u
    285 #define ARM64_RELOC_GOT_LOAD_PAGE21 5u
    286 #define ARM64_RELOC_GOT_LOAD_PAGEOFF12 6u
    287 #define ARM64_RELOC_POINTER_TO_GOT 7u
    288 #define ARM64_RELOC_TLVP_LOAD_PAGE21 8u
    289 #define ARM64_RELOC_TLVP_LOAD_PAGEOFF12 9u
    290 #define ARM64_RELOC_ADDEND 10u
    291 
    292 /* ---- x86_64 reloc types (for the translator that lands when x64
    293  *      codegen does) ---- */
    294 #define X86_64_RELOC_UNSIGNED 0u
    295 #define X86_64_RELOC_SIGNED 1u
    296 #define X86_64_RELOC_BRANCH 2u
    297 #define X86_64_RELOC_GOT_LOAD 3u
    298 #define X86_64_RELOC_GOT 4u
    299 #define X86_64_RELOC_SUBTRACTOR 5u
    300 #define X86_64_RELOC_SIGNED_1 6u
    301 #define X86_64_RELOC_SIGNED_2 7u
    302 #define X86_64_RELOC_SIGNED_4 8u
    303 #define X86_64_RELOC_TLV 9u
    304 
    305 /* Map kit-canonical RelocKind <-> arm64 Mach-O reloc type.  Returns
    306  * (u32)-1 on unsupported kinds; the caller (emit_macho / read_macho)
    307  * panics with a diagnostic.  Stubs in macho_reloc_aarch64.c until the
    308  * Phase 2 writer lands. */
    309 u32 macho_aarch64_reloc_to(u32 kind /* RelocKind */);
    310 u32 macho_aarch64_reloc_pcrel(u32 kind /* RelocKind */);
    311 u32 macho_aarch64_reloc_length(u32 kind /* RelocKind */);
    312 int macho_aarch64_reloc_decode(const MachoRelocEntry*, MachoRelocDecoded*);
    313 u32 macho_x86_64_reloc_to(u32 kind /* RelocKind */);
    314 u32 macho_x86_64_reloc_pcrel(u32 kind /* RelocKind */);
    315 u32 macho_x86_64_reloc_length(u32 kind /* RelocKind */);
    316 int macho_x86_64_reloc_decode(const MachoRelocEntry*, MachoRelocDecoded*);
    317 
    318 #endif