1 /*
2 * Mac OS X ABI Mach-O File Format
3 *
4 * Copyright (C) 2007 Henryk Richter, built upon xdf objfmt (C) Peter Johnson
5 *
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28 /*
29 notes: This implementation is rather basic. There are several implementation
30 issues to be sorted out for full compliance and error resilience.
31 Some examples are given below (nasm syntax).
32
33 1) section placement
34 Mach-O requires BSS sections to be placed last in object files. This
35 has to be done manually.
36 Example:
37
38 section .text
39 mov rax,[qword foo]
40 section .data
41 dw 0
42 section .bss
43 foo dw 0
44
45 2) addressing issues
46
47 2.1) symbol relative relocation (i.e. mov eax,[foo wrt bar])
48 Not implemented yet.
49
50 2.2) data referencing in 64 bit mode
51 While ELF allows 32 bit absolute relocations in 64 bit mode, Mach-O
52 does not. Therefore code like
53 lea rbx,[_foo] ;48 8d 1c 25 00 00 00 00
54 mov rcx,[_bar] ;48 8b 0c 25 00 00 00 00
55 with a 32 bit address field cannot be relocated into an address >= 0x100000000 (OSX actually
56 uses that).
57
58 Actually, the only register where a 64 bit displacement is allowed in x86-64, is rax
59 as in the example 1).
60
61 A plausible workaround is either classic PIC (like in C), which is in turn
62 not implemented in this object format. The recommended was is PC relative
63 code (called RIP-relative in x86-64). So instead of the lines above, just write:
64 lea rbx,[_foo wrt rip]
65 mov rcx,[_bar wrt rip]
66
67 2.3) section/data alignment
68 Normally, you specify sections with a specific alignment
69 and get your data layed out as desired. Unfortunately, the
70 linker in MacOS X seems to ignore the section alignment requests.
71 The workaround is an explicit alignment at the end of the text section.
72
73 section .text
74 movdqa xmm0,[_foo wrt rip]
75
76 align 16
77 section .data align=16
78 _foo dw 32,32,32,32,32,32,32,32
79
80 FIXME: perform that operation implicitly!
81
82 2.4) cross section symbol differences unsupported in current implementation
83 [extern foo]
84 [extern bar]
85 section .data
86 dq bar-foo
87
88 Will currently produce an error though the necessary means are provided
89 by the Mach-O specification.
90
91 */
92
93 #include <util.h>
94
95 #include <libyasm.h>
96
97 /* MACH-O DEFINES */
98 /* Mach-O in-file header structure sizes (32 BIT, see below for 64 bit defs) */
99 #define MACHO_HEADER_SIZE 28
100 #define MACHO_SEGCMD_SIZE 56
101 #define MACHO_SECTCMD_SIZE 68
102 #define MACHO_SYMCMD_SIZE 24
103 #define MACHO_NLIST_SIZE 12
104 #define MACHO_RELINFO_SIZE 8
105
106 /* 64 bit sizes */
107 #define MACHO_HEADER64_SIZE 32
108 #define MACHO_SEGCMD64_SIZE 72
109 #define MACHO_SECTCMD64_SIZE 80
110 #define MACHO_NLIST64_SIZE 16
111 #define MACHO_RELINFO64_SIZE 8
112
113
114 /* Mach-O file header values */
115 #define MH_MAGIC 0xfeedface
116 #define MH_MAGIC_64 0xfeedfacf
117
118 /* CPU machine type */
119 #define CPU_TYPE_I386 7 /* x86 platform */
120 #define CPU_TYPE_X86_64 (CPU_TYPE_I386|CPU_ARCH_ABI64)
121 #define CPU_ARCH_ABI64 0x01000000 /* 64 bit ABI */
122
123 /* CPU machine subtype, e.g. processor */
124 #define CPU_SUBTYPE_I386_ALL 3 /* all-x86 compatible */
125 #define CPU_SUBTYPE_X86_64_ALL CPU_SUBTYPE_I386_ALL
126 #define CPU_SUBTYPE_386 3
127 #define CPU_SUBTYPE_486 4
128 #define CPU_SUBTYPE_486SX (4 + 128)
129 #define CPU_SUBTYPE_586 5
130 #define CPU_SUBTYPE_INTEL(f, m) ((f) + ((m) << 4))
131 #define CPU_SUBTYPE_PENT CPU_SUBTYPE_INTEL(5, 0)
132 #define CPU_SUBTYPE_PENTPRO CPU_SUBTYPE_INTEL(6, 1)
133 #define CPU_SUBTYPE_PENTII_M3 CPU_SUBTYPE_INTEL(6, 3)
134 #define CPU_SUBTYPE_PENTII_M5 CPU_SUBTYPE_INTEL(6, 5)
135 #define CPU_SUBTYPE_PENTIUM_4 CPU_SUBTYPE_INTEL(10, 0)
136
137 #define CPU_SUBTYPE_INTEL_FAMILY(x) ((x) & 15)
138 #define CPU_SUBTYPE_INTEL_FAMILY_MAX 15
139
140 #define CPU_SUBTYPE_INTEL_MODEL(x) ((x) >> 4)
141 #define CPU_SUBTYPE_INTEL_MODEL_ALL 0
142
143 #define MH_OBJECT 0x1 /* object file */
144
145 #define LC_SEGMENT 0x1 /* segment load command */
146 #define LC_SYMTAB 0x2 /* symbol table load command */
147 #define LC_SEGMENT_64 0x19 /* segment load command */
148
149
150 #define VM_PROT_NONE 0x00
151 #define VM_PROT_READ 0x01
152 #define VM_PROT_WRITE 0x02
153 #define VM_PROT_EXECUTE 0x04
154
155 #define VM_PROT_DEFAULT (VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE)
156 #define VM_PROT_ALL (VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE)
157
158 #define SECTION_TYPE 0x000000ff /* section type mask */
159 #define SECTION_ATTRIBUTES 0xffffff00UL/* section attributes mask */
160
161 #define S_REGULAR 0x0 /* standard section */
162 #define S_ZEROFILL 0x1 /* zerofill, in-memory only */
163 #define S_CSTRING_LITERALS 0x2 /* literal C strings */
164 #define S_4BYTE_LITERALS 0x3 /* only 4-byte literals */
165 #define S_8BYTE_LITERALS 0x4 /* only 8-byte literals */
166 #define S_LITERAL_POINTERS 0x5 /* only pointers to literals */
167 #define S_NON_LAZY_SYMBOL_POINTERS 0x6 /* only non-lazy symbol pointers */
168 #define S_LAZY_SYMBOL_POINTERS 0x7 /* only lazy symbol pointers */
169 #define S_SYMBOL_STUBS 0x8 /* only symbol stubs; byte size of
170 * stub in the reserved2 field */
171 #define S_MOD_INIT_FUNC_POINTERS 0x9 /* only function pointers for init */
172 #define S_MOD_TERM_FUNC_POINTERS 0xa /* only function pointers for term */
173 #define S_COALESCED 0xb /* symbols that are to be coalesced */
174 #define S_GB_ZEROFILL 0xc /* >4GB zero fill on demand section */
175 #define S_INTERPOSING 0xd /* only pairs of function pointers for
176 * interposing */
177 #define S_16BYTE_LITERALS 0xe /* only 16 byte literals */
178
179 #define S_ATTR_DEBUG 0x02000000 /* a debug section */
180 #define SECTION_ATTRIBUTES_SYS 0x00ffff00 /* system setable attributes */
181 #define S_ATTR_SOME_INSTRUCTIONS 0x00000400 /* section contains some
182 * machine instructions */
183 #define S_ATTR_EXT_RELOC 0x00000200 /* section has external
184 * relocation entries */
185 #define S_ATTR_LOC_RELOC 0x00000100 /* section has local
186 * relocation entries */
187
188 #define SECTION_ATTRIBUTES_USR 0xff000000UL /* User setable attributes */
189 #define S_ATTR_PURE_INSTRUCTIONS 0x80000000UL /* only true machine insns */
190 #define S_ATTR_NO_TOC 0x40000000UL /* coalesced symbols that are
191 * not to be in a ranlib table
192 * of contents */
193 #define S_ATTR_STRIP_STATIC_SYMS 0x20000000UL /* ok to strip static symbols
194 * in this section in files
195 * with the MH_DYLDLINK flag */
196 #define S_ATTR_NO_DEAD_STRIP 0x10000000UL /* no dead stripping */
197 #define S_ATTR_LIVE_SUPPORT 0x08000000UL /* blocks are live if they
198 * reference live blocks */
199 #define S_ATTR_SELF_MODIFYING_CODE 0x04000000UL /* Used with i386 code stubs
200 * written on by dyld */
201
202 /* macho references symbols in different ways whether they are linked at
203 * runtime (LAZY, read library functions) or at link time (NON_LAZY, mostly
204 * data)
205 *
206 * TODO: proper support for dynamically linkable modules would require the
207 * __import sections as well as the dsymtab command
208 */
209 #define REFERENCE_FLAG_UNDEFINED_NON_LAZY 0x0
210 #define REFERENCE_FLAG_UNDEFINED_LAZY 0x1
211
212 #define align(x, y) \
213 (((x) + (y) - 1) & ~((y) - 1)) /* align x to multiple of y */
214
215 #define align32(x) \
216 align(x, 4) /* align x to 32 bit boundary */
217
218 #define macho_MAGIC 0x87654322
219
220 /* Symbol table type field bit masks */
221 #define N_STAB 0xe0 /* mask indicating stab entry */
222 #define N_PEXT 0x10 /* private external bit */
223 #define N_TYPE 0x0e /* mask for all the type bits */
224 #define N_EXT 0x01 /* external (global) bit */
225
226 /* Symbol table type field values */
227 #define N_UNDF 0x00 /* undefined */
228 #define N_ABS 0x02 /* absolute address */
229 #define N_SECT 0x0e /* symbol is defined in a section */
230
231 #define NO_SECT 0 /* no section for symbol in nlist */
232
233 #define REGULAR_OUTBUF_SIZE 1024
234
235
236 typedef struct macho_reloc {
237 yasm_reloc reloc;
238 int pcrel;
239 int length;
240 int ext;
241 enum reloc_type_x86_64 {
242 /* x86 relocations */
243 GENERIC_RELOC_VANILLA = 0, /* generic relocation */
244 GENERIC_RELOC_PAIR = 1, /* Only follows a GENERIC_RELOC_SECTDIFF */
245 GENERIC_RELOC_SECTDIFF = 2,
246 GENERIC_RELOC_PB_LA_PTR = 3, /* prebound lazy pointer */
247 GENERIC_RELOC_LOCAL_SECTDIFF = 4,
248
249 /* x86-64 relocations */
250 X86_64_RELOC_UNSIGNED = 0, /* for absolute addresses */
251 X86_64_RELOC_SIGNED = 1, /* for signed 32-bit displacement */
252 X86_64_RELOC_BRANCH = 2, /* a CALL/JMP insn with 32-bit disp */
253 X86_64_RELOC_GOT_LOAD = 3, /* a MOVQ load of a GOT entry */
254 X86_64_RELOC_GOT = 4, /* other GOT references */
255 X86_64_RELOC_SUBTRACTOR = 5, /* must be followed by a X86_64_RELOC_UNSIGNED */
256 X86_64_RELOC_SIGNED_1 = 6, /* signed 32-bit disp, -1 addend */
257 X86_64_RELOC_SIGNED_2 = 7, /* signed 32-bit disp, -2 addend */
258 X86_64_RELOC_SIGNED_4 = 8 /* signed 32-bit disp, -4 addend */
259 } type;
260 } macho_reloc;
261
262 typedef struct macho_section_data {
263 /*@dependent@*/ yasm_symrec *sym; /* symbol created for this section */
264 long scnum; /* section number (0=first section) */
265 /*@only@*/ char *segname; /* segment name in file */
266 /*@only@*/ char *sectname; /* section name in file */
267 unsigned long flags; /* S_* flags */
268 unsigned long size; /* size of raw data (section data) in bytes */
269 unsigned long offset; /* offset in raw data within file in bytes */
270 unsigned long vmoff; /* memory offset */
271 unsigned long nreloc; /* number of relocation entries */
272 unsigned int extreloc; /* external relocations present (0/1) */
273 } macho_section_data;
274
275
276 typedef struct macho_symrec_data {
277 unsigned long index; /* index in output order */
278 yasm_intnum *value; /* valid after writing symtable to file */
279 unsigned long length; /* length + 1 (plus auto underscore) */
280 } macho_symrec_data;
281
282
283 typedef struct yasm_objfmt_macho {
284 yasm_objfmt_base objfmt; /* base structure */
285
286 long parse_scnum; /* sect numbering in parser */
287 int bits; /* 32 / 64 */
288
289 yasm_symrec *gotpcrel_sym; /* ..gotpcrel */
290 } yasm_objfmt_macho;
291
292
293 typedef struct macho_objfmt_output_info {
294 yasm_object *object;
295 yasm_objfmt_macho *objfmt_macho;
296 yasm_errwarns *errwarns;
297 /*@dependent@ */ FILE *f;
298 /*@only@ */ unsigned char *buf;
299 yasm_section *sect;
300 /*@dependent@ */ macho_section_data *msd;
301
302 unsigned int is_64; /* write object in 64 bit mode */
303
304 /* vmsize and filesize available after traversing section count routine */
305 unsigned long vmsize; /* raw size of all sections (including BSS) */
306 unsigned long filesize; /* size of sections in file (excluding BSS) */
307 unsigned long offset; /* offset within file */
308
309 /* forward offset tracking */
310 unsigned long rel_base; /* first relocation in file */
311 unsigned long s_reloff; /* in-file offset to relocations */
312
313 unsigned long indx; /* current symbol size in bytes (name length+1) */
314 unsigned long symindex; /* current symbol index in output order */
315 int all_syms; /* outputting all symbols? */
316 unsigned long strlength; /* length of all strings */
317 } macho_objfmt_output_info;
318
319
320 static void macho_section_data_destroy(/*@only@*/ void *d);
321 static void macho_section_data_print(void *data, FILE *f, int indent_level);
322
323 static const yasm_assoc_data_callback macho_section_data_cb = {
324 macho_section_data_destroy,
325 macho_section_data_print
326 };
327
328 static void macho_symrec_data_destroy(/*@only@*/ void *d);
329 static void macho_symrec_data_print(void *data, FILE *f, int indent_level);
330
331 static const yasm_assoc_data_callback macho_symrec_data_cb = {
332 macho_symrec_data_destroy,
333 macho_symrec_data_print
334 };
335
336 yasm_objfmt_module yasm_macho_LTX_objfmt;
337 yasm_objfmt_module yasm_macho32_LTX_objfmt;
338 yasm_objfmt_module yasm_macho64_LTX_objfmt;
339
340 static yasm_objfmt *
macho_objfmt_create_common(yasm_object * object,yasm_objfmt_module * module,int bits_pref)341 macho_objfmt_create_common(yasm_object *object, yasm_objfmt_module *module,
342 int bits_pref)
343 {
344 yasm_objfmt_macho *objfmt_macho = yasm_xmalloc(sizeof(yasm_objfmt_macho));
345
346 objfmt_macho->objfmt.module = module;
347
348 /* Only support x86 arch for now */
349 if (yasm__strcasecmp(yasm_arch_keyword(object->arch), "x86") != 0) {
350 yasm_xfree(objfmt_macho);
351 return NULL;
352 }
353
354 /* Support x86 and amd64 machines of x86 arch */
355 if (yasm__strcasecmp(yasm_arch_get_machine(object->arch), "x86") == 0 &&
356 (bits_pref == 0 || bits_pref == 32)) {
357 objfmt_macho->bits = 32;
358 objfmt_macho->gotpcrel_sym = NULL;
359 } else if (yasm__strcasecmp(yasm_arch_get_machine(object->arch),
360 "amd64") == 0 &&
361 (bits_pref == 0 || bits_pref == 64)) {
362 objfmt_macho->bits = 64;
363 /* FIXME: misuse of NULL bytecode */
364 objfmt_macho->gotpcrel_sym =
365 yasm_symtab_define_label(object->symtab, "..gotpcrel", NULL, 0, 0);
366 } else {
367 yasm_xfree(objfmt_macho);
368 return NULL;
369 }
370
371 objfmt_macho->parse_scnum = 0; /* section numbering starts at 0 */
372 return (yasm_objfmt *)objfmt_macho;
373 }
374
375 static yasm_objfmt *
macho_objfmt_create(yasm_object * object)376 macho_objfmt_create(yasm_object *object)
377 {
378 yasm_objfmt *objfmt;
379 yasm_objfmt_macho *objfmt_macho;
380
381 objfmt = macho_objfmt_create_common(object, &yasm_macho_LTX_objfmt, 0);
382 if (objfmt) {
383 objfmt_macho = (yasm_objfmt_macho *)objfmt;
384 /* Figure out which bitness of object format to use */
385 if (objfmt_macho->bits == 32)
386 objfmt_macho->objfmt.module = &yasm_macho32_LTX_objfmt;
387 else if (objfmt_macho->bits == 64)
388 objfmt_macho->objfmt.module = &yasm_macho64_LTX_objfmt;
389 }
390 return objfmt;
391 }
392
393 static yasm_objfmt *
macho32_objfmt_create(yasm_object * object)394 macho32_objfmt_create(yasm_object *object)
395 {
396 return macho_objfmt_create_common(object, &yasm_macho32_LTX_objfmt, 32);
397 }
398
399 static yasm_objfmt *
macho64_objfmt_create(yasm_object * object)400 macho64_objfmt_create(yasm_object *object)
401 {
402 return macho_objfmt_create_common(object, &yasm_macho64_LTX_objfmt, 64);
403 }
404
405 static int
macho_objfmt_output_value(yasm_value * value,unsigned char * buf,unsigned int destsize,unsigned long offset,yasm_bytecode * bc,int warn,void * d)406 macho_objfmt_output_value(yasm_value *value, unsigned char *buf,
407 unsigned int destsize, unsigned long offset,
408 yasm_bytecode *bc, int warn, /*@null@*/ void *d)
409 {
410 /*@null@*/ macho_objfmt_output_info *info = (macho_objfmt_output_info *)d;
411 yasm_objfmt_macho *objfmt_macho;
412 /*@dependent@*/ /*@null@*/ yasm_intnum *intn;
413 unsigned long intn_minus = 0, intn_plus = 0;
414 int retval;
415 unsigned int valsize = value->size;
416 macho_reloc *reloc = NULL;
417
418 assert(info != NULL);
419 objfmt_macho = info->objfmt_macho;
420
421 if (value->abs)
422 value->abs = yasm_expr_simplify(value->abs, 1);
423
424 /* Try to output constant and PC-relative section-local first.
425 * Note this does NOT output any value with a SEG, WRT, external,
426 * cross-section, or non-PC-relative reference (those are handled below).
427 */
428 switch (yasm_value_output_basic(value, buf, destsize, bc, warn,
429 info->object->arch)) {
430 case -1:
431 return 1;
432 case 0:
433 break;
434 default:
435 return 0;
436 }
437
438 if (value->section_rel) {
439 yasm_error_set(YASM_ERROR_TOO_COMPLEX,
440 N_("macho: relocation too complex for current implementation"));
441 return 1;
442 }
443
444 if (value->rel) {
445 yasm_sym_vis vis = yasm_symrec_get_visibility(value->rel);
446
447 reloc = yasm_xcalloc(sizeof(macho_reloc), 1);
448 reloc->reloc.addr = yasm_intnum_create_uint(bc->offset + offset);
449 reloc->reloc.sym = value->rel;
450 switch (valsize) {
451 case 64:
452 reloc->length = 3;
453 break;
454 case 32:
455 reloc->length = 2;
456 break;
457 case 16:
458 reloc->length = 1;
459 break;
460 case 8:
461 reloc->length = 0;
462 break;
463 default:
464 yasm_error_set(YASM_ERROR_TOO_COMPLEX,
465 N_("macho: relocation size unsupported"));
466 yasm_xfree(reloc);
467 return 1;
468 }
469 reloc->pcrel = 0;
470 reloc->ext = 0;
471 reloc->type = GENERIC_RELOC_VANILLA;
472 /* R_ABS */
473
474 if (value->rshift > 0) {
475 yasm_error_set(YASM_ERROR_TOO_COMPLEX,
476 N_("macho: shifted relocations not supported"));
477 yasm_xfree(reloc);
478 return 1;
479 }
480
481 if (value->seg_of) {
482 yasm_error_set(YASM_ERROR_TOO_COMPLEX,
483 N_("macho: SEG not supported"));
484 yasm_xfree(reloc);
485 return 1;
486 }
487
488 if (value->curpos_rel && objfmt_macho->gotpcrel_sym &&
489 value->wrt == objfmt_macho->gotpcrel_sym) {
490 reloc->type = X86_64_RELOC_GOT;
491 value->wrt = NULL;
492 } else if (value->wrt) {
493 yasm_error_set(YASM_ERROR_TOO_COMPLEX,
494 N_("macho: invalid WRT"));
495 yasm_xfree(reloc);
496 return 1;
497 }
498
499 if (value->curpos_rel) {
500 reloc->pcrel = 1;
501 if (!info->is_64) {
502 /* Adjust to start of section, so subtract out the bytecode
503 * offset.
504 */
505 intn_minus = bc->offset;
506 } else {
507 /* Add in the offset plus value size to end up with 0. */
508 intn_plus = offset+destsize;
509 if (reloc->type == X86_64_RELOC_GOT) {
510 /* XXX: This is a hack */
511 if (offset >= 2 && buf[-2] == 0x8B)
512 reloc->type = X86_64_RELOC_GOT_LOAD;
513 } else if (value->jump_target)
514 reloc->type = X86_64_RELOC_BRANCH;
515 else
516 reloc->type = X86_64_RELOC_SIGNED;
517 }
518 } else if (info->is_64) {
519 if (valsize == 32) {
520 yasm_error_set(YASM_ERROR_NOT_CONSTANT,
521 N_("macho: sorry, cannot apply 32 bit absolute relocations in 64 bit mode, consider \"[_symbol wrt rip]\" for mem access, \"qword\" and \"dq _foo\" for pointers."));
522 return 1;
523 }
524 reloc->type = X86_64_RELOC_UNSIGNED;
525 }
526
527 /* It seems that x86-64 objects need to have all extern relocs? */
528 if (info->is_64)
529 reloc->ext = 1;
530
531 if ((vis & YASM_SYM_EXTERN) || (vis & YASM_SYM_COMMON)) {
532 reloc->ext = 1;
533 info->msd->extreloc = 1; /* section has external relocations */
534 } else if (!info->is_64) {
535 /*@dependent@*/ /*@null@*/ yasm_bytecode *sym_precbc;
536
537 /* Local symbols need valued to their actual address */
538 if (yasm_symrec_get_label(value->rel, &sym_precbc)) {
539 yasm_section *sym_sect = yasm_bc_get_section(sym_precbc);
540 /*@null@*/ macho_section_data *msd;
541 msd = yasm_section_get_data(sym_sect, &macho_section_data_cb);
542 assert(msd != NULL);
543 intn_plus += msd->vmoff + yasm_bc_next_offset(sym_precbc);
544 }
545 }
546
547 info->msd->nreloc++;
548 /*printf("reloc %s type %d ",yasm_symrec_get_name(reloc->reloc.sym),reloc->type);*/
549 yasm_section_add_reloc(info->sect, (yasm_reloc *)reloc, yasm_xfree);
550 }
551
552 if (intn_minus <= intn_plus)
553 intn = yasm_intnum_create_uint(intn_plus-intn_minus);
554 else {
555 intn = yasm_intnum_create_uint(intn_minus-intn_plus);
556 yasm_intnum_calc(intn, YASM_EXPR_NEG, NULL);
557 }
558
559 if (value->abs) {
560 yasm_intnum *intn2 = yasm_expr_get_intnum(&value->abs, 0);
561
562 if (!intn2) {
563 yasm_error_set(YASM_ERROR_TOO_COMPLEX,
564 N_("macho: relocation too complex"));
565 yasm_intnum_destroy(intn);
566 return 1;
567 }
568 yasm_intnum_calc(intn, YASM_EXPR_ADD, intn2);
569 }
570
571 retval = yasm_arch_intnum_tobytes(info->object->arch, intn, buf, destsize,
572 valsize, 0, bc, warn);
573 /*printf("val %ld\n",yasm_intnum_get_int(intn));*/
574 yasm_intnum_destroy(intn);
575 return retval;
576 }
577
578 static int
macho_objfmt_output_bytecode(yasm_bytecode * bc,void * d)579 macho_objfmt_output_bytecode(yasm_bytecode *bc, /*@null@*/ void *d)
580 {
581 /*@null@*/ macho_objfmt_output_info *info = (macho_objfmt_output_info *)d;
582 /*@null@*/ /*@only@*/ unsigned char *bigbuf;
583 unsigned long size = REGULAR_OUTBUF_SIZE;
584 int gap;
585
586 assert(info != NULL);
587
588 bigbuf = yasm_bc_tobytes(bc, info->buf, &size, &gap, info,
589 macho_objfmt_output_value, NULL);
590
591 /* Don't bother doing anything else if size ended up being 0. */
592 if (size == 0) {
593 if (bigbuf)
594 yasm_xfree(bigbuf);
595 return 0;
596 }
597
598 /* Warn that gaps are converted to 0 and write out the 0's. */
599 if (gap) {
600 unsigned long left;
601
602 yasm_warn_set(YASM_WARN_UNINIT_CONTENTS,
603 N_("uninitialized space: zeroing"));
604 /* Write out in chunks */
605 memset(info->buf, 0, REGULAR_OUTBUF_SIZE);
606 left = size;
607 while (left > REGULAR_OUTBUF_SIZE) {
608 fwrite(info->buf, REGULAR_OUTBUF_SIZE, 1, info->f);
609 left -= REGULAR_OUTBUF_SIZE;
610 }
611 fwrite(info->buf, left, 1, info->f);
612 } else {
613 /* Output buf (or bigbuf if non-NULL) to file */
614 fwrite(bigbuf ? bigbuf : info->buf, (size_t) size, 1, info->f);
615 }
616
617 /* If bigbuf was allocated, free it */
618 if (bigbuf)
619 yasm_xfree(bigbuf);
620
621 return 0;
622 }
623
624 static int
macho_objfmt_output_section(yasm_section * sect,void * d)625 macho_objfmt_output_section(yasm_section *sect, /*@null@ */ void *d)
626 {
627 /*@null@ */ macho_objfmt_output_info *info =
628 (macho_objfmt_output_info *) d;
629 /*@dependent@ *//*@null@ */ macho_section_data *msd;
630
631 assert(info != NULL);
632 msd = yasm_section_get_data(sect, &macho_section_data_cb);
633 assert(msd != NULL);
634
635 if (!(msd->flags & S_ZEROFILL)) {
636 /* Output non-BSS sections */
637 info->sect = sect;
638 info->msd = msd;
639 yasm_section_bcs_traverse(sect, info->errwarns, info,
640 macho_objfmt_output_bytecode);
641 }
642 return 0;
643 }
644
645 static int
macho_objfmt_output_relocs(yasm_section * sect,void * d)646 macho_objfmt_output_relocs(yasm_section *sect, /*@null@*/ void *d)
647 {
648 /*@null@*/ macho_objfmt_output_info *info = (macho_objfmt_output_info *)d;
649 /*@dependent@*/ /*@null@*/ macho_section_data *msd;
650 macho_reloc *reloc;
651
652 reloc = (macho_reloc *)yasm_section_relocs_first(sect);
653 while (reloc) {
654 unsigned char *localbuf = info->buf;
655 /*@null@*/ macho_symrec_data *xsymd;
656 unsigned long symnum;
657
658 xsymd = yasm_symrec_get_data(reloc->reloc.sym, &macho_symrec_data_cb);
659 yasm_intnum_get_sized(reloc->reloc.addr, localbuf, 4, 32, 0, 0, 0);
660 localbuf += 4; /* address of relocation */
661
662 if (reloc->ext)
663 symnum = xsymd->index;
664 else {
665 /* find section where the symbol relates to */
666 /*@dependent@*/ /*@null@*/ yasm_section *dsect;
667 /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc;
668 symnum = 0; /* default to absolute */
669 if (yasm_symrec_get_label(reloc->reloc.sym, &precbc) &&
670 (dsect = yasm_bc_get_section(precbc)) &&
671 (msd = yasm_section_get_data(dsect, &macho_section_data_cb)))
672 symnum = msd->scnum+1;
673 }
674 YASM_WRITE_32_L(localbuf,
675 (symnum & 0x00ffffff) |
676 (((unsigned long)reloc->pcrel & 1) << 24) |
677 (((unsigned long)reloc->length & 3) << 25) |
678 (((unsigned long)reloc->ext & 1) << 27) |
679 (((unsigned long)reloc->type & 0xf) << 28));
680 fwrite(info->buf, 8, 1, info->f);
681 reloc = (macho_reloc *)yasm_section_reloc_next((yasm_reloc *)reloc);
682 }
683
684 return 0;
685 }
686
687 static int
exp2_to_bits(unsigned long val)688 exp2_to_bits(unsigned long val)
689 {
690 int ret = 0;
691
692 while (val) {
693 val >>= 1;
694 ret++;
695 }
696 ret = (ret > 0) ? ret - 1 : 0;
697
698 return ret;
699 }
700
701 static int
macho_objfmt_is_section_label(yasm_symrec * sym)702 macho_objfmt_is_section_label(yasm_symrec *sym)
703 {
704 /*@dependent@*/ /*@null@*/ yasm_section *sect;
705 /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc;
706
707 /* Look at symrec for value/scnum/etc. */
708 if (yasm_symrec_get_label(sym, &precbc)) {
709 if (precbc)
710 sect = yasm_bc_get_section(precbc);
711 else
712 sect = NULL;
713 /* it's a label: get value and offset.
714 * If there is not a section, leave as debugging symbol.
715 */
716 if (sect) {
717 /*@dependent@*/ /*@null@*/ macho_section_data *msd;
718
719 msd = yasm_section_get_data(sect, &macho_section_data_cb);
720 if (msd) {
721 if (msd->sym == sym)
722 return 1; /* don't store section names */
723 }
724 }
725 }
726 return 0;
727 }
728
729 static int
macho_objfmt_output_secthead(yasm_section * sect,void * d)730 macho_objfmt_output_secthead(yasm_section *sect, /*@null@*/ void *d)
731 {
732 /*@null@*/ macho_objfmt_output_info *info = (macho_objfmt_output_info *)d;
733 yasm_objfmt_macho *objfmt_macho;
734 /*@dependent@*/ /*@null@*/ macho_section_data *msd;
735 unsigned char *localbuf;
736
737 assert(info != NULL);
738 objfmt_macho = info->objfmt_macho;
739 msd = yasm_section_get_data(sect, &macho_section_data_cb);
740 assert(msd != NULL);
741
742 localbuf = info->buf;
743
744 memset(localbuf, 0, 16);
745 strncpy((char *)localbuf, msd->sectname, 16);
746 localbuf += 16;
747 memset(localbuf, 0, 16);
748 strncpy((char *)localbuf, msd->segname, 16);
749 localbuf += 16;
750 /* section address, size depend on 32/64 bit mode */
751 YASM_WRITE_32_L(localbuf, msd->vmoff); /* address in memory */
752 if (info->is_64)
753 YASM_WRITE_32_L(localbuf, 0); /* 64-bit mode: upper 32 bits = 0 */
754 YASM_WRITE_32_L(localbuf, msd->size); /* size in memory */
755 if (info->is_64)
756 YASM_WRITE_32_L(localbuf, 0); /* 64-bit mode: upper 32 bits = 0 */
757
758 /* offset,align,reloff,nreloc,flags,reserved1,reserved2 are 32 bit */
759 if ((msd->flags & SECTION_TYPE) != S_ZEROFILL) {
760 YASM_WRITE_32_L(localbuf, msd->offset);
761 YASM_WRITE_32_L(localbuf, exp2_to_bits(yasm_section_get_align(sect)));
762 if (msd->nreloc) {
763 msd->flags |= S_ATTR_LOC_RELOC;
764 if (msd->extreloc)
765 msd->flags |= S_ATTR_EXT_RELOC;
766 YASM_WRITE_32_L(localbuf,
767 align32((long)(info->rel_base + info->s_reloff)));
768 YASM_WRITE_32_L(localbuf, msd->nreloc); /* nreloc */
769 } else {
770 YASM_WRITE_32_L(localbuf, 0);
771 YASM_WRITE_32_L(localbuf, 0);
772 }
773
774 info->s_reloff += msd->nreloc * MACHO_RELINFO_SIZE; /* nreloc */
775 } else {
776 YASM_WRITE_32_L(localbuf, 0); /* these are zero in BSS */
777 YASM_WRITE_32_L(localbuf, 0);
778 YASM_WRITE_32_L(localbuf, 0);
779 YASM_WRITE_32_L(localbuf, 0);
780 }
781
782 YASM_WRITE_32_L(localbuf, msd->flags); /* flags */
783 YASM_WRITE_32_L(localbuf, 0); /* reserved 1 */
784 YASM_WRITE_32_L(localbuf, 0); /* reserved 2 */
785
786 if (info->is_64)
787 fwrite(info->buf, MACHO_SECTCMD64_SIZE, 1, info->f);
788 else
789 fwrite(info->buf, MACHO_SECTCMD_SIZE, 1, info->f);
790
791 return 0;
792 }
793
794
795 static int
macho_objfmt_count_sym(yasm_symrec * sym,void * d)796 macho_objfmt_count_sym(yasm_symrec *sym, /*@null@*/ void *d)
797 {
798 /*@null@*/ macho_objfmt_output_info *info = (macho_objfmt_output_info *)d;
799 /*@only@*/ char *name;
800 yasm_sym_vis vis = yasm_symrec_get_visibility(sym);
801
802 assert(info != NULL);
803 if (info->all_syms ||
804 vis & (YASM_SYM_GLOBAL | YASM_SYM_COMMON | YASM_SYM_EXTERN)) {
805 if (0 == macho_objfmt_is_section_label(sym)) {
806 /* Save index in symrec data */
807 macho_symrec_data *sym_data =
808 yasm_symrec_get_data(sym, &macho_symrec_data_cb);
809 if (!sym_data) {
810 sym_data = yasm_xcalloc(sizeof(macho_symrec_data), 1);
811 yasm_symrec_add_data(sym, &macho_symrec_data_cb, sym_data);
812 }
813 sym_data->index = info->symindex;
814 info->symindex++;
815
816 name = yasm_symrec_get_global_name(sym, info->object);
817 /*printf("%s\n",name); */
818 /* name length + delimiter */
819 sym_data->length = (unsigned long)strlen(name) + 1;
820 info->strlength += sym_data->length;
821 info->indx++;
822 yasm_xfree(name);
823 }
824 }
825 return 0;
826 }
827
828
829 static int
macho_objfmt_output_symtable(yasm_symrec * sym,void * d)830 macho_objfmt_output_symtable(yasm_symrec *sym, /*@null@*/ void *d)
831 {
832 /*@null@*/ macho_objfmt_output_info *info = (macho_objfmt_output_info *)d;
833 yasm_sym_vis vis = yasm_symrec_get_visibility(sym);
834
835 assert(info != NULL);
836
837 if (info->all_syms ||
838 vis & (YASM_SYM_GLOBAL | YASM_SYM_COMMON | YASM_SYM_EXTERN)) {
839 const yasm_expr *equ_val;
840 const yasm_intnum *intn;
841 unsigned long value = 0;
842 long scnum = -3; /* -3 = debugging symbol */
843 /*@dependent@*/ /*@null@*/ yasm_section *sect;
844 /*@dependent@*/ /*@null@*/ yasm_bytecode *precbc;
845 unsigned char *localbuf;
846 yasm_intnum *val;
847 unsigned int long_int_bytes = (info->is_64) ? 8 : 4;
848 unsigned int n_type = 0, n_sect = 0, n_desc = 0;
849 macho_symrec_data *symd;
850
851 val = yasm_intnum_create_uint(0);
852
853 symd = yasm_symrec_get_data(sym, &macho_symrec_data_cb);
854
855 /* Look at symrec for value/scnum/etc. */
856 if (yasm_symrec_get_label(sym, &precbc)) {
857 if (precbc)
858 sect = yasm_bc_get_section(precbc);
859 else
860 sect = NULL;
861 /* it's a label: get value and offset.
862 * If there is not a section, leave as debugging symbol.
863 */
864 if (sect) {
865 /*@dependent@*/ /*@null@*/ macho_section_data *msd;
866
867 msd = yasm_section_get_data(sect, &macho_section_data_cb);
868 if (msd) {
869 if (msd->sym == sym) {
870 /* don't store section names */
871 yasm_intnum_destroy(val);
872 return 0;
873 }
874 scnum = msd->scnum;
875 n_type = N_SECT;
876 } else
877 yasm_internal_error(N_("didn't understand section"));
878 if (precbc)
879 value += yasm_bc_next_offset(precbc);
880 /* all values are subject to correction: base offset is first
881 * raw section, therefore add section offset
882 */
883 if (msd)
884 value += msd->vmoff;
885 yasm_intnum_set_uint(val, value);
886 /*printf("%s offset %lx\n",name,value);*/
887 }
888 } else if ((equ_val = yasm_symrec_get_equ(sym))) {
889 yasm_expr *equ_val_copy = yasm_expr_copy(equ_val);
890
891 intn = yasm_expr_get_intnum(&equ_val_copy, 1);
892 if (!intn) {
893 if (vis & YASM_SYM_GLOBAL) {
894 yasm_error_set(YASM_ERROR_NOT_CONSTANT,
895 N_("global EQU value not an integer expression"));
896 yasm_errwarn_propagate(info->errwarns, equ_val->line);
897 }
898 } else
899 value = yasm_intnum_get_uint(intn);
900 yasm_expr_destroy(equ_val_copy);
901 yasm_intnum_set_uint(val, value);
902 n_type = N_ABS;
903 scnum = -2; /* -2 = absolute symbol */
904 }
905
906 if (vis & YASM_SYM_EXTERN) {
907 n_type = N_EXT;
908 scnum = -1;
909 /*n_desc = REFERENCE_FLAG_UNDEFINED_LAZY; * FIXME: see definition of REFERENCE_FLAG_* above */
910 } else if (vis & YASM_SYM_COMMON) {
911 yasm_expr **csize = yasm_symrec_get_common_size(sym);
912 n_type = N_UNDF | N_EXT;
913 if (csize) {
914 intn = yasm_expr_get_intnum(csize, 1);
915 if (!intn) {
916 yasm_error_set(YASM_ERROR_NOT_CONSTANT,
917 N_("COMMON data size not an integer expression"));
918 yasm_errwarn_propagate(info->errwarns, (*csize)->line);
919 } else
920 yasm_intnum_set_uint(val, yasm_intnum_get_uint(intn));
921 }
922 /*printf("common symbol %s val %lu\n", name, yasm_intnum_get_uint(val));*/
923 } else if (vis & YASM_SYM_GLOBAL) {
924 yasm_valparamhead *valparams =
925 yasm_symrec_get_objext_valparams(sym);
926
927 struct macho_global_data {
928 unsigned long flag; /* N_PEXT */
929 } data;
930
931 data.flag = 0;
932
933 if (valparams) {
934 static const yasm_dir_help help[] = {
935 { "private_extern", 0, yasm_dir_helper_flag_set,
936 offsetof(struct macho_global_data, flag), N_PEXT },
937 };
938 yasm_dir_helper(sym, yasm_vps_first(valparams),
939 yasm_symrec_get_decl_line(sym), help, NELEMS(help),
940 &data, yasm_dir_helper_valparam_warn);
941 }
942
943 n_type |= N_EXT | data.flag;
944 }
945
946 localbuf = info->buf;
947 YASM_WRITE_32_L(localbuf, info->indx); /* offset in string table */
948 YASM_WRITE_8(localbuf, n_type); /* type of symbol entry */
949 n_sect = (scnum >= 0) ? scnum + 1 : NO_SECT;
950 YASM_WRITE_8(localbuf, n_sect); /* referring section where symbol is found */
951 YASM_WRITE_16_L(localbuf, n_desc); /* extra description */
952 yasm_intnum_get_sized(val, localbuf, long_int_bytes, ((long_int_bytes) << 3), 0, 0, 0); /* value/argument */
953 localbuf += long_int_bytes;
954 if (symd)
955 symd->value = val;
956 else
957 yasm_intnum_destroy(val);
958
959 info->indx += symd->length;
960
961 fwrite(info->buf, 8 + long_int_bytes, 1, info->f);
962 }
963
964 return 0;
965 }
966
967
968 static int
macho_objfmt_output_str(yasm_symrec * sym,void * d)969 macho_objfmt_output_str(yasm_symrec *sym, /*@null@*/ void *d)
970 {
971 /*@null@*/ macho_objfmt_output_info *info = (macho_objfmt_output_info *)d;
972 yasm_sym_vis vis = yasm_symrec_get_visibility(sym);
973 /*@null@*/ macho_symrec_data *xsymd;
974
975
976 assert(info != NULL);
977
978 if (info->all_syms ||
979 vis & (YASM_SYM_GLOBAL | YASM_SYM_COMMON | YASM_SYM_EXTERN)) {
980 if (0 == macho_objfmt_is_section_label(sym)) {
981 /*@only@*/ char *name =
982 yasm_symrec_get_global_name(sym, info->object);
983 size_t len = strlen(name);
984
985 xsymd = yasm_symrec_get_data(sym, &macho_symrec_data_cb);
986 fwrite(name, len + 1, 1, info->f);
987 yasm_xfree(name);
988 }
989 }
990 return 0;
991 }
992
993 static int
macho_objfmt_calc_sectsize(yasm_section * sect,void * d)994 macho_objfmt_calc_sectsize(yasm_section *sect, /*@null@ */ void *d)
995 {
996 /*@null@ */ macho_objfmt_output_info *info =
997 (macho_objfmt_output_info *) d;
998 /*@dependent@ *//*@null@ */ macho_section_data *msd;
999 unsigned long align;
1000
1001 assert(info != NULL);
1002 msd = yasm_section_get_data(sect, &macho_section_data_cb);
1003 assert(msd != NULL);
1004
1005 msd->size = yasm_bc_next_offset(yasm_section_bcs_last(sect));
1006 if (!(msd->flags & S_ZEROFILL)) {
1007 msd->offset = info->offset;
1008 info->offset += msd->size;
1009 info->filesize += msd->size;
1010 }
1011
1012 /* accumulate size in memory */
1013 msd->vmoff = info->vmsize;
1014 info->vmsize += msd->size;
1015
1016 /* align both start and end of section */
1017 align = yasm_section_get_align(sect);
1018 if (align != 0) {
1019 unsigned long delta = msd->vmoff % align;
1020 if (delta > 0) {
1021 msd->vmoff += align - delta;
1022 info->vmsize += align - delta;
1023 }
1024 }
1025
1026 return 0;
1027 }
1028
1029 /* write object */
1030 static void
macho_objfmt_output(yasm_object * object,FILE * f,int all_syms,yasm_errwarns * errwarns)1031 macho_objfmt_output(yasm_object *object, FILE *f, int all_syms,
1032 yasm_errwarns *errwarns)
1033 {
1034 yasm_objfmt_macho *objfmt_macho = (yasm_objfmt_macho *)object->objfmt;
1035 macho_objfmt_output_info info;
1036 unsigned char *localbuf;
1037 unsigned long symtab_count = 0;
1038 unsigned long headsize;
1039 unsigned int macho_segcmdsize, macho_sectcmdsize, macho_nlistsize;
1040 unsigned int macho_relinfosize, macho_segcmd;
1041 unsigned int head_ncmds, head_sizeofcmds;
1042 unsigned long fileoffset, fileoff_sections;
1043 yasm_intnum *val;
1044 unsigned long long_int_bytes;
1045 const char pad_data[3] = "\0\0\0";
1046
1047 info.object = object;
1048 info.objfmt_macho = objfmt_macho;
1049 info.errwarns = errwarns;
1050 info.f = f;
1051 info.buf = yasm_xmalloc(REGULAR_OUTBUF_SIZE);
1052
1053 if (objfmt_macho->parse_scnum == 0) {
1054 yasm_internal_error(N_("no sections defined"));
1055 /*@notreached@*/
1056 return;
1057 }
1058
1059 val = yasm_intnum_create_uint(0);
1060
1061 /*
1062 * MACH-O Header, Seg CMD, Sect CMDs, Sym Tab, Reloc Data
1063 */
1064 info.is_64 = (objfmt_macho->bits == 32) ? 0 : 1;
1065 if (info.is_64) {
1066 /* this works only when SYMBOLS and SECTIONS present */
1067 headsize =
1068 MACHO_HEADER64_SIZE + MACHO_SEGCMD64_SIZE +
1069 (MACHO_SECTCMD64_SIZE * (objfmt_macho->parse_scnum)) +
1070 MACHO_SYMCMD_SIZE;
1071 macho_segcmd = LC_SEGMENT_64;
1072 macho_segcmdsize = MACHO_SEGCMD64_SIZE;
1073 macho_sectcmdsize = MACHO_SECTCMD64_SIZE;
1074 macho_nlistsize = MACHO_NLIST64_SIZE;
1075 macho_relinfosize = MACHO_RELINFO64_SIZE;
1076 long_int_bytes = 8;
1077 } else {
1078 headsize =
1079 MACHO_HEADER_SIZE + MACHO_SEGCMD_SIZE +
1080 (MACHO_SECTCMD_SIZE * (objfmt_macho->parse_scnum)) +
1081 MACHO_SYMCMD_SIZE;
1082 macho_segcmd = LC_SEGMENT;
1083 macho_segcmdsize = MACHO_SEGCMD_SIZE;
1084 macho_sectcmdsize = MACHO_SECTCMD_SIZE;
1085 macho_nlistsize = MACHO_NLIST_SIZE;
1086 macho_relinfosize = MACHO_RELINFO_SIZE;
1087 long_int_bytes = 4;
1088 }
1089
1090 /* Get number of symbols */
1091 info.symindex = 0;
1092 info.indx = 0;
1093 info.strlength = 1; /* string table starts with a zero byte */
1094 info.all_syms = all_syms || info.is_64;
1095 /*info.all_syms = 1; * force all syms into symbol table */
1096 yasm_symtab_traverse(object->symtab, &info, macho_objfmt_count_sym);
1097 symtab_count = info.indx;
1098
1099 /* write raw section data first */
1100 if (fseek(f, (long)headsize, SEEK_SET) < 0) {
1101 yasm__fatal(N_("could not seek on output file"));
1102 /*@notreached@ */
1103 return;
1104 }
1105
1106 /* get size of sections in memory (including BSS) and size of sections
1107 * in file (without BSS)
1108 */
1109 info.vmsize = 0;
1110 info.filesize = 0;
1111 info.offset = headsize;
1112 yasm_object_sections_traverse(object, &info, macho_objfmt_calc_sectsize);
1113
1114 /* output sections to file */
1115 yasm_object_sections_traverse(object, &info, macho_objfmt_output_section);
1116
1117 fileoff_sections = ftell(f);
1118
1119 /* Write headers */
1120 if (fseek(f, 0, SEEK_SET) < 0) {
1121 yasm__fatal(N_("could not seek on output file"));
1122 /*@notreached@*/
1123 return;
1124 }
1125
1126 localbuf = info.buf;
1127
1128 /* header size is common to 32 bit and 64 bit variants */
1129 if (info.is_64) {
1130 YASM_WRITE_32_L(localbuf, MH_MAGIC_64); /* magic number */
1131 /* i386 64-bit ABI */
1132 YASM_WRITE_32_L(localbuf, CPU_ARCH_ABI64 | CPU_TYPE_I386);
1133 } else {
1134 YASM_WRITE_32_L(localbuf, MH_MAGIC); /* magic number */
1135 YASM_WRITE_32_L(localbuf, CPU_TYPE_I386); /* i386 32-bit ABI */
1136 }
1137 /* i386 all cpu subtype compatible */
1138 YASM_WRITE_32_L(localbuf, CPU_SUBTYPE_I386_ALL);
1139 YASM_WRITE_32_L(localbuf, MH_OBJECT); /* MACH file type */
1140
1141 /* calculate number of commands and their size, put to stream */
1142 head_ncmds = 0;
1143 head_sizeofcmds = 0;
1144 if (objfmt_macho->parse_scnum > 0) {
1145 head_ncmds++;
1146 head_sizeofcmds +=
1147 macho_segcmdsize + macho_sectcmdsize * objfmt_macho->parse_scnum;
1148 }
1149 if (symtab_count > 0) {
1150 head_ncmds++;
1151 head_sizeofcmds += MACHO_SYMCMD_SIZE;
1152 }
1153
1154 YASM_WRITE_32_L(localbuf, head_ncmds);
1155 YASM_WRITE_32_L(localbuf, head_sizeofcmds);
1156 YASM_WRITE_32_L(localbuf, 0); /* no flags (yet) */
1157 if (info.is_64) {
1158 YASM_WRITE_32_L(localbuf, 0); /* reserved in 64 bit */
1159 fileoffset = MACHO_HEADER64_SIZE + head_sizeofcmds;
1160 } else {
1161 /* initial offset to first section */
1162 fileoffset = MACHO_HEADER_SIZE + head_sizeofcmds;
1163 }
1164
1165 /* --------------- write segment header command ---------------- */
1166 YASM_WRITE_32_L(localbuf, macho_segcmd); /* command LC_SEGMENT */
1167 /* size of load command including section load commands */
1168 YASM_WRITE_32_L(localbuf,
1169 macho_segcmdsize +
1170 macho_sectcmdsize * objfmt_macho->parse_scnum);
1171 /* in an MH_OBJECT file all sections are in one unnamed (name all zeros)
1172 * segment (16x0)
1173 */
1174 YASM_WRITE_32_L(localbuf, 0);
1175 YASM_WRITE_32_L(localbuf, 0);
1176 YASM_WRITE_32_L(localbuf, 0);
1177 YASM_WRITE_32_L(localbuf, 0);
1178
1179 /* in-memory offset, in-memory size */
1180 yasm_intnum_set_uint(val, 0); /* offset in memory (vmaddr) */
1181 yasm_intnum_get_sized(val, localbuf, long_int_bytes,
1182 ((long_int_bytes) << 3), 0, 0, 0);
1183 localbuf += long_int_bytes;
1184 yasm_intnum_set_uint(val, info.vmsize); /* size in memory (vmsize) */
1185 yasm_intnum_get_sized(val, localbuf, long_int_bytes,
1186 ((long_int_bytes) << 3), 0, 0, 0);
1187 localbuf += long_int_bytes;
1188 /* offset in file to first section */
1189 yasm_intnum_set_uint(val, fileoffset);
1190 yasm_intnum_get_sized(val, localbuf, long_int_bytes,
1191 ((long_int_bytes) << 3), 0, 0, 0);
1192 localbuf += long_int_bytes;
1193 yasm_intnum_set_uint(val, info.filesize); /* overall size in file */
1194 yasm_intnum_get_sized(val, localbuf, long_int_bytes,
1195 ((long_int_bytes) << 3), 0, 0, 0);
1196 localbuf += long_int_bytes;
1197
1198 YASM_WRITE_32_L(localbuf, VM_PROT_DEFAULT); /* VM protection, maximum */
1199 YASM_WRITE_32_L(localbuf, VM_PROT_DEFAULT); /* VM protection, initial */
1200 /* number of sections */
1201 YASM_WRITE_32_L(localbuf, objfmt_macho->parse_scnum);
1202 YASM_WRITE_32_L(localbuf, 0); /* no flags */
1203
1204 /* write MACH-O header and segment command to outfile */
1205 fwrite(info.buf, (size_t) (localbuf - info.buf), 1, f);
1206
1207 /* next: section headers */
1208 /* offset to relocs for first section */
1209 info.rel_base = align32((long)fileoff_sections);
1210 info.s_reloff = 0; /* offset for relocs of following sections */
1211 yasm_object_sections_traverse(object, &info, macho_objfmt_output_secthead);
1212
1213 localbuf = info.buf;
1214 /* write out symbol command */
1215 YASM_WRITE_32_L(localbuf, LC_SYMTAB); /* cmd == LC_SYMTAB */
1216 YASM_WRITE_32_L(localbuf, MACHO_SYMCMD_SIZE);
1217 /* symbol table offset */
1218 YASM_WRITE_32_L(localbuf, info.rel_base + info.s_reloff);
1219 YASM_WRITE_32_L(localbuf, symtab_count); /* number of symbols */
1220
1221 YASM_WRITE_32_L(localbuf, macho_nlistsize * symtab_count + info.rel_base +
1222 info.s_reloff); /* string table offset */
1223 YASM_WRITE_32_L(localbuf, info.strlength); /* string table size */
1224 /* write symbol command */
1225 fwrite(info.buf, (size_t)(localbuf - info.buf), 1, f);
1226
1227 /*printf("num symbols %d, vmsize %d, filesize %d\n",symtab_count,
1228 info.vmsize, info.filesize ); */
1229
1230 /* get back to end of raw section data */
1231 if (fseek(f, (long)fileoff_sections, SEEK_SET) < 0) {
1232 yasm__fatal(N_("could not seek on output file"));
1233 /*@notreached@*/
1234 return;
1235 }
1236
1237 /* padding to long boundary */
1238 if ((info.rel_base - fileoff_sections) > 0) {
1239 fwrite(pad_data, info.rel_base - fileoff_sections, 1, f);
1240 }
1241
1242 /* relocation data */
1243 yasm_object_sections_traverse(object, &info, macho_objfmt_output_relocs);
1244
1245 /* symbol table (NLIST) */
1246 info.indx = 1; /* restart symbol table indices */
1247 yasm_symtab_traverse(object->symtab, &info, macho_objfmt_output_symtable);
1248
1249 /* symbol strings */
1250 fwrite(pad_data, 1, 1, f);
1251 yasm_symtab_traverse(object->symtab, &info, macho_objfmt_output_str);
1252
1253 yasm_intnum_destroy(val);
1254 yasm_xfree(info.buf);
1255 }
1256
1257 static void
macho_objfmt_destroy(yasm_objfmt * objfmt)1258 macho_objfmt_destroy(yasm_objfmt *objfmt)
1259 {
1260 yasm_xfree(objfmt);
1261 }
1262
1263 static void
macho_objfmt_init_new_section(yasm_section * sect,unsigned long line)1264 macho_objfmt_init_new_section(yasm_section *sect, unsigned long line)
1265 {
1266 yasm_object *object = yasm_section_get_object(sect);
1267 const char *sectname = yasm_section_get_name(sect);
1268 yasm_objfmt_macho *objfmt_macho = (yasm_objfmt_macho *)object->objfmt;
1269 macho_section_data *data;
1270 yasm_symrec *sym;
1271
1272 data = yasm_xmalloc(sizeof(macho_section_data));
1273 data->scnum = objfmt_macho->parse_scnum++;
1274 data->segname = NULL;
1275 data->sectname = NULL;
1276 data->flags = S_REGULAR;
1277 data->size = 0;
1278 data->offset = 0;
1279 data->vmoff = 0;
1280 data->nreloc = 0;
1281 data->extreloc = 0;
1282 yasm_section_add_data(sect, &macho_section_data_cb, data);
1283
1284 sym = yasm_symtab_define_label(object->symtab, sectname,
1285 yasm_section_bcs_first(sect), 1, line);
1286 data->sym = sym;
1287 }
1288
1289 static yasm_section *
macho_objfmt_add_default_section(yasm_object * object)1290 macho_objfmt_add_default_section(yasm_object *object)
1291 {
1292 yasm_section *retval;
1293 macho_section_data *msd;
1294 int isnew;
1295
1296 retval = yasm_object_get_general(object, "LC_SEGMENT.__TEXT.__text", 0, 1,
1297 0, &isnew, 0);
1298 if (isnew) {
1299 msd = yasm_section_get_data(retval, &macho_section_data_cb);
1300 msd->segname = yasm__xstrdup("__TEXT");
1301 msd->sectname = yasm__xstrdup("__text");
1302 msd->flags = S_ATTR_PURE_INSTRUCTIONS;
1303 yasm_section_set_align(retval, 0, 0);
1304 yasm_section_set_default(retval, 1);
1305 }
1306 return retval;
1307 }
1308
1309 static /*@observer@*/ /*@null@*/ yasm_section *
macho_objfmt_section_switch(yasm_object * object,yasm_valparamhead * valparams,yasm_valparamhead * objext_valparams,unsigned long line)1310 macho_objfmt_section_switch(yasm_object *object, yasm_valparamhead *valparams,
1311 /*@unused@*/ /*@null@*/
1312 yasm_valparamhead *objext_valparams,
1313 unsigned long line)
1314 {
1315 yasm_valparam *vp;
1316 yasm_section *retval;
1317 int isnew;
1318 /*@only@*/ char *f_sectname;
1319 unsigned long flags;
1320 unsigned long align;
1321 int flags_override = 0;
1322 const char *sectname;
1323 char *realname;
1324 int resonly = 0;
1325 macho_section_data *msd;
1326 size_t i;
1327
1328 static const struct {
1329 const char *in;
1330 const char *seg;
1331 const char *sect;
1332 unsigned long flags;
1333 unsigned long align;
1334 } section_name_translation[] = {
1335 {".text", "__TEXT", "__text", S_ATTR_PURE_INSTRUCTIONS, 0},
1336 {".const", "__TEXT", "__const", S_REGULAR, 0},
1337 {".static_const", "__TEXT", "__static_const", S_REGULAR, 0},
1338 {".cstring", "__TEXT", "__cstring", S_CSTRING_LITERALS, 0},
1339 {".literal4", "__TEXT", "__literal4", S_4BYTE_LITERALS, 4},
1340 {".literal8", "__TEXT", "__literal8", S_8BYTE_LITERALS, 8},
1341 {".literal16", "__TEXT", "__literal16", S_16BYTE_LITERALS, 16},
1342 {".constructor", "__TEXT", "__constructor", S_REGULAR, 0},
1343 {".destructor", "__TEXT", "__destructor", S_REGULAR, 0},
1344 {".fvmlib_init0", "__TEXT", "__fvmlib_init0", S_REGULAR, 0},
1345 {".fvmlib_init1", "__TEXT", "__fvmlib_init1", S_REGULAR, 0},
1346 {".mod_init_func", "__DATA", "__mod_init_func",
1347 S_MOD_INIT_FUNC_POINTERS, 4},
1348 {".mod_term_func", "__DATA", "__mod_term_func",
1349 S_MOD_TERM_FUNC_POINTERS, 4},
1350 {".dyld", "__DATA", "__dyld", S_REGULAR, 0},
1351 {".data", "__DATA", "__data", S_REGULAR, 0},
1352 {".static_data", "__DATA", "__static_data", S_REGULAR, 0},
1353 {".const_data", "__DATA", "__const", S_REGULAR, 0},
1354 {".rodata", "__DATA", "__const", S_REGULAR, 0},
1355 {".bss", "__DATA", "__bss", S_ZEROFILL, 0},
1356 {".objc_class_names", "__TEXT", "__cstring", S_CSTRING_LITERALS, 0},
1357 {".objc_meth_var_types","__TEXT", "__cstring", S_CSTRING_LITERALS, 0},
1358 {".objc_meth_var_names","__TEXT", "__cstring", S_CSTRING_LITERALS, 0},
1359 {".objc_selector_strs", "__OBJC", "__selector_strs",
1360 S_CSTRING_LITERALS, 0},
1361 {".objc_class", "__OBJC", "__class",
1362 S_ATTR_NO_DEAD_STRIP, 0},
1363 {".objc_meta_class", "__OBJC", "__meta_class",
1364 S_ATTR_NO_DEAD_STRIP, 0},
1365 {".objc_string_object", "__OBJC", "__string_object",
1366 S_ATTR_NO_DEAD_STRIP, 0},
1367 {".objc_protocol", "__OBJC", "__protocol",
1368 S_ATTR_NO_DEAD_STRIP, 0},
1369 {".objc_cat_cls_meth", "__OBJC", "__cat_cls_meth",
1370 S_ATTR_NO_DEAD_STRIP, 0},
1371 {".objc_cat_inst_meth", "__OBJC", "__cat_inst_meth",
1372 S_ATTR_NO_DEAD_STRIP, 0},
1373 {".objc_cls_meth", "__OBJC", "__cls_meth",
1374 S_ATTR_NO_DEAD_STRIP, 0},
1375 {".objc_inst_meth", "__OBJC", "__inst_meth",
1376 S_ATTR_NO_DEAD_STRIP, 0},
1377 {".objc_message_refs", "__OBJC", "__message_refs",
1378 S_LITERAL_POINTERS|S_ATTR_NO_DEAD_STRIP, 4},
1379 {".objc_cls_refs", "__OBJC", "__cls_refs",
1380 S_LITERAL_POINTERS|S_ATTR_NO_DEAD_STRIP, 4},
1381 {".objc_module_info", "__OBJC", "__module_info",
1382 S_ATTR_NO_DEAD_STRIP, 0},
1383 {".objc_symbols", "__OBJC", "__symbols",
1384 S_ATTR_NO_DEAD_STRIP, 0},
1385 {".objc_category", "__OBJC", "__category",
1386 S_ATTR_NO_DEAD_STRIP, 0},
1387 {".objc_class_vars", "__OBJC", "__class_vars",
1388 S_ATTR_NO_DEAD_STRIP, 0},
1389 {".objc_instance_vars", "__OBJC", "__instance_vars",
1390 S_ATTR_NO_DEAD_STRIP, 0}
1391 };
1392
1393 struct macho_section_switch_data {
1394 /*@only@*/ /*@null@*/ char *f_segname;
1395 /*@only@*/ /*@null@*/ yasm_intnum *align_intn;
1396 } data;
1397
1398 static const yasm_dir_help help[] = {
1399 { "segname", 1, yasm_dir_helper_string,
1400 offsetof(struct macho_section_switch_data, f_segname), 0 },
1401 { "align", 1, yasm_dir_helper_intn,
1402 offsetof(struct macho_section_switch_data, align_intn), 0 }
1403 };
1404
1405 data.f_segname = NULL;
1406 data.align_intn = NULL;
1407
1408 vp = yasm_vps_first(valparams);
1409 sectname = yasm_vp_string(vp);
1410 if (!sectname)
1411 return NULL;
1412 vp = yasm_vps_next(vp);
1413
1414 /* translate .text,.data,.bss to __text,__data,__bss... */
1415 for (i=0; i<NELEMS(section_name_translation); i++) {
1416 if (yasm__strcasecmp(sectname, section_name_translation[i].in) == 0)
1417 break;
1418 }
1419
1420 if (i == NELEMS(section_name_translation)) {
1421 const char *s;
1422 if (vp && !vp->val && (s = yasm_vp_string(vp))) {
1423 /* Treat as SEGNAME, SECTNAME */
1424 if (strlen(sectname) > 16)
1425 yasm_warn_set(YASM_WARN_GENERAL,
1426 N_("segment name is too long, max 16 chars; truncating"));
1427 data.f_segname = yasm__xstrndup(sectname, 16);
1428 if (strlen(s) > 16)
1429 yasm_warn_set(YASM_WARN_GENERAL,
1430 N_("section name is too long, max 16 chars; truncating"));
1431 f_sectname = yasm__xstrndup(s, 16);
1432 flags = S_REGULAR;
1433 align = 0;
1434
1435 sectname = s;
1436 vp = yasm_vps_next(vp);
1437 } else {
1438 data.f_segname = NULL;
1439 if (strlen(sectname) > 16)
1440 yasm_warn_set(YASM_WARN_GENERAL,
1441 N_("section name is too long, max 16 chars; truncating"));
1442 f_sectname = yasm__xstrndup(sectname, 16);
1443 flags = S_ATTR_SOME_INSTRUCTIONS;
1444 align = 0;
1445 }
1446 } else {
1447 data.f_segname = yasm__xstrdup(section_name_translation[i].seg);
1448 f_sectname = yasm__xstrdup(section_name_translation[i].sect);
1449 flags = section_name_translation[i].flags;
1450 align = section_name_translation[i].align;
1451 }
1452
1453 flags_override = yasm_dir_helper(object, vp, line, help, NELEMS(help),
1454 &data, yasm_dir_helper_valparam_warn);
1455 if (flags_override < 0)
1456 return NULL; /* error occurred */
1457
1458 if (data.align_intn) {
1459 align = yasm_intnum_get_uint(data.align_intn);
1460 yasm_intnum_destroy(data.align_intn);
1461
1462 /* Alignments must be a power of two. */
1463 if (!is_exp2(align)) {
1464 yasm_error_set(YASM_ERROR_VALUE,
1465 N_("argument to `%s' is not a power of two"),
1466 vp->val);
1467 return NULL;
1468 }
1469
1470 /* Check to see if alignment is supported size */
1471 if (align > 16384) {
1472 yasm_error_set(YASM_ERROR_VALUE,
1473 N_("macho implementation does not support alignments > 16384"));
1474 return NULL;
1475 }
1476 }
1477
1478 if (!data.f_segname) {
1479 yasm_warn_set(YASM_WARN_GENERAL,
1480 N_("Unknown section name, defaulting to __TEXT segment"));
1481 data.f_segname = yasm__xstrdup("__TEXT");
1482 }
1483
1484 /* Build a unique sectname from f_segname and f_sectname. */
1485 realname = yasm_xmalloc(strlen("LC_SEGMENT") + 1 + strlen(data.f_segname) + 1 +
1486 strlen(f_sectname) + 1);
1487 sprintf(realname, "LC_SEGMENT.%s.%s", data.f_segname, f_sectname);
1488 retval = yasm_object_get_general(object, realname, align, 1, resonly,
1489 &isnew, line);
1490 yasm_xfree(realname);
1491
1492 msd = yasm_section_get_data(retval, &macho_section_data_cb);
1493
1494 if (isnew || yasm_section_is_default(retval)) {
1495 yasm_section_set_default(retval, 0);
1496 msd->segname = data.f_segname;
1497 msd->sectname = f_sectname;
1498 msd->flags = flags;
1499 yasm_section_set_align(retval, align, line);
1500 } else if (flags_override) {
1501 /* align is the only value used from overrides. */
1502 if (yasm_section_get_align(retval) != align) {
1503 yasm_warn_set(YASM_WARN_GENERAL,
1504 N_("section flags ignored on section redeclaration"));
1505 }
1506 }
1507 return retval;
1508 }
1509
1510 static /*@observer@*/ /*@null@*/ yasm_symrec *
macho_objfmt_get_special_sym(yasm_object * object,const char * name,const char * parser)1511 macho_objfmt_get_special_sym(yasm_object *object, const char *name,
1512 const char *parser)
1513 {
1514 yasm_objfmt_macho *objfmt_macho = (yasm_objfmt_macho *)object->objfmt;
1515 if (yasm__strcasecmp(name, "gotpcrel") == 0) {
1516 return objfmt_macho->gotpcrel_sym;
1517 }
1518 return NULL;
1519 }
1520
1521 static void
macho_section_data_destroy(void * data)1522 macho_section_data_destroy(void *data)
1523 {
1524 macho_section_data *msd = (macho_section_data *) data;
1525 yasm_xfree(msd->segname);
1526 yasm_xfree(msd->sectname);
1527 yasm_xfree(data);
1528 }
1529
1530 static void
macho_section_data_print(void * data,FILE * f,int indent_level)1531 macho_section_data_print(void *data, FILE *f, int indent_level)
1532 {
1533 macho_section_data *msd = (macho_section_data *) data;
1534
1535 fprintf(f, "%*ssym=\n", indent_level, "");
1536 yasm_symrec_print(msd->sym, f, indent_level + 1);
1537 fprintf(f, "%*sscnum=%ld\n", indent_level, "", msd->scnum);
1538 fprintf(f, "%*sflags=0x%lx\n", indent_level, "", msd->flags);
1539 fprintf(f, "%*ssize=%lu\n", indent_level, "", msd->size);
1540 fprintf(f, "%*snreloc=%lu\n", indent_level, "", msd->nreloc);
1541 fprintf(f, "%*soffset=%lu\n", indent_level, "", msd->offset);
1542 fprintf(f, "%*sextreloc=%u\n", indent_level, "", msd->extreloc);
1543 }
1544
1545 static void
macho_symrec_data_destroy(void * data)1546 macho_symrec_data_destroy(void *data)
1547 {
1548 yasm_xfree(data);
1549 }
1550
1551 static void
macho_symrec_data_print(void * data,FILE * f,int indent_level)1552 macho_symrec_data_print(void *data, FILE *f, int indent_level)
1553 {
1554 macho_symrec_data *msd = (macho_symrec_data *)data;
1555
1556 fprintf(f, "%*sindex=%ld\n", indent_level, "", msd->index);
1557 fprintf(f, "%*svalue=", indent_level, "");
1558 if (msd->value)
1559 fprintf(f, "%ld\n", yasm_intnum_get_int(msd->value));
1560 else
1561 fprintf(f, "nil\n");
1562 }
1563
1564
1565 /* Define valid debug formats to use with this object format */
1566 static const char *macho_objfmt_dbgfmt_keywords[] = {
1567 "null",
1568 NULL
1569 };
1570
1571 /* Define objfmt structure -- see objfmt.h for details */
1572 yasm_objfmt_module yasm_macho_LTX_objfmt = {
1573 "Mac OS X ABI Mach-O File Format",
1574 "macho",
1575 "o",
1576 32,
1577 0,
1578 macho_objfmt_dbgfmt_keywords,
1579 "null",
1580 NULL, /* no directives */
1581 NULL, /* no standard macros */
1582 macho_objfmt_create,
1583 macho_objfmt_output,
1584 macho_objfmt_destroy,
1585 macho_objfmt_add_default_section,
1586 macho_objfmt_init_new_section,
1587 macho_objfmt_section_switch,
1588 macho_objfmt_get_special_sym
1589 };
1590
1591 yasm_objfmt_module yasm_macho32_LTX_objfmt = {
1592 "Mac OS X ABI Mach-O File Format (32-bit)",
1593 "macho32",
1594 "o",
1595 32,
1596 0,
1597 macho_objfmt_dbgfmt_keywords,
1598 "null",
1599 NULL, /* no directives */
1600 NULL, /* no standard macros */
1601 macho32_objfmt_create,
1602 macho_objfmt_output,
1603 macho_objfmt_destroy,
1604 macho_objfmt_add_default_section,
1605 macho_objfmt_init_new_section,
1606 macho_objfmt_section_switch,
1607 macho_objfmt_get_special_sym
1608 };
1609
1610 yasm_objfmt_module yasm_macho64_LTX_objfmt = {
1611 "Mac OS X ABI Mach-O File Format (64-bit)",
1612 "macho64",
1613 "o",
1614 64,
1615 0,
1616 macho_objfmt_dbgfmt_keywords,
1617 "null",
1618 NULL, /* no directives */
1619 NULL, /* no standard macros */
1620 macho64_objfmt_create,
1621 macho_objfmt_output,
1622 macho_objfmt_destroy,
1623 macho_objfmt_add_default_section,
1624 macho_objfmt_init_new_section,
1625 macho_objfmt_section_switch,
1626 macho_objfmt_get_special_sym
1627 };
1628