| @@ -18,6 +18,7 @@ · 17 unmodified lines |
| 18 | 18 | #include "tcc.h" |
| 19 | 19 | |
| 20 | 20 | #define DEBUG_MACHO 0 |
| 21 | +#define dprintf if (DEBUG_MACHO) printf |
| 21 | 22 | |
| 22 | 23 | struct mach_header { |
| 23 | 24 | uint32_t magic; /* mach magic number identifier */ |
| @@ -231,7 +232,9 @@ struct macho { · 207 unmodified lines |
| 231 | 232 | #define LC_SYMTAB 0x2 |
| 232 | 233 | #define LC_DYSYMTAB 0xb |
| 233 | 234 | #define LC_LOAD_DYLIB 0xc |
| 235 | +#define LC_ID_DYLIB 0xd |
| 234 | 236 | #define LC_LOAD_DYLINKER 0xe |
| 237 | +#define LC_REEXPORT_DYLIB (0x1f | LC_REQ_DYLD) |
| 235 | 238 | #define LC_MAIN (0x28|LC_REQ_DYLD) |
| 236 | 239 | |
| 237 | 240 | /* Hack for now, 46_grep.c needs fopen, but due to aliasing games |
| @@ -375,10 +378,9 @@ static int check_symbols(TCCState *s1, struct macho *mo) · 137 unmodified lines |
| 375 | 378 | unsigned bind = ELFW(ST_BIND)(sym->st_info); |
| 376 | 379 | unsigned vis = ELFW(ST_VISIBILITY)(sym->st_other); |
| 377 | 380 | |
| 378 | | − if (DEBUG_MACHO) |
| 379 | | − printf("%4d (%4d): %09llx %4d %4d %4d %3d %s\n", |
| 380 | | − sym_index, elf_index, sym->st_value, |
| 381 | | − type, bind, vis, sym->st_shndx, name); |
| 381 | + dprintf("%4d (%4d): %09llx %4d %4d %4d %3d %s\n", |
| 382 | + sym_index, elf_index, sym->st_value, |
| 383 | + type, bind, vis, sym->st_shndx, name); |
| 382 | 384 | if (bind == STB_LOCAL) { |
| 383 | 385 | if (mo->ilocal == -1) |
| 384 | 386 | mo->ilocal = sym_index - 1; |
| @@ -394,15 +396,12 @@ static int check_symbols(TCCState *s1, struct macho *mo) · 9 unmodified lines |
| 394 | 396 | mo->iundef = sym_index - 1; |
| 395 | 397 | if (ELFW(ST_BIND)(sym->st_info) == STB_WEAK) |
| 396 | 398 | continue; |
| 397 | | − if (get_sym_attr(s1, elf_index, 0)) { |
| 399 | + if (find_elf_sym(s1->dynsymtab_section, name)) { |
| 398 | 400 | /* Mark the symbol as coming from a dylib so that |
| 399 | | − relocate_syms doesn't complain. Normally we would have |
| 400 | | − checked that any dylib in fact exports this one, and listed |
| 401 | | − those in s1->dynsymtab, which would cause us to enter this |
| 402 | | − symbol into s1->dynsym, which is checked by relocate_syms. |
| 403 | | − But for now we fake this and regard all undefined as |
| 404 | | − coming from a dylib, and we don't use the dynsymtab/dynsym |
| 405 | | − scheme. */ |
| 401 | + relocate_syms doesn't complain. Normally bind_exe_dynsyms |
| 402 | + would do this check, and place the symbol into dynsym |
| 403 | + which is checked by relocate_syms. But Mach-O doesn't use |
| 404 | + bind_exe_dynsyms. */ |
| 406 | 405 | sym->st_shndx = SHN_FROMDLL; |
| 407 | 406 | continue; |
| 408 | 407 | } |
| @@ -589,7 +588,11 @@ static void collect_sections(TCCState *s1, struct macho *mo) · 180 unmodified lines |
| 589 | 588 | dysymlc->cmdsize = sizeof(*dysymlc); |
| 590 | 589 | add_lc(mo, dysymlc); |
| 591 | 590 | |
| 592 | | − add_dylib(mo, "/usr/lib/libSystem.B.dylib"); |
| 591 | + for(i = 0; i < s1->nb_loaded_dlls; i++) { |
| 592 | + DLLReference *dllref = s1->loaded_dlls[i]; |
| 593 | + if (dllref->level == 0) |
| 594 | + add_dylib(mo, dllref->name); |
| 595 | + } |
| 593 | 596 | |
| 594 | 597 | mo->linkedit = new_section(s1, "LINKEDIT", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE); |
| 595 | 598 | /* LINKEDIT can't be empty (XXX remove once we have symbol table) */ |
| @@ -683,16 +686,14 @@ static void collect_sections(TCCState *s1, struct macho *mo) · 87 unmodified lines |
| 683 | 686 | for (s = mo->sk_to_sect[sk].s; s; s = s->prev) { |
| 684 | 687 | al = s->sh_addralign; |
| 685 | 688 | curaddr = (curaddr + al - 1) & -al; |
| 686 | | − if (DEBUG_MACHO) |
| 687 | | − printf("curaddr now 0x%llx\n", curaddr); |
| 689 | + dprintf("curaddr now 0x%llx\n", curaddr); |
| 688 | 690 | s->sh_addr = curaddr; |
| 689 | 691 | curaddr += s->sh_size; |
| 690 | 692 | if (s->sh_type != SHT_NOBITS) { |
| 691 | 693 | fileofs = (fileofs + al - 1) & -al; |
| 692 | 694 | s->sh_offset = fileofs; |
| 693 | 695 | fileofs += s->sh_size; |
| 694 | | − if (DEBUG_MACHO) |
| 695 | | − printf("fileofs now %lld\n", fileofs); |
| 696 | + dprintf("fileofs now %lld\n", fileofs); |
| 696 | 697 | } |
| 697 | 698 | if (sec) |
| 698 | 699 | mo->elfsectomacho[s->sh_num] = numsec; |
| @@ -799,7 +800,7 @@ ST_FUNC int macho_output_file(TCCState *s1, const char *filename) · 100 unmodified lines |
| 799 | 800 | int fd, mode, file_type; |
| 800 | 801 | FILE *fp; |
| 801 | 802 | int ret = -1; |
| 802 | | − struct macho mo = {0,}; |
| 803 | + struct macho mo = {}; |
| 803 | 804 | |
| 804 | 805 | file_type = s1->output_type; |
| 805 | 806 | if (file_type == TCC_OUTPUT_OBJ) |
| @@ -845,3 +846,145 @@ ST_FUNC int macho_output_file(TCCState *s1, const char *filename) · 39 unmodified lines |
| 845 | 846 | fclose(fp); |
| 846 | 847 | return ret; |
| 847 | 848 | } |
| 849 | + |
| 850 | +#define FAT_MAGIC 0xcafebabe |
| 851 | +#define FAT_CIGAM 0xbebafeca |
| 852 | +#define FAT_MAGIC_64 0xcafebabf |
| 853 | +#define FAT_CIGAM_64 0xbfbafeca |
| 854 | + |
| 855 | +struct fat_header { |
| 856 | + uint32_t magic; /* FAT_MAGIC or FAT_MAGIC_64 */ |
| 857 | + uint32_t nfat_arch; /* number of structs that follow */ |
| 858 | +}; |
| 859 | + |
| 860 | +struct fat_arch { |
| 861 | + int cputype; /* cpu specifier (int) */ |
| 862 | + int cpusubtype; /* machine specifier (int) */ |
| 863 | + uint32_t offset; /* file offset to this object file */ |
| 864 | + uint32_t size; /* size of this object file */ |
| 865 | + uint32_t align; /* alignment as a power of 2 */ |
| 866 | +}; |
| 867 | + |
| 868 | +#define SWAP(x) (swap ? ntohl(x) : (x)) |
| 869 | +ST_FUNC int macho_load_dll(TCCState *s1, int fd, const char *filename, int lev) |
| 870 | +{ |
| 871 | + unsigned char buf[sizeof(struct mach_header_64)]; |
| 872 | + void *buf2; |
| 873 | + uint32_t machofs = 0; |
| 874 | + struct fat_header fh; |
| 875 | + struct mach_header mh; |
| 876 | + struct load_command *lc; |
| 877 | + int i, swap = 0; |
| 878 | + const char *soname = filename; |
| 879 | + struct nlist_64 *symtab = 0; |
| 880 | + uint32_t nsyms = 0; |
| 881 | + char *strtab = 0; |
| 882 | + uint32_t strsize = 0; |
| 883 | + uint32_t iextdef = 0; |
| 884 | + uint32_t nextdef = 0; |
| 885 | + DLLReference *dllref; |
| 886 | + |
| 887 | + again: |
| 888 | + if (full_read(fd, buf, sizeof(buf)) != sizeof(buf)) |
| 889 | + return -1; |
| 890 | + memcpy(&fh, buf, sizeof(fh)); |
| 891 | + if (fh.magic == FAT_MAGIC || fh.magic == FAT_CIGAM) { |
| 892 | + struct fat_arch *fa = load_data(fd, sizeof(fh), |
| 893 | + fh.nfat_arch * sizeof(*fa)); |
| 894 | + swap = fh.magic == FAT_CIGAM; |
| 895 | + for (i = 0; i < SWAP(fh.nfat_arch); i++) |
| 896 | + if (SWAP(fa[i].cputype) == 0x01000007 /* CPU_TYPE_X86_64 */ |
| 897 | + && SWAP(fa[i].cpusubtype) == 3) /* CPU_SUBTYPE_X86_ALL */ |
| 898 | + break; |
| 899 | + if (i == SWAP(fh.nfat_arch)) { |
| 900 | + tcc_free(fa); |
| 901 | + return -1; |
| 902 | + } |
| 903 | + machofs = SWAP(fa[i].offset); |
| 904 | + tcc_free(fa); |
| 905 | + lseek(fd, machofs, SEEK_SET); |
| 906 | + goto again; |
| 907 | + } else if (fh.magic == FAT_MAGIC_64 || fh.magic == FAT_CIGAM_64) { |
| 908 | + tcc_warning("%s: Mach-O fat 64bit files of type 0x%x not handled", |
| 909 | + filename, fh.magic); |
| 910 | + return -1; |
| 911 | + } |
| 912 | + |
| 913 | + memcpy(&mh, buf, sizeof(mh)); |
| 914 | + if (mh.magic != MH_MAGIC_64) |
| 915 | + return -1; |
| 916 | + dprintf("found Mach-O at %d\n", machofs); |
| 917 | + buf2 = load_data(fd, machofs + sizeof(struct mach_header_64), mh.sizeofcmds); |
| 918 | + for (i = 0, lc = buf2; i < mh.ncmds; i++) { |
| 919 | + dprintf("lc %2d: 0x%08x\n", i, lc->cmd); |
| 920 | + if (lc->cmd == LC_SYMTAB) { |
| 921 | + struct symtab_command *sc = (struct symtab_command*)lc; |
| 922 | + nsyms = sc->nsyms; |
| 923 | + symtab = load_data(fd, machofs + sc->symoff, nsyms * sizeof(*symtab)); |
| 924 | + strsize = sc->strsize; |
| 925 | + strtab = load_data(fd, machofs + sc->stroff, strsize); |
| 926 | + } else if (lc->cmd == LC_ID_DYLIB) { |
| 927 | + struct dylib_command *dc = (struct dylib_command*)lc; |
| 928 | + soname = (char*)lc + dc->name; |
| 929 | + dprintf(" ID_DYLIB %d 0x%x 0x%x %s\n", |
| 930 | + dc->timestamp, dc->current_version, |
| 931 | + dc->compatibility_version, soname); |
| 932 | + } else if (lc->cmd == LC_REEXPORT_DYLIB) { |
| 933 | + struct dylib_command *dc = (struct dylib_command*)lc; |
| 934 | + char *name = (char*)lc + dc->name; |
| 935 | + dprintf(" REEXPORT %s\n", name); |
| 936 | + int subfd = open(name, O_RDONLY | O_BINARY); |
| 937 | + if (subfd < 0) |
| 938 | + tcc_warning("can't open %s (reexported from %s)", name, filename); |
| 939 | + else { |
| 940 | + /* Hopefully the REEXPORTs never form a cycle, we don't check |
| 941 | + for that! */ |
| 942 | + macho_load_dll(s1, subfd, name, lev + 1); |
| 943 | + close(subfd); |
| 944 | + } |
| 945 | + } else if (lc->cmd == LC_DYSYMTAB) { |
| 946 | + struct dysymtab_command *dc = (struct dysymtab_command*)lc; |
| 947 | + iextdef = dc->iextdefsym; |
| 948 | + nextdef = dc->nextdefsym; |
| 949 | + } |
| 950 | + lc = (struct load_command*) ((char*)lc + lc->cmdsize); |
| 951 | + } |
| 952 | + |
| 953 | + /* if the dll is already loaded, do not load it */ |
| 954 | + for(i = 0; i < s1->nb_loaded_dlls; i++) { |
| 955 | + dllref = s1->loaded_dlls[i]; |
| 956 | + if (!strcmp(soname, dllref->name)) { |
| 957 | + /* but update level if needed */ |
| 958 | + if (lev < dllref->level) |
| 959 | + dllref->level = lev; |
| 960 | + goto the_end; |
| 961 | + } |
| 962 | + } |
| 963 | + dllref = tcc_mallocz(sizeof(DLLReference) + strlen(soname)); |
| 964 | + dllref->level = lev; |
| 965 | + strcpy(dllref->name, soname); |
| 966 | + dynarray_add(&s1->loaded_dlls, &s1->nb_loaded_dlls, dllref); |
| 967 | + |
| 968 | + if (!nsyms || !nextdef) |
| 969 | + tcc_warning("%s doesn't export any symbols?", filename); |
| 970 | + |
| 971 | + //dprintf("symbols (all):\n"); |
| 972 | + dprintf("symbols (exported):\n"); |
| 973 | + dprintf(" n: typ sec desc value name\n"); |
| 974 | + //for (i = 0; i < nsyms; i++) { |
| 975 | + for (i = iextdef; i < iextdef + nextdef; i++) { |
| 976 | + struct nlist_64 *sym = symtab + i; |
| 977 | + dprintf("%5d: %3d %3d 0x%04x 0x%016llx %s\n", |
| 978 | + i, sym->n_type, sym->n_sect, sym->n_desc, sym->n_value, |
| 979 | + strtab + sym->n_strx); |
| 980 | + set_elf_sym(s1->dynsymtab_section, 0, 0, |
| 981 | + ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), |
| 982 | + 0, SHN_UNDEF, strtab + sym->n_strx); |
| 983 | + } |
| 984 | + |
| 985 | + the_end: |
| 986 | + tcc_free(strtab); |
| 987 | + tcc_free(symtab); |
| 988 | + tcc_free(buf2); |
| 989 | + return 0; |
| 990 | +} |