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
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) */
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,
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 */
189 sk_nl_ptr
, // non-lazy pointers, aka GOT
190 sk_la_ptr
, // lazy pointers
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) */
206 struct mach_header_64 mh
;
207 struct segment_command_64
*seg
[4];
209 struct load_command
**lc
;
211 struct entry_point_command ep
;
215 } sk_to_sect
[sk_last
];
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
;
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
;
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);
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
;
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
;
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
;
286 lc
->name
= sizeof(*lc
);
287 strcpy((char*)lc
+ lc
->name
, name
);
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
)
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
++) {
306 if (s
->sh_type
!= SHT_RELX
)
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
);
334 *pi
= mo
->e2msym
[sym_index
];
341 static int check_symbols(TCCState
*s1
, struct macho
*mo
)
343 int sym_index
, sym_end
;
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
)
374 if (get_sym_attr(s1
, elf_index
, 0))
376 tcc_error_noabort("undefined symbol '%s'", name
);
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
)) {
392 n
.n_type
= 0xe; /* default type is N_SECT */
395 n
.n_type
= 2; /* N_ABS */
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
);
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
;
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
;
440 r
= (ELFW(ST_BIND
)(sb
->st_info
) == STB_LOCAL
)
441 - (ELFW(ST_BIND
)(sa
->st_info
) == STB_LOCAL
);
444 r
= (sb
->st_shndx
== SHN_UNDEF
) - (sa
->st_shndx
== SHN_UNDEF
);
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
;
457 static void create_symtab(TCCState
*s1
, struct macho
*mo
)
459 int sym_index
, sym_end
;
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
);
476 mo
->e2msym
= tcc_malloc(sym_end
* sizeof(*mo
->e2msym
));
478 for (sym_index
= 1; sym_index
< sym_end
; ++sym_index
) {
479 mo
->e2msym
[pn
[sym_index
- 1].n_value
] = sym_index
- 1;
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
)
499 uint64_t curaddr
, fileofs
;
501 struct segment_command_64
*seg
= NULL
;
502 struct dylinker_command
*dyldlc
;
503 struct symtab_command
*symlc
;
504 struct dysymtab_command
*dysymlc
;
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;
528 i
= (sizeof(*dyldlc
) + strlen("/usr/lib/dyld") + 1 + 7) &-8;
529 dyldlc
= tcc_mallocz(i
);
530 dyldlc
->cmd
= LC_LOAD_DYLINKER
;
532 dyldlc
->name
= sizeof(*dyldlc
);
533 str
= (char*)dyldlc
+ dyldlc
->name
;
534 strcpy(str
, "/usr/lib/dyld");
537 symlc
= tcc_mallocz(sizeof(*symlc
));
538 symlc
->cmd
= LC_SYMTAB
;
539 symlc
->cmdsize
= sizeof(*symlc
);
542 dysymlc
= tcc_mallocz(sizeof(*dysymlc
));
543 dysymlc
->cmd
= LC_DYSYMTAB
;
544 dysymlc
->cmdsize
= sizeof(*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;) {
564 if (flags
& SHF_ALLOC
) {
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;
575 else if (flags
& SHF_EXECINSTR
)
577 else if (flags
& SHF_WRITE
)
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
;
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
;
597 seg
->vmsize
= curaddr
- seg
->vmaddr
;
598 seg
->filesize
= fileofs
- seg
->fileoff
;
600 if (skinfo
[sk
].seg
&& mo
->sk_to_sect
[sk
].s
) {
603 seg
= mo
->seg
[skinfo
[sk
].seg
];
604 if (skinfo
[sk
].name
) {
605 si
= add_section(mo
, &seg
, skinfo
[sk
].name
);
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))
623 s
->sh_size
= s
->data_offset
;
629 tcc_warning("alignment > 4096"), sec
->align
= 12, al
= 4096;
630 curaddr
= (curaddr
+ al
- 1) & -al
;
631 fileofs
= (fileofs
+ al
- 1) & -al
;
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
);
649 mo
->elfsectomacho
[s
->sh_num
] = numsec
;
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",
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" : "???",
666 (unsigned)s
->data_offset
,
668 flags
& SHF_ALLOC
? "alloc" : "",
669 flags
& SHF_WRITE
? "write" : "",
670 flags
& SHF_EXECINSTR
? "exec" : ""
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
)
698 uint64_t fileofs
= 0;
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
)
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
++;
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
;
750 struct macho mo
= {0,};
752 file_type
= s1
->output_type
;
753 if (file_type
== TCC_OUTPUT_OBJ
)
758 fd
= open(filename
, O_WRONLY
| O_CREAT
| O_TRUNC
| O_BINARY
, mode
);
760 tcc_error_noabort("could not write '%s: %s'", filename
, strerror(errno
));
763 fp
= fdopen(fd
, "wb");
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
);
774 collect_sections(s1
, &mo
);
775 relocate_syms(s1
, s1
->symtab
, 0);
779 for(i
= 1; i
< s1
->nb_sections
; i
++) {
782 relocate_section(s1
, s
);
784 convert_symbols(s1
, &mo
);
786 macho_write(s1
, &mo
, fp
);