macos: add __builtin_flt_rounds. Forced to 1 which means 'to nearest'
[tinycc.git] / tccmacho.c
blobbb984dc152965d320401c5875ac8aa8bad592c9e
1 /*
2 * Mach-O file handling for TCC
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 #include "tcc.h"
20 /* In order to make life easy for us we are generating Mach-O files which
21 don't make use of some modern features, but which aren't entirely classic
22 either in that they do use some modern features. We're also only
23 generating 64bit Mach-O files, and only native endian at that.
25 In particular we're generating executables that don't make use of
26 DYLD_INFO for dynamic linking info, as that requires us building a
27 trie of exported names. We're simply using classic symbol tables which
28 are still supported by modern dyld.
30 But we do use LC_MAIN, which is a "modern" feature in order to not have
31 to setup our own crt code. We're not using lazy linking, so even function
32 calls are resolved at startup. */
34 #define DEBUG_MACHO 0
35 #define dprintf if (DEBUG_MACHO) printf
37 struct fat_header {
38 uint32_t magic; /* FAT_MAGIC or FAT_MAGIC_64 */
39 uint32_t nfat_arch; /* number of structs that follow */
42 struct fat_arch {
43 int cputype; /* cpu specifier (int) */
44 int cpusubtype; /* machine specifier (int) */
45 uint32_t offset; /* file offset to this object file */
46 uint32_t size; /* size of this object file */
47 uint32_t align; /* alignment as a power of 2 */
50 #define FAT_MAGIC 0xcafebabe
51 #define FAT_CIGAM 0xbebafeca
52 #define FAT_MAGIC_64 0xcafebabf
53 #define FAT_CIGAM_64 0xbfbafeca
55 struct mach_header {
56 uint32_t magic; /* mach magic number identifier */
57 int cputype; /* cpu specifier */
58 int cpusubtype; /* machine specifier */
59 uint32_t filetype; /* type of file */
60 uint32_t ncmds; /* number of load commands */
61 uint32_t sizeofcmds; /* the size of all the load commands */
62 uint32_t flags; /* flags */
65 struct mach_header_64 {
66 struct mach_header mh;
67 uint32_t reserved; /* reserved, pad to 64bit */
70 /* Constant for the magic field of the mach_header (32-bit architectures) */
71 #define MH_MAGIC 0xfeedface /* the mach magic number */
72 #define MH_CIGAM 0xcefaedfe /* NXSwapInt(MH_MAGIC) */
73 #define MH_MAGIC_64 0xfeedfacf /* the 64-bit mach magic number */
74 #define MH_CIGAM_64 0xcffaedfe /* NXSwapInt(MH_MAGIC_64) */
76 struct load_command {
77 uint32_t cmd; /* type of load command */
78 uint32_t cmdsize; /* total size of command in bytes */
81 #define LC_REQ_DYLD 0x80000000
82 #define LC_SYMTAB 0x2
83 #define LC_DYSYMTAB 0xb
84 #define LC_LOAD_DYLIB 0xc
85 #define LC_ID_DYLIB 0xd
86 #define LC_LOAD_DYLINKER 0xe
87 #define LC_SEGMENT_64 0x19
88 #define LC_REEXPORT_DYLIB (0x1f | LC_REQ_DYLD)
89 #define LC_MAIN (0x28|LC_REQ_DYLD)
91 typedef int vm_prot_t;
93 struct segment_command_64 { /* for 64-bit architectures */
94 uint32_t cmd; /* LC_SEGMENT_64 */
95 uint32_t cmdsize; /* includes sizeof section_64 structs */
96 char segname[16]; /* segment name */
97 uint64_t vmaddr; /* memory address of this segment */
98 uint64_t vmsize; /* memory size of this segment */
99 uint64_t fileoff; /* file offset of this segment */
100 uint64_t filesize; /* amount to map from the file */
101 vm_prot_t maxprot; /* maximum VM protection */
102 vm_prot_t initprot; /* initial VM protection */
103 uint32_t nsects; /* number of sections in segment */
104 uint32_t flags; /* flags */
107 struct section_64 { /* for 64-bit architectures */
108 char sectname[16]; /* name of this section */
109 char segname[16]; /* segment this section goes in */
110 uint64_t addr; /* memory address of this section */
111 uint64_t size; /* size in bytes of this section */
112 uint32_t offset; /* file offset of this section */
113 uint32_t align; /* section alignment (power of 2) */
114 uint32_t reloff; /* file offset of relocation entries */
115 uint32_t nreloc; /* number of relocation entries */
116 uint32_t flags; /* flags (section type and attributes)*/
117 uint32_t reserved1; /* reserved (for offset or index) */
118 uint32_t reserved2; /* reserved (for count or sizeof) */
119 uint32_t reserved3; /* reserved */
122 #define S_REGULAR 0x0
123 #define S_ZEROFILL 0x1
124 #define S_NON_LAZY_SYMBOL_POINTERS 0x6
125 #define S_MOD_INIT_FUNC_POINTERS 0x9
126 #define S_MOD_TERM_FUNC_POINTERS 0xa
128 #define S_ATTR_PURE_INSTRUCTIONS 0x80000000
129 #define S_ATTR_SOME_INSTRUCTIONS 0x00000400
131 typedef uint32_t lc_str;
133 struct dylib_command {
134 uint32_t cmd; /* LC_ID_DYLIB, LC_LOAD_{,WEAK_}DYLIB,
135 LC_REEXPORT_DYLIB */
136 uint32_t cmdsize; /* includes pathname string */
137 lc_str name; /* library's path name */
138 uint32_t timestamp; /* library's build time stamp */
139 uint32_t current_version; /* library's current version number */
140 uint32_t compatibility_version; /* library's compatibility vers number*/
143 struct dylinker_command {
144 uint32_t cmd; /* LC_ID_DYLINKER, LC_LOAD_DYLINKER or
145 LC_DYLD_ENVIRONMENT */
146 uint32_t cmdsize; /* includes pathname string */
147 lc_str name; /* dynamic linker's path name */
150 struct symtab_command {
151 uint32_t cmd; /* LC_SYMTAB */
152 uint32_t cmdsize; /* sizeof(struct symtab_command) */
153 uint32_t symoff; /* symbol table offset */
154 uint32_t nsyms; /* number of symbol table entries */
155 uint32_t stroff; /* string table offset */
156 uint32_t strsize; /* string table size in bytes */
159 struct dysymtab_command {
160 uint32_t cmd; /* LC_DYSYMTAB */
161 uint32_t cmdsize; /* sizeof(struct dysymtab_command) */
163 uint32_t ilocalsym; /* index to local symbols */
164 uint32_t nlocalsym; /* number of local symbols */
166 uint32_t iextdefsym;/* index to externally defined symbols */
167 uint32_t nextdefsym;/* number of externally defined symbols */
169 uint32_t iundefsym; /* index to undefined symbols */
170 uint32_t nundefsym; /* number of undefined symbols */
172 uint32_t tocoff; /* file offset to table of contents */
173 uint32_t ntoc; /* number of entries in table of contents */
175 uint32_t modtaboff; /* file offset to module table */
176 uint32_t nmodtab; /* number of module table entries */
178 uint32_t extrefsymoff; /* offset to referenced symbol table */
179 uint32_t nextrefsyms; /* number of referenced symbol table entries */
181 uint32_t indirectsymoff;/* file offset to the indirect symbol table */
182 uint32_t nindirectsyms; /* number of indirect symbol table entries */
184 uint32_t extreloff; /* offset to external relocation entries */
185 uint32_t nextrel; /* number of external relocation entries */
186 uint32_t locreloff; /* offset to local relocation entries */
187 uint32_t nlocrel; /* number of local relocation entries */
190 #define INDIRECT_SYMBOL_LOCAL 0x80000000
192 struct entry_point_command {
193 uint32_t cmd; /* LC_MAIN only used in MH_EXECUTE filetypes */
194 uint32_t cmdsize; /* 24 */
195 uint64_t entryoff; /* file (__TEXT) offset of main() */
196 uint64_t stacksize;/* if not zero, initial stack size */
199 enum skind {
200 sk_unknown = 0,
201 sk_discard,
202 sk_text,
203 sk_stubs,
204 sk_ro_data,
205 sk_uw_info,
206 sk_nl_ptr, // non-lazy pointers, aka GOT
207 sk_la_ptr, // lazy pointers
208 sk_init,
209 sk_fini,
210 sk_rw_data,
211 sk_bss,
212 sk_linkedit,
213 sk_last
216 struct nlist_64 {
217 uint32_t n_strx; /* index into the string table */
218 uint8_t n_type; /* type flag, see below */
219 uint8_t n_sect; /* section number or NO_SECT */
220 uint16_t n_desc; /* see <mach-o/stab.h> */
221 uint64_t n_value; /* value of this symbol (or stab offset) */
224 #define N_UNDF 0x0
225 #define N_ABS 0x2
226 #define N_EXT 0x1
227 #define N_SECT 0xe
229 #define N_WEAK_REF 0x0040
230 #define N_WEAK_DEF 0x0080
232 struct macho {
233 struct mach_header_64 mh;
234 int seg2lc[4], nseg;
235 struct load_command **lc;
236 struct entry_point_command *ep;
237 int nlc;
238 struct {
239 Section *s;
240 int machosect;
241 } sk_to_sect[sk_last];
242 int *elfsectomacho;
243 int *e2msym;
244 Section *symtab, *strtab, *wdata, *indirsyms, *stubs;
245 int stubsym;
246 uint32_t ilocal, iextdef, iundef;
249 #define SHT_LINKEDIT (SHT_LOOS + 42)
250 #define SHN_FROMDLL (SHN_LOOS + 2) /* Symbol is undefined, comes from a DLL */
252 static void * add_lc(struct macho *mo, uint32_t cmd, uint32_t cmdsize)
254 struct load_command *lc = tcc_mallocz(cmdsize);
255 lc->cmd = cmd;
256 lc->cmdsize = cmdsize;
257 mo->lc = tcc_realloc(mo->lc, sizeof(mo->lc[0]) * (mo->nlc + 1));
258 mo->lc[mo->nlc++] = lc;
259 return lc;
262 static struct segment_command_64 * add_segment(struct macho *mo, char *name)
264 struct segment_command_64 *sc = add_lc(mo, LC_SEGMENT_64, sizeof(*sc));
265 strncpy(sc->segname, name, 16);
266 mo->seg2lc[mo->nseg++] = mo->nlc - 1;
267 return sc;
270 static struct segment_command_64 * get_segment(struct macho *mo, int i)
272 return (struct segment_command_64 *) (mo->lc[mo->seg2lc[i]]);
275 static int add_section(struct macho *mo, struct segment_command_64 **_seg, char *name)
277 struct segment_command_64 *seg = *_seg;
278 int ret = seg->nsects;
279 struct section_64 *sec;
280 seg->nsects++;
281 seg->cmdsize += sizeof(*sec);
282 seg = tcc_realloc(seg, sizeof(*seg) + seg->nsects * sizeof(*sec));
283 sec = (struct section_64*)((char*)seg + sizeof(*seg)) + ret;
284 memset(sec, 0, sizeof(*sec));
285 strncpy(sec->sectname, name, 16);
286 strncpy(sec->segname, seg->segname, 16);
287 *_seg = seg;
288 return ret;
291 static struct section_64 *get_section(struct segment_command_64 *seg, int i)
293 return (struct section_64*)((char*)seg + sizeof(*seg)) + i;
296 static void * add_dylib(struct macho *mo, char *name)
298 struct dylib_command *lc;
299 int sz = (sizeof(*lc) + strlen(name) + 1 + 7) & -8;
300 lc = add_lc(mo, LC_LOAD_DYLIB, sz);
301 lc->name = sizeof(*lc);
302 strcpy((char*)lc + lc->name, name);
303 lc->timestamp = 2;
304 lc->current_version = 1 << 16;
305 lc->compatibility_version = 1 << 16;
306 return lc;
309 static void check_relocs(TCCState *s1, struct macho *mo)
311 Section *s;
312 ElfW_Rel *rel;
313 ElfW(Sym) *sym;
314 int i, type, gotplt_entry, sym_index, for_code;
315 struct sym_attr *attr;
317 s1->got = new_section(s1, ".got", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE);
318 mo->indirsyms = new_section(s1, "LEINDIR", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE);
319 for (i = 1; i < s1->nb_sections; i++) {
320 s = s1->sections[i];
321 if (s->sh_type != SHT_RELX)
322 continue;
323 for_each_elem(s, 0, rel, ElfW_Rel) {
324 type = ELFW(R_TYPE)(rel->r_info);
325 gotplt_entry = gotplt_entry_type(type);
326 for_code = code_reloc(type);
327 /* We generate a non-lazy pointer for used undefined symbols
328 and for defined symbols that must have a place for their
329 address due to codegen (i.e. a reloc requiring a got slot). */
330 sym_index = ELFW(R_SYM)(rel->r_info);
331 sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
332 if (sym->st_shndx == SHN_UNDEF
333 || gotplt_entry == ALWAYS_GOTPLT_ENTRY) {
334 attr = get_sym_attr(s1, sym_index, 1);
335 if (!attr->dyn_index) {
336 uint32_t *pi = section_ptr_add(mo->indirsyms, sizeof(*pi));
337 attr->got_offset = s1->got->data_offset;
338 attr->plt_offset = -1;
339 attr->dyn_index = 1; /* used as flag */
340 section_ptr_add(s1->got, PTR_SIZE);
341 if (ELFW(ST_BIND)(sym->st_info) == STB_LOCAL) {
342 if (sym->st_shndx == SHN_UNDEF)
343 tcc_error("undefined local symbol???");
344 *pi = INDIRECT_SYMBOL_LOCAL;
345 /* The pointer slot we generated must point to the
346 symbol, whose address is only known after layout,
347 so register a simple relocation for that. */
348 put_elf_reloc(s1->symtab, s1->got, attr->got_offset,
349 R_DATA_PTR, sym_index);
350 } else
351 *pi = mo->e2msym[sym_index];
353 if (for_code) {
354 if (attr->plt_offset == -1) {
355 uint8_t *jmp;
356 attr->plt_offset = mo->stubs->data_offset;
357 jmp = section_ptr_add(mo->stubs, 6);
358 jmp[0] = 0xff; /* jmpq *ofs(%rip) */
359 jmp[1] = 0x25;
360 put_elf_reloc(s1->symtab, mo->stubs,
361 attr->plt_offset + 2,
362 R_X86_64_GOTPCREL, sym_index);
364 rel->r_info = ELFW(R_INFO)(mo->stubsym, type);
365 rel->r_addend += attr->plt_offset;
372 static int check_symbols(TCCState *s1, struct macho *mo)
374 int sym_index, sym_end;
375 int ret = 0;
377 mo->ilocal = mo->iextdef = mo->iundef = -1;
378 sym_end = symtab_section->data_offset / sizeof(ElfW(Sym));
379 for (sym_index = 1; sym_index < sym_end; ++sym_index) {
380 int elf_index = ((struct nlist_64 *)mo->symtab->data + sym_index - 1)->n_value;
381 ElfW(Sym) *sym = (ElfW(Sym) *)symtab_section->data + elf_index;
382 const char *name = (char*)symtab_section->link->data + sym->st_name;
383 unsigned type = ELFW(ST_TYPE)(sym->st_info);
384 unsigned bind = ELFW(ST_BIND)(sym->st_info);
385 unsigned vis = ELFW(ST_VISIBILITY)(sym->st_other);
387 dprintf("%4d (%4d): %09llx %4d %4d %4d %3d %s\n",
388 sym_index, elf_index, sym->st_value,
389 type, bind, vis, sym->st_shndx, name);
390 if (bind == STB_LOCAL) {
391 if (mo->ilocal == -1)
392 mo->ilocal = sym_index - 1;
393 if (mo->iextdef != -1 || mo->iundef != -1)
394 tcc_error("local syms after global ones");
395 } else if (sym->st_shndx != SHN_UNDEF) {
396 if (mo->iextdef == -1)
397 mo->iextdef = sym_index - 1;
398 if (mo->iundef != -1)
399 tcc_error("external defined symbol after undefined");
400 } else if (sym->st_shndx == SHN_UNDEF) {
401 if (mo->iundef == -1)
402 mo->iundef = sym_index - 1;
403 if (ELFW(ST_BIND)(sym->st_info) == STB_WEAK
404 || find_elf_sym(s1->dynsymtab_section, name)) {
405 /* Mark the symbol as coming from a dylib so that
406 relocate_syms doesn't complain. Normally bind_exe_dynsyms
407 would do this check, and place the symbol into dynsym
408 which is checked by relocate_syms. But Mach-O doesn't use
409 bind_exe_dynsyms. */
410 sym->st_shndx = SHN_FROMDLL;
411 continue;
413 tcc_error_noabort("undefined symbol '%s'", name);
414 ret = -1;
417 return ret;
420 static void convert_symbol(TCCState *s1, struct macho *mo, struct nlist_64 *pn)
422 struct nlist_64 n = *pn;
423 ElfSym *sym = (ElfW(Sym) *)symtab_section->data + pn->n_value;
424 const char *name = (char*)symtab_section->link->data + sym->st_name;
425 switch(ELFW(ST_TYPE)(sym->st_info)) {
426 case STT_NOTYPE:
427 case STT_OBJECT:
428 case STT_FUNC:
429 case STT_SECTION:
430 n.n_type = N_SECT;
431 break;
432 case STT_FILE:
433 n.n_type = N_ABS;
434 break;
435 default:
436 tcc_error("unhandled ELF symbol type %d %s",
437 ELFW(ST_TYPE)(sym->st_info), name);
439 if (sym->st_shndx == SHN_UNDEF)
440 tcc_error("should have been rewritten to SHN_FROMDLL: %s", name);
441 else if (sym->st_shndx == SHN_FROMDLL)
442 n.n_type = N_UNDF, n.n_sect = 0;
443 else if (sym->st_shndx == SHN_ABS)
444 n.n_type = N_ABS, n.n_sect = 0;
445 else if (sym->st_shndx >= SHN_LORESERVE)
446 tcc_error("unhandled ELF symbol section %d %s", sym->st_shndx, name);
447 else if (!mo->elfsectomacho[sym->st_shndx])
448 tcc_error("ELF section %d not mapped into Mach-O for symbol %s",
449 sym->st_shndx, name);
450 else
451 n.n_sect = mo->elfsectomacho[sym->st_shndx];
452 if (ELFW(ST_BIND)(sym->st_info) == STB_GLOBAL)
453 n.n_type |= N_EXT;
454 else if (ELFW(ST_BIND)(sym->st_info) == STB_WEAK)
455 n.n_desc |= N_WEAK_REF | (n.n_type != N_UNDF ? N_WEAK_DEF : 0);
456 n.n_strx = pn->n_strx;
457 n.n_value = sym->st_value;
458 *pn = n;
461 static void convert_symbols(TCCState *s1, struct macho *mo)
463 struct nlist_64 *pn;
464 for_each_elem(mo->symtab, 0, pn, struct nlist_64)
465 convert_symbol(s1, mo, pn);
468 static int machosymcmp(const void *_a, const void *_b)
470 TCCState *s1 = tcc_state;
471 int ea = ((struct nlist_64 *)_a)->n_value;
472 int eb = ((struct nlist_64 *)_b)->n_value;
473 ElfSym *sa = (ElfSym *)symtab_section->data + ea;
474 ElfSym *sb = (ElfSym *)symtab_section->data + eb;
475 int r;
476 /* locals, then defined externals, then undefined externals, the
477 last two sections also by name, otherwise stable sort */
478 r = (ELFW(ST_BIND)(sb->st_info) == STB_LOCAL)
479 - (ELFW(ST_BIND)(sa->st_info) == STB_LOCAL);
480 if (r)
481 return r;
482 r = (sa->st_shndx == SHN_UNDEF) - (sb->st_shndx == SHN_UNDEF);
483 if (r)
484 return r;
485 if (ELFW(ST_BIND)(sa->st_info) != STB_LOCAL) {
486 const char * na = (char*)symtab_section->link->data + sa->st_name;
487 const char * nb = (char*)symtab_section->link->data + sb->st_name;
488 r = strcmp(na, nb);
489 if (r)
490 return r;
492 return ea - eb;
495 static void create_symtab(TCCState *s1, struct macho *mo)
497 int sym_index, sym_end;
498 struct nlist_64 *pn;
500 /* Stub creation belongs to check_relocs, but we need to create
501 the symbol now, so its included in the sorting. */
502 mo->stubs = new_section(s1, "__stubs", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR);
503 mo->stubsym = put_elf_sym(s1->symtab, 0, 0,
504 ELFW(ST_INFO)(STB_LOCAL, STT_SECTION), 0,
505 mo->stubs->sh_num, ".__stubs");
507 mo->symtab = new_section(s1, "LESYMTAB", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE);
508 mo->strtab = new_section(s1, "LESTRTAB", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE);
509 put_elf_str(mo->strtab, " "); /* Mach-O starts strtab with a space */
510 sym_end = symtab_section->data_offset / sizeof(ElfW(Sym));
511 pn = section_ptr_add(mo->symtab, sizeof(*pn) * (sym_end - 1));
512 for (sym_index = 1; sym_index < sym_end; ++sym_index) {
513 ElfW(Sym) *sym = (ElfW(Sym) *)symtab_section->data + sym_index;
514 const char *name = (char*)symtab_section->link->data + sym->st_name;
515 pn[sym_index - 1].n_strx = put_elf_str(mo->strtab, name);
516 pn[sym_index - 1].n_value = sym_index;
518 tcc_enter_state(s1); /* qsort needs global state */
519 qsort(pn, sym_end - 1, sizeof(*pn), machosymcmp);
520 tcc_exit_state();
521 mo->e2msym = tcc_malloc(sym_end * sizeof(*mo->e2msym));
522 mo->e2msym[0] = -1;
523 for (sym_index = 1; sym_index < sym_end; ++sym_index) {
524 mo->e2msym[pn[sym_index - 1].n_value] = sym_index - 1;
528 struct {
529 int seg;
530 uint32_t flags;
531 char *name;
532 } skinfo[sk_last] = {
533 [sk_text] = { 1, S_REGULAR | S_ATTR_PURE_INSTRUCTIONS
534 | S_ATTR_SOME_INSTRUCTIONS, "__text" },
535 [sk_ro_data] = { 1, S_REGULAR, "__rodata" },
536 [sk_nl_ptr] = { 2, S_NON_LAZY_SYMBOL_POINTERS, "__got" },
537 [sk_init] = { 2, S_MOD_INIT_FUNC_POINTERS, "__mod_init_func" },
538 [sk_fini] = { 2, S_MOD_TERM_FUNC_POINTERS, "__mod_term_func" },
539 [sk_rw_data] = { 2, S_REGULAR, "__data" },
540 [sk_bss] = { 2, S_ZEROFILL, "__bss" },
541 [sk_linkedit] = { 3, S_REGULAR, NULL },
544 static void collect_sections(TCCState *s1, struct macho *mo)
546 int i, sk, numsec;
547 uint64_t curaddr, fileofs;
548 Section *s;
549 struct segment_command_64 *seg = NULL;
550 struct dylinker_command *dyldlc;
551 struct symtab_command *symlc;
552 struct dysymtab_command *dysymlc;
553 char *str;
555 seg = add_segment(mo, "__PAGEZERO");
556 seg->vmsize = (uint64_t)1 << 32;
558 seg = add_segment(mo, "__TEXT");
559 seg->vmaddr = (uint64_t)1 << 32;
560 seg->maxprot = 7; // rwx
561 seg->initprot = 5; // r-x
563 seg = add_segment(mo, "__DATA");
564 seg->vmaddr = -1;
565 seg->maxprot = 7; // rwx
566 seg->initprot = 3; // rw-
568 seg = add_segment(mo, "__LINKEDIT");
569 seg->vmaddr = -1;
570 seg->maxprot = 7; // rwx
571 seg->initprot = 1; // r--
573 mo->ep = add_lc(mo, LC_MAIN, sizeof(*mo->ep));
574 mo->ep->entryoff = 4096;
576 i = (sizeof(*dyldlc) + strlen("/usr/lib/dyld") + 1 + 7) &-8;
577 dyldlc = add_lc(mo, LC_LOAD_DYLINKER, i);
578 dyldlc->name = sizeof(*dyldlc);
579 str = (char*)dyldlc + dyldlc->name;
580 strcpy(str, "/usr/lib/dyld");
582 symlc = add_lc(mo, LC_SYMTAB, sizeof(*symlc));
583 dysymlc = add_lc(mo, LC_DYSYMTAB, sizeof(*dysymlc));
585 for(i = 0; i < s1->nb_loaded_dlls; i++) {
586 DLLReference *dllref = s1->loaded_dlls[i];
587 if (dllref->level == 0)
588 add_dylib(mo, dllref->name);
591 /* dyld requires a writable segment with classic Mach-O, but it ignores
592 zero-sized segments for this, so force to have some data. */
593 section_ptr_add(data_section, 1);
594 memset (mo->sk_to_sect, 0, sizeof(mo->sk_to_sect));
595 for (i = s1->nb_sections; i-- > 1;) {
596 int type, flags;
597 s = s1->sections[i];
598 type = s->sh_type;
599 flags = s->sh_flags;
600 sk = sk_unknown;
601 if (flags & SHF_ALLOC) {
602 switch (type) {
603 default: sk = sk_unknown; break;
604 case SHT_INIT_ARRAY: sk = sk_init; break;
605 case SHT_FINI_ARRAY: sk = sk_fini; break;
606 case SHT_NOBITS: sk = sk_bss; break;
607 case SHT_SYMTAB: sk = sk_discard; break;
608 case SHT_STRTAB: sk = s == stabstr_section ? sk_ro_data : sk_discard; break;
609 case SHT_RELX: sk = sk_discard; break;
610 case SHT_LINKEDIT: sk = sk_linkedit; break;
611 case SHT_PROGBITS:
612 if (s == s1->got)
613 sk = sk_nl_ptr;
614 else if (flags & SHF_EXECINSTR)
615 sk = sk_text;
616 else if (flags & SHF_WRITE)
617 sk = sk_rw_data;
618 else
619 sk = sk_ro_data;
620 break;
622 } else
623 sk = sk_discard;
624 s->prev = mo->sk_to_sect[sk].s;
625 mo->sk_to_sect[sk].s = s;
627 fileofs = 4096; /* leave space for mach-o headers */
628 curaddr = get_segment(mo, 1)->vmaddr;
629 curaddr += 4096;
630 seg = NULL;
631 numsec = 0;
632 mo->elfsectomacho = tcc_mallocz(sizeof(*mo->elfsectomacho) * s1->nb_sections);
633 for (sk = sk_unknown; sk < sk_last; sk++) {
634 struct section_64 *sec = NULL;
635 if (seg) {
636 seg->vmsize = curaddr - seg->vmaddr;
637 seg->filesize = fileofs - seg->fileoff;
639 if (skinfo[sk].seg && mo->sk_to_sect[sk].s) {
640 uint64_t al = 0;
641 int si;
642 seg = get_segment(mo, skinfo[sk].seg);
643 if (skinfo[sk].name) {
644 si = add_section(mo, &seg, skinfo[sk].name);
645 numsec++;
646 mo->lc[mo->seg2lc[skinfo[sk].seg]] = (struct load_command*)seg;
647 mo->sk_to_sect[sk].machosect = si;
648 sec = get_section(seg, si);
649 sec->flags = skinfo[sk].flags;
651 if (seg->vmaddr == -1) {
652 curaddr = (curaddr + 4095) & -4096;
653 seg->vmaddr = curaddr;
654 fileofs = (fileofs + 4095) & -4096;
655 seg->fileoff = fileofs;
658 for (s = mo->sk_to_sect[sk].s; s; s = s->prev) {
659 int a = exact_log2p1(s->sh_addralign);
660 if (a && al < (a - 1))
661 al = a - 1;
662 s->sh_size = s->data_offset;
664 if (sec)
665 sec->align = al;
666 al = 1U << al;
667 if (al > 4096)
668 tcc_warning("alignment > 4096"), sec->align = 12, al = 4096;
669 curaddr = (curaddr + al - 1) & -al;
670 fileofs = (fileofs + al - 1) & -al;
671 if (sec) {
672 sec->addr = curaddr;
673 sec->offset = fileofs;
675 for (s = mo->sk_to_sect[sk].s; s; s = s->prev) {
676 al = s->sh_addralign;
677 curaddr = (curaddr + al - 1) & -al;
678 dprintf("curaddr now 0x%llx\n", curaddr);
679 s->sh_addr = curaddr;
680 curaddr += s->sh_size;
681 if (s->sh_type != SHT_NOBITS) {
682 fileofs = (fileofs + al - 1) & -al;
683 s->sh_offset = fileofs;
684 fileofs += s->sh_size;
685 dprintf("fileofs now %lld\n", fileofs);
687 if (sec)
688 mo->elfsectomacho[s->sh_num] = numsec;
690 if (sec)
691 sec->size = curaddr - sec->addr;
693 if (DEBUG_MACHO)
694 for (s = mo->sk_to_sect[sk].s; s; s = s->prev) {
695 int type = s->sh_type;
696 int flags = s->sh_flags;
697 printf("%d section %-16s %-10s %09llx %04x %02d %s,%s,%s\n",
699 s->name,
700 type == SHT_PROGBITS ? "progbits" :
701 type == SHT_NOBITS ? "nobits" :
702 type == SHT_SYMTAB ? "symtab" :
703 type == SHT_STRTAB ? "strtab" :
704 type == SHT_INIT_ARRAY ? "init" :
705 type == SHT_FINI_ARRAY ? "fini" :
706 type == SHT_RELX ? "rel" : "???",
707 s->sh_addr,
708 (unsigned)s->data_offset,
709 s->sh_addralign,
710 flags & SHF_ALLOC ? "alloc" : "",
711 flags & SHF_WRITE ? "write" : "",
712 flags & SHF_EXECINSTR ? "exec" : ""
716 if (seg) {
717 seg->vmsize = curaddr - seg->vmaddr;
718 seg->filesize = fileofs - seg->fileoff;
721 /* Fill symtab info */
722 symlc->symoff = mo->symtab->sh_offset;
723 symlc->nsyms = mo->symtab->data_offset / sizeof(struct nlist_64);
724 symlc->stroff = mo->strtab->sh_offset;
725 symlc->strsize = mo->strtab->data_offset;
727 dysymlc->iundefsym = mo->iundef == -1 ? symlc->nsyms : mo->iundef;
728 dysymlc->iextdefsym = mo->iextdef == -1 ? dysymlc->iundefsym : mo->iextdef;
729 dysymlc->ilocalsym = mo->ilocal == -1 ? dysymlc->iextdefsym : mo->ilocal;
730 dysymlc->nlocalsym = dysymlc->iextdefsym - dysymlc->ilocalsym;
731 dysymlc->nextdefsym = dysymlc->iundefsym - dysymlc->iextdefsym;
732 dysymlc->nundefsym = symlc->nsyms - dysymlc->iundefsym;
733 dysymlc->indirectsymoff = mo->indirsyms->sh_offset;
734 dysymlc->nindirectsyms = mo->indirsyms->data_offset / sizeof(uint32_t);
737 static void macho_write(TCCState *s1, struct macho *mo, FILE *fp)
739 int i, sk;
740 uint64_t fileofs = 0;
741 Section *s;
742 mo->mh.mh.magic = MH_MAGIC_64;
743 mo->mh.mh.cputype = 0x1000007; // x86_64
744 mo->mh.mh.cpusubtype = 0x80000003;// all | CPU_SUBTYPE_LIB64
745 mo->mh.mh.filetype = 2; // MH_EXECUTE
746 mo->mh.mh.flags = 4; // DYLDLINK
747 mo->mh.mh.ncmds = mo->nlc;
748 mo->mh.mh.sizeofcmds = 0;
749 for (i = 0; i < mo->nlc; i++)
750 mo->mh.mh.sizeofcmds += mo->lc[i]->cmdsize;
752 fwrite(&mo->mh, 1, sizeof(mo->mh), fp);
753 fileofs += sizeof(mo->mh);
754 for (i = 0; i < mo->nlc; i++) {
755 fwrite(mo->lc[i], 1, mo->lc[i]->cmdsize, fp);
756 fileofs += mo->lc[i]->cmdsize;
759 for (sk = sk_unknown; sk < sk_last; sk++) {
760 struct segment_command_64 *seg;
761 if (!skinfo[sk].seg || !mo->sk_to_sect[sk].s)
762 continue;
763 seg = get_segment(mo, skinfo[sk].seg);
764 for (s = mo->sk_to_sect[sk].s; s; s = s->prev) {
765 if (s->sh_type != SHT_NOBITS) {
766 while (fileofs < s->sh_offset)
767 fputc(0, fp), fileofs++;
768 if (s->sh_size) {
769 fwrite(s->data, 1, s->sh_size, fp);
770 fileofs += s->sh_size;
777 ST_FUNC int macho_output_file(TCCState *s1, const char *filename)
779 int fd, mode, file_type;
780 FILE *fp;
781 int i, ret = -1;
782 struct macho mo = {};
784 file_type = s1->output_type;
785 if (file_type == TCC_OUTPUT_OBJ)
786 mode = 0666;
787 else
788 mode = 0777;
789 unlink(filename);
790 fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, mode);
791 if (fd < 0) {
792 tcc_error_noabort("could not write '%s: %s'", filename, strerror(errno));
793 return -1;
795 fp = fdopen(fd, "wb");
796 if (s1->verbose)
797 printf("<- %s\n", filename);
799 tcc_add_runtime(s1);
800 resolve_common_syms(s1);
801 create_symtab(s1, &mo);
802 check_relocs(s1, &mo);
803 ret = check_symbols(s1, &mo);
804 if (!ret) {
805 int i;
806 Section *s;
807 collect_sections(s1, &mo);
808 relocate_syms(s1, s1->symtab, 0);
809 mo.ep->entryoff = get_sym_addr(s1, "_main", 1, 0)
810 - get_segment(&mo, 1)->vmaddr;
811 if (s1->nb_errors)
812 goto do_ret;
814 for(i = 1; i < s1->nb_sections; i++) {
815 s = s1->sections[i];
816 if (s->reloc)
817 relocate_section(s1, s);
819 convert_symbols(s1, &mo);
821 macho_write(s1, &mo, fp);
823 ret = 0;
825 do_ret:
826 for (i = 0; i < mo.nlc; i++)
827 tcc_free(mo.lc[i]);
828 tcc_free(mo.lc);
829 tcc_free(mo.elfsectomacho);
830 tcc_free(mo.e2msym);
832 fclose(fp);
833 return ret;
836 static uint32_t swap32(uint32_t x)
838 return (x >> 24) | (x << 24) | ((x >> 8) & 0xff00) | ((x & 0xff00) << 8);
840 #define SWAP(x) (swap ? swap32(x) : (x))
842 ST_FUNC int macho_load_dll(TCCState *s1, int fd, const char *filename, int lev)
844 unsigned char buf[sizeof(struct mach_header_64)];
845 void *buf2;
846 uint32_t machofs = 0;
847 struct fat_header fh;
848 struct mach_header mh;
849 struct load_command *lc;
850 int i, swap = 0;
851 const char *soname = filename;
852 struct nlist_64 *symtab = 0;
853 uint32_t nsyms = 0;
854 char *strtab = 0;
855 uint32_t strsize = 0;
856 uint32_t iextdef = 0;
857 uint32_t nextdef = 0;
858 DLLReference *dllref;
860 again:
861 if (full_read(fd, buf, sizeof(buf)) != sizeof(buf))
862 return -1;
863 memcpy(&fh, buf, sizeof(fh));
864 if (fh.magic == FAT_MAGIC || fh.magic == FAT_CIGAM) {
865 struct fat_arch *fa = load_data(fd, sizeof(fh),
866 fh.nfat_arch * sizeof(*fa));
867 swap = fh.magic == FAT_CIGAM;
868 for (i = 0; i < SWAP(fh.nfat_arch); i++)
869 if (SWAP(fa[i].cputype) == 0x01000007 /* CPU_TYPE_X86_64 */
870 && SWAP(fa[i].cpusubtype) == 3) /* CPU_SUBTYPE_X86_ALL */
871 break;
872 if (i == SWAP(fh.nfat_arch)) {
873 tcc_free(fa);
874 return -1;
876 machofs = SWAP(fa[i].offset);
877 tcc_free(fa);
878 lseek(fd, machofs, SEEK_SET);
879 goto again;
880 } else if (fh.magic == FAT_MAGIC_64 || fh.magic == FAT_CIGAM_64) {
881 tcc_warning("%s: Mach-O fat 64bit files of type 0x%x not handled",
882 filename, fh.magic);
883 return -1;
886 memcpy(&mh, buf, sizeof(mh));
887 if (mh.magic != MH_MAGIC_64)
888 return -1;
889 dprintf("found Mach-O at %d\n", machofs);
890 buf2 = load_data(fd, machofs + sizeof(struct mach_header_64), mh.sizeofcmds);
891 for (i = 0, lc = buf2; i < mh.ncmds; i++) {
892 dprintf("lc %2d: 0x%08x\n", i, lc->cmd);
893 switch (lc->cmd) {
894 case LC_SYMTAB:
896 struct symtab_command *sc = (struct symtab_command*)lc;
897 nsyms = sc->nsyms;
898 symtab = load_data(fd, machofs + sc->symoff, nsyms * sizeof(*symtab));
899 strsize = sc->strsize;
900 strtab = load_data(fd, machofs + sc->stroff, strsize);
901 break;
903 case LC_ID_DYLIB:
905 struct dylib_command *dc = (struct dylib_command*)lc;
906 soname = (char*)lc + dc->name;
907 dprintf(" ID_DYLIB %d 0x%x 0x%x %s\n",
908 dc->timestamp, dc->current_version,
909 dc->compatibility_version, soname);
910 break;
912 case LC_REEXPORT_DYLIB:
914 struct dylib_command *dc = (struct dylib_command*)lc;
915 char *name = (char*)lc + dc->name;
916 dprintf(" REEXPORT %s\n", name);
917 int subfd = open(name, O_RDONLY | O_BINARY);
918 if (subfd < 0)
919 tcc_warning("can't open %s (reexported from %s)", name, filename);
920 else {
921 /* Hopefully the REEXPORTs never form a cycle, we don't check
922 for that! */
923 macho_load_dll(s1, subfd, name, lev + 1);
924 close(subfd);
926 break;
928 case LC_DYSYMTAB:
930 struct dysymtab_command *dc = (struct dysymtab_command*)lc;
931 iextdef = dc->iextdefsym;
932 nextdef = dc->nextdefsym;
933 break;
936 lc = (struct load_command*) ((char*)lc + lc->cmdsize);
939 /* if the dll is already loaded, do not load it */
940 for(i = 0; i < s1->nb_loaded_dlls; i++) {
941 dllref = s1->loaded_dlls[i];
942 if (!strcmp(soname, dllref->name)) {
943 /* but update level if needed */
944 if (lev < dllref->level)
945 dllref->level = lev;
946 goto the_end;
949 dllref = tcc_mallocz(sizeof(DLLReference) + strlen(soname));
950 dllref->level = lev;
951 strcpy(dllref->name, soname);
952 dynarray_add(&s1->loaded_dlls, &s1->nb_loaded_dlls, dllref);
954 if (!nsyms || !nextdef)
955 tcc_warning("%s doesn't export any symbols?", filename);
957 //dprintf("symbols (all):\n");
958 dprintf("symbols (exported):\n");
959 dprintf(" n: typ sec desc value name\n");
960 //for (i = 0; i < nsyms; i++) {
961 for (i = iextdef; i < iextdef + nextdef; i++) {
962 struct nlist_64 *sym = symtab + i;
963 dprintf("%5d: %3d %3d 0x%04x 0x%016llx %s\n",
964 i, sym->n_type, sym->n_sect, sym->n_desc, sym->n_value,
965 strtab + sym->n_strx);
966 set_elf_sym(s1->dynsymtab_section, 0, 0,
967 ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE),
968 0, SHN_UNDEF, strtab + sym->n_strx);
971 the_end:
972 tcc_free(strtab);
973 tcc_free(symtab);
974 tcc_free(buf2);
975 return 0;