macos: Fix GOT access to local defined symbols
[tinycc.git] / tccmacho.c
blob04c8780b3723b5aba4090879b130512b65d4ba69
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 struct mach_header {
21 uint32_t magic; /* mach magic number identifier */
22 int cputype; /* cpu specifier */
23 int cpusubtype; /* machine specifier */
24 uint32_t filetype; /* type of file */
25 uint32_t ncmds; /* number of load commands */
26 uint32_t sizeofcmds; /* the size of all the load commands */
27 uint32_t flags; /* flags */
30 struct mach_header_64 {
31 struct mach_header mh;
32 uint32_t reserved; /* reserved, pad to 64bit */
35 /* Constant for the magic field of the mach_header (32-bit architectures) */
36 #define MH_MAGIC 0xfeedface /* the mach magic number */
37 #define MH_CIGAM 0xcefaedfe /* NXSwapInt(MH_MAGIC) */
38 #define MH_MAGIC_64 0xfeedfacf /* the 64-bit mach magic number */
39 #define MH_CIGAM_64 0xcffaedfe /* NXSwapInt(MH_MAGIC_64) */
41 struct load_command {
42 uint32_t cmd; /* type of load command */
43 uint32_t cmdsize; /* total size of command in bytes */
46 typedef int vm_prot_t;
48 struct segment_command { /* for 32-bit architectures */
49 uint32_t cmd; /* LC_SEGMENT */
50 uint32_t cmdsize; /* includes sizeof section structs */
51 char segname[16]; /* segment name */
52 uint32_t vmaddr; /* memory address of this segment */
53 uint32_t vmsize; /* memory size of this segment */
54 uint32_t fileoff; /* file offset of this segment */
55 uint32_t filesize; /* amount to map from the file */
56 vm_prot_t maxprot; /* maximum VM protection */
57 vm_prot_t initprot; /* initial VM protection */
58 uint32_t nsects; /* number of sections in segment */
59 uint32_t flags; /* flags */
62 struct segment_command_64 { /* for 64-bit architectures */
63 uint32_t cmd; /* LC_SEGMENT_64 */
64 uint32_t cmdsize; /* includes sizeof section_64 structs */
65 char segname[16]; /* segment name */
66 uint64_t vmaddr; /* memory address of this segment */
67 uint64_t vmsize; /* memory size of this segment */
68 uint64_t fileoff; /* file offset of this segment */
69 uint64_t filesize; /* amount to map from the file */
70 vm_prot_t maxprot; /* maximum VM protection */
71 vm_prot_t initprot; /* initial VM protection */
72 uint32_t nsects; /* number of sections in segment */
73 uint32_t flags; /* flags */
76 struct section { /* for 32-bit architectures */
77 char sectname[16]; /* name of this section */
78 char segname[16]; /* segment this section goes in */
79 uint32_t addr; /* memory address of this section */
80 uint32_t size; /* size in bytes of this section */
81 uint32_t offset; /* file offset of this section */
82 uint32_t align; /* section alignment (power of 2) */
83 uint32_t reloff; /* file offset of relocation entries */
84 uint32_t nreloc; /* number of relocation entries */
85 uint32_t flags; /* flags (section type and attributes)*/
86 uint32_t reserved1; /* reserved (for offset or index) */
87 uint32_t reserved2; /* reserved (for count or sizeof) */
90 struct section_64 { /* for 64-bit architectures */
91 char sectname[16]; /* name of this section */
92 char segname[16]; /* segment this section goes in */
93 uint64_t addr; /* memory address of this section */
94 uint64_t size; /* size in bytes of this section */
95 uint32_t offset; /* file offset of this section */
96 uint32_t align; /* section alignment (power of 2) */
97 uint32_t reloff; /* file offset of relocation entries */
98 uint32_t nreloc; /* number of relocation entries */
99 uint32_t flags; /* flags (section type and attributes)*/
100 uint32_t reserved1; /* reserved (for offset or index) */
101 uint32_t reserved2; /* reserved (for count or sizeof) */
102 uint32_t reserved3; /* reserved */
105 typedef uint32_t lc_str;
107 struct dylib_command {
108 uint32_t cmd; /* LC_ID_DYLIB, LC_LOAD_{,WEAK_}DYLIB,
109 LC_REEXPORT_DYLIB */
110 uint32_t cmdsize; /* includes pathname string */
111 lc_str name; /* library's path name */
112 uint32_t timestamp; /* library's build time stamp */
113 uint32_t current_version; /* library's current version number */
114 uint32_t compatibility_version; /* library's compatibility vers number*/
117 struct dylinker_command {
118 uint32_t cmd; /* LC_ID_DYLINKER, LC_LOAD_DYLINKER or
119 LC_DYLD_ENVIRONMENT */
120 uint32_t cmdsize; /* includes pathname string */
121 lc_str name; /* dynamic linker's path name */
124 struct symtab_command {
125 uint32_t cmd; /* LC_SYMTAB */
126 uint32_t cmdsize; /* sizeof(struct symtab_command) */
127 uint32_t symoff; /* symbol table offset */
128 uint32_t nsyms; /* number of symbol table entries */
129 uint32_t stroff; /* string table offset */
130 uint32_t strsize; /* string table size in bytes */
133 struct dysymtab_command {
134 uint32_t cmd; /* LC_DYSYMTAB */
135 uint32_t cmdsize; /* sizeof(struct dysymtab_command) */
137 uint32_t ilocalsym; /* index to local symbols */
138 uint32_t nlocalsym; /* number of local symbols */
140 uint32_t iextdefsym;/* index to externally defined symbols */
141 uint32_t nextdefsym;/* number of externally defined symbols */
143 uint32_t iundefsym; /* index to undefined symbols */
144 uint32_t nundefsym; /* number of undefined symbols */
146 uint32_t tocoff; /* file offset to table of contents */
147 uint32_t ntoc; /* number of entries in table of contents */
149 uint32_t modtaboff; /* file offset to module table */
150 uint32_t nmodtab; /* number of module table entries */
152 uint32_t extrefsymoff; /* offset to referenced symbol table */
153 uint32_t nextrefsyms; /* number of referenced symbol table entries */
155 uint32_t indirectsymoff; /* file offset to the indirect symbol table */
156 uint32_t nindirectsyms; /* number of indirect symbol table entries */
158 uint32_t extreloff; /* offset to external relocation entries */
159 uint32_t nextrel; /* number of external relocation entries */
160 uint32_t locreloff; /* offset to local relocation entries */
161 uint32_t nlocrel; /* number of local relocation entries */
165 struct linkedit_data_command {
166 uint32_t cmd; /* LC_CODE_SIGNATURE, LC_SEGMENT_SPLIT_INFO,
167 LC_FUNCTION_STARTS, LC_DATA_IN_CODE,
168 LC_DYLIB_CODE_SIGN_DRS or
169 LC_LINKER_OPTIMIZATION_HINT. */
170 uint32_t cmdsize; /* sizeof(struct linkedit_data_command) */
171 uint32_t dataoff; /* file offset of data in __LINKEDIT segment */
172 uint32_t datasize; /* file size of data in __LINKEDIT segment */
175 struct entry_point_command {
176 uint32_t cmd; /* LC_MAIN only used in MH_EXECUTE filetypes */
177 uint32_t cmdsize; /* 24 */
178 uint64_t entryoff; /* file (__TEXT) offset of main() */
179 uint64_t stacksize;/* if not zero, initial stack size */
182 enum skind {
183 sk_unknown = 0,
184 sk_discard,
185 sk_text,
186 sk_stubs,
187 sk_ro_data,
188 sk_uw_info,
189 sk_nl_ptr, // non-lazy pointers, aka GOT
190 sk_la_ptr, // lazy pointers
191 sk_rw_data,
192 sk_bss,
193 sk_linkedit,
194 sk_last
197 struct nlist_64 {
198 uint32_t n_strx; /* index into the string table */
199 uint8_t n_type; /* type flag, see below */
200 uint8_t n_sect; /* section number or NO_SECT */
201 uint16_t n_desc; /* see <mach-o/stab.h> */
202 uint64_t n_value; /* value of this symbol (or stab offset) */
205 struct macho {
206 struct mach_header_64 mh;
207 struct segment_command_64 *seg[4];
208 int nseg;
209 struct load_command **lc;
210 int nlc;
211 struct entry_point_command ep;
212 struct {
213 Section *s;
214 int machosect;
215 } sk_to_sect[sk_last];
216 int *elfsectomacho;
217 int *e2msym;
218 Section *linkedit, *symtab, *strtab, *wdata, *indirsyms;
219 uint32_t ilocal, iextdef, iundef;
222 #define SHT_LINKEDIT (SHT_LOOS + 42)
224 #define LC_REQ_DYLD 0x80000000
225 #define LC_SYMTAB 0x2
226 #define LC_DYSYMTAB 0xb
227 #define LC_LOAD_DYLIB 0xc
228 #define LC_LOAD_DYLINKER 0xe
229 #define LC_MAIN (0x28|LC_REQ_DYLD)
231 /* Hack for now, 46_grep.c needs fopen, but due to aliasing games
232 in darwin headers it's searching for _fopen also via dlsym. */
233 FILE *_fopen(const char*, const char*);
234 FILE *_fopen(const char * filename, const char *mode)
236 return fopen(filename, mode);
239 static struct segment_command_64 * add_segment(struct macho *mo, char *name)
241 struct segment_command_64 *sc = tcc_mallocz(sizeof *sc);
242 strncpy(sc->segname, name, 16);
243 sc->cmd = 0x19; // LC_SEGMENT_64
244 sc->cmdsize = sizeof(*sc);
245 mo->seg[mo->nseg++] = sc;
246 return sc;
249 static int add_section(struct macho *mo, struct segment_command_64 **_seg, char *name)
251 struct segment_command_64 *seg = *_seg;
252 int ret = seg->nsects;
253 struct section_64 *sec;
254 seg->nsects++;
255 seg->cmdsize += sizeof(*sec);
256 seg = tcc_realloc(seg, sizeof(*seg) + seg->nsects * sizeof(*sec));
257 sec = (struct section_64*)((char*)seg + sizeof(*seg)) + ret;
258 memset(sec, 0, sizeof(*sec));
259 strncpy(sec->sectname, name, 16);
260 strncpy(sec->segname, seg->segname, 16);
261 *_seg = seg;
262 return ret;
265 static struct section_64 *get_section(struct segment_command_64 *seg, int i)
267 struct section_64 *sec;
268 sec = (struct section_64*)((char*)seg + sizeof(*seg)) + i;
269 return sec;
272 static void * add_lc(struct macho *mo, void *lc)
274 mo->lc = tcc_realloc(mo->lc, sizeof(mo->lc[0]) * (mo->nlc + 1));
275 mo->lc[mo->nlc++] = lc;
276 return lc;
279 static void * add_dylib(struct macho *mo, char *name)
281 struct dylib_command *lc;
282 int sz = (sizeof(*lc) + strlen(name) + 1 + 7) & -8;
283 lc = tcc_mallocz(sz);
284 lc->cmd = LC_LOAD_DYLIB;
285 lc->cmdsize = sz;
286 lc->name = sizeof(*lc);
287 strcpy((char*)lc + lc->name, name);
288 lc->timestamp = 2;
289 lc->current_version = 1 << 16;
290 lc->compatibility_version = 1 << 16;
291 return add_lc(mo, lc);
294 static void check_relocs(TCCState *s1, struct macho *mo)
296 Section *s;
297 ElfW_Rel *rel;
298 ElfW(Sym) *sym;
299 int i, type, gotplt_entry, sym_index;
300 struct sym_attr *attr;
302 s1->got = new_section(s1, ".got", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE);
303 mo->indirsyms = new_section(s1, "LEINDIR", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE);
304 for (i = 1; i < s1->nb_sections; i++) {
305 s = s1->sections[i];
306 if (s->sh_type != SHT_RELX)
307 continue;
308 for_each_elem(s, 0, rel, ElfW_Rel) {
309 type = ELFW(R_TYPE)(rel->r_info);
310 gotplt_entry = gotplt_entry_type(type);
311 /* We generate a non-lazy pointer for used undefined symbols
312 and for defined symbols that must have a place for their
313 address due to codegen (i.e. a reloc requiring a got slot). */
314 sym_index = ELFW(R_SYM)(rel->r_info);
315 sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
316 if (sym->st_shndx == SHN_UNDEF
317 || gotplt_entry == ALWAYS_GOTPLT_ENTRY) {
318 attr = get_sym_attr(s1, sym_index, 1);
319 if (!attr->plt_offset) {
320 uint32_t *pi = section_ptr_add(mo->indirsyms, sizeof(*pi));
321 attr->got_offset = s1->got->data_offset;
322 attr->plt_offset = 1; /* used as flag */
323 section_ptr_add(s1->got, PTR_SIZE);
324 if (ELFW(ST_BIND)(sym->st_info) == STB_LOCAL) {
325 if (sym->st_shndx == SHN_UNDEF)
326 tcc_error("undefined local symbol???");
327 *pi = 0x80000000; /* INDIRECT_SYMBOL_LOCAL */
328 /* The pointer slot we generated must point to the
329 symbol, whose address is only known after layout,
330 so register a simply relocation for that. */
331 put_elf_reloc (s1->symtab, s1->got, attr->got_offset,
332 R_DATA_PTR, sym_index);
333 } else
334 *pi = mo->e2msym[sym_index];
341 static int check_symbols(TCCState *s1, struct macho *mo)
343 int sym_index, sym_end;
344 int ret = 0;
346 mo->ilocal = mo->iextdef = mo->iundef = -1;
347 sym_end = symtab_section->data_offset / sizeof(ElfW(Sym));
348 for (sym_index = 1; sym_index < sym_end; ++sym_index) {
349 int elf_index = ((struct nlist_64 *)mo->symtab->data + sym_index - 1)->n_value;
350 ElfW(Sym) *sym = (ElfW(Sym) *)symtab_section->data + elf_index;
351 const char *name = (char*)symtab_section->link->data + sym->st_name;
352 unsigned type = ELFW(ST_TYPE)(sym->st_info);
353 unsigned bind = ELFW(ST_BIND)(sym->st_info);
354 unsigned vis = ELFW(ST_VISIBILITY)(sym->st_other);
356 printf("%4d (%4d): %09llx %4d %4d %4d %3d %s\n",
357 sym_index, elf_index, sym->st_value,
358 type, bind, vis, sym->st_shndx, name);
359 if (bind == STB_LOCAL) {
360 if (mo->ilocal == -1)
361 mo->ilocal = sym_index - 1;
362 if (mo->iextdef != -1 || mo->iundef != -1)
363 tcc_error("local syms after global ones");
364 } else if (sym->st_shndx != SHN_UNDEF) {
365 if (mo->iextdef == -1)
366 mo->iextdef = sym_index - 1;
367 if (mo->iundef != -1)
368 tcc_error("external defined symbol after undefined");
369 } else if (sym->st_shndx == SHN_UNDEF) {
370 if (mo->iundef == -1)
371 mo->iundef = sym_index - 1;
372 if (ELFW(ST_BIND)(sym->st_info) == STB_WEAK)
373 continue;
374 if (get_sym_attr(s1, elf_index, 0))
375 continue;
376 tcc_error_noabort("undefined symbol '%s'", name);
377 ret = -1;
380 return ret;
383 static void convert_symbol(TCCState *s1, struct macho *mo, struct nlist_64 *pn)
385 struct nlist_64 n = *pn;
386 ElfSym *sym = (ElfW(Sym) *)symtab_section->data + pn->n_value;
387 const char *name = (char*)symtab_section->link->data + sym->st_name;
388 switch(ELFW(ST_TYPE)(sym->st_info)) {
389 case STT_NOTYPE:
390 case STT_OBJECT:
391 case STT_FUNC:
392 n.n_type = 0xe; /* default type is N_SECT */
393 break;
394 case STT_FILE:
395 n.n_type = 2; /* N_ABS */
396 break;
397 default:
398 tcc_error("unhandled ELF symbol type %d %s",
399 ELFW(ST_TYPE)(sym->st_info), name);
401 if (sym->st_shndx == SHN_UNDEF)
402 n.n_type = 0 /* N_UNDF */, n.n_sect = 0;
403 else if (sym->st_shndx == SHN_ABS)
404 n.n_type = 2 /* N_ABS */, n.n_sect = 0;
405 else if (sym->st_shndx >= SHN_LORESERVE)
406 tcc_error("unhandled ELF symbol section %d %s", sym->st_shndx, name);
407 else if (!mo->elfsectomacho[sym->st_shndx])
408 tcc_error("ELF section %d not mapped into Mach-O for symbol %s",
409 sym->st_shndx, name);
410 else
411 n.n_sect = mo->elfsectomacho[sym->st_shndx];
412 if (ELFW(ST_BIND)(sym->st_info) == STB_GLOBAL)
413 n.n_type |= 1; /* N_EXT */
414 else if (ELFW(ST_BIND)(sym->st_info) == STB_WEAK)
415 tcc_error("weak symbol %s unhandled", name);
416 n.n_strx = pn->n_strx;
417 n.n_value = sym->st_value;
418 *pn = n;
421 static void convert_symbols(TCCState *s1, struct macho *mo)
423 int sym_index, sym_end;
424 struct nlist_64 *pn = (struct nlist_64 *)mo->symtab->data;
426 sym_end = symtab_section->data_offset / sizeof(ElfW(Sym));
427 for (sym_index = 1; sym_index < sym_end; ++sym_index) {
428 convert_symbol(s1, mo, pn + sym_index - 1);
432 static int machosymcmp(const void *_a, const void *_b)
434 TCCState *s1 = tcc_state;
435 int ea = ((struct nlist_64 *)_a)->n_value;
436 int eb = ((struct nlist_64 *)_b)->n_value;
437 ElfSym *sa = (ElfSym *)symtab_section->data + ea;
438 ElfSym *sb = (ElfSym *)symtab_section->data + eb;
439 int r;
440 r = (ELFW(ST_BIND)(sb->st_info) == STB_LOCAL)
441 - (ELFW(ST_BIND)(sa->st_info) == STB_LOCAL);
442 if (r)
443 return r;
444 r = (sb->st_shndx == SHN_UNDEF) - (sa->st_shndx == SHN_UNDEF);
445 if (r)
446 return r;
447 if (ELFW(ST_BIND)(sa->st_info) != STB_LOCAL) {
448 const char * na = (char*)symtab_section->link->data + sa->st_name;
449 const char * nb = (char*)symtab_section->link->data + sb->st_name;
450 r = strcmp(na, nb);
451 if (r)
452 return r;
454 return ea - eb;
457 static void create_symtab(TCCState *s1, struct macho *mo)
459 int sym_index, sym_end;
460 struct nlist_64 *pn;
462 mo->symtab = new_section(s1, "LESYMTAB", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE);
463 mo->strtab = new_section(s1, "LESTRTAB", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE);
464 put_elf_str(mo->strtab, " "); /* Mach-O starts strtab with a space */
465 sym_end = symtab_section->data_offset / sizeof(ElfW(Sym));
466 pn = section_ptr_add(mo->symtab, sizeof(*pn) * (sym_end - 1));
467 for (sym_index = 1; sym_index < sym_end; ++sym_index) {
468 ElfW(Sym) *sym = (ElfW(Sym) *)symtab_section->data + sym_index;
469 const char *name = (char*)symtab_section->link->data + sym->st_name;
470 pn[sym_index - 1].n_strx = put_elf_str(mo->strtab, name);
471 pn[sym_index - 1].n_value = sym_index;
473 tcc_enter_state(s1); /* qsort needs global state */
474 qsort(pn, sym_end - 1, sizeof(*pn), machosymcmp);
475 tcc_exit_state();
476 mo->e2msym = tcc_malloc(sym_end * sizeof(*mo->e2msym));
477 mo->e2msym[0] = -1;
478 for (sym_index = 1; sym_index < sym_end; ++sym_index) {
479 mo->e2msym[pn[sym_index - 1].n_value] = sym_index - 1;
483 struct {
484 int seg;
485 uint32_t flags;
486 char *name;
487 } skinfo[sk_last] = {
488 [sk_text] = { 1, 0x80000400, "__text" },
489 [sk_ro_data] = { 1, 0, "__rodata" },
490 [sk_nl_ptr] = { 2, 6, "__got" }, /* S_NON_LAZY_SYMBOL_POINTERS */
491 [sk_rw_data] = { 2, 0, "__data" },
492 [sk_bss] = { 2, 1, "__bss" },
493 [sk_linkedit] = { 3, 0, NULL },
496 static void collect_sections(TCCState *s1, struct macho *mo)
498 int i, sk, numsec;
499 uint64_t curaddr, fileofs;
500 Section *s;
501 struct segment_command_64 *seg = NULL;
502 struct dylinker_command *dyldlc;
503 struct symtab_command *symlc;
504 struct dysymtab_command *dysymlc;
505 char *str;
506 //struct segment_command_64 *zc, *tc, *sc, *lc;
507 add_segment(mo, "__PAGEZERO");
508 add_segment(mo, "__TEXT");
509 add_segment(mo, "__DATA");
510 add_segment(mo, "__LINKEDIT");
511 mo->seg[0]->vmsize = (uint64_t)1 << 32;
512 mo->seg[1]->vmaddr = (uint64_t)1 << 32;
513 mo->seg[1]->maxprot = 7; // rwx
514 mo->seg[1]->initprot = 5; // r-x
515 mo->seg[2]->vmaddr = -1;
516 mo->seg[2]->maxprot = 7; // rwx
517 mo->seg[2]->initprot = 3; // rw-
518 mo->seg[3]->vmaddr = -1;
519 mo->seg[3]->maxprot = 7; // rwx
520 mo->seg[3]->initprot = 1; // r--
522 mo->ep.cmd = LC_MAIN;
523 mo->ep.cmdsize = sizeof(mo->ep);
524 mo->ep.entryoff = 4096; // XXX
525 mo->ep.stacksize = 0;
526 add_lc(mo, &mo->ep);
528 i = (sizeof(*dyldlc) + strlen("/usr/lib/dyld") + 1 + 7) &-8;
529 dyldlc = tcc_mallocz(i);
530 dyldlc->cmd = LC_LOAD_DYLINKER;
531 dyldlc->cmdsize = i;
532 dyldlc->name = sizeof(*dyldlc);
533 str = (char*)dyldlc + dyldlc->name;
534 strcpy(str, "/usr/lib/dyld");
535 add_lc(mo, dyldlc);
537 symlc = tcc_mallocz(sizeof(*symlc));
538 symlc->cmd = LC_SYMTAB;
539 symlc->cmdsize = sizeof(*symlc);
540 add_lc(mo, symlc);
542 dysymlc = tcc_mallocz(sizeof(*dysymlc));
543 dysymlc->cmd = LC_DYSYMTAB;
544 dysymlc->cmdsize = sizeof(*dysymlc);
545 add_lc(mo, dysymlc);
547 add_dylib(mo, "/usr/lib/libSystem.B.dylib");
549 mo->linkedit = new_section(s1, "LINKEDIT", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE);
550 /* LINKEDIT can't be empty (XXX remove once we have symbol table) */
551 section_ptr_add(mo->linkedit, 256);
553 /* dyld requires a writable segment, but ignores zero-sized segments
554 for this, so force to have some data. */
555 mo->wdata = new_section(s1, " wdata", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE);
556 section_ptr_add(mo->wdata, 64);
557 memset (mo->sk_to_sect, 0, sizeof(mo->sk_to_sect));
558 for (i = s1->nb_sections; i-- > 1;) {
559 int type, flags;
560 s = s1->sections[i];
561 type = s->sh_type;
562 flags = s->sh_flags;
563 sk = sk_unknown;
564 if (flags & SHF_ALLOC) {
565 switch (type) {
566 default: sk = sk_unknown; break;
567 case SHT_NOBITS: sk = sk_bss; break;
568 case SHT_SYMTAB: sk = sk_discard; break;
569 case SHT_STRTAB: sk = sk_discard; break;
570 case SHT_RELX: sk = sk_discard; break;
571 case SHT_LINKEDIT: sk = sk_linkedit; break;
572 case SHT_PROGBITS:
573 if (s == s1->got)
574 sk = sk_nl_ptr;
575 else if (flags & SHF_EXECINSTR)
576 sk = sk_text;
577 else if (flags & SHF_WRITE)
578 sk = sk_rw_data;
579 else
580 sk = sk_ro_data;
581 break;
583 } else
584 sk = sk_discard;
585 s->prev = mo->sk_to_sect[sk].s;
586 mo->sk_to_sect[sk].s = s;
588 fileofs = 4096; /* leave space for mach-o headers */
589 curaddr = mo->seg[1]->vmaddr;
590 curaddr += 4096;
591 seg = NULL;
592 numsec = 0;
593 mo->elfsectomacho = tcc_mallocz(sizeof(*mo->elfsectomacho) * s1->nb_sections);
594 for (sk = sk_unknown; sk < sk_last; sk++) {
595 struct section_64 *sec = NULL;
596 if (seg) {
597 seg->vmsize = curaddr - seg->vmaddr;
598 seg->filesize = fileofs - seg->fileoff;
600 if (skinfo[sk].seg && mo->sk_to_sect[sk].s) {
601 uint64_t al = 0;
602 int si;
603 seg = mo->seg[skinfo[sk].seg];
604 if (skinfo[sk].name) {
605 si = add_section(mo, &seg, skinfo[sk].name);
606 numsec++;
607 mo->seg[skinfo[sk].seg] = seg;
608 mo->sk_to_sect[sk].machosect = si;
609 sec = get_section(seg, si);
610 sec->flags = skinfo[sk].flags;
612 if (seg->vmaddr == -1) {
613 curaddr = (curaddr + 4095) & -4096;
614 seg->vmaddr = curaddr;
615 fileofs = (fileofs + 4095) & -4096;
616 seg->fileoff = fileofs;
619 for (s = mo->sk_to_sect[sk].s; s; s = s->prev) {
620 int a = exact_log2p1(s->sh_addralign);
621 if (a && al < (a - 1))
622 al = a - 1;
623 s->sh_size = s->data_offset;
625 if (sec)
626 sec->align = al;
627 al = 1U << al;
628 if (al > 4096)
629 tcc_warning("alignment > 4096"), sec->align = 12, al = 4096;
630 curaddr = (curaddr + al - 1) & -al;
631 fileofs = (fileofs + al - 1) & -al;
632 if (sec) {
633 sec->addr = curaddr;
634 sec->offset = fileofs;
636 for (s = mo->sk_to_sect[sk].s; s; s = s->prev) {
637 al = s->sh_addralign;
638 curaddr = (curaddr + al - 1) & -al;
639 tcc_warning("curaddr now 0x%llx", curaddr);
640 s->sh_addr = curaddr;
641 curaddr += s->sh_size;
642 if (s->sh_type != SHT_NOBITS) {
643 fileofs = (fileofs + al - 1) & -al;
644 s->sh_offset = fileofs;
645 fileofs += s->sh_size;
646 tcc_warning("fileofs now %lld", fileofs);
648 if (sec)
649 mo->elfsectomacho[s->sh_num] = numsec;
651 if (sec)
652 sec->size = curaddr - sec->addr;
654 for (s = mo->sk_to_sect[sk].s; s; s = s->prev) {
655 int type = s->sh_type;
656 int flags = s->sh_flags;
657 printf("%d section %-16s %-10s %09llx %04x %02d %s,%s,%s\n",
659 s->name,
660 type == SHT_PROGBITS ? "progbits" :
661 type == SHT_NOBITS ? "nobits" :
662 type == SHT_SYMTAB ? "symtab" :
663 type == SHT_STRTAB ? "strtab" :
664 type == SHT_RELX ? "rel" : "???",
665 s->sh_addr,
666 (unsigned)s->data_offset,
667 s->sh_addralign,
668 flags & SHF_ALLOC ? "alloc" : "",
669 flags & SHF_WRITE ? "write" : "",
670 flags & SHF_EXECINSTR ? "exec" : ""
674 if (seg) {
675 seg->vmsize = curaddr - seg->vmaddr;
676 seg->filesize = fileofs - seg->fileoff;
679 /* Fill symtab info */
680 symlc->symoff = mo->symtab->sh_offset;
681 symlc->nsyms = mo->symtab->data_offset / sizeof(struct nlist_64);
682 symlc->stroff = mo->strtab->sh_offset;
683 symlc->strsize = mo->strtab->data_offset;
685 dysymlc->iundefsym = mo->iundef == -1 ? symlc->nsyms : mo->iundef;
686 dysymlc->iextdefsym = mo->iextdef == -1 ? dysymlc->iundefsym : mo->iextdef;
687 dysymlc->ilocalsym = mo->ilocal == -1 ? dysymlc->iextdefsym : mo->ilocal;
688 dysymlc->nlocalsym = dysymlc->iextdefsym - dysymlc->ilocalsym;
689 dysymlc->nextdefsym = dysymlc->iundefsym - dysymlc->iextdefsym;
690 dysymlc->nundefsym = symlc->nsyms - dysymlc->iundefsym;
691 dysymlc->indirectsymoff = mo->indirsyms->sh_offset;
692 dysymlc->nindirectsyms = mo->indirsyms->data_offset / sizeof(uint32_t);
695 static void macho_write(TCCState *s1, struct macho *mo, FILE *fp)
697 int i, sk;
698 uint64_t fileofs = 0;
699 Section *s;
700 mo->mh.mh.magic = MH_MAGIC_64;
701 mo->mh.mh.cputype = 0x1000007; // x86_64
702 mo->mh.mh.cpusubtype = 0x80000003;// all | CPU_SUBTYPE_LIB64
703 mo->mh.mh.filetype = 2; // MH_EXECUTE
704 mo->mh.mh.flags = 4; // DYLDLINK
705 mo->mh.mh.ncmds = mo->nseg + mo->nlc;
706 mo->mh.mh.sizeofcmds = 0;
707 for (i = 0; i < mo->nseg; i++)
708 mo->mh.mh.sizeofcmds += mo->seg[i]->cmdsize;
709 for (i = 0; i < mo->nlc; i++)
710 mo->mh.mh.sizeofcmds += mo->lc[i]->cmdsize;
712 fwrite(&mo->mh, 1, sizeof(mo->mh), fp);
713 fileofs += sizeof(mo->mh);
714 for (i = 0; i < mo->nseg; i++) {
715 fwrite(mo->seg[i], 1, mo->seg[i]->cmdsize, fp);
716 fileofs += mo->seg[i]->cmdsize;
718 for (i = 0; i < mo->nlc; i++) {
719 fwrite(mo->lc[i], 1, mo->lc[i]->cmdsize, fp);
720 fileofs += mo->lc[i]->cmdsize;
723 for (sk = sk_unknown; sk < sk_last; sk++) {
724 struct segment_command_64 *seg;
725 //struct section_64 *sec;
726 if (!skinfo[sk].seg || !mo->sk_to_sect[sk].s)
727 continue;
728 seg = mo->seg[skinfo[sk].seg];
729 /*sec = get_section(seg, mo->sk_to_sect[sk].machosect);
730 while (fileofs < sec->offset)
731 fputc(0, fp), fileofs++;*/
732 for (s = mo->sk_to_sect[sk].s; s; s = s->prev) {
733 if (s->sh_type != SHT_NOBITS) {
734 while (fileofs < s->sh_offset)
735 fputc(0, fp), fileofs++;
736 if (s->sh_size) {
737 fwrite(s->data, 1, s->sh_size, fp);
738 fileofs += s->sh_size;
745 ST_FUNC int macho_output_file(TCCState *s1, const char *filename)
747 int fd, mode, file_type;
748 FILE *fp;
749 int ret = -1;
750 struct macho mo = {0,};
752 file_type = s1->output_type;
753 if (file_type == TCC_OUTPUT_OBJ)
754 mode = 0666;
755 else
756 mode = 0777;
757 unlink(filename);
758 fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, mode);
759 if (fd < 0) {
760 tcc_error_noabort("could not write '%s: %s'", filename, strerror(errno));
761 return -1;
763 fp = fdopen(fd, "wb");
764 if (s1->verbose)
765 printf("<- %s\n", filename);
767 resolve_common_syms(s1);
768 create_symtab(s1, &mo);
769 check_relocs(s1, &mo);
770 ret = check_symbols(s1, &mo);
771 if (!ret) {
772 int i;
773 Section *s;
774 collect_sections(s1, &mo);
775 relocate_syms(s1, s1->symtab, 0);
776 if (s1->nb_errors)
777 goto do_ret;
779 for(i = 1; i < s1->nb_sections; i++) {
780 s = s1->sections[i];
781 if (s->reloc)
782 relocate_section(s1, s);
784 convert_symbols(s1, &mo);
786 macho_write(s1, &mo, fp);
788 ret = 0;
790 do_ret:
791 fclose(fp);
792 return ret;