tccelf: avoid find_section() for known section
[tinycc.git] / tccmacho.c
blob333a50e2d04010b9e8b1f3009babd40c4b90b5ff
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 typedef int vm_prot_t;
117 struct segment_command_64 { /* for 64-bit architectures */
118 uint32_t cmd; /* LC_SEGMENT_64 */
119 uint32_t cmdsize; /* includes sizeof section_64 structs */
120 char segname[16]; /* segment name */
121 uint64_t vmaddr; /* memory address of this segment */
122 uint64_t vmsize; /* memory size of this segment */
123 uint64_t fileoff; /* file offset of this segment */
124 uint64_t filesize; /* amount to map from the file */
125 vm_prot_t maxprot; /* maximum VM protection */
126 vm_prot_t initprot; /* initial VM protection */
127 uint32_t nsects; /* number of sections in segment */
128 uint32_t flags; /* flags */
131 struct section_64 { /* for 64-bit architectures */
132 char sectname[16]; /* name of this section */
133 char segname[16]; /* segment this section goes in */
134 uint64_t addr; /* memory address of this section */
135 uint64_t size; /* size in bytes of this section */
136 uint32_t offset; /* file offset of this section */
137 uint32_t align; /* section alignment (power of 2) */
138 uint32_t reloff; /* file offset of relocation entries */
139 uint32_t nreloc; /* number of relocation entries */
140 uint32_t flags; /* flags (section type and attributes)*/
141 uint32_t reserved1; /* reserved (for offset or index) */
142 uint32_t reserved2; /* reserved (for count or sizeof) */
143 uint32_t reserved3; /* reserved */
146 enum {
147 DYLD_CHAINED_IMPORT = 1,
150 struct dyld_chained_fixups_header {
151 uint32_t fixups_version; ///< 0
152 uint32_t starts_offset; ///< Offset of dyld_chained_starts_in_image.
153 uint32_t imports_offset; ///< Offset of imports table in chain_data.
154 uint32_t symbols_offset; ///< Offset of symbol strings in chain_data.
155 uint32_t imports_count; ///< Number of imported symbol names.
156 uint32_t imports_format; ///< DYLD_CHAINED_IMPORT*
157 uint32_t symbols_format; ///< 0 => uncompressed, 1 => zlib compressed
160 struct dyld_chained_starts_in_image
162 uint32_t seg_count;
163 uint32_t seg_info_offset[1]; // each entry is offset into this struct for that segment
164 // followed by pool of dyld_chain_starts_in_segment data
167 enum {
168 DYLD_CHAINED_PTR_64 = 2, // target is vmaddr
169 DYLD_CHAINED_PTR_64_OFFSET = 6, // target is vm offset
172 enum {
173 DYLD_CHAINED_PTR_START_NONE = 0xFFFF, // used in page_start[] to denote a page with no fixups
176 #define SEG_PAGE_SIZE 16384
178 struct dyld_chained_starts_in_segment
180 uint32_t size; // size of this (amount kernel needs to copy)
181 uint16_t page_size; // 0x1000 or 0x4000
182 uint16_t pointer_format; // DYLD_CHAINED_PTR_*
183 uint64_t segment_offset; // offset in memory to start of segment
184 uint32_t max_valid_pointer; // for 32-bit OS, any value beyond this is not a pointer
185 uint16_t page_count; // how many pages are in array
186 uint16_t page_start[1]; // each entry is offset in each page of first element in chain
187 // or DYLD_CHAINED_PTR_START_NONE if no fixups on page
190 enum BindSpecialDylib {
191 BIND_SPECIAL_DYLIB_FLAT_LOOKUP = -2,
194 struct dyld_chained_import
196 uint32_t lib_ordinal : 8,
197 weak_import : 1,
198 name_offset : 23;
201 struct dyld_chained_ptr_64_rebase
203 uint64_t target : 36, // vmaddr, 64GB max image size
204 high8 : 8, // top 8 bits set to this after slide added
205 reserved : 7, // all zeros
206 next : 12, // 4-byte stride
207 bind : 1; // == 0
210 struct dyld_chained_ptr_64_bind
212 uint64_t ordinal : 24,
213 addend : 8, // 0 thru 255
214 reserved : 19, // all zeros
215 next : 12, // 4-byte stride
216 bind : 1; // == 1
219 #define S_REGULAR 0x0
220 #define S_ZEROFILL 0x1
221 #define S_NON_LAZY_SYMBOL_POINTERS 0x6
222 #define S_LAZY_SYMBOL_POINTERS 0x7
223 #define S_SYMBOL_STUBS 0x8
224 #define S_MOD_INIT_FUNC_POINTERS 0x9
225 #define S_MOD_TERM_FUNC_POINTERS 0xa
227 #define S_ATTR_PURE_INSTRUCTIONS 0x80000000
228 #define S_ATTR_SOME_INSTRUCTIONS 0x00000400
230 typedef uint32_t lc_str;
232 struct dylib_command {
233 uint32_t cmd; /* LC_ID_DYLIB, LC_LOAD_{,WEAK_}DYLIB,
234 LC_REEXPORT_DYLIB */
235 uint32_t cmdsize; /* includes pathname string */
236 lc_str name; /* library's path name */
237 uint32_t timestamp; /* library's build time stamp */
238 uint32_t current_version; /* library's current version number */
239 uint32_t compatibility_version; /* library's compatibility vers number*/
242 struct dylinker_command {
243 uint32_t cmd; /* LC_ID_DYLINKER, LC_LOAD_DYLINKER or
244 LC_DYLD_ENVIRONMENT */
245 uint32_t cmdsize; /* includes pathname string */
246 lc_str name; /* dynamic linker's path name */
249 struct linkedit_data_command {
250 uint32_t cmd; /* LC_CODE_SIGNATURE, LC_SEGMENT_SPLIT_INFO,
251 LC_FUNCTION_STARTS, LC_DATA_IN_CODE,
252 LC_DYLIB_CODE_SIGN_DRS,
253 LC_LINKER_OPTIMIZATION_HINT,
254 LC_DYLD_EXPORTS_TRIE, or
255 LC_DYLD_CHAINED_FIXUPS. */
256 uint32_t cmdsize; /* sizeof(struct linkedit_data_command) */
257 uint32_t dataoff; /* file offset of data in __LINKEDIT segment */
258 uint32_t datasize; /* file size of data in __LINKEDIT segment */
261 #define PLATFORM_MACOS 1
263 struct build_version_command {
264 uint32_t cmd; /* LC_BUILD_VERSION */
265 uint32_t cmdsize; /* sizeof(struct build_version_command) plus */
266 /* ntools * sizeof(struct build_tool_version) */
267 uint32_t platform; /* platform */
268 uint32_t minos; /* X.Y.Z is encoded in nibbles xxxx.yy.zz */
269 uint32_t sdk; /* X.Y.Z is encoded in nibbles xxxx.yy.zz */
270 uint32_t ntools; /* number of tool entries following this */
273 struct source_version_command {
274 uint32_t cmd; /* LC_SOURCE_VERSION */
275 uint32_t cmdsize; /* 16 */
276 uint64_t version; /* A.B.C.D.E packed as a24.b10.c10.d10.e10 */
279 struct symtab_command {
280 uint32_t cmd; /* LC_SYMTAB */
281 uint32_t cmdsize; /* sizeof(struct symtab_command) */
282 uint32_t symoff; /* symbol table offset */
283 uint32_t nsyms; /* number of symbol table entries */
284 uint32_t stroff; /* string table offset */
285 uint32_t strsize; /* string table size in bytes */
288 struct dysymtab_command {
289 uint32_t cmd; /* LC_DYSYMTAB */
290 uint32_t cmdsize; /* sizeof(struct dysymtab_command) */
292 uint32_t ilocalsym; /* index to local symbols */
293 uint32_t nlocalsym; /* number of local symbols */
295 uint32_t iextdefsym;/* index to externally defined symbols */
296 uint32_t nextdefsym;/* number of externally defined symbols */
298 uint32_t iundefsym; /* index to undefined symbols */
299 uint32_t nundefsym; /* number of undefined symbols */
301 uint32_t tocoff; /* file offset to table of contents */
302 uint32_t ntoc; /* number of entries in table of contents */
304 uint32_t modtaboff; /* file offset to module table */
305 uint32_t nmodtab; /* number of module table entries */
307 uint32_t extrefsymoff; /* offset to referenced symbol table */
308 uint32_t nextrefsyms; /* number of referenced symbol table entries */
310 uint32_t indirectsymoff;/* file offset to the indirect symbol table */
311 uint32_t nindirectsyms; /* number of indirect symbol table entries */
313 uint32_t extreloff; /* offset to external relocation entries */
314 uint32_t nextrel; /* number of external relocation entries */
315 uint32_t locreloff; /* offset to local relocation entries */
316 uint32_t nlocrel; /* number of local relocation entries */
319 #define BIND_OPCODE_DONE 0x00
320 #define BIND_OPCODE_SET_DYLIB_SPECIAL_IMM 0x30
321 #define BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM 0x40
322 #define BIND_OPCODE_SET_TYPE_IMM 0x50
323 #define BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB 0x70
324 #define BIND_OPCODE_DO_BIND 0x90
326 #define BIND_TYPE_POINTER 1
327 #define BIND_SPECIAL_DYLIB_FLAT_LOOKUP -2
329 #define REBASE_OPCODE_DONE 0x00
330 #define REBASE_OPCODE_SET_TYPE_IMM 0x10
331 #define REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB 0x20
332 #define REBASE_OPCODE_DO_REBASE_IMM_TIMES 0x50
334 #define REBASE_TYPE_POINTER 1
336 #define EXPORT_SYMBOL_FLAGS_KIND_REGULAR 0x00
337 #define EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE 0x02
338 #define EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION 0x04
340 struct dyld_info_command {
341 uint32_t cmd; /* LC_DYLD_INFO or LC_DYLD_INFO_ONLY */
342 uint32_t cmdsize; /* sizeof(struct dyld_info_command) */
343 uint32_t rebase_off; /* file offset to rebase info */
344 uint32_t rebase_size; /* size of rebase info */
345 uint32_t bind_off; /* file offset to binding info */
346 uint32_t bind_size; /* size of binding info */
347 uint32_t weak_bind_off; /* file offset to weak binding info */
348 uint32_t weak_bind_size; /* size of weak binding info */
349 uint32_t lazy_bind_off; /* file offset to lazy binding info */
350 uint32_t lazy_bind_size; /* size of lazy binding infs */
351 uint32_t export_off; /* file offset to lazy binding info */
352 uint32_t export_size; /* size of lazy binding infs */
355 #define INDIRECT_SYMBOL_LOCAL 0x80000000
357 struct entry_point_command {
358 uint32_t cmd; /* LC_MAIN only used in MH_EXECUTE filetypes */
359 uint32_t cmdsize; /* 24 */
360 uint64_t entryoff; /* file (__TEXT) offset of main() */
361 uint64_t stacksize;/* if not zero, initial stack size */
364 enum skind {
365 sk_unknown = 0,
366 sk_discard,
367 sk_text,
368 sk_stubs,
369 sk_stub_helper,
370 sk_ro_data,
371 sk_uw_info,
372 sk_nl_ptr, // non-lazy pointers, aka GOT
373 sk_la_ptr, // lazy pointers
374 sk_init,
375 sk_fini,
376 sk_rw_data,
377 sk_stab,
378 sk_stab_str,
379 sk_debug_info,
380 sk_debug_abbrev,
381 sk_debug_line,
382 sk_debug_aranges,
383 sk_debug_str,
384 sk_debug_line_str,
385 sk_bss,
386 sk_linkedit,
387 sk_last
390 struct nlist_64 {
391 uint32_t n_strx; /* index into the string table */
392 uint8_t n_type; /* type flag, see below */
393 uint8_t n_sect; /* section number or NO_SECT */
394 uint16_t n_desc; /* see <mach-o/stab.h> */
395 uint64_t n_value; /* value of this symbol (or stab offset) */
398 #define N_UNDF 0x0
399 #define N_ABS 0x2
400 #define N_EXT 0x1
401 #define N_SECT 0xe
403 #define N_WEAK_REF 0x0040
404 #define N_WEAK_DEF 0x0080
406 struct macho {
407 struct mach_header_64 mh;
408 int seg2lc[4], nseg;
409 struct load_command **lc;
410 struct entry_point_command *ep;
411 int nlc;
412 struct {
413 Section *s;
414 int machosect;
415 } sk_to_sect[sk_last];
416 int *elfsectomacho;
417 int *e2msym;
418 Section *symtab, *strtab, *wdata, *indirsyms, *stubs, *exports;
419 uint32_t ilocal, iextdef, iundef;
420 int stubsym, n_got, nr_plt;
421 #ifdef CONFIG_NEW_MACHO
422 Section *chained_fixups;
423 int n_bind;
424 int n_bind_rebase;
425 struct bind_rebase {
426 int section;
427 int bind;
428 ElfW_Rel rel;
429 } *bind_rebase;
430 #else
431 Section *rebase, *binding, *weak_binding, *lazy_binding;
432 Section *stub_helper, *la_symbol_ptr;
433 struct dyld_info_command *dyldinfo;
434 int helpsym, lasym, dyld_private, dyld_stub_binder;
435 int n_lazy_bind;
436 struct s_lazy_bind {
437 int section;
438 int bind_offset;
439 int la_symbol_offset;
440 ElfW_Rel rel;
441 } *s_lazy_bind;
442 int n_rebase;
443 struct s_rebase {
444 int section;
445 ElfW_Rel rel;
446 } *s_rebase;
447 int n_bind;
448 struct bind {
449 int section;
450 ElfW_Rel rel;
451 } *bind;
452 #endif
455 #define SHT_LINKEDIT (SHT_LOOS + 42)
456 #define SHN_FROMDLL (SHN_LOOS + 2) /* Symbol is undefined, comes from a DLL */
458 static void * add_lc(struct macho *mo, uint32_t cmd, uint32_t cmdsize)
460 struct load_command *lc = tcc_mallocz(cmdsize);
461 lc->cmd = cmd;
462 lc->cmdsize = cmdsize;
463 mo->lc = tcc_realloc(mo->lc, sizeof(mo->lc[0]) * (mo->nlc + 1));
464 mo->lc[mo->nlc++] = lc;
465 return lc;
468 static struct segment_command_64 * add_segment(struct macho *mo, const char *name)
470 struct segment_command_64 *sc = add_lc(mo, LC_SEGMENT_64, sizeof(*sc));
471 strncpy(sc->segname, name, 16);
472 mo->seg2lc[mo->nseg++] = mo->nlc - 1;
473 return sc;
476 static struct segment_command_64 * get_segment(struct macho *mo, int i)
478 return (struct segment_command_64 *) (mo->lc[mo->seg2lc[i]]);
481 static int add_section(struct macho *mo, struct segment_command_64 **_seg, const char *name)
483 struct segment_command_64 *seg = *_seg;
484 int ret = seg->nsects;
485 struct section_64 *sec;
486 seg->nsects++;
487 seg->cmdsize += sizeof(*sec);
488 seg = tcc_realloc(seg, sizeof(*seg) + seg->nsects * sizeof(*sec));
489 sec = (struct section_64*)((char*)seg + sizeof(*seg)) + ret;
490 memset(sec, 0, sizeof(*sec));
491 strncpy(sec->sectname, name, 16);
492 strncpy(sec->segname, seg->segname, 16);
493 *_seg = seg;
494 return ret;
497 static struct section_64 *get_section(struct segment_command_64 *seg, int i)
499 return (struct section_64*)((char*)seg + sizeof(*seg)) + i;
502 static void * add_dylib(struct macho *mo, char *name)
504 struct dylib_command *lc;
505 int sz = (sizeof(*lc) + strlen(name) + 1 + 7) & -8;
506 lc = add_lc(mo, LC_LOAD_DYLIB, sz);
507 lc->name = sizeof(*lc);
508 strcpy((char*)lc + lc->name, name);
509 lc->timestamp = 2;
510 lc->current_version = 1 << 16;
511 lc->compatibility_version = 1 << 16;
512 return lc;
515 static int uleb128_size (unsigned long long value)
517 int size = 0;
519 do {
520 value >>= 7;
521 size++;
522 } while (value != 0);
523 return size;
526 static void write_uleb128(Section *section, uint64_t value)
528 do {
529 unsigned char byte = value & 0x7f;
530 uint8_t *ptr = section_ptr_add(section, 1);
532 value >>= 7;
533 *ptr = byte | (value ? 0x80 : 0);
534 } while (value != 0);
537 static void tcc_macho_add_destructor(TCCState *s1)
539 int init_sym, mh_execute_header, at_exit_sym;
540 Section *s;
541 ElfW_Rel *rel;
542 uint8_t *ptr;
544 mh_execute_header = put_elf_sym(s1->symtab, -4096, 0,
545 ELFW(ST_INFO)(STB_GLOBAL, STT_OBJECT), 0,
546 text_section->sh_num, "__mh_execute_header");
547 s = find_section(s1, ".fini_array");
548 if (s->data_offset == 0)
549 return;
550 init_sym = put_elf_sym(s1->symtab, text_section->data_offset, 0,
551 ELFW(ST_INFO)(STB_LOCAL, STT_FUNC), 0,
552 text_section->sh_num, "___GLOBAL_init_65535");
553 at_exit_sym = put_elf_sym(s1->symtab, 0, 0,
554 ELFW(ST_INFO)(STB_GLOBAL, STT_FUNC), 0,
555 SHN_UNDEF, "___cxa_atexit");
556 #ifdef TCC_TARGET_X86_64
557 ptr = section_ptr_add(text_section, 4);
558 ptr[0] = 0x55; // pushq %rbp
559 ptr[1] = 0x48; // movq %rsp, %rbp
560 ptr[2] = 0x89;
561 ptr[3] = 0xe5;
562 for_each_elem(s->reloc, 0, rel, ElfW_Rel) {
563 int sym_index = ELFW(R_SYM)(rel->r_info);
565 ptr = section_ptr_add(text_section, 26);
566 ptr[0] = 0x48; // lea destructor(%rip),%rax
567 ptr[1] = 0x8d;
568 ptr[2] = 0x05;
569 put_elf_reloca(s1->symtab, text_section,
570 text_section->data_offset - 23,
571 R_X86_64_PC32, sym_index, -4);
572 ptr[7] = 0x48; // mov %rax,%rdi
573 ptr[8] = 0x89;
574 ptr[9] = 0xc7;
575 ptr[10] = 0x31; // xorl %ecx, %ecx
576 ptr[11] = 0xc9;
577 ptr[12] = 0x89; // movl %ecx, %esi
578 ptr[13] = 0xce;
579 ptr[14] = 0x48; // lea mh_execute_header(%rip),%rdx
580 ptr[15] = 0x8d;
581 ptr[16] = 0x15;
582 put_elf_reloca(s1->symtab, text_section,
583 text_section->data_offset - 9,
584 R_X86_64_PC32, mh_execute_header, -4);
585 ptr[21] = 0xe8; // call __cxa_atexit
586 put_elf_reloca(s1->symtab, text_section,
587 text_section->data_offset - 4,
588 R_X86_64_PLT32, at_exit_sym, -4);
590 ptr = section_ptr_add(text_section, 2);
591 ptr[0] = 0x5d; // pop %rbp
592 ptr[1] = 0xc3; // ret
593 #elif defined TCC_TARGET_ARM64
594 ptr = section_ptr_add(text_section, 8);
595 write32le(ptr, 0xa9bf7bfd); // stp x29, x30, [sp, #-16]!
596 write32le(ptr + 4, 0x910003fd); // mov x29, sp
597 for_each_elem(s->reloc, 0, rel, ElfW_Rel) {
598 int sym_index = ELFW(R_SYM)(rel->r_info);
600 ptr = section_ptr_add(text_section, 24);
601 put_elf_reloc(s1->symtab, text_section,
602 text_section->data_offset - 24,
603 R_AARCH64_ADR_PREL_PG_HI21, sym_index);
604 write32le(ptr, 0x90000000); // adrp x0, destructor@page
605 put_elf_reloc(s1->symtab, text_section,
606 text_section->data_offset - 20,
607 R_AARCH64_LDST8_ABS_LO12_NC, sym_index);
608 write32le(ptr + 4, 0x91000000); // add x0,x0,destructor@pageoff
609 write32le(ptr + 8, 0xd2800001); // mov x1, #0
610 put_elf_reloc(s1->symtab, text_section,
611 text_section->data_offset - 12,
612 R_AARCH64_ADR_PREL_PG_HI21, mh_execute_header);
613 write32le(ptr + 12, 0x90000002); // adrp x2, mh_execute_header@page
614 put_elf_reloc(s1->symtab, text_section,
615 text_section->data_offset - 8,
616 R_AARCH64_LDST8_ABS_LO12_NC, mh_execute_header);
617 write32le(ptr + 16, 0x91000042); // add x2,x2,mh_execute_header@pageoff
618 put_elf_reloc(s1->symtab, text_section,
619 text_section->data_offset - 4,
620 R_AARCH64_CALL26, at_exit_sym);
621 write32le(ptr + 20, 0x94000000); // bl __cxa_atexit
623 ptr = section_ptr_add(text_section, 8);
624 write32le(ptr, 0xa8c17bfd); // ldp x29, x30, [sp], #16
625 write32le(ptr + 4, 0xd65f03c0); // ret
626 #endif
627 s->reloc->data_offset = s->data_offset = 0;
628 s->sh_flags &= ~SHF_ALLOC;
629 add_array (s1, ".init_array", init_sym);
632 #ifdef CONFIG_NEW_MACHO
633 static void bind_rebase_add(struct macho *mo, int bind, int sh_info,
634 ElfW_Rel *rel, struct sym_attr *attr)
636 mo->bind_rebase = tcc_realloc(mo->bind_rebase, (mo->n_bind_rebase + 1) *
637 sizeof(struct bind_rebase));
638 mo->bind_rebase[mo->n_bind_rebase].section = sh_info;
639 mo->bind_rebase[mo->n_bind_rebase].bind = bind;
640 mo->bind_rebase[mo->n_bind_rebase].rel = *rel;
641 if (attr)
642 mo->bind_rebase[mo->n_bind_rebase].rel.r_offset = attr->got_offset;
643 mo->n_bind_rebase++;
644 mo->n_bind += bind;
647 static void check_relocs(TCCState *s1, struct macho *mo)
649 Section *s;
650 ElfW_Rel *rel;
651 ElfW(Sym) *sym;
652 int i, type, gotplt_entry, sym_index, for_code;
653 int sh_num, debug;
654 uint32_t *pi, *goti;
655 struct sym_attr *attr;
657 mo->indirsyms = new_section(s1, "LEINDIR", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE);
658 goti = NULL;
659 mo->nr_plt = mo->n_got = 0;
660 for (i = 1; i < s1->nb_sections; i++) {
661 s = s1->sections[i];
662 if (s->sh_type != SHT_RELX)
663 continue;
664 sh_num = s1->sections[s->sh_info]->sh_num;
665 debug = sh_num >= s1->dwlo && sh_num < s1->dwhi;
666 if (debug)
667 continue;
668 for_each_elem(s, 0, rel, ElfW_Rel) {
669 type = ELFW(R_TYPE)(rel->r_info);
670 gotplt_entry = gotplt_entry_type(type);
671 for_code = code_reloc(type);
672 /* We generate a non-lazy pointer for used undefined symbols
673 and for defined symbols that must have a place for their
674 address due to codegen (i.e. a reloc requiring a got slot). */
675 sym_index = ELFW(R_SYM)(rel->r_info);
676 sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
677 if (sym->st_shndx == SHN_UNDEF
678 || gotplt_entry == ALWAYS_GOTPLT_ENTRY) {
679 attr = get_sym_attr(s1, sym_index, 1);
680 if (!attr->dyn_index) {
681 attr->got_offset = s1->got->data_offset;
682 attr->plt_offset = -1;
683 attr->dyn_index = 1; /* used as flag */
684 section_ptr_add(s1->got, PTR_SIZE);
685 put_elf_reloc(s1->symtab, s1->got, attr->got_offset,
686 R_DATA_PTR, sym_index);
687 goti = tcc_realloc(goti, (mo->n_got + 1) * sizeof(*goti));
688 if (ELFW(ST_BIND)(sym->st_info) == STB_LOCAL) {
689 if (sym->st_shndx == SHN_UNDEF)
690 tcc_error("undefined local symbo: '%s'",
691 (char *) symtab_section->link->data + sym->st_name);
692 goti[mo->n_got++] = INDIRECT_SYMBOL_LOCAL;
693 } else {
694 goti[mo->n_got++] = mo->e2msym[sym_index];
695 if (sym->st_shndx == SHN_UNDEF
696 #ifdef TCC_TARGET_X86_64
697 && type == R_X86_64_GOTPCREL
698 #elif defined TCC_TARGET_ARM64
699 && type == R_AARCH64_ADR_GOT_PAGE
700 #endif
702 bind_rebase_add(mo, 1, s1->got->reloc->sh_info, rel, attr);
703 attr->plt_offset = 0; // ignore next bind
704 s1->got->reloc->data_offset -= sizeof (ElfW_Rel);
706 if (for_code && sym->st_shndx == SHN_UNDEF)
707 s1->got->reloc->data_offset -= sizeof (ElfW_Rel);
710 if (for_code && sym->st_shndx == SHN_UNDEF) {
711 if (attr->plt_offset == -1) {
712 uint8_t *jmp;
714 attr->plt_offset = mo->stubs->data_offset;
715 #ifdef TCC_TARGET_X86_64
716 if (type != R_X86_64_PLT32)
717 continue;
718 jmp = section_ptr_add(mo->stubs, 6);
719 jmp[0] = 0xff; /* jmpq *ofs(%rip) */
720 jmp[1] = 0x25;
721 put_elf_reloc(s1->symtab, mo->stubs,
722 attr->plt_offset + 2,
723 R_X86_64_GOTPCREL, sym_index);
724 #elif defined TCC_TARGET_ARM64
725 if (type != R_AARCH64_CALL26)
726 continue;
727 jmp = section_ptr_add(mo->stubs, 12);
728 put_elf_reloc(s1->symtab, mo->stubs,
729 attr->plt_offset,
730 R_AARCH64_ADR_GOT_PAGE, sym_index);
731 write32le(jmp, // adrp x16, #sym
732 0x90000010);
733 put_elf_reloc(s1->symtab, mo->stubs,
734 attr->plt_offset + 4,
735 R_AARCH64_LD64_GOT_LO12_NC, sym_index);
736 write32le(jmp + 4, // ld x16,[x16, #sym]
737 0xf9400210);
738 write32le(jmp + 8, // br x16
739 0xd61f0200);
740 #endif
741 bind_rebase_add(mo, 1, s1->got->reloc->sh_info, rel, attr);
742 pi = section_ptr_add(mo->indirsyms, sizeof(*pi));
743 *pi = mo->e2msym[sym_index];
744 mo->nr_plt++;
746 rel->r_info = ELFW(R_INFO)(mo->stubsym, type);
747 rel->r_addend += attr->plt_offset;
750 if (type == R_DATA_PTR)
751 bind_rebase_add(mo, 0, s->sh_info, rel, NULL);
754 pi = section_ptr_add(mo->indirsyms, mo->n_got * sizeof(*pi));
755 memcpy(pi, goti, mo->n_got * sizeof(*pi));
756 tcc_free(goti);
759 #else
761 static void check_relocs(TCCState *s1, struct macho *mo)
763 uint8_t *jmp;
764 Section *s;
765 ElfW_Rel *rel;
766 ElfW(Sym) *sym;
767 int i, type, gotplt_entry, sym_index, for_code;
768 int sh_num, debug, bind_offset, la_symbol_offset;
769 uint32_t *pi, *goti;
770 struct sym_attr *attr;
772 mo->indirsyms = new_section(s1, "LEINDIR", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE);
774 #ifdef TCC_TARGET_X86_64
775 jmp = section_ptr_add(mo->stub_helper, 16);
776 jmp[0] = 0x4c; /* leaq _dyld_private(%rip), %r11 */
777 jmp[1] = 0x8d;
778 jmp[2] = 0x1d;
779 put_elf_reloca(s1->symtab, mo->stub_helper, 3,
780 R_X86_64_PC32, mo->dyld_private, -4);
781 jmp[7] = 0x41; /* pushq %r11 */
782 jmp[8] = 0x53;
783 jmp[9] = 0xff; /* jmpq *dyld_stub_binder@GOT(%rip) */
784 jmp[10] = 0x25;
785 put_elf_reloca(s1->symtab, mo->stub_helper, 11,
786 R_X86_64_GOTPCREL, mo->dyld_stub_binder, -4);
787 jmp[15] = 0x90; /* nop */
788 #elif defined TCC_TARGET_ARM64
789 jmp = section_ptr_add(mo->stub_helper, 24);
790 put_elf_reloc(s1->symtab, mo->stub_helper, 0,
791 R_AARCH64_ADR_PREL_PG_HI21, mo->dyld_private);
792 write32le(jmp, 0x90000011); // adrp x17, _dyld_private@page
793 put_elf_reloc(s1->symtab, mo->stub_helper, 4,
794 R_AARCH64_LDST64_ABS_LO12_NC, mo->dyld_private);
795 write32le(jmp + 4, 0x91000231); // add x17,x17,_dyld_private@pageoff
796 write32le(jmp + 8, 0xa9bf47f0); // stp x16/x17, [sp, #-16]!
797 put_elf_reloc(s1->symtab, mo->stub_helper, 12,
798 R_AARCH64_ADR_GOT_PAGE, mo->dyld_stub_binder);
799 write32le(jmp + 12, 0x90000010); // adrp x16, dyld_stub_binder@page
800 put_elf_reloc(s1->symtab, mo->stub_helper, 16,
801 R_AARCH64_LD64_GOT_LO12_NC, mo->dyld_stub_binder);
802 write32le(jmp + 16, 0xf9400210); // ldr x16,[x16,dyld_stub_binder@pageoff]
803 write32le(jmp + 20, 0xd61f0200); // br x16
804 #endif
806 goti = NULL;
807 mo->nr_plt = mo->n_got = 0;
808 for (i = 1; i < s1->nb_sections; i++) {
809 s = s1->sections[i];
810 if (s->sh_type != SHT_RELX)
811 continue;
812 sh_num = s1->sections[s->sh_info]->sh_num;
813 debug = sh_num >= s1->dwlo && sh_num < s1->dwhi;
814 for_each_elem(s, 0, rel, ElfW_Rel) {
815 type = ELFW(R_TYPE)(rel->r_info);
816 gotplt_entry = gotplt_entry_type(type);
817 for_code = code_reloc(type);
818 /* We generate a non-lazy pointer for used undefined symbols
819 and for defined symbols that must have a place for their
820 address due to codegen (i.e. a reloc requiring a got slot). */
821 sym_index = ELFW(R_SYM)(rel->r_info);
822 sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
823 if (!debug &&
824 (sym->st_shndx == SHN_UNDEF
825 || gotplt_entry == ALWAYS_GOTPLT_ENTRY)) {
826 attr = get_sym_attr(s1, sym_index, 1);
827 if (!attr->dyn_index) {
828 attr->got_offset = s1->got->data_offset;
829 attr->plt_offset = -1;
830 attr->dyn_index = 1; /* used as flag */
831 section_ptr_add(s1->got, PTR_SIZE);
832 put_elf_reloc(s1->symtab, s1->got, attr->got_offset,
833 R_DATA_PTR, sym_index);
834 goti = tcc_realloc(goti, (mo->n_got + 1) * sizeof(*goti));
835 if (ELFW(ST_BIND)(sym->st_info) == STB_LOCAL) {
836 if (sym->st_shndx == SHN_UNDEF)
837 tcc_error("undefined local symbo: '%s'",
838 (char *) symtab_section->link->data + sym->st_name);
839 goti[mo->n_got++] = INDIRECT_SYMBOL_LOCAL;
840 } else {
841 goti[mo->n_got++] = mo->e2msym[sym_index];
842 if (sym->st_shndx == SHN_UNDEF
843 #ifdef TCC_TARGET_X86_64
844 && type == R_X86_64_GOTPCREL
845 #elif defined TCC_TARGET_ARM64
846 && type == R_AARCH64_ADR_GOT_PAGE
847 #endif
849 mo->bind =
850 tcc_realloc(mo->bind,
851 (mo->n_bind + 1) *
852 sizeof(struct bind));
853 mo->bind[mo->n_bind].section = s1->got->reloc->sh_info;
854 mo->bind[mo->n_bind].rel = *rel;
855 mo->bind[mo->n_bind].rel.r_offset = attr->got_offset;
856 mo->n_bind++;
857 s1->got->reloc->data_offset -= sizeof (ElfW_Rel);
861 if (for_code && sym->st_shndx == SHN_UNDEF) {
862 if (attr->plt_offset == -1) {
863 attr->plt_offset = mo->stubs->data_offset;
864 #ifdef TCC_TARGET_X86_64
865 if (type != R_X86_64_PLT32)
866 continue;
867 /* __stubs */
868 jmp = section_ptr_add(mo->stubs, 6);
869 jmp[0] = 0xff; /* jmpq *__la_symbol_ptr(%rip) */
870 jmp[1] = 0x25;
871 put_elf_reloca(s1->symtab, mo->stubs,
872 mo->stubs->data_offset - 4,
873 R_X86_64_PC32, mo->lasym,
874 mo->la_symbol_ptr->data_offset - 4);
876 /* __stub_helper */
877 bind_offset = mo->stub_helper->data_offset + 1;
878 jmp = section_ptr_add(mo->stub_helper, 10);
879 jmp[0] = 0x68; /* pushq $bind_offset */
880 jmp[5] = 0xe9; /* jmpq __stub_helper */
881 write32le(jmp + 6, -mo->stub_helper->data_offset);
883 /* __la_symbol_ptr */
884 la_symbol_offset = mo->la_symbol_ptr->data_offset;
885 put_elf_reloca(s1->symtab, mo->la_symbol_ptr,
886 mo->la_symbol_ptr->data_offset,
887 R_DATA_PTR, mo->helpsym,
888 mo->stub_helper->data_offset - 10);
889 section_ptr_add(mo->la_symbol_ptr, PTR_SIZE);
890 #elif defined TCC_TARGET_ARM64
891 if (type != R_AARCH64_CALL26)
892 continue;
893 /* __stubs */
894 jmp = section_ptr_add(mo->stubs, 12);
895 put_elf_reloca(s1->symtab, mo->stubs,
896 mo->stubs->data_offset - 12,
897 R_AARCH64_ADR_PREL_PG_HI21, mo->lasym,
898 mo->la_symbol_ptr->data_offset);
899 write32le(jmp, // adrp x16, __la_symbol_ptr@page
900 0x90000010);
901 put_elf_reloca(s1->symtab, mo->stubs,
902 mo->stubs->data_offset - 8,
903 R_AARCH64_LDST64_ABS_LO12_NC, mo->lasym,
904 mo->la_symbol_ptr->data_offset);
905 write32le(jmp + 4, // ldr x16,[x16, __la_symbol_ptr@pageoff]
906 0xf9400210);
907 write32le(jmp + 8, // br x16
908 0xd61f0200);
910 /* __stub_helper */
911 bind_offset = mo->stub_helper->data_offset + 8;
912 jmp = section_ptr_add(mo->stub_helper, 12);
913 write32le(jmp + 0, // ldr w16, l0
914 0x18000050);
915 write32le(jmp + 4, // b stubHelperHeader
916 0x14000000 +
917 ((-(mo->stub_helper->data_offset - 8) / 4) &
918 0x3ffffff));
919 write32le(jmp + 8, 0); // l0: .long bind_offset
921 /* __la_symbol_ptr */
922 la_symbol_offset = mo->la_symbol_ptr->data_offset;
923 put_elf_reloca(s1->symtab, mo->la_symbol_ptr,
924 mo->la_symbol_ptr->data_offset,
925 R_DATA_PTR, mo->helpsym,
926 mo->stub_helper->data_offset - 12);
927 section_ptr_add(mo->la_symbol_ptr, PTR_SIZE);
928 #endif
929 mo->s_lazy_bind =
930 tcc_realloc(mo->s_lazy_bind, (mo->n_lazy_bind + 1) *
931 sizeof(struct s_lazy_bind));
932 mo->s_lazy_bind[mo->n_lazy_bind].section =
933 mo->stub_helper->reloc->sh_info;
934 mo->s_lazy_bind[mo->n_lazy_bind].bind_offset =
935 bind_offset;
936 mo->s_lazy_bind[mo->n_lazy_bind].la_symbol_offset =
937 la_symbol_offset;
938 mo->s_lazy_bind[mo->n_lazy_bind].rel = *rel;
939 mo->s_lazy_bind[mo->n_lazy_bind].rel.r_offset =
940 attr->plt_offset;
941 mo->n_lazy_bind++;
942 pi = section_ptr_add(mo->indirsyms, sizeof(*pi));
943 *pi = mo->e2msym[sym_index];
944 mo->nr_plt++;
946 rel->r_info = ELFW(R_INFO)(mo->stubsym, type);
947 rel->r_addend += attr->plt_offset;
950 if (type == R_DATA_PTR) {
951 mo->s_rebase =
952 tcc_realloc(mo->s_rebase, (mo->n_rebase + 1) *
953 sizeof(struct s_rebase));
954 mo->s_rebase[mo->n_rebase].section = s->sh_info;
955 mo->s_rebase[mo->n_rebase].rel = *rel;
956 mo->n_rebase++;
960 pi = section_ptr_add(mo->indirsyms, mo->n_got * sizeof(*pi));
961 memcpy(pi, goti, mo->n_got * sizeof(*pi));
962 pi = section_ptr_add(mo->indirsyms, mo->nr_plt * sizeof(*pi));
963 memcpy(pi, mo->indirsyms->data, mo->nr_plt * sizeof(*pi));
964 tcc_free(goti);
966 #endif
968 static int check_symbols(TCCState *s1, struct macho *mo)
970 int sym_index, sym_end;
971 int ret = 0;
973 mo->ilocal = mo->iextdef = mo->iundef = -1;
974 sym_end = symtab_section->data_offset / sizeof(ElfW(Sym));
975 for (sym_index = 1; sym_index < sym_end; ++sym_index) {
976 int elf_index = ((struct nlist_64 *)mo->symtab->data + sym_index - 1)->n_value;
977 ElfW(Sym) *sym = (ElfW(Sym) *)symtab_section->data + elf_index;
978 const char *name = (char*)symtab_section->link->data + sym->st_name;
979 unsigned type = ELFW(ST_TYPE)(sym->st_info);
980 unsigned bind = ELFW(ST_BIND)(sym->st_info);
981 unsigned vis = ELFW(ST_VISIBILITY)(sym->st_other);
983 dprintf("%4d (%4d): %09lx %4d %4d %4d %3d %s\n",
984 sym_index, elf_index, (long)sym->st_value,
985 type, bind, vis, sym->st_shndx, name);
986 if (bind == STB_LOCAL) {
987 if (mo->ilocal == -1)
988 mo->ilocal = sym_index - 1;
989 if (mo->iextdef != -1 || mo->iundef != -1)
990 tcc_error("local syms after global ones");
991 } else if (sym->st_shndx != SHN_UNDEF) {
992 if (mo->iextdef == -1)
993 mo->iextdef = sym_index - 1;
994 if (mo->iundef != -1)
995 tcc_error("external defined symbol after undefined");
996 } else if (sym->st_shndx == SHN_UNDEF) {
997 if (mo->iundef == -1)
998 mo->iundef = sym_index - 1;
999 if (ELFW(ST_BIND)(sym->st_info) == STB_WEAK
1000 || find_elf_sym(s1->dynsymtab_section, name)) {
1001 /* Mark the symbol as coming from a dylib so that
1002 relocate_syms doesn't complain. Normally bind_exe_dynsyms
1003 would do this check, and place the symbol into dynsym
1004 which is checked by relocate_syms. But Mach-O doesn't use
1005 bind_exe_dynsyms. */
1006 sym->st_shndx = SHN_FROMDLL;
1007 continue;
1009 tcc_error_noabort("undefined symbol '%s'", name);
1010 ret = -1;
1013 return ret;
1016 static void convert_symbol(TCCState *s1, struct macho *mo, struct nlist_64 *pn)
1018 struct nlist_64 n = *pn;
1019 ElfSym *sym = (ElfW(Sym) *)symtab_section->data + pn->n_value;
1020 const char *name = (char*)symtab_section->link->data + sym->st_name;
1021 switch(ELFW(ST_TYPE)(sym->st_info)) {
1022 case STT_NOTYPE:
1023 case STT_OBJECT:
1024 case STT_FUNC:
1025 case STT_SECTION:
1026 n.n_type = N_SECT;
1027 break;
1028 case STT_FILE:
1029 n.n_type = N_ABS;
1030 break;
1031 default:
1032 tcc_error("unhandled ELF symbol type %d %s",
1033 ELFW(ST_TYPE)(sym->st_info), name);
1035 if (sym->st_shndx == SHN_UNDEF)
1036 tcc_error("should have been rewritten to SHN_FROMDLL: %s", name);
1037 else if (sym->st_shndx == SHN_FROMDLL)
1038 n.n_type = N_UNDF, n.n_sect = 0;
1039 else if (sym->st_shndx == SHN_ABS)
1040 n.n_type = N_ABS, n.n_sect = 0;
1041 else if (sym->st_shndx >= SHN_LORESERVE)
1042 tcc_error("unhandled ELF symbol section %d %s", sym->st_shndx, name);
1043 else if (!mo->elfsectomacho[sym->st_shndx]) {
1044 int sh_num = s1->sections[sym->st_shndx]->sh_num;
1045 if (sh_num < s1->dwlo || sh_num >= s1->dwhi)
1046 tcc_error("ELF section %d(%s) not mapped into Mach-O for symbol %s",
1047 sym->st_shndx, s1->sections[sym->st_shndx]->name, name);
1049 else
1050 n.n_sect = mo->elfsectomacho[sym->st_shndx];
1051 if (ELFW(ST_BIND)(sym->st_info) == STB_GLOBAL)
1052 n.n_type |= N_EXT;
1053 else if (ELFW(ST_BIND)(sym->st_info) == STB_WEAK)
1054 n.n_desc |= N_WEAK_REF | (n.n_type != N_UNDF ? N_WEAK_DEF : 0);
1055 n.n_strx = pn->n_strx;
1056 n.n_value = sym->st_value;
1057 *pn = n;
1060 static void convert_symbols(TCCState *s1, struct macho *mo)
1062 struct nlist_64 *pn;
1063 for_each_elem(mo->symtab, 0, pn, struct nlist_64)
1064 convert_symbol(s1, mo, pn);
1067 static int machosymcmp(const void *_a, const void *_b, void *arg)
1069 TCCState *s1 = arg;
1070 int ea = ((struct nlist_64 *)_a)->n_value;
1071 int eb = ((struct nlist_64 *)_b)->n_value;
1072 ElfSym *sa = (ElfSym *)symtab_section->data + ea;
1073 ElfSym *sb = (ElfSym *)symtab_section->data + eb;
1074 int r;
1075 /* locals, then defined externals, then undefined externals, the
1076 last two sections also by name, otherwise stable sort */
1077 r = (ELFW(ST_BIND)(sb->st_info) == STB_LOCAL)
1078 - (ELFW(ST_BIND)(sa->st_info) == STB_LOCAL);
1079 if (r)
1080 return r;
1081 r = (sa->st_shndx == SHN_UNDEF) - (sb->st_shndx == SHN_UNDEF);
1082 if (r)
1083 return r;
1084 if (ELFW(ST_BIND)(sa->st_info) != STB_LOCAL) {
1085 const char * na = (char*)symtab_section->link->data + sa->st_name;
1086 const char * nb = (char*)symtab_section->link->data + sb->st_name;
1087 r = strcmp(na, nb);
1088 if (r)
1089 return r;
1091 return ea - eb;
1094 /* cannot use qsort because code has to be reentrant */
1095 static void tcc_qsort (void *base, size_t nel, size_t width,
1096 int (*comp)(const void *, const void *, void *), void *arg)
1098 size_t wnel, gap, wgap, i, j, k;
1099 char *a, *b, tmp;
1101 wnel = width * nel;
1102 for (gap = 0; ++gap < nel;)
1103 gap *= 3;
1104 while ( gap /= 3 ) {
1105 wgap = width * gap;
1106 for (i = wgap; i < wnel; i += width) {
1107 for (j = i - wgap; ;j -= wgap) {
1108 a = j + (char *)base;
1109 b = a + wgap;
1110 if ( (*comp)(a, b, arg) <= 0 )
1111 break;
1112 k = width;
1113 do {
1114 tmp = *a;
1115 *a++ = *b;
1116 *b++ = tmp;
1117 } while ( --k );
1118 if (j < wgap)
1119 break;
1125 static void create_symtab(TCCState *s1, struct macho *mo)
1127 int sym_index, sym_end;
1128 struct nlist_64 *pn;
1130 /* Stub creation belongs to check_relocs, but we need to create
1131 the symbol now, so its included in the sorting. */
1132 mo->stubs = new_section(s1, "__stubs", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR);
1133 s1->got = new_section(s1, ".got", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE);
1134 mo->stubsym = put_elf_sym(s1->symtab, 0, 0,
1135 ELFW(ST_INFO)(STB_LOCAL, STT_SECTION), 0,
1136 mo->stubs->sh_num, ".__stubs");
1137 #ifdef CONFIG_NEW_MACHO
1138 mo->chained_fixups = new_section(s1, "CHAINED_FIXUPS",
1139 SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE);
1140 #else
1141 mo->stub_helper = new_section(s1, "__stub_helper", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR);
1142 mo->la_symbol_ptr = new_section(s1, "__la_symbol_ptr", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE);
1143 mo->helpsym = put_elf_sym(s1->symtab, 0, 0,
1144 ELFW(ST_INFO)(STB_LOCAL, STT_SECTION), 0,
1145 mo->stub_helper->sh_num, ".__stub_helper");
1146 mo->lasym = put_elf_sym(s1->symtab, 0, 0,
1147 ELFW(ST_INFO)(STB_LOCAL, STT_SECTION), 0,
1148 mo->la_symbol_ptr->sh_num, ".__la_symbol_ptr");
1149 section_ptr_add(data_section, -data_section->data_offset & (PTR_SIZE - 1));
1150 mo->dyld_private = put_elf_sym(s1->symtab, data_section->data_offset, PTR_SIZE,
1151 ELFW(ST_INFO)(STB_LOCAL, STT_OBJECT), 0,
1152 data_section->sh_num, ".__dyld_private");
1153 section_ptr_add(data_section, PTR_SIZE);
1154 mo->dyld_stub_binder = put_elf_sym(s1->symtab, 0, 0,
1155 ELFW(ST_INFO)(STB_GLOBAL, STT_OBJECT), 0,
1156 SHN_UNDEF, "dyld_stub_binder");
1157 mo->rebase = new_section(s1, "REBASE", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE);
1158 mo->binding = new_section(s1, "BINDING", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE);
1159 mo->weak_binding = new_section(s1, "WEAK_BINDING", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE);
1160 mo->lazy_binding = new_section(s1, "LAZY_BINDING", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE);
1161 #endif
1162 mo->exports = new_section(s1, "EXPORT", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE);
1164 mo->symtab = new_section(s1, "LESYMTAB", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE);
1165 mo->strtab = new_section(s1, "LESTRTAB", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE);
1166 put_elf_str(mo->strtab, " "); /* Mach-O starts strtab with a space */
1167 sym_end = symtab_section->data_offset / sizeof(ElfW(Sym));
1168 pn = section_ptr_add(mo->symtab, sizeof(*pn) * (sym_end - 1));
1169 for (sym_index = 1; sym_index < sym_end; ++sym_index) {
1170 ElfW(Sym) *sym = (ElfW(Sym) *)symtab_section->data + sym_index;
1171 const char *name = (char*)symtab_section->link->data + sym->st_name;
1172 pn[sym_index - 1].n_strx = put_elf_str(mo->strtab, name);
1173 pn[sym_index - 1].n_value = sym_index;
1175 tcc_qsort(pn, sym_end - 1, sizeof(*pn), machosymcmp, s1);
1176 mo->e2msym = tcc_malloc(sym_end * sizeof(*mo->e2msym));
1177 mo->e2msym[0] = -1;
1178 for (sym_index = 1; sym_index < sym_end; ++sym_index) {
1179 mo->e2msym[pn[sym_index - 1].n_value] = sym_index - 1;
1183 const struct {
1184 int seg;
1185 uint32_t flags;
1186 const char *name;
1187 } skinfo[sk_last] = {
1188 /*[sk_unknown] =*/ { 0 },
1189 /*[sk_discard] =*/ { 0 },
1190 /*[sk_text] =*/ { 1, S_REGULAR | S_ATTR_PURE_INSTRUCTIONS
1191 | S_ATTR_SOME_INSTRUCTIONS, "__text" },
1192 /*[sk_stubs] =*/ { 1, S_REGULAR | S_ATTR_PURE_INSTRUCTIONS | S_SYMBOL_STUBS
1193 | S_ATTR_SOME_INSTRUCTIONS , "__stubs" },
1194 /*[sk_stub_helper] =*/ { 1, S_REGULAR | S_ATTR_PURE_INSTRUCTIONS
1195 | S_ATTR_SOME_INSTRUCTIONS , "__stub_helper" },
1196 /*[sk_ro_data] =*/ { 1, S_REGULAR, "__rodata" },
1197 /*[sk_uw_info] =*/ { 0 },
1198 /*[sk_nl_ptr] =*/ { 2, S_NON_LAZY_SYMBOL_POINTERS, "__got" },
1199 /*[sk_la_ptr] =*/ { 2, S_LAZY_SYMBOL_POINTERS, "__la_symbol_ptr" },
1200 /*[sk_init] =*/ { 2, S_MOD_INIT_FUNC_POINTERS, "__mod_init_func" },
1201 /*[sk_fini] =*/ { 2, S_MOD_TERM_FUNC_POINTERS, "__mod_term_func" },
1202 /*[sk_rw_data] =*/ { 2, S_REGULAR, "__data" },
1203 /*[sk_stab] =*/ { 2, S_REGULAR, "__stab" },
1204 /*[sk_stab_str] =*/ { 2, S_REGULAR, "__stab_str" },
1205 /*[sk_debug_info] =*/ { 2, S_REGULAR, "__debug_info" },
1206 /*[sk_debug_abbrev] =*/ { 2, S_REGULAR, "__debug_abbrev" },
1207 /*[sk_debug_line] =*/ { 2, S_REGULAR, "__debug_line" },
1208 /*[sk_debug_aranges] =*/ { 2, S_REGULAR, "__debug_aranges" },
1209 /*[sk_debug_str] =*/ { 2, S_REGULAR, "__debug_str" },
1210 /*[sk_debug_line_str] =*/ { 2, S_REGULAR, "__debug_line_str" },
1211 /*[sk_bss] =*/ { 2, S_ZEROFILL, "__bss" },
1212 /*[sk_linkedit] =*/ { 3, S_REGULAR, NULL },
1215 #ifdef CONFIG_NEW_MACHO
1216 static void calc_fixup_size(TCCState *s1, struct macho *mo)
1218 int i, size;
1220 size = (sizeof(struct dyld_chained_fixups_header) + 7) & -8;
1221 size += (sizeof(struct dyld_chained_starts_in_image) + (mo->nseg - 1) * sizeof(uint32_t) + 7) & -8;
1222 for (i = 1; i < mo->nseg - 1; i++) {
1223 int page_count = (get_segment(mo, i)->vmsize + SEG_PAGE_SIZE - 1) / SEG_PAGE_SIZE;
1224 size += (sizeof(struct dyld_chained_starts_in_segment) + (page_count - 1) * sizeof(uint16_t) + 7) & -8;
1226 size += mo->n_bind * sizeof (struct dyld_chained_import) + 1;
1227 for (i = 0; i < mo->n_bind_rebase; i++) {
1228 if (mo->bind_rebase[i].bind) {
1229 int sym_index = ELFW(R_SYM)(mo->bind_rebase[i].rel.r_info);
1230 ElfW(Sym) *sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
1231 const char *name = (char *) symtab_section->link->data + sym->st_name;
1232 size += strlen(name) + 1;
1235 size = (size + 7) & -8;
1236 section_ptr_add(mo->chained_fixups, size);
1239 #else
1241 static void set_segment_and_offset(struct macho *mo, addr_t addr,
1242 uint8_t *ptr, int opcode,
1243 Section *sec, addr_t offset)
1245 int i;
1246 struct segment_command_64 *seg = NULL;
1248 for (i = 1; i < mo->nseg - 1; i++) {
1249 seg = get_segment(mo, i);
1250 if (addr >= seg->vmaddr && addr < (seg->vmaddr + seg->vmsize))
1251 break;
1253 *ptr = opcode | i;
1254 write_uleb128(sec, offset - seg->vmaddr);
1257 static void bind_rebase(TCCState *s1, struct macho *mo)
1259 int i;
1260 uint8_t *ptr;
1261 ElfW(Sym) *sym;
1262 const char *name;
1264 for (i = 0; i < mo->n_lazy_bind; i++) {
1265 int sym_index = ELFW(R_SYM)(mo->s_lazy_bind[i].rel.r_info);
1267 sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
1268 name = (char *) symtab_section->link->data + sym->st_name;
1269 write32le(mo->stub_helper->data +
1270 mo->s_lazy_bind[i].bind_offset,
1271 mo->lazy_binding->data_offset);
1272 ptr = section_ptr_add(mo->lazy_binding, 1);
1273 set_segment_and_offset(mo, mo->la_symbol_ptr->sh_addr, ptr,
1274 BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB,
1275 mo->lazy_binding,
1276 mo->s_lazy_bind[i].la_symbol_offset +
1277 mo->la_symbol_ptr->sh_addr);
1278 ptr = section_ptr_add(mo->lazy_binding, 5 + strlen(name));
1279 *ptr++ = BIND_OPCODE_SET_DYLIB_SPECIAL_IMM |
1280 (BIND_SPECIAL_DYLIB_FLAT_LOOKUP & 0xf);
1281 *ptr++ = BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM | 0;
1282 strcpy(ptr, name);
1283 ptr += strlen(name) + 1;
1284 *ptr++ = BIND_OPCODE_DO_BIND;
1285 *ptr = BIND_OPCODE_DONE;
1287 for (i = 0; i < mo->n_rebase; i++) {
1288 int sym_index = ELFW(R_SYM)(mo->s_rebase[i].rel.r_info);
1289 Section *s = s1->sections[mo->s_rebase[i].section];
1291 sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
1292 name = (char *) symtab_section->link->data + sym->st_name;
1293 ptr = section_ptr_add(mo->rebase, 2);
1294 *ptr++ = REBASE_OPCODE_SET_TYPE_IMM | REBASE_TYPE_POINTER;
1295 set_segment_and_offset(mo, s->sh_addr, ptr,
1296 REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB,
1297 mo->rebase,
1298 mo->s_rebase[i].rel.r_offset +
1299 s->sh_addr);
1300 ptr = section_ptr_add(mo->rebase, 1);
1301 *ptr = REBASE_OPCODE_DO_REBASE_IMM_TIMES | 1;
1303 for (i = 0; i < mo->n_bind; i++) {
1304 int sym_index = ELFW(R_SYM)(mo->bind[i].rel.r_info);
1305 Section *s = s1->sections[mo->bind[i].section];
1306 Section *binding;
1308 sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
1309 name = (char *) symtab_section->link->data + sym->st_name;
1310 binding = ELFW(ST_BIND)(sym->st_info) == STB_WEAK
1311 ? mo->weak_binding : mo->binding;
1312 ptr = section_ptr_add(binding, 5 + strlen(name));
1313 *ptr++ = BIND_OPCODE_SET_DYLIB_SPECIAL_IMM |
1314 (BIND_SPECIAL_DYLIB_FLAT_LOOKUP & 0xf);
1315 *ptr++ = BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM | 0;
1316 strcpy(ptr, name);
1317 ptr += strlen(name) + 1;
1318 *ptr++ = BIND_OPCODE_SET_TYPE_IMM | BIND_TYPE_POINTER;
1319 set_segment_and_offset(mo, s->sh_addr, ptr,
1320 BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB,
1321 binding,
1322 mo->bind[i].rel.r_offset + s->sh_addr);
1323 ptr = section_ptr_add(binding, 1);
1324 *ptr++ = BIND_OPCODE_DO_BIND;
1326 if (mo->rebase->data_offset) {
1327 ptr = section_ptr_add(mo->rebase, 1);
1328 *ptr = REBASE_OPCODE_DONE;
1330 if (mo->binding->data_offset) {
1331 ptr = section_ptr_add(mo->binding, 1);
1332 *ptr = BIND_OPCODE_DONE;
1334 if (mo->weak_binding->data_offset) {
1335 ptr = section_ptr_add(mo->weak_binding, 1);
1336 *ptr = BIND_OPCODE_DONE;
1338 tcc_free(mo->s_lazy_bind);
1339 tcc_free(mo->s_rebase);
1340 tcc_free(mo->bind);
1342 #endif
1344 struct trie {
1345 const char *name;
1346 int flag;
1347 addr_t addr;
1348 int offset_size;
1349 int str_size;
1350 int term_size;
1351 int term_offset;
1354 static int triecmp(const void *_a, const void *_b, void *arg)
1356 struct trie *a = (struct trie *) _a;
1357 struct trie *b = (struct trie *) _b;
1359 return strcmp(a->name, b->name);
1362 static void export_trie(TCCState *s1, struct macho *mo)
1364 int i, j, n, m, offset;
1365 uint8_t *ptr;
1366 int sym_index;
1367 int sym_end = symtab_section->data_offset / sizeof(ElfW(Sym));
1368 int n_trie = 0;
1369 struct trie *trie = NULL;
1370 addr_t vm_addr = get_segment(mo, 1)->vmaddr;
1372 for (sym_index = 1; sym_index < sym_end; ++sym_index) {
1373 ElfW(Sym) *sym = (ElfW(Sym) *)symtab_section->data + sym_index;
1374 const char *name = (char*)symtab_section->link->data + sym->st_name;
1376 if (sym->st_shndx == text_section->sh_num &&
1377 (ELFW(ST_BIND)(sym->st_info) == STB_GLOBAL ||
1378 ELFW(ST_BIND)(sym->st_info) == STB_WEAK)) {
1379 int flag = EXPORT_SYMBOL_FLAGS_KIND_REGULAR;
1380 addr_t addr =
1381 sym->st_value + s1->sections[sym->st_shndx]->sh_addr - vm_addr;
1383 if (ELFW(ST_BIND)(sym->st_info) == STB_WEAK)
1384 flag |= EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION;
1385 dprintf ("%s %d %llx\n", name, flag, addr + vm_addr);
1386 trie = tcc_realloc(trie, (n_trie + 1) * sizeof(struct trie));
1387 trie[n_trie].name = name;
1388 trie[n_trie].flag = flag;
1389 trie[n_trie].addr = addr;
1390 trie[n_trie].offset_size = 1;
1391 trie[n_trie].str_size = strlen(name) + 1;
1392 trie[n_trie].term_size = uleb128_size(flag) + uleb128_size(addr);
1393 trie[n_trie].term_offset = 0;
1394 n_trie++;
1397 /* FIXME: generate tree */
1398 if (n_trie > 255) {
1399 tcc_warning("Fix trie code. n_trie(%d) > 255", n_trie);
1400 n_trie = 255;
1402 if (n_trie) {
1403 tcc_qsort(trie, n_trie, sizeof(struct trie), triecmp, NULL);
1404 offset = 1 + 1;
1405 for (i = 0; i < n_trie; i++)
1406 offset += trie[i].str_size + trie[i].offset_size;
1407 for (i = 0; i < n_trie; i++) {
1408 n = uleb128_size(offset);
1409 trie[i].term_offset = offset + n - 1;
1410 trie[i].offset_size = n;
1411 offset += 1 + trie[i].term_size + 1 + n - 1;
1412 if (n > 1)
1413 for (j = i - 1; j >= 0; j--) {
1414 trie[j].term_offset += n - 1;
1415 m = uleb128_size(trie[j].term_offset);
1416 if (m != trie[j].offset_size) {
1417 n += m - trie[j].offset_size;
1418 offset += m - trie[j].offset_size;
1419 trie[j].offset_size = m;
1423 ptr = section_ptr_add(mo->exports, 2);
1424 *ptr++ = 0;
1425 *ptr = n_trie;
1426 for (i = 0; i < n_trie; i++) {
1427 ptr = section_ptr_add(mo->exports, trie[i].str_size);
1428 memcpy(ptr, trie[i].name, trie[i].str_size);
1429 write_uleb128(mo->exports, trie[i].term_offset);
1431 for (i = 0; i < n_trie; i++) {
1432 write_uleb128(mo->exports, trie[i].term_size);
1433 write_uleb128(mo->exports, trie[i].flag);
1434 write_uleb128(mo->exports, trie[i].addr);
1435 ptr = section_ptr_add(mo->exports, 1);
1436 *ptr = 0;
1438 section_ptr_add(mo->exports, -mo->exports->data_offset & 7);
1440 tcc_free(trie);
1443 static void collect_sections(TCCState *s1, struct macho *mo)
1445 int i, sk, numsec;
1446 uint64_t curaddr, fileofs;
1447 Section *s;
1448 struct segment_command_64 *seg = NULL;
1449 #ifdef CONFIG_NEW_MACHO
1450 struct linkedit_data_command *chained_fixups_lc;
1451 struct linkedit_data_command *export_trie_lc;
1452 #endif
1453 struct build_version_command *dyldbv;
1454 struct source_version_command *dyldsv;
1455 struct dylinker_command *dyldlc;
1456 struct symtab_command *symlc;
1457 struct dysymtab_command *dysymlc;
1458 char *str;
1460 seg = add_segment(mo, "__PAGEZERO");
1461 seg->vmsize = (uint64_t)1 << 32;
1463 seg = add_segment(mo, "__TEXT");
1464 seg->vmaddr = (uint64_t)1 << 32;
1465 seg->maxprot = 7; // rwx
1466 seg->initprot = 5; // r-x
1468 seg = add_segment(mo, "__DATA");
1469 seg->vmaddr = -1;
1470 seg->maxprot = 7; // rwx
1471 seg->initprot = 3; // rw-
1473 seg = add_segment(mo, "__LINKEDIT");
1474 seg->vmaddr = -1;
1475 seg->maxprot = 7; // rwx
1476 seg->initprot = 1; // r--
1478 #ifdef CONFIG_NEW_MACHO
1479 chained_fixups_lc = add_lc(mo, LC_DYLD_CHAINED_FIXUPS,
1480 sizeof(struct linkedit_data_command));
1481 export_trie_lc = add_lc(mo, LC_DYLD_EXPORTS_TRIE,
1482 sizeof(struct linkedit_data_command));
1483 #else
1484 mo->dyldinfo = add_lc(mo, LC_DYLD_INFO_ONLY, sizeof(*mo->dyldinfo));
1485 #endif
1487 symlc = add_lc(mo, LC_SYMTAB, sizeof(*symlc));
1488 dysymlc = add_lc(mo, LC_DYSYMTAB, sizeof(*dysymlc));
1490 i = (sizeof(*dyldlc) + strlen("/usr/lib/dyld") + 1 + 7) &-8;
1491 dyldlc = add_lc(mo, LC_LOAD_DYLINKER, i);
1492 dyldlc->name = sizeof(*dyldlc);
1493 str = (char*)dyldlc + dyldlc->name;
1494 strcpy(str, "/usr/lib/dyld");
1496 dyldbv = add_lc(mo, LC_BUILD_VERSION, sizeof(*dyldbv));
1497 dyldbv->platform = PLATFORM_MACOS;
1498 dyldbv->minos = (10 << 16) + (6 << 8);
1499 dyldbv->sdk = (10 << 16) + (6 << 8);
1500 dyldbv->ntools = 0;
1502 dyldsv = add_lc(mo, LC_SOURCE_VERSION, sizeof(*dyldsv));
1503 dyldsv->version = 0;
1505 mo->ep = add_lc(mo, LC_MAIN, sizeof(*mo->ep));
1506 mo->ep->entryoff = 4096;
1508 for(i = 0; i < s1->nb_loaded_dlls; i++) {
1509 DLLReference *dllref = s1->loaded_dlls[i];
1510 if (dllref->level == 0)
1511 add_dylib(mo, dllref->name);
1514 /* dyld requires a writable segment with classic Mach-O, but it ignores
1515 zero-sized segments for this, so force to have some data. */
1516 section_ptr_add(data_section, 1);
1517 memset (mo->sk_to_sect, 0, sizeof(mo->sk_to_sect));
1518 for (i = s1->nb_sections; i-- > 1;) {
1519 int type, flags;
1520 s = s1->sections[i];
1521 type = s->sh_type;
1522 flags = s->sh_flags;
1523 sk = sk_unknown;
1524 if (flags & SHF_ALLOC) {
1525 switch (type) {
1526 default: sk = sk_unknown; break;
1527 case SHT_INIT_ARRAY: sk = sk_init; break;
1528 case SHT_FINI_ARRAY: sk = sk_fini; break;
1529 case SHT_NOBITS: sk = sk_bss; break;
1530 case SHT_SYMTAB: sk = sk_discard; break;
1531 case SHT_STRTAB:
1532 if (s == stabstr_section)
1533 sk = sk_stab_str;
1534 else
1535 sk = sk_discard;
1536 break;
1537 case SHT_RELX: sk = sk_discard; break;
1538 case SHT_LINKEDIT: sk = sk_linkedit; break;
1539 case SHT_PROGBITS:
1540 if (s == mo->stubs)
1541 sk = sk_stubs;
1542 #ifndef CONFIG_NEW_MACHO
1543 else if (s == mo->stub_helper)
1544 sk = sk_stub_helper;
1545 else if (s == mo->la_symbol_ptr)
1546 sk = sk_la_ptr;
1547 #endif
1548 else if (s == s1->got)
1549 sk = sk_nl_ptr;
1550 else if (s == stab_section)
1551 sk = sk_stab;
1552 else if (s == dwarf_info_section)
1553 sk = sk_debug_info;
1554 else if (s == dwarf_abbrev_section)
1555 sk = sk_debug_abbrev;
1556 else if (s == dwarf_line_section)
1557 sk = sk_debug_line;
1558 else if (s == dwarf_aranges_section)
1559 sk = sk_debug_aranges;
1560 else if (s == dwarf_str_section)
1561 sk = sk_debug_str;
1562 else if (s == dwarf_line_str_section)
1563 sk = sk_debug_line_str;
1564 else if (flags & SHF_EXECINSTR)
1565 sk = sk_text;
1566 else if (flags & SHF_WRITE)
1567 sk = sk_rw_data;
1568 else
1569 sk = sk_ro_data;
1570 break;
1572 } else
1573 sk = sk_discard;
1574 s->prev = mo->sk_to_sect[sk].s;
1575 mo->sk_to_sect[sk].s = s;
1577 fileofs = 4096; /* leave space for mach-o headers */
1578 curaddr = get_segment(mo, 1)->vmaddr;
1579 curaddr += 4096;
1580 seg = NULL;
1581 numsec = 0;
1582 mo->elfsectomacho = tcc_mallocz(sizeof(*mo->elfsectomacho) * s1->nb_sections);
1583 for (sk = sk_unknown; sk < sk_last; sk++) {
1584 struct section_64 *sec = NULL;
1585 if (seg) {
1586 seg->vmsize = (curaddr - seg->vmaddr + SEG_PAGE_SIZE - 1) & -SEG_PAGE_SIZE;
1587 seg->filesize = (fileofs - seg->fileoff + SEG_PAGE_SIZE - 1) & -SEG_PAGE_SIZE;
1588 curaddr = seg->vmaddr + seg->vmsize;
1589 fileofs = seg->fileoff + seg->filesize;
1591 #ifdef CONFIG_NEW_MACHO
1592 if (sk == sk_linkedit) {
1593 calc_fixup_size(s1, mo);
1594 export_trie(s1, mo);
1596 #else
1597 if (sk == sk_linkedit) {
1598 bind_rebase(s1, mo);
1599 export_trie(s1, mo);
1601 #endif
1602 if (skinfo[sk].seg && mo->sk_to_sect[sk].s) {
1603 uint64_t al = 0;
1604 int si;
1605 seg = get_segment(mo, skinfo[sk].seg);
1606 if (skinfo[sk].name) {
1607 si = add_section(mo, &seg, skinfo[sk].name);
1608 numsec++;
1609 mo->lc[mo->seg2lc[skinfo[sk].seg]] = (struct load_command*)seg;
1610 mo->sk_to_sect[sk].machosect = si;
1611 sec = get_section(seg, si);
1612 sec->flags = skinfo[sk].flags;
1613 if (sk == sk_stubs)
1614 #ifdef TCC_TARGET_X86_64
1615 sec->reserved2 = 6;
1616 #elif defined TCC_TARGET_ARM64
1617 sec->reserved2 = 12;
1618 #endif
1619 if (sk == sk_nl_ptr)
1620 sec->reserved1 = mo->nr_plt;
1621 #ifndef CONFIG_NEW_MACHO
1622 if (sk == sk_la_ptr)
1623 sec->reserved1 = mo->nr_plt + mo->n_got;
1624 #endif
1626 if (seg->vmaddr == -1) {
1627 #ifdef CONFIG_NEW_MACHO
1628 curaddr = (curaddr + SEG_PAGE_SIZE - 1) & -SEG_PAGE_SIZE;
1629 seg->vmaddr = curaddr;
1630 fileofs = (fileofs + SEG_PAGE_SIZE - 1) & -SEG_PAGE_SIZE;
1631 seg->fileoff = fileofs;
1632 #else
1633 curaddr = (curaddr + 4095) & -4096;
1634 seg->vmaddr = curaddr;
1635 fileofs = (fileofs + 4095) & -4096;
1636 seg->fileoff = fileofs;
1637 #endif
1640 for (s = mo->sk_to_sect[sk].s; s; s = s->prev) {
1641 int a = exact_log2p1(s->sh_addralign);
1642 if (a && al < (a - 1))
1643 al = a - 1;
1644 s->sh_size = s->data_offset;
1646 if (sec)
1647 sec->align = al;
1648 al = 1ULL << al;
1649 if (al > 4096)
1650 tcc_warning("alignment > 4096"), sec->align = 12, al = 4096;
1651 curaddr = (curaddr + al - 1) & -al;
1652 fileofs = (fileofs + al - 1) & -al;
1653 if (sec) {
1654 sec->addr = curaddr;
1655 sec->offset = fileofs;
1657 for (s = mo->sk_to_sect[sk].s; s; s = s->prev) {
1658 al = s->sh_addralign;
1659 curaddr = (curaddr + al - 1) & -al;
1660 dprintf("curaddr now 0x%lx\n", (long)curaddr);
1661 s->sh_addr = curaddr;
1662 curaddr += s->sh_size;
1663 if (s->sh_type != SHT_NOBITS) {
1664 fileofs = (fileofs + al - 1) & -al;
1665 s->sh_offset = fileofs;
1666 fileofs += s->sh_size;
1667 dprintf("fileofs now %ld\n", (long)fileofs);
1669 if (sec)
1670 mo->elfsectomacho[s->sh_num] = numsec;
1672 if (sec)
1673 sec->size = curaddr - sec->addr;
1675 if (DEBUG_MACHO)
1676 for (s = mo->sk_to_sect[sk].s; s; s = s->prev) {
1677 int type = s->sh_type;
1678 int flags = s->sh_flags;
1679 printf("%d section %-16s %-10s %09lx %04x %02d %s,%s,%s\n",
1681 s->name,
1682 type == SHT_PROGBITS ? "progbits" :
1683 type == SHT_NOBITS ? "nobits" :
1684 type == SHT_SYMTAB ? "symtab" :
1685 type == SHT_STRTAB ? "strtab" :
1686 type == SHT_INIT_ARRAY ? "init" :
1687 type == SHT_FINI_ARRAY ? "fini" :
1688 type == SHT_RELX ? "rel" : "???",
1689 (long)s->sh_addr,
1690 (unsigned)s->data_offset,
1691 s->sh_addralign,
1692 flags & SHF_ALLOC ? "alloc" : "",
1693 flags & SHF_WRITE ? "write" : "",
1694 flags & SHF_EXECINSTR ? "exec" : ""
1698 if (seg) {
1699 seg->vmsize = curaddr - seg->vmaddr;
1700 seg->filesize = fileofs - seg->fileoff;
1703 /* Fill symtab info */
1704 symlc->symoff = mo->symtab->sh_offset;
1705 symlc->nsyms = mo->symtab->data_offset / sizeof(struct nlist_64);
1706 symlc->stroff = mo->strtab->sh_offset;
1707 symlc->strsize = mo->strtab->data_offset;
1709 dysymlc->iundefsym = mo->iundef == -1 ? symlc->nsyms : mo->iundef;
1710 dysymlc->iextdefsym = mo->iextdef == -1 ? dysymlc->iundefsym : mo->iextdef;
1711 dysymlc->ilocalsym = mo->ilocal == -1 ? dysymlc->iextdefsym : mo->ilocal;
1712 dysymlc->nlocalsym = dysymlc->iextdefsym - dysymlc->ilocalsym;
1713 dysymlc->nextdefsym = dysymlc->iundefsym - dysymlc->iextdefsym;
1714 dysymlc->nundefsym = symlc->nsyms - dysymlc->iundefsym;
1715 dysymlc->indirectsymoff = mo->indirsyms->sh_offset;
1716 dysymlc->nindirectsyms = mo->indirsyms->data_offset / sizeof(uint32_t);
1718 #ifdef CONFIG_NEW_MACHO
1719 if (mo->chained_fixups->data_offset) {
1720 chained_fixups_lc->dataoff = mo->chained_fixups->sh_offset;
1721 chained_fixups_lc->datasize = mo->chained_fixups->data_offset;
1723 if (mo->exports->data_offset) {
1724 export_trie_lc->dataoff = mo->exports->sh_offset;
1725 export_trie_lc->datasize = mo->exports->data_offset;
1727 #else
1728 if (mo->rebase->data_offset) {
1729 mo->dyldinfo->rebase_off = mo->rebase->sh_offset;
1730 mo->dyldinfo->rebase_size = mo->rebase->data_offset;
1732 if (mo->binding->data_offset) {
1733 mo->dyldinfo->bind_off = mo->binding->sh_offset;
1734 mo->dyldinfo->bind_size = mo->binding->data_offset;
1736 if (mo->weak_binding->data_offset) {
1737 mo->dyldinfo->weak_bind_off = mo->weak_binding->sh_offset;
1738 mo->dyldinfo->weak_bind_size = mo->weak_binding->data_offset;
1740 if (mo->lazy_binding->data_offset) {
1741 mo->dyldinfo->lazy_bind_off = mo->lazy_binding->sh_offset;
1742 mo->dyldinfo->lazy_bind_size = mo->lazy_binding->data_offset;
1744 if (mo->exports->data_offset) {
1745 mo->dyldinfo->export_off = mo->exports->sh_offset;
1746 mo->dyldinfo->export_size = mo->exports->data_offset;
1748 #endif
1751 static void macho_write(TCCState *s1, struct macho *mo, FILE *fp)
1753 int i, sk;
1754 uint64_t fileofs = 0;
1755 Section *s;
1756 mo->mh.mh.magic = MH_MAGIC_64;
1757 #ifdef TCC_TARGET_X86_64
1758 mo->mh.mh.cputype = CPU_TYPE_X86_64;
1759 mo->mh.mh.cpusubtype = CPU_SUBTYPE_LIB64 | CPU_SUBTYPE_X86_ALL;
1760 #elif defined TCC_TARGET_ARM64
1761 mo->mh.mh.cputype = CPU_TYPE_ARM64;
1762 mo->mh.mh.cpusubtype = CPU_SUBTYPE_ARM64_ALL;
1763 #endif
1764 mo->mh.mh.filetype = MH_EXECUTE;
1765 mo->mh.mh.flags = MH_DYLDLINK | MH_PIE;
1766 mo->mh.mh.ncmds = mo->nlc;
1767 mo->mh.mh.sizeofcmds = 0;
1768 for (i = 0; i < mo->nlc; i++)
1769 mo->mh.mh.sizeofcmds += mo->lc[i]->cmdsize;
1771 fwrite(&mo->mh, 1, sizeof(mo->mh), fp);
1772 fileofs += sizeof(mo->mh);
1773 for (i = 0; i < mo->nlc; i++) {
1774 fwrite(mo->lc[i], 1, mo->lc[i]->cmdsize, fp);
1775 fileofs += mo->lc[i]->cmdsize;
1778 for (sk = sk_unknown; sk < sk_last; sk++) {
1779 //struct segment_command_64 *seg;
1780 if (!skinfo[sk].seg || !mo->sk_to_sect[sk].s)
1781 continue;
1782 /*seg =*/ get_segment(mo, skinfo[sk].seg);
1783 for (s = mo->sk_to_sect[sk].s; s; s = s->prev) {
1784 if (s->sh_type != SHT_NOBITS) {
1785 while (fileofs < s->sh_offset)
1786 fputc(0, fp), fileofs++;
1787 if (s->sh_size) {
1788 fwrite(s->data, 1, s->sh_size, fp);
1789 fileofs += s->sh_size;
1796 #ifdef CONFIG_NEW_MACHO
1797 static int bind_rebase_cmp(const void *_a, const void *_b, void *arg)
1799 TCCState *s1 = arg;
1800 struct bind_rebase *a = (struct bind_rebase *) _a;
1801 struct bind_rebase *b = (struct bind_rebase *) _b;
1802 addr_t aa = s1->sections[a->section]->sh_addr + a->rel.r_offset;
1803 addr_t ab = s1->sections[b->section]->sh_addr + b->rel.r_offset;
1805 return aa > ab ? 1 : aa < ab ? -1 : 0;
1808 ST_FUNC void bind_rebase_import(TCCState *s1, struct macho *mo)
1810 int i, j, k, bind_index, size, page_count, sym_index;
1811 const char *name;
1812 ElfW_Rel rel;
1813 ElfW(Sym) *sym;
1814 unsigned char *data = mo->chained_fixups->data;
1815 struct segment_command_64 *seg;
1816 struct dyld_chained_fixups_header *header;
1817 struct dyld_chained_starts_in_image *image;
1818 struct dyld_chained_starts_in_segment *segment;
1819 struct dyld_chained_import *import;
1821 tcc_qsort(mo->bind_rebase, mo->n_bind_rebase, sizeof(struct bind_rebase),
1822 bind_rebase_cmp, s1);
1823 for (i = 0; i < mo->n_bind_rebase - 1; i++)
1824 if (mo->bind_rebase[i].section == mo->bind_rebase[i + 1].section &&
1825 mo->bind_rebase[i].rel.r_offset == mo->bind_rebase[i + 1].rel.r_offset) {
1826 sym_index = ELFW(R_SYM)(mo->bind_rebase[i].rel.r_info);
1827 sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
1828 name = (char *) symtab_section->link->data + sym->st_name;
1829 tcc_error("Overlap %s/%s %s:%s",
1830 mo->bind_rebase[i].bind ? "bind" : "rebase",
1831 mo->bind_rebase[i + 1].bind ? "bind" : "rebase",
1832 s1->sections[mo->bind_rebase[i].section]->name, name);
1834 header = (struct dyld_chained_fixups_header *) data;
1835 data += (sizeof(struct dyld_chained_fixups_header) + 7) & -8;
1836 header->starts_offset = data - mo->chained_fixups->data;
1837 header->imports_count = mo->n_bind;
1838 header->imports_format = DYLD_CHAINED_IMPORT;
1839 header->symbols_format = 0;
1840 size = sizeof(struct dyld_chained_starts_in_image) +
1841 (mo->nseg - 1) * sizeof(uint32_t);
1842 image = (struct dyld_chained_starts_in_image *) data;
1843 data += (size + 7) & -8;
1844 image->seg_count = mo->nseg;
1845 for (i = 1; i < mo->nseg - 1; i++) {
1846 image->seg_info_offset[i] = (data - mo->chained_fixups->data) -
1847 header->starts_offset;
1848 seg = get_segment(mo, i);
1849 page_count = (seg->vmsize + SEG_PAGE_SIZE - 1) / SEG_PAGE_SIZE;
1850 size = sizeof(struct dyld_chained_starts_in_segment) +
1851 (page_count - 1) * sizeof(uint16_t);
1852 segment = (struct dyld_chained_starts_in_segment *) data;
1853 data += (size + 7) & -8;
1854 segment->size = size;
1855 segment->page_size = SEG_PAGE_SIZE;
1856 #if 1
1857 #define PTR_64_OFFSET 0
1858 #define PTR_64_MASK 0x7FFFFFFFFFFULL
1859 segment->pointer_format = DYLD_CHAINED_PTR_64;
1860 #else
1861 #define PTR_64_OFFSET 0x100000000ULL
1862 #define PTR_64_MASK 0xFFFFFFFFFFFFFFULL
1863 segment->pointer_format = DYLD_CHAINED_PTR_64_OFFSET;
1864 #endif
1865 segment->segment_offset = seg->fileoff;
1866 segment->max_valid_pointer = 0;
1867 segment->page_count = page_count;
1868 // add bind/rebase
1869 for (j = 0; j < page_count; j++) {
1870 uint64_t start = seg->vmaddr + j * SEG_PAGE_SIZE;
1871 uint64_t end = start + SEG_PAGE_SIZE;
1872 void *last;
1873 addr_t last_o = 0;
1874 uint64_t cur_o, cur;
1875 struct dyld_chained_ptr_64_rebase *rebase;
1876 struct dyld_chained_ptr_64_bind *bind;
1877 Section *s;
1879 segment->page_start[j] = DYLD_CHAINED_PTR_START_NONE;
1880 for (k = 0, bind_index = 0; k < mo->n_bind_rebase; k++) {
1881 uint64_t addr;
1883 s = s1->sections[mo->bind_rebase[k].section];
1884 rel = mo->bind_rebase[k].rel;
1885 if ((rel.r_offset & 3) ||
1886 (rel.r_offset & (SEG_PAGE_SIZE - 1)) >
1887 SEG_PAGE_SIZE - PTR_SIZE)
1888 tcc_error("Illegal rel_offset %s %lld",
1889 s->name, (long long)rel.r_offset);
1890 addr = s->sh_addr + rel.r_offset;
1891 if (addr >= start && addr < end) {
1892 cur_o = addr - start;
1893 if (mo->bind_rebase[k].bind) {
1894 if (segment->page_start[j] == DYLD_CHAINED_PTR_START_NONE)
1895 segment->page_start[j] = cur_o;
1896 else {
1897 bind = (struct dyld_chained_ptr_64_bind *) last;
1898 bind->next = (cur_o - last_o) / 4;
1900 bind = (struct dyld_chained_ptr_64_bind *)
1901 (s->data + rel.r_offset);
1902 last = bind;
1903 last_o = cur_o;
1904 bind->ordinal = bind_index;
1905 bind->addend = 0;
1906 bind->reserved = 0;
1907 bind->next = 0;
1908 bind->bind = 1;
1910 else {
1911 if (segment->page_start[j] == DYLD_CHAINED_PTR_START_NONE)
1912 segment->page_start[j] = cur_o;
1913 else {
1914 rebase = (struct dyld_chained_ptr_64_rebase *) last;
1915 rebase->next = (cur_o - last_o) / 4;
1917 rebase = (struct dyld_chained_ptr_64_rebase *)
1918 (s->data + rel.r_offset);
1919 last = rebase;
1920 last_o = cur_o;
1921 cur = (*(uint64_t *) (s->data + rel.r_offset)) -
1922 PTR_64_OFFSET;
1923 rebase->target = cur & PTR_64_MASK;
1924 rebase->high8 = cur >> (64 - 8);
1925 if (cur != ((uint64_t)rebase->high8 << (64 - 8)) + rebase->target)
1926 tcc_error("rebase error");
1927 rebase->reserved = 0;
1928 rebase->next = 0;
1929 rebase->bind = 0;
1932 bind_index += mo->bind_rebase[k].bind;
1936 // add imports
1937 header->imports_offset = data - mo->chained_fixups->data;
1938 import = (struct dyld_chained_import *) data;
1939 data += mo->n_bind * sizeof (struct dyld_chained_import);
1940 header->symbols_offset = data - mo->chained_fixups->data;
1941 data++;
1942 for (i = 0, bind_index = 0; i < mo->n_bind_rebase; i++) {
1943 if (mo->bind_rebase[i].bind) {
1944 import[bind_index].lib_ordinal =
1945 BIND_SPECIAL_DYLIB_FLAT_LOOKUP & 0xffu;
1946 import[bind_index].name_offset =
1947 (data - mo->chained_fixups->data) - header->symbols_offset;
1948 sym_index = ELFW(R_SYM)(mo->bind_rebase[i].rel.r_info);
1949 sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
1950 import[bind_index].weak_import =
1951 ELFW(ST_BIND)(sym->st_info) == STB_WEAK;
1952 name = (char *) symtab_section->link->data + sym->st_name;
1953 strcpy((char *) data, name);
1954 data += strlen(name) + 1;
1955 bind_index++;
1958 tcc_free(mo->bind_rebase);
1960 #endif
1962 ST_FUNC int macho_output_file(TCCState *s1, const char *filename)
1964 int fd, mode, file_type;
1965 FILE *fp;
1966 int i, ret = -1;
1967 struct macho mo;
1969 (void)memset(&mo, 0, sizeof(mo));
1971 file_type = s1->output_type;
1972 if (file_type == TCC_OUTPUT_OBJ)
1973 mode = 0666;
1974 else
1975 mode = 0777;
1976 unlink(filename);
1977 fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, mode);
1978 if (fd < 0 || (fp = fdopen(fd, "wb")) == NULL) {
1979 tcc_error_noabort("could not write '%s: %s'", filename, strerror(errno));
1980 return -1;
1982 if (s1->verbose)
1983 printf("<- %s\n", filename);
1985 tcc_add_runtime(s1);
1986 tcc_macho_add_destructor(s1);
1987 resolve_common_syms(s1);
1988 create_symtab(s1, &mo);
1989 check_relocs(s1, &mo);
1990 ret = check_symbols(s1, &mo);
1991 if (!ret) {
1992 collect_sections(s1, &mo);
1993 relocate_syms(s1, s1->symtab, 0);
1994 mo.ep->entryoff = get_sym_addr(s1, "main", 1, 1)
1995 - get_segment(&mo, 1)->vmaddr;
1996 if (s1->nb_errors)
1997 goto do_ret;
1998 relocate_sections(s1);
1999 #ifdef CONFIG_NEW_MACHO
2000 bind_rebase_import(s1, &mo);
2001 #endif
2002 convert_symbols(s1, &mo);
2003 macho_write(s1, &mo, fp);
2006 do_ret:
2007 for (i = 0; i < mo.nlc; i++)
2008 tcc_free(mo.lc[i]);
2009 tcc_free(mo.lc);
2010 tcc_free(mo.elfsectomacho);
2011 tcc_free(mo.e2msym);
2013 fclose(fp);
2014 #ifdef CONFIG_CODESIGN
2016 char command[1024];
2017 int retval;
2019 snprintf(command, sizeof(command), "codesign -f -s - %s", filename);
2020 retval = system (command);
2021 if (retval == -1 || !(WIFEXITED(retval) && WEXITSTATUS(retval) == 0))
2022 tcc_error ("command failed '%s'", command);
2024 #endif
2025 return ret;
2028 static uint32_t macho_swap32(uint32_t x)
2030 return (x >> 24) | (x << 24) | ((x >> 8) & 0xff00) | ((x & 0xff00) << 8);
2032 #define SWAP(x) (swap ? macho_swap32(x) : (x))
2033 #define tbd_parse_movepast(s) \
2034 (pos = (pos = strstr(pos, s)) ? pos + strlen(s) : NULL)
2035 #define tbd_parse_movetoany(cs) (pos = strpbrk(pos, cs))
2036 #define tbd_parse_skipws while (*pos && (*pos==' '||*pos=='\n')) ++pos
2037 #define tbd_parse_tramplequote if(*pos=='\''||*pos=='"') tbd_parse_trample
2038 #define tbd_parse_tramplespace if(*pos==' ') tbd_parse_trample
2039 #define tbd_parse_trample *pos++=0
2041 #ifdef TCC_IS_NATIVE
2042 /* Looks for the active developer SDK set by xcode-select (or the default
2043 one set during installation.) */
2044 ST_FUNC void tcc_add_macos_sdkpath(TCCState* s)
2046 char *sdkroot = NULL, *pos = NULL;
2047 void* xcs = dlopen("libxcselect.dylib", RTLD_GLOBAL | RTLD_LAZY);
2048 CString path;
2049 int (*f)(unsigned int, char**) = dlsym(xcs, "xcselect_host_sdk_path");
2050 cstr_new(&path);
2051 if (f) f(1, &sdkroot);
2052 if (sdkroot)
2053 pos = strstr(sdkroot,"SDKs/MacOSX");
2054 if (pos)
2055 cstr_printf(&path, "%.*s.sdk/usr/lib", (int)(pos - sdkroot + 11), sdkroot);
2056 /* must use free from libc directly */
2057 #pragma push_macro("free")
2058 #undef free
2059 free(sdkroot);
2060 #pragma pop_macro("free")
2061 if (path.size)
2062 tcc_add_library_path(s, (char*)path.data);
2063 else
2064 tcc_add_library_path(s,
2065 "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/lib"
2066 ":" "/Applications/Xcode.app/Developer/SDKs/MacOSX.sdk/usr/lib"
2068 cstr_free(&path);
2071 ST_FUNC const char* macho_tbd_soname(const char* filename) {
2072 char *soname, *data, *pos;
2073 const char *ret = filename;
2075 int fd = open(filename,O_RDONLY);
2076 if (fd<0) return ret;
2077 pos = data = tcc_load_text(fd);
2078 if (!tbd_parse_movepast("install-name: ")) goto the_end;
2079 tbd_parse_skipws;
2080 tbd_parse_tramplequote;
2081 soname = pos;
2082 if (!tbd_parse_movetoany("\n \"'")) goto the_end;
2083 tbd_parse_trample;
2084 ret = tcc_strdup(soname);
2085 the_end:
2086 tcc_free(data);
2087 return ret;
2089 #endif /* TCC_IS_NATIVE */
2091 ST_FUNC int macho_load_tbd(TCCState* s1, int fd, const char* filename, int lev)
2093 char *soname, *data, *pos;
2094 int ret = -1;
2096 pos = data = tcc_load_text(fd);
2097 if (!tbd_parse_movepast("install-name: ")) goto the_end;
2098 tbd_parse_skipws;
2099 tbd_parse_tramplequote;
2100 soname = pos;
2101 if (!tbd_parse_movetoany("\n \"'")) goto the_end;
2102 tbd_parse_trample;
2103 ret = 0;
2104 if (tcc_add_dllref(s1, soname, lev)->found)
2105 goto the_end;
2106 while(pos) {
2107 char* sym = NULL;
2108 int cont = 1;
2109 if (!tbd_parse_movepast("symbols: ")) break;
2110 if (!tbd_parse_movepast("[")) break;
2111 while (cont) {
2112 tbd_parse_skipws;
2113 tbd_parse_tramplequote;
2114 sym = pos;
2115 if (!tbd_parse_movetoany(",] \"'")) break;
2116 tbd_parse_tramplequote;
2117 tbd_parse_tramplespace;
2118 tbd_parse_skipws;
2119 if (*pos==0||*pos==']') cont=0;
2120 tbd_parse_trample;
2121 set_elf_sym(s1->dynsymtab_section, 0, 0,
2122 ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, SHN_UNDEF, sym);
2126 the_end:
2127 tcc_free(data);
2128 return ret;
2131 ST_FUNC int macho_load_dll(TCCState * s1, int fd, const char* filename, int lev)
2133 unsigned char buf[sizeof(struct mach_header_64)];
2134 void *buf2;
2135 uint32_t machofs = 0;
2136 struct fat_header fh;
2137 struct mach_header mh;
2138 struct load_command *lc;
2139 int i, swap = 0;
2140 const char *soname = filename;
2141 struct nlist_64 *symtab = 0;
2142 uint32_t nsyms = 0;
2143 char *strtab = 0;
2144 uint32_t strsize = 0;
2145 uint32_t iextdef = 0;
2146 uint32_t nextdef = 0;
2148 again:
2149 if (full_read(fd, buf, sizeof(buf)) != sizeof(buf))
2150 return -1;
2151 memcpy(&fh, buf, sizeof(fh));
2152 if (fh.magic == FAT_MAGIC || fh.magic == FAT_CIGAM) {
2153 struct fat_arch *fa = load_data(fd, sizeof(fh),
2154 fh.nfat_arch * sizeof(*fa));
2155 swap = fh.magic == FAT_CIGAM;
2156 for (i = 0; i < SWAP(fh.nfat_arch); i++)
2157 #ifdef TCC_TARGET_X86_64
2158 if (SWAP(fa[i].cputype) == CPU_TYPE_X86_64
2159 && SWAP(fa[i].cpusubtype) == CPU_SUBTYPE_X86_ALL)
2160 #elif defined TCC_TARGET_ARM64
2161 if (SWAP(fa[i].cputype) == CPU_TYPE_ARM64
2162 && SWAP(fa[i].cpusubtype) == CPU_SUBTYPE_ARM64_ALL)
2163 #endif
2164 break;
2165 if (i == SWAP(fh.nfat_arch)) {
2166 tcc_free(fa);
2167 return -1;
2169 machofs = SWAP(fa[i].offset);
2170 tcc_free(fa);
2171 lseek(fd, machofs, SEEK_SET);
2172 goto again;
2173 } else if (fh.magic == FAT_MAGIC_64 || fh.magic == FAT_CIGAM_64) {
2174 tcc_warning("%s: Mach-O fat 64bit files of type 0x%x not handled",
2175 filename, fh.magic);
2176 return -1;
2179 memcpy(&mh, buf, sizeof(mh));
2180 if (mh.magic != MH_MAGIC_64)
2181 return -1;
2182 dprintf("found Mach-O at %d\n", machofs);
2183 buf2 = load_data(fd, machofs + sizeof(struct mach_header_64), mh.sizeofcmds);
2184 for (i = 0, lc = buf2; i < mh.ncmds; i++) {
2185 dprintf("lc %2d: 0x%08x\n", i, lc->cmd);
2186 switch (lc->cmd) {
2187 case LC_SYMTAB:
2189 struct symtab_command *sc = (struct symtab_command*)lc;
2190 nsyms = sc->nsyms;
2191 symtab = load_data(fd, machofs + sc->symoff, nsyms * sizeof(*symtab));
2192 strsize = sc->strsize;
2193 strtab = load_data(fd, machofs + sc->stroff, strsize);
2194 break;
2196 case LC_ID_DYLIB:
2198 struct dylib_command *dc = (struct dylib_command*)lc;
2199 soname = (char*)lc + dc->name;
2200 dprintf(" ID_DYLIB %d 0x%x 0x%x %s\n",
2201 dc->timestamp, dc->current_version,
2202 dc->compatibility_version, soname);
2203 break;
2205 case LC_REEXPORT_DYLIB:
2207 struct dylib_command *dc = (struct dylib_command*)lc;
2208 char *name = (char*)lc + dc->name;
2209 int subfd = open(name, O_RDONLY | O_BINARY);
2210 dprintf(" REEXPORT %s\n", name);
2211 if (subfd < 0)
2212 tcc_warning("can't open %s (reexported from %s)", name, filename);
2213 else {
2214 /* Hopefully the REEXPORTs never form a cycle, we don't check
2215 for that! */
2216 macho_load_dll(s1, subfd, name, lev + 1);
2217 close(subfd);
2219 break;
2221 case LC_DYSYMTAB:
2223 struct dysymtab_command *dc = (struct dysymtab_command*)lc;
2224 iextdef = dc->iextdefsym;
2225 nextdef = dc->nextdefsym;
2226 break;
2229 lc = (struct load_command*) ((char*)lc + lc->cmdsize);
2232 if (tcc_add_dllref(s1, soname, lev)->found)
2233 goto the_end;
2235 if (!nsyms || !nextdef)
2236 tcc_warning("%s doesn't export any symbols?", filename);
2238 //dprintf("symbols (all):\n");
2239 dprintf("symbols (exported):\n");
2240 dprintf(" n: typ sec desc value name\n");
2241 //for (i = 0; i < nsyms; i++) {
2242 for (i = iextdef; i < iextdef + nextdef; i++) {
2243 struct nlist_64 *sym = symtab + i;
2244 dprintf("%5d: %3d %3d 0x%04x 0x%016lx %s\n",
2245 i, sym->n_type, sym->n_sect, sym->n_desc, (long)sym->n_value,
2246 strtab + sym->n_strx);
2247 set_elf_sym(s1->dynsymtab_section, 0, 0,
2248 ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE),
2249 0, SHN_UNDEF, strtab + sym->n_strx);
2252 the_end:
2253 tcc_free(strtab);
2254 tcc_free(symtab);
2255 tcc_free(buf2);
2256 return 0;