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
];
217 Section
*linkedit
, *symtab
, *strtab
, *wdata
;
220 #define SHT_LINKEDIT (SHT_LOOS + 42)
222 #define LC_REQ_DYLD 0x80000000
223 #define LC_SYMTAB 0x2
224 #define LC_DYSYMTAB 0xb
225 #define LC_LOAD_DYLIB 0xc
226 #define LC_LOAD_DYLINKER 0xe
227 #define LC_MAIN (0x28|LC_REQ_DYLD)
229 /* Hack for now, 46_grep.c needs fopen, but due to aliasing games
230 in darwin headers it's searching for _fopen also via dlsym. */
231 FILE *_fopen(const char*, const char*);
232 FILE *_fopen(const char * filename
, const char *mode
)
234 return fopen(filename
, mode
);
237 static struct segment_command_64
* add_segment(struct macho
*mo
, char *name
)
239 struct segment_command_64
*sc
= tcc_mallocz(sizeof *sc
);
240 strncpy(sc
->segname
, name
, 16);
241 sc
->cmd
= 0x19; // LC_SEGMENT_64
242 sc
->cmdsize
= sizeof(*sc
);
243 mo
->seg
[mo
->nseg
++] = sc
;
247 static int add_section(struct macho
*mo
, struct segment_command_64
**_seg
, char *name
)
249 struct segment_command_64
*seg
= *_seg
;
250 int ret
= seg
->nsects
;
251 struct section_64
*sec
;
253 seg
->cmdsize
+= sizeof(*sec
);
254 seg
= tcc_realloc(seg
, sizeof(*seg
) + seg
->nsects
* sizeof(*sec
));
255 sec
= (struct section_64
*)((char*)seg
+ sizeof(*seg
)) + ret
;
256 memset(sec
, 0, sizeof(*sec
));
257 strncpy(sec
->sectname
, name
, 16);
258 strncpy(sec
->segname
, seg
->segname
, 16);
263 static struct section_64
*get_section(struct segment_command_64
*seg
, int i
)
265 struct section_64
*sec
;
266 sec
= (struct section_64
*)((char*)seg
+ sizeof(*seg
)) + i
;
270 static void * add_lc(struct macho
*mo
, void *lc
)
272 mo
->lc
= tcc_realloc(mo
->lc
, sizeof(mo
->lc
[0]) * (mo
->nlc
+ 1));
273 mo
->lc
[mo
->nlc
++] = lc
;
277 static void * add_dylib(struct macho
*mo
, char *name
)
279 struct dylib_command
*lc
;
280 int sz
= (sizeof(*lc
) + strlen(name
) + 1 + 7) & -8;
281 lc
= tcc_mallocz(sz
);
282 lc
->cmd
= LC_LOAD_DYLIB
;
284 lc
->name
= sizeof(*lc
);
285 strcpy((char*)lc
+ lc
->name
, name
);
287 lc
->current_version
= 1 << 16;
288 lc
->compatibility_version
= 1 << 16;
289 return add_lc(mo
, lc
);
292 static int check_symbols(TCCState
*s1
)
294 int sym_index
, sym_end
;
297 sym_end
= symtab_section
->data_offset
/ sizeof(ElfW(Sym
));
298 for (sym_index
= 1; sym_index
< sym_end
; ++sym_index
) {
299 ElfW(Sym
) *sym
= (ElfW(Sym
) *)symtab_section
->data
+ sym_index
;
300 const char *name
= (char*)symtab_section
->link
->data
+ sym
->st_name
;
301 unsigned type
= ELFW(ST_TYPE
)(sym
->st_info
);
302 unsigned bind
= ELFW(ST_BIND
)(sym
->st_info
);
303 unsigned vis
= ELFW(ST_VISIBILITY
)(sym
->st_other
);
305 printf("%4d: %09llx %4d %4d %4d %3d %s\n",
306 sym_index
, sym
->st_value
,
307 type
, bind
, vis
, sym
->st_shndx
, name
);
308 if (sym
->st_shndx
== SHN_UNDEF
) {
309 if (ELFW(ST_BIND
)(sym
->st_info
) == STB_WEAK
)
311 tcc_error_noabort("undefined symbol '%s'", name
);
318 static void convert_symbol(TCCState
*s1
, struct macho
*mo
, struct nlist_64
*pn
, ElfSym
*sym
)
320 struct nlist_64 n
= *pn
;
321 const char *name
= (char*)symtab_section
->link
->data
+ sym
->st_name
;
322 if (sym
!= (ElfW(Sym
) *)symtab_section
->data
+ pn
->n_value
)
324 switch(ELFW(ST_TYPE
)(sym
->st_info
)) {
328 n
.n_type
= 0xe; /* default type is N_SECT */
331 n
.n_type
= 2; /* N_ABS */
334 tcc_error("unhandled ELF symbol type %d %s",
335 ELFW(ST_TYPE
)(sym
->st_info
), name
);
337 if (sym
->st_shndx
== SHN_UNDEF
)
338 n
.n_type
= 0 /* N_UNDF */, n
.n_sect
= 0;
339 else if (sym
->st_shndx
== SHN_ABS
)
340 n
.n_type
= 2 /* N_ABS */, n
.n_sect
= 0;
341 else if (sym
->st_shndx
>= SHN_LORESERVE
)
342 tcc_error("unhandled ELF symbol section %d %s", sym
->st_shndx
, name
);
343 else if (!mo
->elfsectomacho
[sym
->st_shndx
])
344 tcc_error("ELF section %d not mapped into Mach-O for symbol %s",
345 sym
->st_shndx
, name
);
347 n
.n_sect
= mo
->elfsectomacho
[sym
->st_shndx
];
348 if (ELFW(ST_BIND
)(sym
->st_info
) == STB_GLOBAL
)
349 n
.n_type
|= 1; /* N_EXT */
350 else if (ELFW(ST_BIND
)(sym
->st_info
) == STB_WEAK
)
351 tcc_error("weak symbol %s unhandled", name
);
352 n
.n_strx
= pn
->n_strx
;
353 n
.n_value
= sym
->st_value
;
357 static void convert_symbols(TCCState
*s1
, struct macho
*mo
)
359 int sym_index
, sym_end
;
360 struct nlist_64
*pn
= (struct nlist_64
*)mo
->symtab
->data
;
362 sym_end
= symtab_section
->data_offset
/ sizeof(ElfW(Sym
));
363 for (sym_index
= 1; sym_index
< sym_end
; ++sym_index
) {
364 ElfW(Sym
) *sym
= (ElfW(Sym
) *)symtab_section
->data
+ sym_index
;
365 convert_symbol(s1
, mo
, pn
+ sym_index
- 1, sym
);
369 static void create_symtab(TCCState
*s1
, struct macho
*mo
)
371 int sym_index
, sym_end
;
374 mo
->symtab
= new_section(s1
, "LESYMTAB", SHT_LINKEDIT
, SHF_ALLOC
| SHF_WRITE
);
375 mo
->strtab
= new_section(s1
, "LESTRTAB", SHT_LINKEDIT
, SHF_ALLOC
| SHF_WRITE
);
376 put_elf_str(mo
->strtab
, " "); /* Mach-O start strtab with a space */
377 sym_end
= symtab_section
->data_offset
/ sizeof(ElfW(Sym
));
378 pn
= section_ptr_add(mo
->symtab
, sizeof(*pn
) * (sym_end
- 1));
379 for (sym_index
= 1; sym_index
< sym_end
; ++sym_index
) {
380 ElfW(Sym
) *sym
= (ElfW(Sym
) *)symtab_section
->data
+ sym_index
;
381 const char *name
= (char*)symtab_section
->link
->data
+ sym
->st_name
;
382 pn
[sym_index
- 1].n_strx
= put_elf_str(mo
->strtab
, name
);
383 pn
[sym_index
- 1].n_value
= sym_index
;
391 } skinfo
[sk_last
] = {
392 [sk_text
] = { 1, 0x80000400, "__text" },
393 [sk_ro_data
] = { 1, 0, "__rodata" },
394 [sk_rw_data
] = { 2, 0, "__data" },
395 [sk_bss
] = { 2, 1, "__bss" },
396 [sk_linkedit
] = { 3, 0, NULL
},
399 static void collect_sections(TCCState
*s1
, struct macho
*mo
)
402 uint64_t curaddr
, fileofs
;
404 struct segment_command_64
*seg
= NULL
;
405 struct dylinker_command
*dyldlc
;
406 struct symtab_command
*symlc
;
407 struct dysymtab_command
*dysymlc
;
409 //struct segment_command_64 *zc, *tc, *sc, *lc;
410 add_segment(mo
, "__PAGEZERO");
411 add_segment(mo
, "__TEXT");
412 add_segment(mo
, "__DATA");
413 add_segment(mo
, "__LINKEDIT");
414 mo
->seg
[0]->vmsize
= (uint64_t)1 << 32;
415 mo
->seg
[1]->vmaddr
= (uint64_t)1 << 32;
416 mo
->seg
[1]->maxprot
= 7; // rwx
417 mo
->seg
[1]->initprot
= 5; // r-x
418 mo
->seg
[2]->vmaddr
= -1;
419 mo
->seg
[2]->maxprot
= 7; // rwx
420 mo
->seg
[2]->initprot
= 3; // rw-
421 mo
->seg
[3]->vmaddr
= -1;
422 mo
->seg
[3]->maxprot
= 7; // rwx
423 mo
->seg
[3]->initprot
= 1; // r--
425 mo
->ep
.cmd
= LC_MAIN
;
426 mo
->ep
.cmdsize
= sizeof(mo
->ep
);
427 mo
->ep
.entryoff
= 4096; // XXX
428 mo
->ep
.stacksize
= 0;
431 i
= (sizeof(*dyldlc
) + strlen("/usr/lib/dyld") + 1 + 7) &-8;
432 dyldlc
= tcc_mallocz(i
);
433 dyldlc
->cmd
= LC_LOAD_DYLINKER
;
435 dyldlc
->name
= sizeof(*dyldlc
);
436 str
= (char*)dyldlc
+ dyldlc
->name
;
437 strcpy(str
, "/usr/lib/dyld");
440 symlc
= tcc_mallocz(sizeof(*symlc
));
441 symlc
->cmd
= LC_SYMTAB
;
442 symlc
->cmdsize
= sizeof(*symlc
);
445 dysymlc
= tcc_mallocz(sizeof(*dysymlc
));
446 dysymlc
->cmd
= LC_DYSYMTAB
;
447 dysymlc
->cmdsize
= sizeof(*dysymlc
);
450 add_dylib(mo
, "/usr/lib/libSystem.B.dylib");
452 mo
->linkedit
= new_section(s1
, "LINKEDIT", SHT_LINKEDIT
, SHF_ALLOC
| SHF_WRITE
);
453 /* LINKEDIT can't be empty (XXX remove once we have symbol table) */
454 section_ptr_add(mo
->linkedit
, 256);
456 create_symtab(s1
, mo
);
458 /* dyld requires a writable segment, but ignores zero-sized segments
459 for this, so force to have some data. */
460 mo
->wdata
= new_section(s1
, " wdata", SHT_PROGBITS
, SHF_ALLOC
| SHF_WRITE
);
461 section_ptr_add(mo
->wdata
, 64);
462 memset (mo
->sk_to_sect
, 0, sizeof(mo
->sk_to_sect
));
463 for (i
= s1
->nb_sections
; i
-- > 1;) {
469 if (flags
& SHF_ALLOC
) {
471 default: sk
= sk_unknown
; break;
472 case SHT_NOBITS
: sk
= sk_bss
; break;
473 case SHT_SYMTAB
: sk
= sk_discard
; break;
474 case SHT_STRTAB
: sk
= sk_discard
; break;
475 case SHT_RELX
: sk
= sk_discard
; break;
476 case SHT_LINKEDIT
: sk
= sk_linkedit
; break;
478 if (flags
& SHF_EXECINSTR
)
480 else if (flags
& SHF_WRITE
)
488 s
->prev
= mo
->sk_to_sect
[sk
].s
;
489 mo
->sk_to_sect
[sk
].s
= s
;
491 fileofs
= 4096; /* leave space for mach-o headers */
492 curaddr
= mo
->seg
[1]->vmaddr
;
496 mo
->elfsectomacho
= tcc_mallocz(sizeof(*mo
->elfsectomacho
) * s1
->nb_sections
);
497 for (sk
= sk_unknown
; sk
< sk_last
; sk
++) {
498 struct section_64
*sec
= NULL
;
500 seg
->vmsize
= curaddr
- seg
->vmaddr
;
501 seg
->filesize
= fileofs
- seg
->fileoff
;
503 if (skinfo
[sk
].seg
&& mo
->sk_to_sect
[sk
].s
) {
506 seg
= mo
->seg
[skinfo
[sk
].seg
];
507 if (skinfo
[sk
].name
) {
508 si
= add_section(mo
, &seg
, skinfo
[sk
].name
);
510 mo
->seg
[skinfo
[sk
].seg
] = seg
;
511 mo
->sk_to_sect
[sk
].machosect
= si
;
512 sec
= get_section(seg
, si
);
513 sec
->flags
= skinfo
[sk
].flags
;
515 if (seg
->vmaddr
== -1) {
516 curaddr
= (curaddr
+ 4095) & -4096;
517 seg
->vmaddr
= curaddr
;
518 fileofs
= (fileofs
+ 4095) & -4096;
519 seg
->fileoff
= fileofs
;
522 for (s
= mo
->sk_to_sect
[sk
].s
; s
; s
= s
->prev
) {
523 int a
= exact_log2p1(s
->sh_addralign
);
524 if (a
&& al
< (a
- 1))
526 s
->sh_size
= s
->data_offset
;
532 tcc_warning("alignment > 4096"), sec
->align
= 12, al
= 4096;
533 curaddr
= (curaddr
+ al
- 1) & -al
;
534 fileofs
= (fileofs
+ al
- 1) & -al
;
537 sec
->offset
= fileofs
;
539 for (s
= mo
->sk_to_sect
[sk
].s
; s
; s
= s
->prev
) {
540 al
= s
->sh_addralign
;
541 curaddr
= (curaddr
+ al
- 1) & -al
;
542 tcc_warning("curaddr now 0x%llx", curaddr
);
543 s
->sh_addr
= curaddr
;
544 curaddr
+= s
->sh_size
;
545 if (s
->sh_type
!= SHT_NOBITS
) {
546 fileofs
= (fileofs
+ al
- 1) & -al
;
547 s
->sh_offset
= fileofs
;
548 fileofs
+= s
->sh_size
;
549 tcc_warning("fileofs now %lld", fileofs
);
552 mo
->elfsectomacho
[s
->sh_num
] = numsec
;
555 sec
->size
= curaddr
- sec
->addr
;
557 for (s
= mo
->sk_to_sect
[sk
].s
; s
; s
= s
->prev
) {
558 int type
= s
->sh_type
;
559 int flags
= s
->sh_flags
;
560 printf("%d section %-16s %-10s %09llx %04x %02d %s,%s,%s\n",
563 type
== SHT_PROGBITS
? "progbits" :
564 type
== SHT_NOBITS
? "nobits" :
565 type
== SHT_SYMTAB
? "symtab" :
566 type
== SHT_STRTAB
? "strtab" :
567 type
== SHT_RELX
? "rel" : "???",
569 (unsigned)s
->data_offset
,
571 flags
& SHF_ALLOC
? "alloc" : "",
572 flags
& SHF_WRITE
? "write" : "",
573 flags
& SHF_EXECINSTR
? "exec" : ""
578 seg
->vmsize
= curaddr
- seg
->vmaddr
;
579 seg
->filesize
= fileofs
- seg
->fileoff
;
582 /* Fill symtab info */
583 symlc
->symoff
= mo
->symtab
->sh_offset
;
584 symlc
->nsyms
= mo
->symtab
->data_offset
/ sizeof(struct nlist_64
);
585 symlc
->stroff
= mo
->strtab
->sh_offset
;
586 symlc
->strsize
= mo
->strtab
->data_offset
;
589 static void macho_write(TCCState
*s1
, struct macho
*mo
, FILE *fp
)
592 uint64_t fileofs
= 0;
594 mo
->mh
.mh
.magic
= MH_MAGIC_64
;
595 mo
->mh
.mh
.cputype
= 0x1000007; // x86_64
596 mo
->mh
.mh
.cpusubtype
= 0x80000003;// all | CPU_SUBTYPE_LIB64
597 mo
->mh
.mh
.filetype
= 2; // MH_EXECUTE
598 mo
->mh
.mh
.flags
= 4; // DYLDLINK
599 mo
->mh
.mh
.ncmds
= mo
->nseg
+ mo
->nlc
;
600 mo
->mh
.mh
.sizeofcmds
= 0;
601 for (i
= 0; i
< mo
->nseg
; i
++)
602 mo
->mh
.mh
.sizeofcmds
+= mo
->seg
[i
]->cmdsize
;
603 for (i
= 0; i
< mo
->nlc
; i
++)
604 mo
->mh
.mh
.sizeofcmds
+= mo
->lc
[i
]->cmdsize
;
606 fwrite(&mo
->mh
, 1, sizeof(mo
->mh
), fp
);
607 fileofs
+= sizeof(mo
->mh
);
608 for (i
= 0; i
< mo
->nseg
; i
++) {
609 fwrite(mo
->seg
[i
], 1, mo
->seg
[i
]->cmdsize
, fp
);
610 fileofs
+= mo
->seg
[i
]->cmdsize
;
612 for (i
= 0; i
< mo
->nlc
; i
++) {
613 fwrite(mo
->lc
[i
], 1, mo
->lc
[i
]->cmdsize
, fp
);
614 fileofs
+= mo
->lc
[i
]->cmdsize
;
617 for (sk
= sk_unknown
; sk
< sk_last
; sk
++) {
618 struct segment_command_64
*seg
;
619 //struct section_64 *sec;
620 if (!skinfo
[sk
].seg
|| !mo
->sk_to_sect
[sk
].s
)
622 seg
= mo
->seg
[skinfo
[sk
].seg
];
623 /*sec = get_section(seg, mo->sk_to_sect[sk].machosect);
624 while (fileofs < sec->offset)
625 fputc(0, fp), fileofs++;*/
626 for (s
= mo
->sk_to_sect
[sk
].s
; s
; s
= s
->prev
) {
627 if (s
->sh_type
!= SHT_NOBITS
) {
628 while (fileofs
< s
->sh_offset
)
629 fputc(0, fp
), fileofs
++;
631 fwrite(s
->data
, 1, s
->sh_size
, fp
);
632 fileofs
+= s
->sh_size
;
639 ST_FUNC
int macho_output_file(TCCState
*s1
, const char *filename
)
641 int fd
, mode
, file_type
;
644 struct macho mo
= {0,};
646 file_type
= s1
->output_type
;
647 if (file_type
== TCC_OUTPUT_OBJ
)
652 fd
= open(filename
, O_WRONLY
| O_CREAT
| O_TRUNC
| O_BINARY
, mode
);
654 tcc_error_noabort("could not write '%s: %s'", filename
, strerror(errno
));
657 fp
= fdopen(fd
, "wb");
659 printf("<- %s\n", filename
);
661 resolve_common_syms(s1
);
662 ret
= check_symbols(s1
);
666 collect_sections(s1
, &mo
);
667 relocate_syms(s1
, s1
->symtab
, 0);
671 for(i
= 1; i
< s1
->nb_sections
; i
++) {
674 relocate_section(s1
, s
);
676 convert_symbols(s1
, &mo
);
678 macho_write(s1
, &mo
, fp
);