History

macos: Read exported symbols from dylibs

up to now we simply assumed that any undefined symbols will be provided by some shared libs on the cmdline. Now we check this.

Michael Matz committed 6 years ago

Commit c86760c1 parent fbfe6204 files · +168 −21Browse files

Unified · Split

4 files
  1. libtcc.c +2 −1
  2. tcc.h +3 −0
  3. tccelf.c +2 −2
  4. tccmacho.c +161 −18
libtcc.c+2−1
@@ -1124,7 +1124,8 @@ ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags) · 1123 unmodified lines
1124 ret = tcc_load_dll(s1, fd, filename,1124 ret = tcc_load_dll(s1, fd, filename,
1125 (flags & AFF_REFERENCED_DLL) != 0);1125 (flags & AFF_REFERENCED_DLL) != 0);
1126#else1126#else
1127 ret = 0;1127 ret = macho_load_dll(s1, fd, filename,
1128 (flags & AFF_REFERENCED_DLL) != 0);
1128#endif1129#endif
1129 }1130 }
1130 break;1131 break;
tcc.h+3−0
@@ -1531,6 +1531,8 @@ ST_FUNC void resolve_common_syms(TCCState *s1); · 1530 unmodified lines
1531ST_FUNC void relocate_syms(TCCState *s1, Section *symtab, int do_resolve);1531ST_FUNC void relocate_syms(TCCState *s1, Section *symtab, int do_resolve);
1532ST_FUNC void relocate_section(TCCState *s1, Section *s);1532ST_FUNC void relocate_section(TCCState *s1, Section *s);
1533 1533
1534ST_FUNC ssize_t full_read(int fd, void *buf, size_t count);
1535ST_FUNC void *load_data(int fd, unsigned long file_offset, unsigned long size);
1534ST_FUNC int tcc_object_type(int fd, ElfW(Ehdr) *h);1536ST_FUNC int tcc_object_type(int fd, ElfW(Ehdr) *h);
1535ST_FUNC int tcc_load_object_file(TCCState *s1, int fd, unsigned long file_offset);1537ST_FUNC int tcc_load_object_file(TCCState *s1, int fd, unsigned long file_offset);
1536ST_FUNC int tcc_load_archive(TCCState *s1, int fd, int alacarte);1538ST_FUNC int tcc_load_archive(TCCState *s1, int fd, int alacarte);
@@ -1747,6 +1749,7 @@ PUB_FUNC int tcc_get_dllexports(const char *filename, char **pp); · 210 unmodified lines
1747/* ------------ tccmacho.c ----------------- */1749/* ------------ tccmacho.c ----------------- */
1748#ifdef TCC_TARGET_MACHO1750#ifdef TCC_TARGET_MACHO
1749ST_FUNC int macho_output_file(TCCState * s1, const char *filename);1751ST_FUNC int macho_output_file(TCCState * s1, const char *filename);
1752ST_FUNC int macho_load_dll(TCCState *s1, int fd, const char *filename, int lev);
1750#endif1753#endif
1751/* ------------ tccrun.c ----------------- */1754/* ------------ tccrun.c ----------------- */
1752#ifdef TCC_IS_NATIVE1755#ifdef TCC_IS_NATIVE
tccelf.c+2−2
@@ -2547,7 +2547,7 @@ LIBTCCAPI int tcc_output_file(TCCState *s, const char *filename) · 2546 unmodified lines
2547 return ret;2547 return ret;
2548}2548}
2549 2549
2550ssize_t full_read(int fd, void *buf, size_t count) {2550ST_FUNC ssize_t full_read(int fd, void *buf, size_t count) {
2551 char *cbuf = buf;2551 char *cbuf = buf;
2552 size_t rnum = 0;2552 size_t rnum = 0;
2553 while (1) {2553 while (1) {
@@ -2559,7 +2559,7 @@ ssize_t full_read(int fd, void *buf, size_t count) { · 5 unmodified lines
2559 }2559 }
2560}2560}
2561 2561
2562static void *load_data(int fd, unsigned long file_offset, unsigned long size)2562ST_FUNC void *load_data(int fd, unsigned long file_offset, unsigned long size)
2563{2563{
2564 void *data;2564 void *data;
2565 2565
tccmacho.c+161−18
@@ -18,6 +18,7 @@ · 17 unmodified lines
18#include "tcc.h"18#include "tcc.h"
19 19
20#define DEBUG_MACHO 020#define DEBUG_MACHO 0
21#define dprintf if (DEBUG_MACHO) printf
21 22
22struct mach_header {23struct mach_header {
23 uint32_t magic; /* mach magic number identifier */24 uint32_t magic; /* mach magic number identifier */
@@ -231,7 +232,9 @@ struct macho { · 207 unmodified lines
231#define LC_SYMTAB 0x2232#define LC_SYMTAB 0x2
232#define LC_DYSYMTAB 0xb233#define LC_DYSYMTAB 0xb
233#define LC_LOAD_DYLIB 0xc234#define LC_LOAD_DYLIB 0xc
235#define LC_ID_DYLIB 0xd
234#define LC_LOAD_DYLINKER 0xe236#define LC_LOAD_DYLINKER 0xe
237#define LC_REEXPORT_DYLIB (0x1f | LC_REQ_DYLD)
235#define LC_MAIN (0x28|LC_REQ_DYLD)238#define LC_MAIN (0x28|LC_REQ_DYLD)
236 239
237/* Hack for now, 46_grep.c needs fopen, but due to aliasing games240/* 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 unsigned bind = ELFW(ST_BIND)(sym->st_info);378 unsigned bind = ELFW(ST_BIND)(sym->st_info);
376 unsigned vis = ELFW(ST_VISIBILITY)(sym->st_other);379 unsigned vis = ELFW(ST_VISIBILITY)(sym->st_other);
377 380
378 if (DEBUG_MACHO)381 dprintf("%4d (%4d): %09llx %4d %4d %4d %3d %s\n",
379 printf("%4d (%4d): %09llx %4d %4d %4d %3d %s\n",382 sym_index, elf_index, sym->st_value,
380 sym_index, elf_index, sym->st_value,383 type, bind, vis, sym->st_shndx, name);
381 type, bind, vis, sym->st_shndx, name);
382 if (bind == STB_LOCAL) {384 if (bind == STB_LOCAL) {
383 if (mo->ilocal == -1)385 if (mo->ilocal == -1)
384 mo->ilocal = sym_index - 1;386 mo->ilocal = sym_index - 1;
@@ -394,15 +396,12 @@ static int check_symbols(TCCState *s1, struct macho *mo) · 9 unmodified lines
394 mo->iundef = sym_index - 1;396 mo->iundef = sym_index - 1;
395 if (ELFW(ST_BIND)(sym->st_info) == STB_WEAK)397 if (ELFW(ST_BIND)(sym->st_info) == STB_WEAK)
396 continue;398 continue;
397 if (get_sym_attr(s1, elf_index, 0)) {399 if (find_elf_sym(s1->dynsymtab_section, name)) {
398 /* Mark the symbol as coming from a dylib so that400 /* Mark the symbol as coming from a dylib so that
399 relocate_syms doesn't complain. Normally we would have401 relocate_syms doesn't complain. Normally bind_exe_dynsyms
400 checked that any dylib in fact exports this one, and listed402 would do this check, and place the symbol into dynsym
401 those in s1->dynsymtab, which would cause us to enter this403 which is checked by relocate_syms. But Mach-O doesn't use
402 symbol into s1->dynsym, which is checked by relocate_syms.404 bind_exe_dynsyms. */
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. */
406 sym->st_shndx = SHN_FROMDLL;405 sym->st_shndx = SHN_FROMDLL;
407 continue;406 continue;
408 }407 }
@@ -589,7 +588,11 @@ static void collect_sections(TCCState *s1, struct macho *mo) · 180 unmodified lines
589 dysymlc->cmdsize = sizeof(*dysymlc);588 dysymlc->cmdsize = sizeof(*dysymlc);
590 add_lc(mo, dysymlc);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 mo->linkedit = new_section(s1, "LINKEDIT", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE);597 mo->linkedit = new_section(s1, "LINKEDIT", SHT_LINKEDIT, SHF_ALLOC | SHF_WRITE);
595 /* LINKEDIT can't be empty (XXX remove once we have symbol table) */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 for (s = mo->sk_to_sect[sk].s; s; s = s->prev) {686 for (s = mo->sk_to_sect[sk].s; s; s = s->prev) {
684 al = s->sh_addralign;687 al = s->sh_addralign;
685 curaddr = (curaddr + al - 1) & -al;688 curaddr = (curaddr + al - 1) & -al;
686 if (DEBUG_MACHO)689 dprintf("curaddr now 0x%llx\n", curaddr);
687 printf("curaddr now 0x%llx\n", curaddr);
688 s->sh_addr = curaddr;690 s->sh_addr = curaddr;
689 curaddr += s->sh_size;691 curaddr += s->sh_size;
690 if (s->sh_type != SHT_NOBITS) {692 if (s->sh_type != SHT_NOBITS) {
691 fileofs = (fileofs + al - 1) & -al;693 fileofs = (fileofs + al - 1) & -al;
692 s->sh_offset = fileofs;694 s->sh_offset = fileofs;
693 fileofs += s->sh_size;695 fileofs += s->sh_size;
694 if (DEBUG_MACHO)696 dprintf("fileofs now %lld\n", fileofs);
695 printf("fileofs now %lld\n", fileofs);
696 }697 }
697 if (sec)698 if (sec)
698 mo->elfsectomacho[s->sh_num] = numsec;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 int fd, mode, file_type;800 int fd, mode, file_type;
800 FILE *fp;801 FILE *fp;
801 int ret = -1;802 int ret = -1;
802 struct macho mo = {0,};803 struct macho mo = {};
803 804
804 file_type = s1->output_type;805 file_type = s1->output_type;
805 if (file_type == TCC_OUTPUT_OBJ)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 fclose(fp);846 fclose(fp);
846 return ret;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
855struct fat_header {
856 uint32_t magic; /* FAT_MAGIC or FAT_MAGIC_64 */
857 uint32_t nfat_arch; /* number of structs that follow */
858};
859
860struct 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))
869ST_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}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t