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