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