x86asm: Add lzcnt/tzcnt support
[tinycc.git] / tccmacho.c
blob109eaa86f083bc22596f1692ebfc348992b53d5d
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 #if !defined TCC_TARGET_X86_64 && !defined TCC_TARGET_ARM64
35 #error Platform not supported
36 #endif
38 #define DEBUG_MACHO 0
39 #define dprintf if (DEBUG_MACHO) printf
41 #define MH_EXECUTE (0x2)
42 #define MH_DYLDLINK (0x4)
43 #define MH_PIE (0x200000)
45 #define CPU_SUBTYPE_LIB64 (0x80000000)
46 #define CPU_SUBTYPE_X86_ALL (3)
47 #define CPU_SUBTYPE_ARM64_ALL (0)
49 #define CPU_ARCH_ABI64 (0x01000000)
51 #define CPU_TYPE_X86 (7)
52 #define CPU_TYPE_X86_64 (CPU_TYPE_X86 | CPU_ARCH_ABI64)
53 #define CPU_TYPE_ARM (12)
54 #define CPU_TYPE_ARM64 (CPU_TYPE_ARM | CPU_ARCH_ABI64)
56 struct fat_header {
57 uint32_t magic; /* FAT_MAGIC or FAT_MAGIC_64 */
58 uint32_t nfat_arch; /* number of structs that follow */
61 struct fat_arch {
62 int cputype; /* cpu specifier (int) */
63 int cpusubtype; /* machine specifier (int) */
64 uint32_t offset; /* file offset to this object file */
65 uint32_t size; /* size of this object file */
66 uint32_t align; /* alignment as a power of 2 */
69 #define FAT_MAGIC 0xcafebabe
70 #define FAT_CIGAM 0xbebafeca
71 #define FAT_MAGIC_64 0xcafebabf
72 #define FAT_CIGAM_64 0xbfbafeca
74 struct mach_header {
75 uint32_t magic; /* mach magic number identifier */
76 int cputype; /* cpu specifier */
77 int cpusubtype; /* machine specifier */
78 uint32_t filetype; /* type of file */
79 uint32_t ncmds; /* number of load commands */
80 uint32_t sizeofcmds; /* the size of all the load commands */
81 uint32_t flags; /* flags */
84 struct mach_header_64 {
85 struct mach_header mh;
86 uint32_t reserved; /* reserved, pad to 64bit */
89 /* Constant for the magic field of the mach_header (32-bit architectures) */
90 #define MH_MAGIC 0xfeedface /* the mach magic number */
91 #define MH_CIGAM 0xcefaedfe /* NXSwapInt(MH_MAGIC) */
92 #define MH_MAGIC_64 0xfeedfacf /* the 64-bit mach magic number */
93 #define MH_CIGAM_64 0xcffaedfe /* NXSwapInt(MH_MAGIC_64) */
95 struct load_command {
96 uint32_t cmd; /* type of load command */
97 uint32_t cmdsize; /* total size of command in bytes */
100 #define LC_REQ_DYLD 0x80000000
101 #define LC_SYMTAB 0x2
102 #define LC_DYSYMTAB 0xb
103 #define LC_LOAD_DYLIB 0xc
104 #define LC_ID_DYLIB 0xd
105 #define LC_LOAD_DYLINKER 0xe
106 #define LC_SEGMENT_64 0x19
107 #define LC_REEXPORT_DYLIB (0x1f | LC_REQ_DYLD)
108 #define LC_DYLD_INFO_ONLY (0x22|LC_REQ_DYLD)
109 #define LC_MAIN (0x28|LC_REQ_DYLD)
110 #define LC_SOURCE_VERSION 0x2A
111 #define LC_BUILD_VERSION 0x32
112 #define LC_DYLD_EXPORTS_TRIE (0x33 | LC_REQ_DYLD)
113 #define LC_DYLD_CHAINED_FIXUPS (0x34 | LC_REQ_DYLD)
115 #define SG_READ_ONLY 0x10 /* This segment is made read-only after fixups */
117 typedef int vm_prot_t;
119 struct segment_command_64 { /* for 64-bit architectures */
120 uint32_t cmd; /* LC_SEGMENT_64 */
121 uint32_t cmdsize; /* includes sizeof section_64 structs */
122 char segname[16]; /* segment name */
123 uint64_t vmaddr; /* memory address of this segment */
124 uint64_t vmsize; /* memory size of this segment */
125 uint64_t fileoff; /* file offset of this segment */
126 uint64_t filesize; /* amount to map from the file */
127 vm_prot_t maxprot; /* maximum VM protection */
128 vm_prot_t initprot; /* initial VM protection */
129 uint32_t nsects; /* number of sections in segment */
130 uint32_t flags; /* flags */
133 struct section_64 { /* for 64-bit architectures */
134 char sectname[16]; /* name of this section */
135 char segname[16]; /* segment this section goes in */
136 uint64_t addr; /* memory address of this section */
137 uint64_t size; /* size in bytes of this section */
138 uint32_t offset; /* file offset of this section */
139 uint32_t align; /* section alignment (power of 2) */
140 uint32_t reloff; /* file offset of relocation entries */
141 uint32_t nreloc; /* number of relocation entries */
142 uint32_t flags; /* flags (section type and attributes)*/
143 uint32_t reserved1; /* reserved (for offset or index) */
144 uint32_t reserved2; /* reserved (for count or sizeof) */
145 uint32_t reserved3; /* reserved */
148 enum {
149 DYLD_CHAINED_IMPORT = 1,
152 struct dyld_chained_fixups_header {
153 uint32_t fixups_version; ///< 0
154 uint32_t starts_offset; ///< Offset of dyld_chained_starts_in_image.
155 uint32_t imports_offset; ///< Offset of imports table in chain_data.
156 uint32_t symbols_offset; ///< Offset of symbol strings in chain_data.
157 uint32_t imports_count; ///< Number of imported symbol names.
158 uint32_t imports_format; ///< DYLD_CHAINED_IMPORT*
159 uint32_t symbols_format; ///< 0 => uncompressed, 1 => zlib compressed
162 struct dyld_chained_starts_in_image
164 uint32_t seg_count;
165 uint32_t seg_info_offset[1]; // each entry is offset into this struct for that segment
166 // followed by pool of dyld_chain_starts_in_segment data
169 enum {
170 DYLD_CHAINED_PTR_64 = 2, // target is vmaddr
171 DYLD_CHAINED_PTR_64_OFFSET = 6, // target is vm offset
174 enum {
175 DYLD_CHAINED_PTR_START_NONE = 0xFFFF, // used in page_start[] to denote a page with no fixups
178 #define SEG_PAGE_SIZE 16384
180 struct dyld_chained_starts_in_segment
182 uint32_t size; // size of this (amount kernel needs to copy)
183 uint16_t page_size; // 0x1000 or 0x4000
184 uint16_t pointer_format; // DYLD_CHAINED_PTR_*
185 uint64_t segment_offset; // offset in memory to start of segment
186 uint32_t max_valid_pointer; // for 32-bit OS, any value beyond this is not a pointer
187 uint16_t page_count; // how many pages are in array
188 uint16_t page_start[1]; // each entry is offset in each page of first element in chain
189 // or DYLD_CHAINED_PTR_START_NONE if no fixups on page
192 enum BindSpecialDylib {
193 BIND_SPECIAL_DYLIB_FLAT_LOOKUP = -2,
196 struct dyld_chained_import
198 uint32_t lib_ordinal : 8,
199 weak_import : 1,
200 name_offset : 23;
203 struct dyld_chained_ptr_64_rebase
205 uint64_t target : 36, // vmaddr, 64GB max image size
206 high8 : 8, // top 8 bits set to this after slide added
207 reserved : 7, // all zeros
208 next : 12, // 4-byte stride
209 bind : 1; // == 0
212 struct dyld_chained_ptr_64_bind
214 uint64_t ordinal : 24,
215 addend : 8, // 0 thru 255
216 reserved : 19, // all zeros
217 next : 12, // 4-byte stride
218 bind : 1; // == 1
221 #define S_REGULAR 0x0
222 #define S_ZEROFILL 0x1
223 #define S_NON_LAZY_SYMBOL_POINTERS 0x6
224 #define S_LAZY_SYMBOL_POINTERS 0x7
225 #define S_SYMBOL_STUBS 0x8
226 #define S_MOD_INIT_FUNC_POINTERS 0x9
227 #define S_MOD_TERM_FUNC_POINTERS 0xa
229 #define S_ATTR_PURE_INSTRUCTIONS 0x80000000
230 #define S_ATTR_SOME_INSTRUCTIONS 0x00000400
231 #define S_ATTR_DEBUG 0x02000000
234 typedef uint32_t lc_str;
236 struct dylib_command {
237 uint32_t cmd; /* LC_ID_DYLIB, LC_LOAD_{,WEAK_}DYLIB,
238 LC_REEXPORT_DYLIB */
239 uint32_t cmdsize; /* includes pathname string */
240 lc_str name; /* library's path name */
241 uint32_t timestamp; /* library's build time stamp */
242 uint32_t current_version; /* library's current version number */
243 uint32_t compatibility_version; /* library's compatibility vers number*/
246 struct dylinker_command {
247 uint32_t cmd; /* LC_ID_DYLINKER, LC_LOAD_DYLINKER or
248 LC_DYLD_ENVIRONMENT */
249 uint32_t cmdsize; /* includes pathname string */
250 lc_str name; /* dynamic linker's path name */
253 struct linkedit_data_command {
254 uint32_t cmd; /* LC_CODE_SIGNATURE, LC_SEGMENT_SPLIT_INFO,
255 LC_FUNCTION_STARTS, LC_DATA_IN_CODE,
256 LC_DYLIB_CODE_SIGN_DRS,
257 LC_LINKER_OPTIMIZATION_HINT,
258 LC_DYLD_EXPORTS_TRIE, or
259 LC_DYLD_CHAINED_FIXUPS. */
260 uint32_t cmdsize; /* sizeof(struct linkedit_data_command) */
261 uint32_t dataoff; /* file offset of data in __LINKEDIT segment */
262 uint32_t datasize; /* file size of data in __LINKEDIT segment */
265 #define PLATFORM_MACOS 1
267 struct build_version_command {
268 uint32_t cmd; /* LC_BUILD_VERSION */
269 uint32_t cmdsize; /* sizeof(struct build_version_command) plus */
270 /* ntools * sizeof(struct build_tool_version) */
271 uint32_t platform; /* platform */
272 uint32_t minos; /* X.Y.Z is encoded in nibbles xxxx.yy.zz */
273 uint32_t sdk; /* X.Y.Z is encoded in nibbles xxxx.yy.zz */
274 uint32_t ntools; /* number of tool entries following this */
277 struct source_version_command {
278 uint32_t cmd; /* LC_SOURCE_VERSION */
279 uint32_t cmdsize; /* 16 */
280 uint64_t version; /* A.B.C.D.E packed as a24.b10.c10.d10.e10 */
283 struct symtab_command {
284 uint32_t cmd; /* LC_SYMTAB */
285 uint32_t cmdsize; /* sizeof(struct symtab_command) */
286 uint32_t symoff; /* symbol table offset */
287 uint32_t nsyms; /* number of symbol table entries */
288 uint32_t stroff; /* string table offset */
289 uint32_t strsize; /* string table size in bytes */
292 struct dysymtab_command {
293 uint32_t cmd; /* LC_DYSYMTAB */
294 uint32_t cmdsize; /* sizeof(struct dysymtab_command) */
296 uint32_t ilocalsym; /* index to local symbols */
297 uint32_t nlocalsym; /* number of local symbols */
299 uint32_t iextdefsym;/* index to externally defined symbols */
300 uint32_t nextdefsym;/* number of externally defined symbols */
302 uint32_t iundefsym; /* index to undefined symbols */
303 uint32_t nundefsym; /* number of undefined symbols */
305 uint32_t tocoff; /* file offset to table of contents */
306 uint32_t ntoc; /* number of entries in table of contents */
308 uint32_t modtaboff; /* file offset to module table */
309 uint32_t nmodtab; /* number of module table entries */
311 uint32_t extrefsymoff; /* offset to referenced symbol table */
312 uint32_t nextrefsyms; /* number of referenced symbol table entries */
314 uint32_t indirectsymoff;/* file offset to the indirect symbol table */
315 uint32_t nindirectsyms; /* number of indirect symbol table entries */
317 uint32_t extreloff; /* offset to external relocation entries */
318 uint32_t nextrel; /* number of external relocation entries */
319 uint32_t locreloff; /* offset to local relocation entries */
320 uint32_t nlocrel; /* number of local relocation entries */
323 #define BIND_OPCODE_DONE 0x00
324 #define BIND_OPCODE_SET_DYLIB_SPECIAL_IMM 0x30
325 #define BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM 0x40
326 #define BIND_OPCODE_SET_TYPE_IMM 0x50
327 #define BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB 0x70
328 #define BIND_OPCODE_DO_BIND 0x90
330 #define BIND_TYPE_POINTER 1
331 #define BIND_SPECIAL_DYLIB_FLAT_LOOKUP -2
333 #define REBASE_OPCODE_DONE 0x00
334 #define REBASE_OPCODE_SET_TYPE_IMM 0x10
335 #define REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB 0x20
336 #define REBASE_OPCODE_DO_REBASE_IMM_TIMES 0x50
338 #define REBASE_TYPE_POINTER 1
340 #define EXPORT_SYMBOL_FLAGS_KIND_REGULAR 0x00
341 #define EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE 0x02
342 #define EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION 0x04
344 struct dyld_info_command {
345 uint32_t cmd; /* LC_DYLD_INFO or LC_DYLD_INFO_ONLY */
346 uint32_t cmdsize; /* sizeof(struct dyld_info_command) */
347 uint32_t rebase_off; /* file offset to rebase info */
348 uint32_t rebase_size; /* size of rebase info */
349 uint32_t bind_off; /* file offset to binding info */
350 uint32_t bind_size; /* size of binding info */
351 uint32_t weak_bind_off; /* file offset to weak binding info */
352 uint32_t weak_bind_size; /* size of weak binding info */
353 uint32_t lazy_bind_off; /* file offset to lazy binding info */
354 uint32_t lazy_bind_size; /* size of lazy binding infs */
355 uint32_t export_off; /* file offset to lazy binding info */
356 uint32_t export_size; /* size of lazy binding infs */
359 #define INDIRECT_SYMBOL_LOCAL 0x80000000
361 struct entry_point_command {
362 uint32_t cmd; /* LC_MAIN only used in MH_EXECUTE filetypes */
363 uint32_t cmdsize; /* 24 */
364 uint64_t entryoff; /* file (__TEXT) offset of main() */
365 uint64_t stacksize;/* if not zero, initial stack size */
368 enum skind {
369 sk_unknown = 0,
370 sk_discard,
371 sk_text,
372 sk_stubs,
373 sk_stub_helper,
374 sk_ro_data,
375 sk_uw_info,
376 sk_nl_ptr, // non-lazy pointers, aka GOT
377 sk_debug_info,
378 sk_debug_abbrev,
379 sk_debug_line,
380 sk_debug_aranges,
381 sk_debug_str,
382 sk_debug_line_str,
383 sk_stab,
384 sk_stab_str,
385 sk_la_ptr, // lazy pointers
386 sk_init,
387 sk_fini,
388 sk_rw_data,
389 sk_bss,
390 sk_linkedit,
391 sk_last
394 struct nlist_64 {
395 uint32_t n_strx; /* index into the string table */
396 uint8_t n_type; /* type flag, see below */
397 uint8_t n_sect; /* section number or NO_SECT */
398 uint16_t n_desc; /* see <mach-o/stab.h> */
399 uint64_t n_value; /* value of this symbol (or stab offset) */
402 #define N_UNDF 0x0
403 #define N_ABS 0x2
404 #define N_EXT 0x1
405 #define N_SECT 0xe
407 #define N_WEAK_REF 0x0040
408 #define N_WEAK_DEF 0x0080
410 struct macho {
411 struct mach_header_64 mh;
412 int *seg2lc, nseg;
413 struct load_command **lc;
414 struct entry_point_command *ep;
415 int nlc;
416 struct {
417 Section *s;
418 int machosect;
419 } sk_to_sect[sk_last];
420 int *elfsectomacho;
421 int *e2msym;
422 Section *symtab, *strtab, *wdata, *indirsyms, *stubs, *exports;
423 uint32_t ilocal, iextdef, iundef;
424 int stubsym, n_got, nr_plt;
425 int segment[sk_last];
426 #ifdef CONFIG_NEW_MACHO
427 Section *chained_fixups;
428 int n_bind;
429 int n_bind_rebase;
430 struct bind_rebase {
431 int section;
432 int bind;
433 ElfW_Rel rel;
434 } *bind_rebase;
435 #else
436 Section *rebase, *binding, *weak_binding, *lazy_binding;
437 Section *stub_helper, *la_symbol_ptr;
438 struct dyld_info_command *dyldinfo;
439 int helpsym, lasym, dyld_private, dyld_stub_binder;
440 int n_lazy_bind;
441 struct s_lazy_bind {
442 int section;
443 int bind_offset;
444 int la_symbol_offset;
445 ElfW_Rel rel;
446 } *s_lazy_bind;
447 int n_rebase;
448 struct s_rebase {
449 int section;
450 ElfW_Rel rel;
451 } *s_rebase;
452 int n_bind;
453 struct bind {
454 int section;
455 ElfW_Rel rel;
456 } *bind;
457 #endif
460 #define SHT_LINKEDIT (SHT_LOOS + 42)
461 #define SHN_FROMDLL (SHN_LOOS + 2) /* Symbol is undefined, comes from a DLL */
463 static void * add_lc(struct macho *mo, uint32_t cmd, uint32_t cmdsize)
465 struct load_command *lc = tcc_mallocz(cmdsize);
466 lc->cmd = cmd;
467 lc->cmdsize = cmdsize;
468 mo->lc = tcc_realloc(mo->lc, sizeof(mo->lc[0]) * (mo->nlc + 1));
469 mo->lc[mo->nlc++] = lc;
470 return lc;
473 static struct segment_command_64 * add_segment(struct macho *mo, const char *name)
475 struct segment_command_64 *sc = add_lc(mo, LC_SEGMENT_64, sizeof(*sc));
476 strncpy(sc->segname, name, 16);
477 mo->seg2lc = tcc_realloc(mo->seg2lc, sizeof(*mo->seg2lc) * (mo->nseg + 1));
478 mo->seg2lc[mo->nseg++] = mo->nlc - 1;
479 return sc;
482 static struct segment_command_64 * get_segment(struct macho *mo, int i)
484 return (struct segment_command_64 *) (mo->lc[mo->seg2lc[i]]);
487 static int add_section(struct macho *mo, struct segment_command_64 **_seg, const char *name)
489 struct segment_command_64 *seg = *_seg;
490 int ret = seg->nsects;
491 struct section_64 *sec;
492 seg->nsects++;
493 seg->cmdsize += sizeof(*sec);
494 seg = tcc_realloc(seg, sizeof(*seg) + seg->nsects * sizeof(*sec));
495 sec = (struct section_64*)((char*)seg + sizeof(*seg)) + ret;
496 memset(sec, 0, sizeof(*sec));
497 strncpy(sec->sectname, name, 16);
498 strncpy(sec->segname, seg->segname, 16);
499 *_seg = seg;
500 return ret;
503 static struct section_64 *get_section(struct segment_command_64 *seg, int i)
505 return (struct section_64*)((char*)seg + sizeof(*seg)) + i;
508 static void * add_dylib(struct macho *mo, char *name)
510 struct dylib_command *lc;
511 int sz = (sizeof(*lc) + strlen(name) + 1 + 7) & -8;
512 lc = add_lc(mo, LC_LOAD_DYLIB, sz);
513 lc->name = sizeof(*lc);
514 strcpy((char*)lc + lc->name, name);
515 lc->timestamp = 2;
516 lc->current_version = 1 << 16;
517 lc->compatibility_version = 1 << 16;
518 return lc;
521 static int uleb128_size (unsigned long long value)
523 int size = 0;
525 do {
526 value >>= 7;
527 size++;
528 } while (value != 0);
529 return size;
532 static void write_uleb128(Section *section, uint64_t value)
534 do {
535 unsigned char byte = value & 0x7f;
536 uint8_t *ptr = section_ptr_add(section, 1);
538 value >>= 7;
539 *ptr = byte | (value ? 0x80 : 0);
540 } while (value != 0);
543 static void tcc_macho_add_destructor(TCCState *s1)
545 int init_sym, mh_execute_header, at_exit_sym;
546 Section *s;
547 ElfW_Rel *rel;
548 uint8_t *ptr;
550 mh_execute_header = put_elf_sym(s1->symtab, -4096, 0,
551 ELFW(ST_INFO)(STB_GLOBAL, STT_OBJECT), 0,
552 text_section->sh_num, "__mh_execute_header");
553 s = find_section(s1, ".fini_array");
554 if (s->data_offset == 0)
555 return;
556 init_sym = put_elf_sym(s1->symtab, text_section->data_offset, 0,
557 ELFW(ST_INFO)(STB_LOCAL, STT_FUNC), 0,
558 text_section->sh_num, "___GLOBAL_init_65535");
559 at_exit_sym = put_elf_sym(s1->symtab, 0, 0,
560 ELFW(ST_INFO)(STB_GLOBAL, STT_FUNC), 0,
561 SHN_UNDEF, "___cxa_atexit");
562 #ifdef TCC_TARGET_X86_64
563 ptr = section_ptr_add(text_section, 4);
564 ptr[0] = 0x55; // pushq %rbp
565 ptr[1] = 0x48; // movq %rsp, %rbp
566 ptr[2] = 0x89;
567 ptr[3] = 0xe5;
568 for_each_elem(s->reloc, 0, rel, ElfW_Rel) {
569 int sym_index = ELFW(R_SYM)(rel->r_info);
571 ptr = section_ptr_add(text_section, 26);
572 ptr[0] = 0x48; // lea destructor(%rip),%rax
573 ptr[1] = 0x8d;
574 ptr[2] = 0x05;
575 put_elf_reloca(s1->symtab, text_section,
576 text_section->data_offset - 23,
577 R_X86_64_PC32, sym_index, -4);
578 ptr[7] = 0x48; // mov %rax,%rdi
579 ptr[8] = 0x89;
580 ptr[9] = 0xc7;
581 ptr[10] = 0x31; // xorl %ecx, %ecx
582 ptr[11] = 0xc9;
583 ptr[12] = 0x89; // movl %ecx, %esi
584 ptr[13] = 0xce;
585 ptr[14] = 0x48; // lea mh_execute_header(%rip),%rdx
586 ptr[15] = 0x8d;
587 ptr[16] = 0x15;
588 put_elf_reloca(s1->symtab, text_section,
589 text_section->data_offset - 9,
590 R_X86_64_PC32, mh_execute_header, -4);
591 ptr[21] = 0xe8; // call __cxa_atexit
592 put_elf_reloca(s1->symtab, text_section,
593 text_section->data_offset - 4,
594 R_X86_64_PLT32, at_exit_sym, -4);
596 ptr = section_ptr_add(text_section, 2);
597 ptr[0] = 0x5d; // pop %rbp
598 ptr[1] = 0xc3; // ret
599 #elif defined TCC_TARGET_ARM64
600 ptr = section_ptr_add(text_section, 8);
601 write32le(ptr, 0xa9bf7bfd); // stp x29, x30, [sp, #-16]!
602 write32le(ptr + 4, 0x910003fd); // mov x29, sp
603 for_each_elem(s->reloc, 0, rel, ElfW_Rel) {
604 int sym_index = ELFW(R_SYM)(rel->r_info);
606 ptr = section_ptr_add(text_section, 24);
607 put_elf_reloc(s1->symtab, text_section,
608 text_section->data_offset - 24,
609 R_AARCH64_ADR_PREL_PG_HI21, sym_index);
610 write32le(ptr, 0x90000000); // adrp x0, destructor@page
611 put_elf_reloc(s1->symtab, text_section,
612 text_section->data_offset - 20,
613 R_AARCH64_LDST8_ABS_LO12_NC, sym_index);
614 write32le(ptr + 4, 0x91000000); // add x0,x0,destructor@pageoff
615 write32le(ptr + 8, 0xd2800001); // mov x1, #0
616 put_elf_reloc(s1->symtab, text_section,
617 text_section->data_offset - 12,
618 R_AARCH64_ADR_PREL_PG_HI21, mh_execute_header);
619 write32le(ptr + 12, 0x90000002); // adrp x2, mh_execute_header@page
620 put_elf_reloc(s1->symtab, text_section,
621 text_section->data_offset - 8,
622 R_AARCH64_LDST8_ABS_LO12_NC, mh_execute_header);
623 write32le(ptr + 16, 0x91000042); // add x2,x2,mh_execute_header@pageoff
624 put_elf_reloc(s1->symtab, text_section,
625 text_section->data_offset - 4,
626 R_AARCH64_CALL26, at_exit_sym);
627 write32le(ptr + 20, 0x94000000); // bl __cxa_atexit
629 ptr = section_ptr_add(text_section, 8);
630 write32le(ptr, 0xa8c17bfd); // ldp x29, x30, [sp], #16
631 write32le(ptr + 4, 0xd65f03c0); // ret
632 #endif
633 s->reloc->data_offset = s->data_offset = 0;
634 s->sh_flags &= ~SHF_ALLOC;
635 add_array (s1, ".init_array", init_sym);
638 #ifdef CONFIG_NEW_MACHO
639 static void bind_rebase_add(struct macho *mo, int bind, int sh_info,
640 ElfW_Rel *rel, struct sym_attr *attr)
642 mo->bind_rebase = tcc_realloc(mo->bind_rebase, (mo->n_bind_rebase + 1) *
643 sizeof(struct bind_rebase));
644 mo->bind_rebase[mo->n_bind_rebase].section = sh_info;
645 mo->bind_rebase[mo->n_bind_rebase].bind = bind;
646 mo->bind_rebase[mo->n_bind_rebase].rel = *rel;
647 if (attr)
648 mo->bind_rebase[mo->n_bind_rebase].rel.r_offset = attr->got_offset;
649 mo->n_bind_rebase++;
650 mo->n_bind += bind;
653 static void check_relocs(TCCState *s1, struct macho *mo)
655 Section *s;
656 ElfW_Rel *rel;
657 ElfW(Sym) *sym;
658 int i, type, gotplt_entry, sym_index, for_code;
659 uint32_t *pi, *goti;
660 struct sym_attr *attr;
662 mo->indirsyms = new_section(s1, "LEINDIR", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE);
663 goti = NULL;
664 mo->nr_plt = mo->n_got = 0;
665 for (i = 1; i < s1->nb_sections; i++) {
666 s = s1->sections[i];
667 if (s->sh_type != SHT_RELX ||
668 !strncmp(s1->sections[s->sh_info]->name, ".debug_", 7))
669 continue;
670 for_each_elem(s, 0, rel, ElfW_Rel) {
671 type = ELFW(R_TYPE)(rel->r_info);
672 gotplt_entry = gotplt_entry_type(type);
673 for_code = code_reloc(type);
674 /* We generate a non-lazy pointer for used undefined symbols
675 and for defined symbols that must have a place for their
676 address due to codegen (i.e. a reloc requiring a got slot). */
677 sym_index = ELFW(R_SYM)(rel->r_info);
678 sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
679 if (sym->st_shndx == SHN_UNDEF
680 || gotplt_entry == ALWAYS_GOTPLT_ENTRY) {
681 attr = get_sym_attr(s1, sym_index, 1);
682 if (!attr->dyn_index) {
683 attr->got_offset = s1->got->data_offset;
684 attr->plt_offset = -1;
685 attr->dyn_index = 1; /* used as flag */
686 section_ptr_add(s1->got, PTR_SIZE);
687 put_elf_reloc(s1->symtab, s1->got, attr->got_offset,
688 R_DATA_PTR, sym_index);
689 goti = tcc_realloc(goti, (mo->n_got + 1) * sizeof(*goti));
690 if (ELFW(ST_BIND)(sym->st_info) == STB_LOCAL) {
691 if (sym->st_shndx == SHN_UNDEF)
692 tcc_error("undefined local symbo: '%s'",
693 (char *) symtab_section->link->data + sym->st_name);
694 goti[mo->n_got++] = INDIRECT_SYMBOL_LOCAL;
695 } else {
696 goti[mo->n_got++] = mo->e2msym[sym_index];
697 if (sym->st_shndx == SHN_UNDEF
698 #ifdef TCC_TARGET_X86_64
699 && type == R_X86_64_GOTPCREL
700 #elif defined TCC_TARGET_ARM64
701 && type == R_AARCH64_ADR_GOT_PAGE
702 #endif
704 bind_rebase_add(mo, 1, s1->got->reloc->sh_info, rel, attr);
705 attr->plt_offset = 0; // ignore next bind
706 s1->got->reloc->data_offset -= sizeof (ElfW_Rel);
708 if (for_code && sym->st_shndx == SHN_UNDEF)
709 s1->got->reloc->data_offset -= sizeof (ElfW_Rel);
712 if (for_code && sym->st_shndx == SHN_UNDEF) {
713 if (attr->plt_offset == -1) {
714 uint8_t *jmp;
716 attr->plt_offset = mo->stubs->data_offset;
717 #ifdef TCC_TARGET_X86_64
718 if (type != R_X86_64_PLT32)
719 continue;
720 jmp = section_ptr_add(mo->stubs, 6);
721 jmp[0] = 0xff; /* jmpq *ofs(%rip) */
722 jmp[1] = 0x25;
723 put_elf_reloc(s1->symtab, mo->stubs,
724 attr->plt_offset + 2,
725 R_X86_64_GOTPCREL, sym_index);
726 #elif defined TCC_TARGET_ARM64
727 if (type != R_AARCH64_CALL26)
728 continue;
729 jmp = section_ptr_add(mo->stubs, 12);
730 put_elf_reloc(s1->symtab, mo->stubs,
731 attr->plt_offset,
732 R_AARCH64_ADR_GOT_PAGE, sym_index);
733 write32le(jmp, // adrp x16, #sym
734 0x90000010);
735 put_elf_reloc(s1->symtab, mo->stubs,
736 attr->plt_offset + 4,
737 R_AARCH64_LD64_GOT_LO12_NC, sym_index);
738 write32le(jmp + 4, // ld x16,[x16, #sym]
739 0xf9400210);
740 write32le(jmp + 8, // br x16
741 0xd61f0200);
742 #endif
743 bind_rebase_add(mo, 1, s1->got->reloc->sh_info, rel, attr);
744 pi = section_ptr_add(mo->indirsyms, sizeof(*pi));
745 *pi = mo->e2msym[sym_index];
746 mo->nr_plt++;
748 rel->r_info = ELFW(R_INFO)(mo->stubsym, type);
749 rel->r_addend += attr->plt_offset;
752 if (type == R_DATA_PTR)
753 bind_rebase_add(mo, sym->st_shndx == SHN_UNDEF ? 1 : 0,
754 s->sh_info, rel, NULL);
757 pi = section_ptr_add(mo->indirsyms, mo->n_got * sizeof(*pi));
758 memcpy(pi, goti, mo->n_got * sizeof(*pi));
759 tcc_free(goti);
762 #else
764 static void check_relocs(TCCState *s1, struct macho *mo)
766 uint8_t *jmp;
767 Section *s;
768 ElfW_Rel *rel;
769 ElfW(Sym) *sym;
770 int i, type, gotplt_entry, sym_index, for_code;
771 int bind_offset, la_symbol_offset;
772 uint32_t *pi, *goti;
773 struct sym_attr *attr;
775 mo->indirsyms = new_section(s1, "LEINDIR", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE);
777 #ifdef TCC_TARGET_X86_64
778 jmp = section_ptr_add(mo->stub_helper, 16);
779 jmp[0] = 0x4c; /* leaq _dyld_private(%rip), %r11 */
780 jmp[1] = 0x8d;
781 jmp[2] = 0x1d;
782 put_elf_reloca(s1->symtab, mo->stub_helper, 3,
783 R_X86_64_PC32, mo->dyld_private, -4);
784 jmp[7] = 0x41; /* pushq %r11 */
785 jmp[8] = 0x53;
786 jmp[9] = 0xff; /* jmpq *dyld_stub_binder@GOT(%rip) */
787 jmp[10] = 0x25;
788 put_elf_reloca(s1->symtab, mo->stub_helper, 11,
789 R_X86_64_GOTPCREL, mo->dyld_stub_binder, -4);
790 jmp[15] = 0x90; /* nop */
791 #elif defined TCC_TARGET_ARM64
792 jmp = section_ptr_add(mo->stub_helper, 24);
793 put_elf_reloc(s1->symtab, mo->stub_helper, 0,
794 R_AARCH64_ADR_PREL_PG_HI21, mo->dyld_private);
795 write32le(jmp, 0x90000011); // adrp x17, _dyld_private@page
796 put_elf_reloc(s1->symtab, mo->stub_helper, 4,
797 R_AARCH64_LDST64_ABS_LO12_NC, mo->dyld_private);
798 write32le(jmp + 4, 0x91000231); // add x17,x17,_dyld_private@pageoff
799 write32le(jmp + 8, 0xa9bf47f0); // stp x16/x17, [sp, #-16]!
800 put_elf_reloc(s1->symtab, mo->stub_helper, 12,
801 R_AARCH64_ADR_GOT_PAGE, mo->dyld_stub_binder);
802 write32le(jmp + 12, 0x90000010); // adrp x16, dyld_stub_binder@page
803 put_elf_reloc(s1->symtab, mo->stub_helper, 16,
804 R_AARCH64_LD64_GOT_LO12_NC, mo->dyld_stub_binder);
805 write32le(jmp + 16, 0xf9400210); // ldr x16,[x16,dyld_stub_binder@pageoff]
806 write32le(jmp + 20, 0xd61f0200); // br x16
807 #endif
809 goti = NULL;
810 mo->nr_plt = mo->n_got = 0;
811 for (i = 1; i < s1->nb_sections; i++) {
812 s = s1->sections[i];
813 if (s->sh_type != SHT_RELX ||
814 !strncmp(s1->sections[s->sh_info]->name, ".debug_", 7))
815 continue;
816 for_each_elem(s, 0, rel, ElfW_Rel) {
817 type = ELFW(R_TYPE)(rel->r_info);
818 gotplt_entry = gotplt_entry_type(type);
819 for_code = code_reloc(type);
820 /* We generate a non-lazy pointer for used undefined symbols
821 and for defined symbols that must have a place for their
822 address due to codegen (i.e. a reloc requiring a got slot). */
823 sym_index = ELFW(R_SYM)(rel->r_info);
824 sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
825 if (sym->st_shndx == SHN_UNDEF
826 || gotplt_entry == ALWAYS_GOTPLT_ENTRY) {
827 attr = get_sym_attr(s1, sym_index, 1);
828 if (!attr->dyn_index) {
829 attr->got_offset = s1->got->data_offset;
830 attr->plt_offset = -1;
831 attr->dyn_index = 1; /* used as flag */
832 section_ptr_add(s1->got, PTR_SIZE);
833 put_elf_reloc(s1->symtab, s1->got, attr->got_offset,
834 R_DATA_PTR, sym_index);
835 goti = tcc_realloc(goti, (mo->n_got + 1) * sizeof(*goti));
836 if (ELFW(ST_BIND)(sym->st_info) == STB_LOCAL) {
837 if (sym->st_shndx == SHN_UNDEF)
838 tcc_error("undefined local symbo: '%s'",
839 (char *) symtab_section->link->data + sym->st_name);
840 goti[mo->n_got++] = INDIRECT_SYMBOL_LOCAL;
841 } else {
842 goti[mo->n_got++] = mo->e2msym[sym_index];
843 if (sym->st_shndx == SHN_UNDEF
844 #ifdef TCC_TARGET_X86_64
845 && type == R_X86_64_GOTPCREL
846 #elif defined TCC_TARGET_ARM64
847 && type == R_AARCH64_ADR_GOT_PAGE
848 #endif
850 mo->bind =
851 tcc_realloc(mo->bind,
852 (mo->n_bind + 1) *
853 sizeof(struct bind));
854 mo->bind[mo->n_bind].section = s1->got->reloc->sh_info;
855 mo->bind[mo->n_bind].rel = *rel;
856 mo->bind[mo->n_bind].rel.r_offset = attr->got_offset;
857 mo->n_bind++;
858 s1->got->reloc->data_offset -= sizeof (ElfW_Rel);
862 if (for_code && sym->st_shndx == SHN_UNDEF) {
863 if (attr->plt_offset == -1) {
864 attr->plt_offset = mo->stubs->data_offset;
865 #ifdef TCC_TARGET_X86_64
866 if (type != R_X86_64_PLT32)
867 continue;
868 /* __stubs */
869 jmp = section_ptr_add(mo->stubs, 6);
870 jmp[0] = 0xff; /* jmpq *__la_symbol_ptr(%rip) */
871 jmp[1] = 0x25;
872 put_elf_reloca(s1->symtab, mo->stubs,
873 mo->stubs->data_offset - 4,
874 R_X86_64_PC32, mo->lasym,
875 mo->la_symbol_ptr->data_offset - 4);
877 /* __stub_helper */
878 bind_offset = mo->stub_helper->data_offset + 1;
879 jmp = section_ptr_add(mo->stub_helper, 10);
880 jmp[0] = 0x68; /* pushq $bind_offset */
881 jmp[5] = 0xe9; /* jmpq __stub_helper */
882 write32le(jmp + 6, -mo->stub_helper->data_offset);
884 /* __la_symbol_ptr */
885 la_symbol_offset = mo->la_symbol_ptr->data_offset;
886 put_elf_reloca(s1->symtab, mo->la_symbol_ptr,
887 mo->la_symbol_ptr->data_offset,
888 R_DATA_PTR, mo->helpsym,
889 mo->stub_helper->data_offset - 10);
890 section_ptr_add(mo->la_symbol_ptr, PTR_SIZE);
891 #elif defined TCC_TARGET_ARM64
892 if (type != R_AARCH64_CALL26)
893 continue;
894 /* __stubs */
895 jmp = section_ptr_add(mo->stubs, 12);
896 put_elf_reloca(s1->symtab, mo->stubs,
897 mo->stubs->data_offset - 12,
898 R_AARCH64_ADR_PREL_PG_HI21, mo->lasym,
899 mo->la_symbol_ptr->data_offset);
900 write32le(jmp, // adrp x16, __la_symbol_ptr@page
901 0x90000010);
902 put_elf_reloca(s1->symtab, mo->stubs,
903 mo->stubs->data_offset - 8,
904 R_AARCH64_LDST64_ABS_LO12_NC, mo->lasym,
905 mo->la_symbol_ptr->data_offset);
906 write32le(jmp + 4, // ldr x16,[x16, __la_symbol_ptr@pageoff]
907 0xf9400210);
908 write32le(jmp + 8, // br x16
909 0xd61f0200);
911 /* __stub_helper */
912 bind_offset = mo->stub_helper->data_offset + 8;
913 jmp = section_ptr_add(mo->stub_helper, 12);
914 write32le(jmp + 0, // ldr w16, l0
915 0x18000050);
916 write32le(jmp + 4, // b stubHelperHeader
917 0x14000000 +
918 ((-(mo->stub_helper->data_offset - 8) / 4) &
919 0x3ffffff));
920 write32le(jmp + 8, 0); // l0: .long bind_offset
922 /* __la_symbol_ptr */
923 la_symbol_offset = mo->la_symbol_ptr->data_offset;
924 put_elf_reloca(s1->symtab, mo->la_symbol_ptr,
925 mo->la_symbol_ptr->data_offset,
926 R_DATA_PTR, mo->helpsym,
927 mo->stub_helper->data_offset - 12);
928 section_ptr_add(mo->la_symbol_ptr, PTR_SIZE);
929 #endif
930 mo->s_lazy_bind =
931 tcc_realloc(mo->s_lazy_bind, (mo->n_lazy_bind + 1) *
932 sizeof(struct s_lazy_bind));
933 mo->s_lazy_bind[mo->n_lazy_bind].section =
934 mo->stub_helper->reloc->sh_info;
935 mo->s_lazy_bind[mo->n_lazy_bind].bind_offset =
936 bind_offset;
937 mo->s_lazy_bind[mo->n_lazy_bind].la_symbol_offset =
938 la_symbol_offset;
939 mo->s_lazy_bind[mo->n_lazy_bind].rel = *rel;
940 mo->s_lazy_bind[mo->n_lazy_bind].rel.r_offset =
941 attr->plt_offset;
942 mo->n_lazy_bind++;
943 pi = section_ptr_add(mo->indirsyms, sizeof(*pi));
944 *pi = mo->e2msym[sym_index];
945 mo->nr_plt++;
947 rel->r_info = ELFW(R_INFO)(mo->stubsym, type);
948 rel->r_addend += attr->plt_offset;
951 if (type == R_DATA_PTR) {
952 if (sym->st_shndx == SHN_UNDEF) {
953 mo->bind = tcc_realloc(mo->bind,
954 (mo->n_bind + 1) *
955 sizeof(struct bind));
956 mo->bind[mo->n_bind].section = s->sh_info;
957 mo->bind[mo->n_bind].rel = *rel;
958 mo->n_bind++;
960 else {
961 mo->s_rebase =
962 tcc_realloc(mo->s_rebase, (mo->n_rebase + 1) *
963 sizeof(struct s_rebase));
964 mo->s_rebase[mo->n_rebase].section = s->sh_info;
965 mo->s_rebase[mo->n_rebase].rel = *rel;
966 mo->n_rebase++;
971 pi = section_ptr_add(mo->indirsyms, mo->n_got * sizeof(*pi));
972 memcpy(pi, goti, mo->n_got * sizeof(*pi));
973 pi = section_ptr_add(mo->indirsyms, mo->nr_plt * sizeof(*pi));
974 memcpy(pi, mo->indirsyms->data, mo->nr_plt * sizeof(*pi));
975 tcc_free(goti);
977 #endif
979 static int check_symbols(TCCState *s1, struct macho *mo)
981 int sym_index, sym_end;
982 int ret = 0;
984 mo->ilocal = mo->iextdef = mo->iundef = -1;
985 sym_end = symtab_section->data_offset / sizeof(ElfW(Sym));
986 for (sym_index = 1; sym_index < sym_end; ++sym_index) {
987 int elf_index = ((struct nlist_64 *)mo->symtab->data + sym_index - 1)->n_value;
988 ElfW(Sym) *sym = (ElfW(Sym) *)symtab_section->data + elf_index;
989 const char *name = (char*)symtab_section->link->data + sym->st_name;
990 unsigned type = ELFW(ST_TYPE)(sym->st_info);
991 unsigned bind = ELFW(ST_BIND)(sym->st_info);
992 unsigned vis = ELFW(ST_VISIBILITY)(sym->st_other);
994 dprintf("%4d (%4d): %09lx %4d %4d %4d %3d %s\n",
995 sym_index, elf_index, (long)sym->st_value,
996 type, bind, vis, sym->st_shndx, name);
997 if (bind == STB_LOCAL) {
998 if (mo->ilocal == -1)
999 mo->ilocal = sym_index - 1;
1000 if (mo->iextdef != -1 || mo->iundef != -1)
1001 tcc_error("local syms after global ones");
1002 } else if (sym->st_shndx != SHN_UNDEF) {
1003 if (mo->iextdef == -1)
1004 mo->iextdef = sym_index - 1;
1005 if (mo->iundef != -1)
1006 tcc_error("external defined symbol after undefined");
1007 } else if (sym->st_shndx == SHN_UNDEF) {
1008 if (mo->iundef == -1)
1009 mo->iundef = sym_index - 1;
1010 if (ELFW(ST_BIND)(sym->st_info) == STB_WEAK
1011 || find_elf_sym(s1->dynsymtab_section, name)) {
1012 /* Mark the symbol as coming from a dylib so that
1013 relocate_syms doesn't complain. Normally bind_exe_dynsyms
1014 would do this check, and place the symbol into dynsym
1015 which is checked by relocate_syms. But Mach-O doesn't use
1016 bind_exe_dynsyms. */
1017 sym->st_shndx = SHN_FROMDLL;
1018 continue;
1020 tcc_error_noabort("undefined symbol '%s'", name);
1021 ret = -1;
1024 return ret;
1027 static void convert_symbol(TCCState *s1, struct macho *mo, struct nlist_64 *pn)
1029 struct nlist_64 n = *pn;
1030 ElfSym *sym = (ElfW(Sym) *)symtab_section->data + pn->n_value;
1031 const char *name = (char*)symtab_section->link->data + sym->st_name;
1032 switch(ELFW(ST_TYPE)(sym->st_info)) {
1033 case STT_NOTYPE:
1034 case STT_OBJECT:
1035 case STT_FUNC:
1036 case STT_SECTION:
1037 n.n_type = N_SECT;
1038 break;
1039 case STT_FILE:
1040 n.n_type = N_ABS;
1041 break;
1042 default:
1043 tcc_error("unhandled ELF symbol type %d %s",
1044 ELFW(ST_TYPE)(sym->st_info), name);
1046 if (sym->st_shndx == SHN_UNDEF)
1047 tcc_error("should have been rewritten to SHN_FROMDLL: %s", name);
1048 else if (sym->st_shndx == SHN_FROMDLL)
1049 n.n_type = N_UNDF, n.n_sect = 0;
1050 else if (sym->st_shndx == SHN_ABS)
1051 n.n_type = N_ABS, n.n_sect = 0;
1052 else if (sym->st_shndx >= SHN_LORESERVE)
1053 tcc_error("unhandled ELF symbol section %d %s", sym->st_shndx, name);
1054 else if (!mo->elfsectomacho[sym->st_shndx]) {
1055 if (strncmp(s1->sections[sym->st_shndx]->name, ".debug_", 7))
1056 tcc_error("ELF section %d(%s) not mapped into Mach-O for symbol %s",
1057 sym->st_shndx, s1->sections[sym->st_shndx]->name, name);
1059 else
1060 n.n_sect = mo->elfsectomacho[sym->st_shndx];
1061 if (ELFW(ST_BIND)(sym->st_info) == STB_GLOBAL)
1062 n.n_type |= N_EXT;
1063 else if (ELFW(ST_BIND)(sym->st_info) == STB_WEAK)
1064 n.n_desc |= N_WEAK_REF | (n.n_type != N_UNDF ? N_WEAK_DEF : 0);
1065 n.n_strx = pn->n_strx;
1066 n.n_value = sym->st_value;
1067 *pn = n;
1070 static void convert_symbols(TCCState *s1, struct macho *mo)
1072 struct nlist_64 *pn;
1073 for_each_elem(mo->symtab, 0, pn, struct nlist_64)
1074 convert_symbol(s1, mo, pn);
1077 static int machosymcmp(const void *_a, const void *_b, void *arg)
1079 TCCState *s1 = arg;
1080 int ea = ((struct nlist_64 *)_a)->n_value;
1081 int eb = ((struct nlist_64 *)_b)->n_value;
1082 ElfSym *sa = (ElfSym *)symtab_section->data + ea;
1083 ElfSym *sb = (ElfSym *)symtab_section->data + eb;
1084 int r;
1085 /* locals, then defined externals, then undefined externals, the
1086 last two sections also by name, otherwise stable sort */
1087 r = (ELFW(ST_BIND)(sb->st_info) == STB_LOCAL)
1088 - (ELFW(ST_BIND)(sa->st_info) == STB_LOCAL);
1089 if (r)
1090 return r;
1091 r = (sa->st_shndx == SHN_UNDEF) - (sb->st_shndx == SHN_UNDEF);
1092 if (r)
1093 return r;
1094 if (ELFW(ST_BIND)(sa->st_info) != STB_LOCAL) {
1095 const char * na = (char*)symtab_section->link->data + sa->st_name;
1096 const char * nb = (char*)symtab_section->link->data + sb->st_name;
1097 r = strcmp(na, nb);
1098 if (r)
1099 return r;
1101 return ea - eb;
1104 /* cannot use qsort because code has to be reentrant */
1105 static void tcc_qsort (void *base, size_t nel, size_t width,
1106 int (*comp)(const void *, const void *, void *), void *arg)
1108 size_t wnel, gap, wgap, i, j, k;
1109 char *a, *b, tmp;
1111 wnel = width * nel;
1112 for (gap = 0; ++gap < nel;)
1113 gap *= 3;
1114 while ( gap /= 3 ) {
1115 wgap = width * gap;
1116 for (i = wgap; i < wnel; i += width) {
1117 for (j = i - wgap; ;j -= wgap) {
1118 a = j + (char *)base;
1119 b = a + wgap;
1120 if ( (*comp)(a, b, arg) <= 0 )
1121 break;
1122 k = width;
1123 do {
1124 tmp = *a;
1125 *a++ = *b;
1126 *b++ = tmp;
1127 } while ( --k );
1128 if (j < wgap)
1129 break;
1135 static void create_symtab(TCCState *s1, struct macho *mo)
1137 int sym_index, sym_end;
1138 struct nlist_64 *pn;
1140 /* Stub creation belongs to check_relocs, but we need to create
1141 the symbol now, so its included in the sorting. */
1142 mo->stubs = new_section(s1, "__stubs", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR);
1143 s1->got = new_section(s1, ".got", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE);
1144 mo->stubsym = put_elf_sym(s1->symtab, 0, 0,
1145 ELFW(ST_INFO)(STB_LOCAL, STT_SECTION), 0,
1146 mo->stubs->sh_num, ".__stubs");
1147 #ifdef CONFIG_NEW_MACHO
1148 mo->chained_fixups = new_section(s1, "CHAINED_FIXUPS",
1149 SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE);
1150 #else
1151 mo->stub_helper = new_section(s1, "__stub_helper", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR);
1152 mo->la_symbol_ptr = new_section(s1, "__la_symbol_ptr", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE);
1153 mo->helpsym = put_elf_sym(s1->symtab, 0, 0,
1154 ELFW(ST_INFO)(STB_LOCAL, STT_SECTION), 0,
1155 mo->stub_helper->sh_num, ".__stub_helper");
1156 mo->lasym = put_elf_sym(s1->symtab, 0, 0,
1157 ELFW(ST_INFO)(STB_LOCAL, STT_SECTION), 0,
1158 mo->la_symbol_ptr->sh_num, ".__la_symbol_ptr");
1159 section_ptr_add(data_section, -data_section->data_offset & (PTR_SIZE - 1));
1160 mo->dyld_private = put_elf_sym(s1->symtab, data_section->data_offset, PTR_SIZE,
1161 ELFW(ST_INFO)(STB_LOCAL, STT_OBJECT), 0,
1162 data_section->sh_num, ".__dyld_private");
1163 section_ptr_add(data_section, PTR_SIZE);
1164 mo->dyld_stub_binder = put_elf_sym(s1->symtab, 0, 0,
1165 ELFW(ST_INFO)(STB_GLOBAL, STT_OBJECT), 0,
1166 SHN_UNDEF, "dyld_stub_binder");
1167 mo->rebase = new_section(s1, "REBASE", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE);
1168 mo->binding = new_section(s1, "BINDING", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE);
1169 mo->weak_binding = new_section(s1, "WEAK_BINDING", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE);
1170 mo->lazy_binding = new_section(s1, "LAZY_BINDING", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE);
1171 #endif
1172 mo->exports = new_section(s1, "EXPORT", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE);
1174 mo->symtab = new_section(s1, "LESYMTAB", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE);
1175 mo->strtab = new_section(s1, "LESTRTAB", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE);
1176 put_elf_str(mo->strtab, " "); /* Mach-O starts strtab with a space */
1177 sym_end = symtab_section->data_offset / sizeof(ElfW(Sym));
1178 pn = section_ptr_add(mo->symtab, sizeof(*pn) * (sym_end - 1));
1179 for (sym_index = 1; sym_index < sym_end; ++sym_index) {
1180 ElfW(Sym) *sym = (ElfW(Sym) *)symtab_section->data + sym_index;
1181 const char *name = (char*)symtab_section->link->data + sym->st_name;
1182 pn[sym_index - 1].n_strx = put_elf_str(mo->strtab, name);
1183 pn[sym_index - 1].n_value = sym_index;
1185 tcc_qsort(pn, sym_end - 1, sizeof(*pn), machosymcmp, s1);
1186 mo->e2msym = tcc_malloc(sym_end * sizeof(*mo->e2msym));
1187 mo->e2msym[0] = -1;
1188 for (sym_index = 1; sym_index < sym_end; ++sym_index) {
1189 mo->e2msym[pn[sym_index - 1].n_value] = sym_index - 1;
1193 const struct {
1194 int seg_initial;
1195 uint32_t flags;
1196 const char *name;
1197 } skinfo[sk_last] = {
1198 /*[sk_unknown] =*/ { 0 },
1199 /*[sk_discard] =*/ { 0 },
1200 /*[sk_text] =*/ { 1, S_REGULAR | S_ATTR_PURE_INSTRUCTIONS
1201 | S_ATTR_SOME_INSTRUCTIONS, "__text" },
1202 /*[sk_stubs] =*/ { 1, S_REGULAR | S_ATTR_PURE_INSTRUCTIONS | S_SYMBOL_STUBS
1203 | S_ATTR_SOME_INSTRUCTIONS , "__stubs" },
1204 /*[sk_stub_helper] =*/ { 1, S_REGULAR | S_ATTR_PURE_INSTRUCTIONS
1205 | S_ATTR_SOME_INSTRUCTIONS , "__stub_helper" },
1206 /*[sk_ro_data] =*/ { 2, S_REGULAR, "__rodata" },
1207 /*[sk_uw_info] =*/ { 0 },
1208 /*[sk_nl_ptr] =*/ { 2, S_NON_LAZY_SYMBOL_POINTERS, "__got" },
1209 /*[sk_debug_info] =*/ { 3, S_REGULAR | S_ATTR_DEBUG, "__debug_info" },
1210 /*[sk_debug_abbrev] =*/ { 3, S_REGULAR | S_ATTR_DEBUG, "__debug_abbrev" },
1211 /*[sk_debug_line] =*/ { 3, S_REGULAR | S_ATTR_DEBUG, "__debug_line" },
1212 /*[sk_debug_aranges] =*/ { 3, S_REGULAR | S_ATTR_DEBUG, "__debug_aranges" },
1213 /*[sk_debug_str] =*/ { 3, S_REGULAR | S_ATTR_DEBUG, "__debug_str" },
1214 /*[sk_debug_line_str] =*/ { 3, S_REGULAR | S_ATTR_DEBUG, "__debug_line_str" },
1215 /*[sk_stab] =*/ { 4, S_REGULAR, "__stab" },
1216 /*[sk_stab_str] =*/ { 4, S_REGULAR, "__stab_str" },
1217 /*[sk_la_ptr] =*/ { 4, S_LAZY_SYMBOL_POINTERS, "__la_symbol_ptr" },
1218 /*[sk_init] =*/ { 4, S_MOD_INIT_FUNC_POINTERS, "__mod_init_func" },
1219 /*[sk_fini] =*/ { 4, S_MOD_TERM_FUNC_POINTERS, "__mod_term_func" },
1220 /*[sk_rw_data] =*/ { 4, S_REGULAR, "__data" },
1221 /*[sk_bss] =*/ { 4, S_ZEROFILL, "__bss" },
1222 /*[sk_linkedit] =*/ { 5, S_REGULAR, NULL },
1225 #define START ((uint64_t)1 << 32)
1227 const struct {
1228 int used;
1229 const char *name;
1230 uint64_t vmaddr;
1231 uint64_t vmsize;
1232 vm_prot_t maxprot;
1233 vm_prot_t initprot;
1234 uint32_t flags;
1235 } all_segment[] = {
1236 { 1, "__PAGEZERO", 0, START, 0, 0, 0 },
1237 { 0, "__TEXT", START, 0, 5, 5, 0 },
1238 { 0, "__DATA_CONST", -1, 0, 3, 3, SG_READ_ONLY },
1239 { 0, "__DWARF", -1, 0, 7, 3, 0 },
1240 { 0, "__DATA", -1, 0, 3, 3, 0 },
1241 { 1, "__LINKEDIT", -1, 0, 1, 1, 0 },
1244 #define N_SEGMENT (sizeof(all_segment)/sizeof(all_segment[0]))
1246 #ifdef CONFIG_NEW_MACHO
1247 static void calc_fixup_size(TCCState *s1, struct macho *mo)
1249 int i, size;
1251 size = (sizeof(struct dyld_chained_fixups_header) + 7) & -8;
1252 size += (sizeof(struct dyld_chained_starts_in_image) + (mo->nseg - 1) * sizeof(uint32_t) + 7) & -8;
1253 for (i = 1; i < mo->nseg - 1; i++) {
1254 int page_count = (get_segment(mo, i)->vmsize + SEG_PAGE_SIZE - 1) / SEG_PAGE_SIZE;
1255 size += (sizeof(struct dyld_chained_starts_in_segment) + (page_count - 1) * sizeof(uint16_t) + 7) & -8;
1257 size += mo->n_bind * sizeof (struct dyld_chained_import) + 1;
1258 for (i = 0; i < mo->n_bind_rebase; i++) {
1259 if (mo->bind_rebase[i].bind) {
1260 int sym_index = ELFW(R_SYM)(mo->bind_rebase[i].rel.r_info);
1261 ElfW(Sym) *sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
1262 const char *name = (char *) symtab_section->link->data + sym->st_name;
1263 size += strlen(name) + 1;
1266 size = (size + 7) & -8;
1267 section_ptr_add(mo->chained_fixups, size);
1270 #else
1272 static void set_segment_and_offset(struct macho *mo, addr_t addr,
1273 uint8_t *ptr, int opcode,
1274 Section *sec, addr_t offset)
1276 int i;
1277 struct segment_command_64 *seg = NULL;
1279 for (i = 1; i < mo->nseg - 1; i++) {
1280 seg = get_segment(mo, i);
1281 if (addr >= seg->vmaddr && addr < (seg->vmaddr + seg->vmsize))
1282 break;
1284 *ptr = opcode | i;
1285 write_uleb128(sec, offset - seg->vmaddr);
1288 static void bind_rebase(TCCState *s1, struct macho *mo)
1290 int i;
1291 uint8_t *ptr;
1292 ElfW(Sym) *sym;
1293 const char *name;
1295 for (i = 0; i < mo->n_lazy_bind; i++) {
1296 int sym_index = ELFW(R_SYM)(mo->s_lazy_bind[i].rel.r_info);
1298 sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
1299 name = (char *) symtab_section->link->data + sym->st_name;
1300 write32le(mo->stub_helper->data +
1301 mo->s_lazy_bind[i].bind_offset,
1302 mo->lazy_binding->data_offset);
1303 ptr = section_ptr_add(mo->lazy_binding, 1);
1304 set_segment_and_offset(mo, mo->la_symbol_ptr->sh_addr, ptr,
1305 BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB,
1306 mo->lazy_binding,
1307 mo->s_lazy_bind[i].la_symbol_offset +
1308 mo->la_symbol_ptr->sh_addr);
1309 ptr = section_ptr_add(mo->lazy_binding, 5 + strlen(name));
1310 *ptr++ = BIND_OPCODE_SET_DYLIB_SPECIAL_IMM |
1311 (BIND_SPECIAL_DYLIB_FLAT_LOOKUP & 0xf);
1312 *ptr++ = BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM | 0;
1313 strcpy((char *)ptr, name);
1314 ptr += strlen(name) + 1;
1315 *ptr++ = BIND_OPCODE_DO_BIND;
1316 *ptr = BIND_OPCODE_DONE;
1318 for (i = 0; i < mo->n_rebase; i++) {
1319 Section *s = s1->sections[mo->s_rebase[i].section];
1321 ptr = section_ptr_add(mo->rebase, 2);
1322 *ptr++ = REBASE_OPCODE_SET_TYPE_IMM | REBASE_TYPE_POINTER;
1323 set_segment_and_offset(mo, s->sh_addr, ptr,
1324 REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB,
1325 mo->rebase,
1326 mo->s_rebase[i].rel.r_offset +
1327 s->sh_addr);
1328 ptr = section_ptr_add(mo->rebase, 1);
1329 *ptr = REBASE_OPCODE_DO_REBASE_IMM_TIMES | 1;
1331 for (i = 0; i < mo->n_bind; i++) {
1332 int sym_index = ELFW(R_SYM)(mo->bind[i].rel.r_info);
1333 Section *s = s1->sections[mo->bind[i].section];
1334 Section *binding;
1336 sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
1337 name = (char *) symtab_section->link->data + sym->st_name;
1338 binding = ELFW(ST_BIND)(sym->st_info) == STB_WEAK
1339 ? mo->weak_binding : mo->binding;
1340 ptr = section_ptr_add(binding, 5 + strlen(name));
1341 *ptr++ = BIND_OPCODE_SET_DYLIB_SPECIAL_IMM |
1342 (BIND_SPECIAL_DYLIB_FLAT_LOOKUP & 0xf);
1343 *ptr++ = BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM | 0;
1344 strcpy((char *)ptr, name);
1345 ptr += strlen(name) + 1;
1346 *ptr++ = BIND_OPCODE_SET_TYPE_IMM | BIND_TYPE_POINTER;
1347 set_segment_and_offset(mo, s->sh_addr, ptr,
1348 BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB,
1349 binding,
1350 mo->bind[i].rel.r_offset + s->sh_addr);
1351 ptr = section_ptr_add(binding, 1);
1352 *ptr++ = BIND_OPCODE_DO_BIND;
1354 if (mo->rebase->data_offset) {
1355 ptr = section_ptr_add(mo->rebase, 1);
1356 *ptr = REBASE_OPCODE_DONE;
1358 if (mo->binding->data_offset) {
1359 ptr = section_ptr_add(mo->binding, 1);
1360 *ptr = BIND_OPCODE_DONE;
1362 if (mo->weak_binding->data_offset) {
1363 ptr = section_ptr_add(mo->weak_binding, 1);
1364 *ptr = BIND_OPCODE_DONE;
1366 tcc_free(mo->s_lazy_bind);
1367 tcc_free(mo->s_rebase);
1368 tcc_free(mo->bind);
1370 #endif
1372 struct trie_info {
1373 const char *name;
1374 int flag;
1375 addr_t addr;
1376 int str_size;
1377 int term_size;
1380 struct trie_node {
1381 int start;
1382 int end;
1383 int index_start;
1384 int index_end;
1385 int n_child;
1386 struct trie_node *child;
1389 struct trie_seq {
1390 int n_child;
1391 struct trie_node *node;
1392 int offset;
1393 int nest_offset;
1396 static void create_trie(struct trie_node *node,
1397 int from, int to, int index_start,
1398 int n_trie, struct trie_info *trie)
1400 int i;
1401 int start, end, index_end;
1402 char cur;
1403 struct trie_node *child;
1405 for (i = from; i < to; i = end) {
1406 cur = trie[i].name[index_start];
1407 start = i++;
1408 for (; i < to; i++)
1409 if (cur != trie[i].name[index_start])
1410 break;
1411 end = i;
1412 if (start == end - 1 ||
1413 (trie[start].name[index_start] &&
1414 trie[start].name[index_start + 1] == 0))
1415 index_end = trie[start].str_size - 1;
1416 else {
1417 index_end = index_start + 1;
1418 for (;;) {
1419 cur = trie[start].name[index_end];
1420 for (i = start + 1; i < end; i++)
1421 if (cur != trie[i].name[index_end])
1422 break;
1423 if (trie[start].name[index_end] &&
1424 trie[start].name[index_end + 1] == 0) {
1425 end = start + 1;
1426 index_end = trie[start].str_size - 1;
1427 break;
1429 if (i != end)
1430 break;
1431 index_end++;
1434 node->child = tcc_realloc(node->child,
1435 (node->n_child + 1) *
1436 sizeof(struct trie_node));
1437 child = &node->child[node->n_child];
1438 child->start = start;
1439 child->end = end;
1440 child->index_start = index_start;
1441 child->index_end = index_end;
1442 child->n_child = 0;
1443 child->child = NULL;
1444 node->n_child++;
1445 if (start != end - 1)
1446 create_trie(child, start, end, index_end, n_trie, trie);
1450 static int create_seq(int *offset, int *n_seq, struct trie_seq **seq,
1451 struct trie_node *node,
1452 int n_trie, struct trie_info *trie)
1454 int i, nest_offset, last_seq = *n_seq, retval = *offset;
1455 struct trie_seq *p_seq;
1456 struct trie_node *p_nest;
1458 for (i = 0; i < node->n_child; i++) {
1459 p_nest = &node->child[i];
1460 *seq = tcc_realloc(*seq, (*n_seq + 1) * sizeof(struct trie_seq));
1461 p_seq = &(*seq)[(*n_seq)++];
1462 p_seq->n_child = i == 0 ? node->n_child : -1;
1463 p_seq->node = p_nest;
1464 p_seq->offset = *offset;
1465 p_seq->nest_offset = 0;
1466 *offset += (i == 0 ? 1 + 1 : 0) +
1467 p_nest->index_end - p_nest->index_start + 1 + 3;
1469 for (i = 0; i < node->n_child; i++) {
1470 nest_offset =
1471 create_seq(offset, n_seq, seq, &node->child[i], n_trie, trie);
1472 p_seq = &(*seq)[last_seq + i];
1473 p_seq->nest_offset = nest_offset;
1475 return retval;
1478 static void node_free(struct trie_node *node)
1480 int i;
1482 for (i = 0; i < node->n_child; i++)
1483 node_free(&node->child[i]);
1484 tcc_free(node->child);
1487 static int triecmp(const void *_a, const void *_b, void *arg)
1489 struct trie_info *a = (struct trie_info *) _a;
1490 struct trie_info *b = (struct trie_info *) _b;
1492 return strcmp(a->name, b->name);
1495 static void export_trie(TCCState *s1, struct macho *mo)
1497 int i, size, offset = 0, save_offset;
1498 uint8_t *ptr;
1499 int sym_index;
1500 int sym_end = symtab_section->data_offset / sizeof(ElfW(Sym));
1501 int n_trie = 0, n_seq = 0;
1502 struct trie_info *trie = NULL, *p_trie;
1503 struct trie_node node, *p_node;
1504 struct trie_seq *seq = NULL;
1505 addr_t vm_addr = get_segment(mo, 1)->vmaddr;
1507 for (sym_index = 1; sym_index < sym_end; ++sym_index) {
1508 ElfW(Sym) *sym = (ElfW(Sym) *)symtab_section->data + sym_index;
1509 const char *name = (char*)symtab_section->link->data + sym->st_name;
1511 if (sym->st_shndx == text_section->sh_num &&
1512 (ELFW(ST_BIND)(sym->st_info) == STB_GLOBAL ||
1513 ELFW(ST_BIND)(sym->st_info) == STB_WEAK)) {
1514 int flag = EXPORT_SYMBOL_FLAGS_KIND_REGULAR;
1515 addr_t addr =
1516 sym->st_value + s1->sections[sym->st_shndx]->sh_addr - vm_addr;
1518 if (ELFW(ST_BIND)(sym->st_info) == STB_WEAK)
1519 flag |= EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION;
1520 dprintf ("%s %d %llx\n", name, flag, addr + vm_addr);
1521 trie = tcc_realloc(trie, (n_trie + 1) * sizeof(struct trie_info));
1522 trie[n_trie].name = name;
1523 trie[n_trie].flag = flag;
1524 trie[n_trie].addr = addr;
1525 trie[n_trie].str_size = strlen(name) + 1;
1526 trie[n_trie].term_size = uleb128_size(flag) + uleb128_size(addr);
1527 n_trie++;
1530 if (n_trie) {
1531 tcc_qsort(trie, n_trie, sizeof(struct trie_info), triecmp, NULL);
1532 memset(&node, 0, sizeof(node));
1533 create_trie(&node, 0, n_trie, 0, n_trie, trie);
1534 create_seq(&offset, &n_seq, &seq, &node, n_trie, trie);
1535 save_offset = offset;
1536 for (i = 0; i < n_seq; i++) {
1537 p_node = seq[i].node;
1538 if (p_node->n_child == 0) {
1539 p_trie = &trie[p_node->start];
1540 seq[i].nest_offset = offset;
1541 offset += 1 + p_trie->term_size + 1;
1544 for (i = 0; i < n_seq; i++) {
1545 p_node = seq[i].node;
1546 p_trie = &trie[p_node->start];
1547 if (seq[i].n_child >= 0) {
1548 section_ptr_add(mo->exports,
1549 seq[i].offset - mo->exports->data_offset);
1550 ptr = section_ptr_add(mo->exports, 2);
1551 *ptr++ = 0;
1552 *ptr = seq[i].n_child;
1554 size = p_node->index_end - p_node->index_start;
1555 ptr = section_ptr_add(mo->exports, size + 1);
1556 memcpy(ptr, &p_trie->name[p_node->index_start], size);
1557 ptr[size] = 0;
1558 write_uleb128(mo->exports, seq[i].nest_offset);
1560 section_ptr_add(mo->exports, save_offset - mo->exports->data_offset);
1561 for (i = 0; i < n_seq; i++) {
1562 p_node = seq[i].node;
1563 if (p_node->n_child == 0) {
1564 p_trie = &trie[p_node->start];
1565 write_uleb128(mo->exports, p_trie->term_size);
1566 write_uleb128(mo->exports, p_trie->flag);
1567 write_uleb128(mo->exports, p_trie->addr);
1568 ptr = section_ptr_add(mo->exports, 1);
1569 *ptr = 0;
1572 section_ptr_add(mo->exports, -mo->exports->data_offset & 7);
1573 node_free(&node);
1574 tcc_free(seq);
1576 tcc_free(trie);
1579 static void collect_sections(TCCState *s1, struct macho *mo)
1581 int i, sk, numsec;
1582 int used_segment[N_SEGMENT];
1583 uint64_t curaddr, fileofs;
1584 Section *s;
1585 struct segment_command_64 *seg;
1586 #ifdef CONFIG_NEW_MACHO
1587 struct linkedit_data_command *chained_fixups_lc;
1588 struct linkedit_data_command *export_trie_lc;
1589 #endif
1590 struct build_version_command *dyldbv;
1591 struct source_version_command *dyldsv;
1592 struct dylinker_command *dyldlc;
1593 struct symtab_command *symlc;
1594 struct dysymtab_command *dysymlc;
1595 char *str;
1597 for (i = 0; i < N_SEGMENT; i++)
1598 used_segment[i] = all_segment[i].used;
1600 memset (mo->sk_to_sect, 0, sizeof(mo->sk_to_sect));
1601 for (i = s1->nb_sections; i-- > 1;) {
1602 int type, flags;
1603 s = s1->sections[i];
1604 type = s->sh_type;
1605 flags = s->sh_flags;
1606 sk = sk_unknown;
1607 /* debug sections have sometimes no SHF_ALLOC */
1608 if ((flags & SHF_ALLOC) || !strncmp(s->name, ".debug_", 7)) {
1609 switch (type) {
1610 default: sk = sk_unknown; break;
1611 case SHT_INIT_ARRAY: sk = sk_init; break;
1612 case SHT_FINI_ARRAY: sk = sk_fini; break;
1613 case SHT_NOBITS: sk = sk_bss; break;
1614 case SHT_SYMTAB: sk = sk_discard; break;
1615 case SHT_STRTAB:
1616 if (s == stabstr_section)
1617 sk = sk_stab_str;
1618 else
1619 sk = sk_discard;
1620 break;
1621 case SHT_RELX: sk = sk_discard; break;
1622 case SHT_LINKEDIT: sk = sk_linkedit; break;
1623 case SHT_PROGBITS:
1624 if (s == mo->stubs)
1625 sk = sk_stubs;
1626 #ifndef CONFIG_NEW_MACHO
1627 else if (s == mo->stub_helper)
1628 sk = sk_stub_helper;
1629 else if (s == mo->la_symbol_ptr)
1630 sk = sk_la_ptr;
1631 #endif
1632 else if (s == rodata_section)
1633 sk = sk_ro_data;
1634 else if (s == s1->got)
1635 sk = sk_nl_ptr;
1636 else if (s == stab_section)
1637 sk = sk_stab;
1638 else if (s == dwarf_info_section)
1639 sk = sk_debug_info;
1640 else if (s == dwarf_abbrev_section)
1641 sk = sk_debug_abbrev;
1642 else if (s == dwarf_line_section)
1643 sk = sk_debug_line;
1644 else if (s == dwarf_aranges_section)
1645 sk = sk_debug_aranges;
1646 else if (s == dwarf_str_section)
1647 sk = sk_debug_str;
1648 else if (s == dwarf_line_str_section)
1649 sk = sk_debug_line_str;
1650 else if (flags & SHF_EXECINSTR)
1651 sk = sk_text;
1652 else if (flags & SHF_WRITE)
1653 sk = sk_rw_data;
1654 else
1655 sk = sk_ro_data;
1656 break;
1658 } else
1659 sk = sk_discard;
1660 s->prev = mo->sk_to_sect[sk].s;
1661 mo->sk_to_sect[sk].s = s;
1662 used_segment[skinfo[sk].seg_initial] = 1;
1665 for (i = 0; i < N_SEGMENT; i++)
1666 if (used_segment[i]) {
1667 seg = add_segment(mo, all_segment[i].name);
1668 seg->vmaddr = all_segment[i].vmaddr;
1669 seg->vmsize = all_segment[i].vmsize;
1670 seg->maxprot = all_segment[i].maxprot;
1671 seg->initprot = all_segment[i].initprot;
1672 seg->flags = all_segment[i].flags;
1673 for (sk = sk_unknown; sk < sk_last; sk++)
1674 if (skinfo[sk].seg_initial == i)
1675 mo->segment[sk] = mo->nseg - 1;
1678 #ifdef CONFIG_NEW_MACHO
1679 chained_fixups_lc = add_lc(mo, LC_DYLD_CHAINED_FIXUPS,
1680 sizeof(struct linkedit_data_command));
1681 export_trie_lc = add_lc(mo, LC_DYLD_EXPORTS_TRIE,
1682 sizeof(struct linkedit_data_command));
1683 #else
1684 mo->dyldinfo = add_lc(mo, LC_DYLD_INFO_ONLY, sizeof(*mo->dyldinfo));
1685 #endif
1687 symlc = add_lc(mo, LC_SYMTAB, sizeof(*symlc));
1688 dysymlc = add_lc(mo, LC_DYSYMTAB, sizeof(*dysymlc));
1690 i = (sizeof(*dyldlc) + strlen("/usr/lib/dyld") + 1 + 7) &-8;
1691 dyldlc = add_lc(mo, LC_LOAD_DYLINKER, i);
1692 dyldlc->name = sizeof(*dyldlc);
1693 str = (char*)dyldlc + dyldlc->name;
1694 strcpy(str, "/usr/lib/dyld");
1696 dyldbv = add_lc(mo, LC_BUILD_VERSION, sizeof(*dyldbv));
1697 dyldbv->platform = PLATFORM_MACOS;
1698 dyldbv->minos = (10 << 16) + (6 << 8);
1699 dyldbv->sdk = (10 << 16) + (6 << 8);
1700 dyldbv->ntools = 0;
1702 dyldsv = add_lc(mo, LC_SOURCE_VERSION, sizeof(*dyldsv));
1703 dyldsv->version = 0;
1705 mo->ep = add_lc(mo, LC_MAIN, sizeof(*mo->ep));
1706 mo->ep->entryoff = 4096;
1708 for(i = 0; i < s1->nb_loaded_dlls; i++) {
1709 DLLReference *dllref = s1->loaded_dlls[i];
1710 if (dllref->level == 0)
1711 add_dylib(mo, dllref->name);
1714 fileofs = 4096; /* leave space for mach-o headers */
1715 curaddr = get_segment(mo, 1)->vmaddr;
1716 curaddr += 4096;
1717 seg = NULL;
1718 numsec = 0;
1719 mo->elfsectomacho = tcc_mallocz(sizeof(*mo->elfsectomacho) * s1->nb_sections);
1720 for (sk = sk_unknown; sk < sk_last; sk++) {
1721 struct section_64 *sec = NULL;
1722 if (seg) {
1723 seg->vmsize = curaddr - seg->vmaddr;
1724 seg->filesize = fileofs - seg->fileoff;
1726 #ifdef CONFIG_NEW_MACHO
1727 if (sk == sk_linkedit) {
1728 calc_fixup_size(s1, mo);
1729 export_trie(s1, mo);
1731 #else
1732 if (sk == sk_linkedit) {
1733 bind_rebase(s1, mo);
1734 export_trie(s1, mo);
1736 #endif
1737 if (mo->segment[sk] && mo->sk_to_sect[sk].s) {
1738 uint64_t al = 0;
1739 int si;
1740 seg = get_segment(mo, mo->segment[sk]);
1741 if (skinfo[sk].name) {
1742 si = add_section(mo, &seg, skinfo[sk].name);
1743 numsec++;
1744 mo->lc[mo->seg2lc[mo->segment[sk]]] = (struct load_command*)seg;
1745 mo->sk_to_sect[sk].machosect = si;
1746 sec = get_section(seg, si);
1747 sec->flags = skinfo[sk].flags;
1748 if (sk == sk_stubs)
1749 #ifdef TCC_TARGET_X86_64
1750 sec->reserved2 = 6;
1751 #elif defined TCC_TARGET_ARM64
1752 sec->reserved2 = 12;
1753 #endif
1754 if (sk == sk_nl_ptr)
1755 sec->reserved1 = mo->nr_plt;
1756 #ifndef CONFIG_NEW_MACHO
1757 if (sk == sk_la_ptr)
1758 sec->reserved1 = mo->nr_plt + mo->n_got;
1759 #endif
1761 if (seg->vmaddr == -1) {
1762 curaddr = (curaddr + SEG_PAGE_SIZE - 1) & -SEG_PAGE_SIZE;
1763 seg->vmaddr = curaddr;
1764 fileofs = (fileofs + SEG_PAGE_SIZE - 1) & -SEG_PAGE_SIZE;
1765 seg->fileoff = fileofs;
1768 for (s = mo->sk_to_sect[sk].s; s; s = s->prev) {
1769 int a = exact_log2p1(s->sh_addralign);
1770 if (a && al < (a - 1))
1771 al = a - 1;
1772 s->sh_size = s->data_offset;
1774 if (sec)
1775 sec->align = al;
1776 al = 1ULL << al;
1777 if (al > 4096)
1778 tcc_warning("alignment > 4096"), sec->align = 12, al = 4096;
1779 curaddr = (curaddr + al - 1) & -al;
1780 fileofs = (fileofs + al - 1) & -al;
1781 if (sec) {
1782 sec->addr = curaddr;
1783 sec->offset = fileofs;
1785 for (s = mo->sk_to_sect[sk].s; s; s = s->prev) {
1786 al = s->sh_addralign;
1787 curaddr = (curaddr + al - 1) & -al;
1788 dprintf("curaddr now 0x%lx\n", (long)curaddr);
1789 s->sh_addr = curaddr;
1790 curaddr += s->sh_size;
1791 if (s->sh_type != SHT_NOBITS) {
1792 fileofs = (fileofs + al - 1) & -al;
1793 s->sh_offset = fileofs;
1794 fileofs += s->sh_size;
1795 dprintf("fileofs now %ld\n", (long)fileofs);
1797 if (sec)
1798 mo->elfsectomacho[s->sh_num] = numsec;
1800 if (sec)
1801 sec->size = curaddr - sec->addr;
1803 if (DEBUG_MACHO)
1804 for (s = mo->sk_to_sect[sk].s; s; s = s->prev) {
1805 int type = s->sh_type;
1806 int flags = s->sh_flags;
1807 printf("%d section %-16s %-10s %09lx %04x %02d %s,%s,%s\n",
1809 s->name,
1810 type == SHT_PROGBITS ? "progbits" :
1811 type == SHT_NOBITS ? "nobits" :
1812 type == SHT_SYMTAB ? "symtab" :
1813 type == SHT_STRTAB ? "strtab" :
1814 type == SHT_INIT_ARRAY ? "init" :
1815 type == SHT_FINI_ARRAY ? "fini" :
1816 type == SHT_RELX ? "rel" : "???",
1817 (long)s->sh_addr,
1818 (unsigned)s->data_offset,
1819 s->sh_addralign,
1820 flags & SHF_ALLOC ? "alloc" : "",
1821 flags & SHF_WRITE ? "write" : "",
1822 flags & SHF_EXECINSTR ? "exec" : ""
1826 if (seg) {
1827 seg->vmsize = curaddr - seg->vmaddr;
1828 seg->filesize = fileofs - seg->fileoff;
1831 /* Fill symtab info */
1832 symlc->symoff = mo->symtab->sh_offset;
1833 symlc->nsyms = mo->symtab->data_offset / sizeof(struct nlist_64);
1834 symlc->stroff = mo->strtab->sh_offset;
1835 symlc->strsize = mo->strtab->data_offset;
1837 dysymlc->iundefsym = mo->iundef == -1 ? symlc->nsyms : mo->iundef;
1838 dysymlc->iextdefsym = mo->iextdef == -1 ? dysymlc->iundefsym : mo->iextdef;
1839 dysymlc->ilocalsym = mo->ilocal == -1 ? dysymlc->iextdefsym : mo->ilocal;
1840 dysymlc->nlocalsym = dysymlc->iextdefsym - dysymlc->ilocalsym;
1841 dysymlc->nextdefsym = dysymlc->iundefsym - dysymlc->iextdefsym;
1842 dysymlc->nundefsym = symlc->nsyms - dysymlc->iundefsym;
1843 dysymlc->indirectsymoff = mo->indirsyms->sh_offset;
1844 dysymlc->nindirectsyms = mo->indirsyms->data_offset / sizeof(uint32_t);
1846 #ifdef CONFIG_NEW_MACHO
1847 if (mo->chained_fixups->data_offset) {
1848 chained_fixups_lc->dataoff = mo->chained_fixups->sh_offset;
1849 chained_fixups_lc->datasize = mo->chained_fixups->data_offset;
1851 if (mo->exports->data_offset) {
1852 export_trie_lc->dataoff = mo->exports->sh_offset;
1853 export_trie_lc->datasize = mo->exports->data_offset;
1855 #else
1856 if (mo->rebase->data_offset) {
1857 mo->dyldinfo->rebase_off = mo->rebase->sh_offset;
1858 mo->dyldinfo->rebase_size = mo->rebase->data_offset;
1860 if (mo->binding->data_offset) {
1861 mo->dyldinfo->bind_off = mo->binding->sh_offset;
1862 mo->dyldinfo->bind_size = mo->binding->data_offset;
1864 if (mo->weak_binding->data_offset) {
1865 mo->dyldinfo->weak_bind_off = mo->weak_binding->sh_offset;
1866 mo->dyldinfo->weak_bind_size = mo->weak_binding->data_offset;
1868 if (mo->lazy_binding->data_offset) {
1869 mo->dyldinfo->lazy_bind_off = mo->lazy_binding->sh_offset;
1870 mo->dyldinfo->lazy_bind_size = mo->lazy_binding->data_offset;
1872 if (mo->exports->data_offset) {
1873 mo->dyldinfo->export_off = mo->exports->sh_offset;
1874 mo->dyldinfo->export_size = mo->exports->data_offset;
1876 #endif
1879 static void macho_write(TCCState *s1, struct macho *mo, FILE *fp)
1881 int i, sk;
1882 uint64_t fileofs = 0;
1883 Section *s;
1884 mo->mh.mh.magic = MH_MAGIC_64;
1885 #ifdef TCC_TARGET_X86_64
1886 mo->mh.mh.cputype = CPU_TYPE_X86_64;
1887 mo->mh.mh.cpusubtype = CPU_SUBTYPE_LIB64 | CPU_SUBTYPE_X86_ALL;
1888 #elif defined TCC_TARGET_ARM64
1889 mo->mh.mh.cputype = CPU_TYPE_ARM64;
1890 mo->mh.mh.cpusubtype = CPU_SUBTYPE_ARM64_ALL;
1891 #endif
1892 mo->mh.mh.filetype = MH_EXECUTE;
1893 mo->mh.mh.flags = MH_DYLDLINK | MH_PIE;
1894 mo->mh.mh.ncmds = mo->nlc;
1895 mo->mh.mh.sizeofcmds = 0;
1896 for (i = 0; i < mo->nlc; i++)
1897 mo->mh.mh.sizeofcmds += mo->lc[i]->cmdsize;
1899 fwrite(&mo->mh, 1, sizeof(mo->mh), fp);
1900 fileofs += sizeof(mo->mh);
1901 for (i = 0; i < mo->nlc; i++) {
1902 fwrite(mo->lc[i], 1, mo->lc[i]->cmdsize, fp);
1903 fileofs += mo->lc[i]->cmdsize;
1906 for (sk = sk_unknown; sk < sk_last; sk++) {
1907 //struct segment_command_64 *seg;
1908 if (!mo->segment[sk] || !mo->sk_to_sect[sk].s)
1909 continue;
1910 /*seg =*/ get_segment(mo, mo->segment[sk]);
1911 for (s = mo->sk_to_sect[sk].s; s; s = s->prev) {
1912 if (s->sh_type != SHT_NOBITS) {
1913 while (fileofs < s->sh_offset)
1914 fputc(0, fp), fileofs++;
1915 if (s->sh_size) {
1916 fwrite(s->data, 1, s->sh_size, fp);
1917 fileofs += s->sh_size;
1924 #ifdef CONFIG_NEW_MACHO
1925 static int bind_rebase_cmp(const void *_a, const void *_b, void *arg)
1927 TCCState *s1 = arg;
1928 struct bind_rebase *a = (struct bind_rebase *) _a;
1929 struct bind_rebase *b = (struct bind_rebase *) _b;
1930 addr_t aa = s1->sections[a->section]->sh_addr + a->rel.r_offset;
1931 addr_t ab = s1->sections[b->section]->sh_addr + b->rel.r_offset;
1933 return aa > ab ? 1 : aa < ab ? -1 : 0;
1936 ST_FUNC void bind_rebase_import(TCCState *s1, struct macho *mo)
1938 int i, j, k, bind_index, size, page_count, sym_index;
1939 const char *name;
1940 ElfW(Sym) *sym;
1941 unsigned char *data = mo->chained_fixups->data;
1942 struct segment_command_64 *seg;
1943 struct dyld_chained_fixups_header *header;
1944 struct dyld_chained_starts_in_image *image;
1945 struct dyld_chained_starts_in_segment *segment;
1946 struct dyld_chained_import *import;
1948 tcc_qsort(mo->bind_rebase, mo->n_bind_rebase, sizeof(struct bind_rebase),
1949 bind_rebase_cmp, s1);
1950 for (i = 0; i < mo->n_bind_rebase - 1; i++)
1951 if (mo->bind_rebase[i].section == mo->bind_rebase[i + 1].section &&
1952 mo->bind_rebase[i].rel.r_offset == mo->bind_rebase[i + 1].rel.r_offset) {
1953 sym_index = ELFW(R_SYM)(mo->bind_rebase[i].rel.r_info);
1954 sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
1955 name = (char *) symtab_section->link->data + sym->st_name;
1956 tcc_error("Overlap %s/%s %s:%s",
1957 mo->bind_rebase[i].bind ? "bind" : "rebase",
1958 mo->bind_rebase[i + 1].bind ? "bind" : "rebase",
1959 s1->sections[mo->bind_rebase[i].section]->name, name);
1961 header = (struct dyld_chained_fixups_header *) data;
1962 data += (sizeof(struct dyld_chained_fixups_header) + 7) & -8;
1963 header->starts_offset = data - mo->chained_fixups->data;
1964 header->imports_count = mo->n_bind;
1965 header->imports_format = DYLD_CHAINED_IMPORT;
1966 header->symbols_format = 0;
1967 size = sizeof(struct dyld_chained_starts_in_image) +
1968 (mo->nseg - 1) * sizeof(uint32_t);
1969 image = (struct dyld_chained_starts_in_image *) data;
1970 data += (size + 7) & -8;
1971 image->seg_count = mo->nseg;
1972 for (i = 1; i < mo->nseg - 1; i++) {
1973 image->seg_info_offset[i] = (data - mo->chained_fixups->data) -
1974 header->starts_offset;
1975 seg = get_segment(mo, i);
1976 page_count = (seg->vmsize + SEG_PAGE_SIZE - 1) / SEG_PAGE_SIZE;
1977 size = sizeof(struct dyld_chained_starts_in_segment) +
1978 (page_count - 1) * sizeof(uint16_t);
1979 segment = (struct dyld_chained_starts_in_segment *) data;
1980 data += (size + 7) & -8;
1981 segment->size = size;
1982 segment->page_size = SEG_PAGE_SIZE;
1983 #if 1
1984 #define PTR_64_OFFSET 0
1985 #define PTR_64_MASK 0x7FFFFFFFFFFULL
1986 segment->pointer_format = DYLD_CHAINED_PTR_64;
1987 #else
1988 #define PTR_64_OFFSET 0x100000000ULL
1989 #define PTR_64_MASK 0xFFFFFFFFFFFFFFULL
1990 segment->pointer_format = DYLD_CHAINED_PTR_64_OFFSET;
1991 #endif
1992 segment->segment_offset = seg->fileoff;
1993 segment->max_valid_pointer = 0;
1994 segment->page_count = page_count;
1995 // add bind/rebase
1996 bind_index = 0;
1997 k = 0;
1998 for (j = 0; j < page_count; j++) {
1999 addr_t start = seg->vmaddr + j * SEG_PAGE_SIZE;
2000 addr_t end = start + SEG_PAGE_SIZE;
2001 void *last;
2002 addr_t last_o = 0;
2003 addr_t cur_o, cur;
2004 struct dyld_chained_ptr_64_rebase *rebase;
2005 struct dyld_chained_ptr_64_bind *bind;
2007 segment->page_start[j] = DYLD_CHAINED_PTR_START_NONE;
2008 for (; k < mo->n_bind_rebase; k++) {
2009 Section *s = s1->sections[mo->bind_rebase[k].section];
2010 addr_t r_offset = mo->bind_rebase[k].rel.r_offset;
2011 addr_t addr = s->sh_addr + r_offset;
2013 if ((addr & 3) ||
2014 (addr & (SEG_PAGE_SIZE - 1)) > SEG_PAGE_SIZE - PTR_SIZE)
2015 tcc_error("Illegal rel_offset %s %lld",
2016 s->name, (long long)r_offset);
2017 if (addr >= end)
2018 break;
2019 if (addr >= start) {
2020 cur_o = addr - start;
2021 if (mo->bind_rebase[k].bind) {
2022 if (segment->page_start[j] == DYLD_CHAINED_PTR_START_NONE)
2023 segment->page_start[j] = cur_o;
2024 else {
2025 bind = (struct dyld_chained_ptr_64_bind *) last;
2026 bind->next = (cur_o - last_o) / 4;
2028 bind = (struct dyld_chained_ptr_64_bind *)
2029 (s->data + r_offset);
2030 last = bind;
2031 last_o = cur_o;
2032 bind->ordinal = bind_index;
2033 bind->addend = 0;
2034 bind->reserved = 0;
2035 bind->next = 0;
2036 bind->bind = 1;
2038 else {
2039 if (segment->page_start[j] == DYLD_CHAINED_PTR_START_NONE)
2040 segment->page_start[j] = cur_o;
2041 else {
2042 rebase = (struct dyld_chained_ptr_64_rebase *) last;
2043 rebase->next = (cur_o - last_o) / 4;
2045 rebase = (struct dyld_chained_ptr_64_rebase *)
2046 (s->data + r_offset);
2047 last = rebase;
2048 last_o = cur_o;
2049 cur = (*(uint64_t *) (s->data + r_offset)) -
2050 PTR_64_OFFSET;
2051 rebase->target = cur & PTR_64_MASK;
2052 rebase->high8 = cur >> (64 - 8);
2053 if (cur != ((uint64_t)rebase->high8 << (64 - 8)) + rebase->target)
2054 tcc_error("rebase error");
2055 rebase->reserved = 0;
2056 rebase->next = 0;
2057 rebase->bind = 0;
2060 bind_index += mo->bind_rebase[k].bind;
2064 // add imports
2065 header->imports_offset = data - mo->chained_fixups->data;
2066 import = (struct dyld_chained_import *) data;
2067 data += mo->n_bind * sizeof (struct dyld_chained_import);
2068 header->symbols_offset = data - mo->chained_fixups->data;
2069 data++;
2070 for (i = 0, bind_index = 0; i < mo->n_bind_rebase; i++) {
2071 if (mo->bind_rebase[i].bind) {
2072 import[bind_index].lib_ordinal =
2073 BIND_SPECIAL_DYLIB_FLAT_LOOKUP & 0xffu;
2074 import[bind_index].name_offset =
2075 (data - mo->chained_fixups->data) - header->symbols_offset;
2076 sym_index = ELFW(R_SYM)(mo->bind_rebase[i].rel.r_info);
2077 sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
2078 import[bind_index].weak_import =
2079 ELFW(ST_BIND)(sym->st_info) == STB_WEAK;
2080 name = (char *) symtab_section->link->data + sym->st_name;
2081 strcpy((char *) data, name);
2082 data += strlen(name) + 1;
2083 bind_index++;
2086 tcc_free(mo->bind_rebase);
2088 #endif
2090 ST_FUNC int macho_output_file(TCCState *s1, const char *filename)
2092 int fd, mode, file_type;
2093 FILE *fp;
2094 int i, ret = -1;
2095 struct macho mo;
2097 (void)memset(&mo, 0, sizeof(mo));
2099 file_type = s1->output_type;
2100 if (file_type == TCC_OUTPUT_OBJ)
2101 mode = 0666;
2102 else
2103 mode = 0777;
2104 unlink(filename);
2105 fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, mode);
2106 if (fd < 0 || (fp = fdopen(fd, "wb")) == NULL) {
2107 tcc_error_noabort("could not write '%s: %s'", filename, strerror(errno));
2108 return -1;
2110 if (s1->verbose)
2111 printf("<- %s\n", filename);
2113 tcc_add_runtime(s1);
2114 tcc_macho_add_destructor(s1);
2115 resolve_common_syms(s1);
2116 create_symtab(s1, &mo);
2117 check_relocs(s1, &mo);
2118 ret = check_symbols(s1, &mo);
2119 if (!ret) {
2120 collect_sections(s1, &mo);
2121 relocate_syms(s1, s1->symtab, 0);
2122 mo.ep->entryoff = get_sym_addr(s1, "main", 1, 1)
2123 - get_segment(&mo, 1)->vmaddr;
2124 if (s1->nb_errors)
2125 goto do_ret;
2126 relocate_sections(s1);
2127 #ifdef CONFIG_NEW_MACHO
2128 bind_rebase_import(s1, &mo);
2129 #endif
2130 convert_symbols(s1, &mo);
2131 macho_write(s1, &mo, fp);
2134 do_ret:
2135 for (i = 0; i < mo.nlc; i++)
2136 tcc_free(mo.lc[i]);
2137 tcc_free(mo.seg2lc);
2138 tcc_free(mo.lc);
2139 tcc_free(mo.elfsectomacho);
2140 tcc_free(mo.e2msym);
2142 fclose(fp);
2143 #ifdef CONFIG_CODESIGN
2145 char command[1024];
2146 int retval;
2148 snprintf(command, sizeof(command), "codesign -f -s - %s", filename);
2149 retval = system (command);
2150 if (retval == -1 || !(WIFEXITED(retval) && WEXITSTATUS(retval) == 0))
2151 tcc_error ("command failed '%s'", command);
2153 #endif
2154 return ret;
2157 static uint32_t macho_swap32(uint32_t x)
2159 return (x >> 24) | (x << 24) | ((x >> 8) & 0xff00) | ((x & 0xff00) << 8);
2161 #define SWAP(x) (swap ? macho_swap32(x) : (x))
2162 #define tbd_parse_movepast(s) \
2163 (pos = (pos = strstr(pos, s)) ? pos + strlen(s) : NULL)
2164 #define tbd_parse_movetoany(cs) (pos = strpbrk(pos, cs))
2165 #define tbd_parse_skipws while (*pos && (*pos==' '||*pos=='\n')) ++pos
2166 #define tbd_parse_tramplequote if(*pos=='\''||*pos=='"') tbd_parse_trample
2167 #define tbd_parse_tramplespace if(*pos==' ') tbd_parse_trample
2168 #define tbd_parse_trample *pos++=0
2170 #ifdef TCC_IS_NATIVE
2171 /* Looks for the active developer SDK set by xcode-select (or the default
2172 one set during installation.) */
2173 ST_FUNC void tcc_add_macos_sdkpath(TCCState* s)
2175 char *sdkroot = NULL, *pos = NULL;
2176 void* xcs = dlopen("libxcselect.dylib", RTLD_GLOBAL | RTLD_LAZY);
2177 CString path;
2178 int (*f)(unsigned int, char**) = dlsym(xcs, "xcselect_host_sdk_path");
2179 cstr_new(&path);
2180 if (f) f(1, &sdkroot);
2181 if (sdkroot)
2182 pos = strstr(sdkroot,"SDKs/MacOSX");
2183 if (pos)
2184 cstr_printf(&path, "%.*s.sdk/usr/lib", (int)(pos - sdkroot + 11), sdkroot);
2185 /* must use free from libc directly */
2186 #pragma push_macro("free")
2187 #undef free
2188 free(sdkroot);
2189 #pragma pop_macro("free")
2190 if (path.size)
2191 tcc_add_library_path(s, (char*)path.data);
2192 else
2193 tcc_add_library_path(s,
2194 "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib"
2195 ":" "/Applications/Xcode.app/Developer/SDKs/MacOSX.sdk/usr/lib"
2197 cstr_free(&path);
2200 ST_FUNC const char* macho_tbd_soname(const char* filename) {
2201 char *soname, *data, *pos;
2202 const char *ret = filename;
2204 int fd = open(filename,O_RDONLY);
2205 if (fd<0) return ret;
2206 pos = data = tcc_load_text(fd);
2207 if (!tbd_parse_movepast("install-name: ")) goto the_end;
2208 tbd_parse_skipws;
2209 tbd_parse_tramplequote;
2210 soname = pos;
2211 if (!tbd_parse_movetoany("\n \"'")) goto the_end;
2212 tbd_parse_trample;
2213 ret = tcc_strdup(soname);
2214 the_end:
2215 tcc_free(data);
2216 return ret;
2218 #endif /* TCC_IS_NATIVE */
2220 ST_FUNC int macho_load_tbd(TCCState* s1, int fd, const char* filename, int lev)
2222 char *soname, *data, *pos;
2223 int ret = -1;
2225 pos = data = tcc_load_text(fd);
2226 if (!tbd_parse_movepast("install-name: ")) goto the_end;
2227 tbd_parse_skipws;
2228 tbd_parse_tramplequote;
2229 soname = pos;
2230 if (!tbd_parse_movetoany("\n \"'")) goto the_end;
2231 tbd_parse_trample;
2232 ret = 0;
2233 if (tcc_add_dllref(s1, soname, lev)->found)
2234 goto the_end;
2235 while(pos) {
2236 char* sym = NULL;
2237 int cont = 1;
2238 if (!tbd_parse_movepast("symbols: ")) break;
2239 if (!tbd_parse_movepast("[")) break;
2240 while (cont) {
2241 tbd_parse_skipws;
2242 tbd_parse_tramplequote;
2243 sym = pos;
2244 if (!tbd_parse_movetoany(",] \"'")) break;
2245 tbd_parse_tramplequote;
2246 tbd_parse_tramplespace;
2247 tbd_parse_skipws;
2248 if (*pos==0||*pos==']') cont=0;
2249 tbd_parse_trample;
2250 set_elf_sym(s1->dynsymtab_section, 0, 0,
2251 ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, SHN_UNDEF, sym);
2255 the_end:
2256 tcc_free(data);
2257 return ret;
2260 ST_FUNC int macho_load_dll(TCCState * s1, int fd, const char* filename, int lev)
2262 unsigned char buf[sizeof(struct mach_header_64)];
2263 void *buf2;
2264 uint32_t machofs = 0;
2265 struct fat_header fh;
2266 struct mach_header mh;
2267 struct load_command *lc;
2268 int i, swap = 0;
2269 const char *soname = filename;
2270 struct nlist_64 *symtab = 0;
2271 uint32_t nsyms = 0;
2272 char *strtab = 0;
2273 uint32_t strsize = 0;
2274 uint32_t iextdef = 0;
2275 uint32_t nextdef = 0;
2277 again:
2278 if (full_read(fd, buf, sizeof(buf)) != sizeof(buf))
2279 return -1;
2280 memcpy(&fh, buf, sizeof(fh));
2281 if (fh.magic == FAT_MAGIC || fh.magic == FAT_CIGAM) {
2282 struct fat_arch *fa = load_data(fd, sizeof(fh),
2283 fh.nfat_arch * sizeof(*fa));
2284 swap = fh.magic == FAT_CIGAM;
2285 for (i = 0; i < SWAP(fh.nfat_arch); i++)
2286 #ifdef TCC_TARGET_X86_64
2287 if (SWAP(fa[i].cputype) == CPU_TYPE_X86_64
2288 && SWAP(fa[i].cpusubtype) == CPU_SUBTYPE_X86_ALL)
2289 #elif defined TCC_TARGET_ARM64
2290 if (SWAP(fa[i].cputype) == CPU_TYPE_ARM64
2291 && SWAP(fa[i].cpusubtype) == CPU_SUBTYPE_ARM64_ALL)
2292 #endif
2293 break;
2294 if (i == SWAP(fh.nfat_arch)) {
2295 tcc_free(fa);
2296 return -1;
2298 machofs = SWAP(fa[i].offset);
2299 tcc_free(fa);
2300 lseek(fd, machofs, SEEK_SET);
2301 goto again;
2302 } else if (fh.magic == FAT_MAGIC_64 || fh.magic == FAT_CIGAM_64) {
2303 tcc_warning("%s: Mach-O fat 64bit files of type 0x%x not handled",
2304 filename, fh.magic);
2305 return -1;
2308 memcpy(&mh, buf, sizeof(mh));
2309 if (mh.magic != MH_MAGIC_64)
2310 return -1;
2311 dprintf("found Mach-O at %d\n", machofs);
2312 buf2 = load_data(fd, machofs + sizeof(struct mach_header_64), mh.sizeofcmds);
2313 for (i = 0, lc = buf2; i < mh.ncmds; i++) {
2314 dprintf("lc %2d: 0x%08x\n", i, lc->cmd);
2315 switch (lc->cmd) {
2316 case LC_SYMTAB:
2318 struct symtab_command *sc = (struct symtab_command*)lc;
2319 nsyms = sc->nsyms;
2320 symtab = load_data(fd, machofs + sc->symoff, nsyms * sizeof(*symtab));
2321 strsize = sc->strsize;
2322 strtab = load_data(fd, machofs + sc->stroff, strsize);
2323 break;
2325 case LC_ID_DYLIB:
2327 struct dylib_command *dc = (struct dylib_command*)lc;
2328 soname = (char*)lc + dc->name;
2329 dprintf(" ID_DYLIB %d 0x%x 0x%x %s\n",
2330 dc->timestamp, dc->current_version,
2331 dc->compatibility_version, soname);
2332 break;
2334 case LC_REEXPORT_DYLIB:
2336 struct dylib_command *dc = (struct dylib_command*)lc;
2337 char *name = (char*)lc + dc->name;
2338 int subfd = open(name, O_RDONLY | O_BINARY);
2339 dprintf(" REEXPORT %s\n", name);
2340 if (subfd < 0)
2341 tcc_warning("can't open %s (reexported from %s)", name, filename);
2342 else {
2343 /* Hopefully the REEXPORTs never form a cycle, we don't check
2344 for that! */
2345 macho_load_dll(s1, subfd, name, lev + 1);
2346 close(subfd);
2348 break;
2350 case LC_DYSYMTAB:
2352 struct dysymtab_command *dc = (struct dysymtab_command*)lc;
2353 iextdef = dc->iextdefsym;
2354 nextdef = dc->nextdefsym;
2355 break;
2358 lc = (struct load_command*) ((char*)lc + lc->cmdsize);
2361 if (tcc_add_dllref(s1, soname, lev)->found)
2362 goto the_end;
2364 if (!nsyms || !nextdef)
2365 tcc_warning("%s doesn't export any symbols?", filename);
2367 //dprintf("symbols (all):\n");
2368 dprintf("symbols (exported):\n");
2369 dprintf(" n: typ sec desc value name\n");
2370 //for (i = 0; i < nsyms; i++) {
2371 for (i = iextdef; i < iextdef + nextdef; i++) {
2372 struct nlist_64 *sym = symtab + i;
2373 dprintf("%5d: %3d %3d 0x%04x 0x%016lx %s\n",
2374 i, sym->n_type, sym->n_sect, sym->n_desc, (long)sym->n_value,
2375 strtab + sym->n_strx);
2376 set_elf_sym(s1->dynsymtab_section, 0, 0,
2377 ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE),
2378 0, SHN_UNDEF, strtab + sym->n_strx);
2381 the_end:
2382 tcc_free(strtab);
2383 tcc_free(symtab);
2384 tcc_free(buf2);
2385 return 0;