1 
2 /* Mach-O object file format
3  * Translated to D from mach.h
4  */
5 
6 module dmd.backend.mach;
7 
8 // Online documentation: https://dlang.org/phobos/dmd_backend_mach.html
9 
10 alias cpu_type_t = int;
11 alias cpu_subtype_t = int;
12 alias vm_prot_t = int;
13 
14 enum
15 {
16     // magic
17     MH_MAGIC = 0xfeedface,
18     MH_CIGAM = 0xcefaedfe,
19 
20     // cputype
21     CPU_TYPE_I386      =  cast(cpu_type_t)7,
22     CPU_TYPE_X86_64    = cast(cpu_type_t)7 | 0x1000000,
23     CPU_TYPE_POWERPC   = cast(cpu_type_t)18,
24     CPU_TYPE_POWERPC64 = CPU_TYPE_POWERPC | 0x1000000,
25 
26     // cpusubtype
27     CPU_SUBTYPE_POWERPC_ALL = cast(cpu_subtype_t)0,
28     CPU_SUBTYPE_I386_ALL    = cast(cpu_subtype_t)3,
29 
30     // filetype
31     MH_OBJECT       = 1,
32     MH_EXECUTE      = 2,
33     MH_BUNDLE       = 8,
34     MH_DYLIB        = 6,
35     MH_PRELOAD      = 5,
36     MH_CORE         = 4,
37     MH_DYLINKER     = 7,
38     MH_DSYM         = 10,
39 
40     // flags
41     MH_NOUNDEFS                = 1,
42     MH_INCRLINK                = 2,
43     MH_DYLDLINK                = 4,
44     MH_TWOLEVEL                = 0x80,
45     MH_BINDATLOAD              = 8,
46     MH_PREBOUND                = 0x10,
47     MH_PREBINDABLE             = 0x800,
48     MH_NOFIXPREBINDING         = 0x400,
49     MH_ALLMODSBOUND            = 0x1000,
50     MH_CANONICAL               = 0x4000,
51     MH_SPLIT_SEGS              = 0x20,
52     MH_FORCE_FLAT              = 0x100,
53     MH_SUBSECTIONS_VIA_SYMBOLS = 0x2000,
54     MH_NOMULTIDEFS             = 0x200,
55 }
56 
57 struct mach_header
58 {
59     uint magic;
60     cpu_type_t cputype;
61     cpu_subtype_t cpusubtype;
62     uint filetype;
63     uint ncmds;
64     uint sizeofcmds;
65     uint flags;
66 }
67 
68 enum
69 {
70     // magic
71     MH_MAGIC_64 = 0xfeedfacf,
72     MH_CIGAM_64 = 0xcffaedfe,
73 }
74 
75 struct mach_header_64
76 {
77     uint magic;
78     cpu_type_t cputype;
79     cpu_subtype_t cpusubtype;
80     uint filetype;
81     uint ncmds;
82     uint sizeofcmds;
83     uint flags;
84     uint reserved;
85 }
86 
87 enum
88 {
89     // cmd
90     LC_SEGMENT      = 1,
91     LC_SYMTAB       = 2,
92     LC_DYSYMTAB     = 11,
93     LC_SEGMENT_64   = 0x19,
94 }
95 
96 struct load_command
97 {
98     uint cmd;
99     uint cmdsize;
100 }
101 
102 struct uuid_command
103 {
104     uint cmd;
105     uint cmdsize;
106     ubyte[16] uuid;
107 }
108 
109 enum
110 {
111     // flags
112     SG_HIGHVM              = 1,
113     SG_FVMLIB              = 2,
114     SG_NORELOC             = 4,
115     SG_PROTECTED_VERSION_1 = 8,
116 }
117 
118 struct segment_command
119 {
120     uint cmd;
121     uint cmdsize;
122     char[16] segname;
123     uint vmaddr;
124     uint vmsize;
125     uint fileoff;
126     uint filesize;
127     vm_prot_t maxprot;
128     vm_prot_t initprot;
129     uint nsects;
130     uint flags;
131 }
132 
133 struct segment_command_64
134 {
135     uint cmd;
136     uint cmdsize;
137     char[16] segname;
138     ulong vmaddr;
139     ulong vmsize;
140     ulong fileoff;
141     ulong filesize;
142     vm_prot_t maxprot;
143     vm_prot_t initprot;
144     uint nsects;
145     uint flags;
146 }
147 
148 enum
149 {
150     // flags
151     SECTION_TYPE       = 0xFF,
152     SECTION_ATTRIBUTES = 0xFFFFFF00,
153 
154     S_REGULAR               = 0,
155     S_ZEROFILL              = 1,
156     S_CSTRING_LITERALS      = 2,
157     S_4BYTE_LITERALS        = 3,
158     S_8BYTE_LITERALS        = 4,
159     S_LITERAL_POINTERS      = 5,
160 
161     S_NON_LAZY_SYMBOL_POINTERS      = 6,
162     S_LAZY_SYMBOL_POINTERS          = 7,
163     S_SYMBOL_STUBS                  = 8,
164     S_MOD_INIT_FUNC_POINTERS        = 9,
165     S_MOD_TERM_FUNC_POINTERS        = 10,
166     S_COALESCED                     = 11,
167     S_GB_ZEROFILL                   = 12,
168     S_INTERPOSING                   = 13,
169     S_16BYTE_LITERALS               = 14,
170     S_DTRACE_DOF                    = 15,
171 
172     S_THREAD_LOCAL_REGULAR          = 0x11, // template of initial values for TLVs
173     S_THREAD_LOCAL_ZEROFILL         = 0x12, // template of initial values for TLVs
174     S_THREAD_LOCAL_VARIABLES        = 0x13, // TLV descriptors
175 
176     SECTION_ATTRIBUTES_USR          = 0xFF000000,
177     S_ATTR_PURE_INSTRUCTIONS        = 0x80000000,
178     S_ATTR_NO_TOC                   = 0x40000000,
179     S_ATTR_STRIP_STATIC_SYMS        = 0x20000000,
180     S_ATTR_NO_DEAD_STRIP            = 0x10000000,
181     S_ATTR_LIVE_SUPPORT             = 0x8000000,
182     S_ATTR_SELF_MODIFYING_CODE      = 0x4000000,
183     S_ATTR_DEBUG                    = 0x2000000,
184 
185     SECTION_ATTRIBUTES_SYS          = 0xFFFF00,
186     S_ATTR_SOME_INSTRUCTIONS        = 0x000400,
187     S_ATTR_EXT_RELOC                = 0x000200,
188     S_ATTR_LOC_RELOC                = 0x000100,
189 }
190 
191 struct section
192 {
193     char[16] sectname;
194     char[16] segname;
195     uint addr;
196     uint size;
197     uint offset;
198     uint _align;
199     uint reloff;
200     uint nreloc;
201     uint flags;
202 
203     uint reserved1;
204     uint reserved2;
205 }
206 
207 struct section_64
208 {
209     char[16] sectname;
210     char[16] segname;
211     ulong addr;
212     ulong size;
213     uint offset;
214     uint _align;
215     uint reloff;
216     uint nreloc;
217     uint flags;
218     uint reserved1;
219     uint reserved2;
220     uint reserved3;
221 }
222 
223 struct twolevel_hints_command
224 {
225     uint cmd;
226     uint cmdsize;
227     uint offset;
228     uint nhints;
229 }
230 
231 struct twolevel_hint
232 {
233     version (all)
234     {
235         uint xxx;
236     }
237     else
238     {
239         // uint isub_image:8, itoc:24;
240     }
241 }
242 
243 struct symtab_command
244 {
245     uint cmd;
246     uint cmdsize;
247     uint symoff;
248     uint nsyms;
249     uint stroff;
250     uint strsize;
251 }
252 
253 enum
254 {
255     // n_type
256     N_EXT   = 1,
257     N_STAB  = 0xE0,
258     N_PEXT  = 0x10,
259     N_TYPE  = 0x0E,
260     N_UNDF  = 0,
261     N_ABS   = 2,
262     N_INDR  = 10,
263     N_PBUD  = 12,
264     N_SECT  = 14,
265 }
266 
267 enum
268 {
269     // n_desc
270     N_ARM_THUMB_DEF   =     8,
271     N_NO_DEAD_STRIP   =  0x20,
272     N_DESC_DISCARDED  =  0x20,
273     N_WEAK_REF        =  0x40,
274     N_WEAK_DEF        =  0x80,
275     N_REF_TO_WEAK     =  0x80,
276     N_SYMBOL_RESOLVER = 0x100,
277 }
278 
279 enum
280 {
281     // n_desc
282     REFERENCE_FLAG_UNDEFINED_NON_LAZY         = 0,
283     REFERENCE_FLAG_UNDEFINED_LAZY             = 1,
284     REFERENCE_FLAG_DEFINED                    = 2,
285     REFERENCE_FLAG_PRIVATE_DEFINED            = 3,
286     REFERENCE_FLAG_PRIVATE_UNDEFINED_NON_LAZY = 4,
287     REFERENCE_FLAG_PRIVATE_UNDEFINED_LAZY     = 5,
288 }
289 
290 struct nlist
291 {
292     union
293     {
294         int n_strx;
295     }
296     ubyte n_type;
297     ubyte n_sect;
298     short n_desc;
299     uint n_value;
300 }
301 
302 struct nlist_64
303 {
304     union
305     {
306         uint n_strx;
307     }
308     ubyte n_type;
309     ubyte n_sect;
310     ushort n_desc;
311     ulong n_value;
312 }
313 
314 struct dysymtab_command
315 {
316     uint cmd;
317     uint cmdsize;
318     uint ilocalsym;
319     uint nlocalsym;
320     uint iextdefsym;
321     uint nextdefsym;
322     uint iundefsym;
323     uint nundefsym;
324     uint tocoff;
325     uint ntoc;
326     uint modtaboff;
327     uint nmodtab;
328     uint extrefsymoff;
329     uint nextrefsyms;
330     uint indirectsymoff;
331     uint nindirectsyms;
332     uint extreloff;
333     uint nextrel;
334     uint locreloff;
335     uint nlocrel;
336 }
337 
338 enum
339 {
340     // r_address
341     R_SCATTERED = 0x80000000,
342 
343     // r_type
344     // for i386
345     GENERIC_RELOC_VANILLA               = 0,
346     GENERIC_RELOC_PAIR                  = 1,
347     GENERIC_RELOC_SECTDIFF              = 2,
348     GENERIC_RELOC_PB_LA_PTR             = 3,
349     GENERIC_RELOC_LOCAL_SECTDIFF        = 4,
350 
351     // for x86_64
352     X86_64_RELOC_UNSIGNED               = 0,
353     X86_64_RELOC_SIGNED                 = 1,
354     X86_64_RELOC_BRANCH                 = 2,
355     X86_64_RELOC_GOT_LOAD               = 3,
356     X86_64_RELOC_GOT                    = 4,
357     X86_64_RELOC_SUBTRACTOR             = 5,
358     X86_64_RELOC_SIGNED_1               = 6,
359     X86_64_RELOC_SIGNED_2               = 7,
360     X86_64_RELOC_SIGNED_4               = 8,
361     X86_64_RELOC_TLV                    = 9, // for thread local variables
362 }
363 
364 struct relocation_info
365 {
366     int r_address;
367 
368     /* LITTLE_ENDIAN for x86
369      * uint r_symbolnum:24,
370      *      r_pcrel    :1,
371      *      r_length   :2,
372      *      r_extern   :1,
373      *      r_type     :4;
374      */
375     uint xxx;
376     nothrow:
377     void r_symbolnum(uint r) { assert(!(r & ~0x00FF_FFFF)); xxx = (xxx & ~0x00FF_FFFF) | r; }
378     void r_pcrel    (uint r) { assert(!(r & ~1));           xxx = (xxx & ~0x0100_0000) | (r << 24); }
379     void r_length   (uint r) { assert(!(r & ~3));           xxx = (xxx & ~0x0600_0000) | (r << (24 + 1)); }
380     void r_extern   (uint r) { assert(!(r & ~1));           xxx = (xxx & ~0x0800_0000) | (r << (24 + 1 + 2)); }
381     void r_type     (uint r) { assert(!(r & ~0xF));         xxx = (xxx & ~0xF000_0000) | (r << (24 + 1 + 2 + 1)); }
382 
383     uint r_pcrel() { return (xxx >> 24) & 1; }
384 }
385 
386 struct scattered_relocation_info
387 {
388     /* LITTLE_ENDIAN for x86
389      * uint r_address  :24,
390      *      r_type     :4,
391      *      r_length   :2,
392      *      r_pcrel    :1,
393      *      r_scattered:1;
394      */
395     uint xxx;
396     nothrow:
397     void r_address  (uint r) { assert(!(r & ~0x00FF_FFFF)); xxx = (xxx & ~0x00FF_FFFF) | r; }
398     void r_type     (uint r) { assert(!(r & ~0xF));         xxx = (xxx & ~0x0F00_0000) | (r << 24); }
399     void r_length   (uint r) { assert(!(r & ~3));           xxx = (xxx & ~0x3000_0000) | (r << (24 + 4)); }
400     void r_pcrel    (uint r) { assert(!(r & ~1));           xxx = (xxx & ~0x4000_0000) | (r << (24 + 4 + 2)); }
401     void r_scattered(uint r) { assert(!(r & ~1));           xxx = (xxx & ~0x8000_0000) | (r << (24 + 4 + 2 + 1)); }
402 
403     uint r_pcrel() { return (xxx >> (24 + 4 + 2)) & 1; }
404 
405     int r_value;
406 }