macOS 11: link using dyld shared cache
Supports linking using .tbd definitions found in the default installed command-line tools SDK or Xcode.app SDK. Only for creating executables (not yet for `tcc -run`).
This commit is contained in:
		
							parent
							
								
									e3a0eb5089
								
							
						
					
					
						commit
						f6fb4d0cf1
					
				
					 3 changed files with 103 additions and 20 deletions
				
			
		
							
								
								
									
										8
									
								
								libtcc.c
									
										
									
									
									
								
							
							
						
						
									
										8
									
								
								libtcc.c
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -1006,7 +1006,9 @@ ST_FUNC int tcc_add_file_internal(TCCState *s1, const char *filename, int flags)
 | 
			
		|||
        lseek(fd, 0, SEEK_SET);
 | 
			
		||||
 | 
			
		||||
#ifdef TCC_TARGET_MACHO
 | 
			
		||||
        if (0 == obj_type && 0 == strcmp(tcc_fileextension(filename), ".dylib"))
 | 
			
		||||
        if (0 == obj_type
 | 
			
		||||
            && (0 == strcmp(tcc_fileextension(filename), ".dylib")
 | 
			
		||||
            ||  0 == strcmp(tcc_fileextension(filename), ".tbd")))
 | 
			
		||||
            obj_type = AFF_BINTYPE_DYN;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1142,8 +1144,8 @@ LIBTCCAPI int tcc_add_library(TCCState *s, const char *libraryname)
 | 
			
		|||
    static const char * const libs[] = { "%s/%s.def", "%s/lib%s.def", "%s/%s.dll", "%s/lib%s.dll", "%s/lib%s.a", NULL };
 | 
			
		||||
    const char * const *pp = s->static_link ? libs + 4 : libs;
 | 
			
		||||
#elif defined TCC_TARGET_MACHO
 | 
			
		||||
    static const char * const libs[] = { "%s/lib%s.dylib", "%s/lib%s.a", NULL };
 | 
			
		||||
    const char * const *pp = s->static_link ? libs + 1 : libs;
 | 
			
		||||
    static const char * const libs[] = { "%s/lib%s.dylib", "%s/lib%s.tbd", "%s/lib%s.a", NULL };
 | 
			
		||||
    const char * const *pp = s->static_link ? libs + 2 : libs;
 | 
			
		||||
#elif defined TARGETOS_OpenBSD
 | 
			
		||||
    static const char * const libs[] = { "%s/lib%s.so.*", "%s/lib%s.a", NULL };
 | 
			
		||||
    const char * const *pp = s->static_link ? libs + 1 : libs;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										16
									
								
								tcc.h
									
										
									
									
									
								
							
							
						
						
									
										16
									
								
								tcc.h
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -42,6 +42,7 @@
 | 
			
		|||
#ifndef _WIN32
 | 
			
		||||
# include <unistd.h>
 | 
			
		||||
# include <sys/time.h>
 | 
			
		||||
# include <sys/stat.h>
 | 
			
		||||
# ifndef CONFIG_TCC_STATIC
 | 
			
		||||
#  include <dlfcn.h>
 | 
			
		||||
# endif
 | 
			
		||||
| 
						 | 
				
			
			@ -246,6 +247,12 @@ extern long double strtold (const char *__nptr, char **__endptr);
 | 
			
		|||
# define ALSO_TRIPLET(s) s
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
// FIXME: do this at runtime instead; check output of `xcode-select -p`. libxcselect provides this stuff
 | 
			
		||||
#ifndef CONFIG_OSX_SDK1
 | 
			
		||||
# define CONFIG_OSX_SDK1 "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk"
 | 
			
		||||
# define CONFIG_OSX_SDK2 "/Applications/Xcode.app/Developer/SDKs/MacOSX.sdk"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* path to find crt1.o, crti.o and crtn.o */
 | 
			
		||||
#ifndef CONFIG_TCC_CRTPREFIX
 | 
			
		||||
# define CONFIG_TCC_CRTPREFIX USE_TRIPLET(CONFIG_SYSROOT "/usr/" CONFIG_LDDIR)
 | 
			
		||||
| 
						 | 
				
			
			@ -274,11 +281,20 @@ extern long double strtold (const char *__nptr, char **__endptr);
 | 
			
		|||
# ifdef TCC_TARGET_PE
 | 
			
		||||
#  define CONFIG_TCC_LIBPATHS "{B}/lib"
 | 
			
		||||
# else
 | 
			
		||||
#  ifdef TCC_TARGET_MACHO
 | 
			
		||||
#   define CONFIG_TCC_LIBPATHS \
 | 
			
		||||
        ALSO_TRIPLET(CONFIG_SYSROOT "/usr/" CONFIG_LDDIR) \
 | 
			
		||||
    ":" ALSO_TRIPLET(CONFIG_SYSROOT "/" CONFIG_LDDIR) \
 | 
			
		||||
    ":" ALSO_TRIPLET(CONFIG_SYSROOT "/usr/local/" CONFIG_LDDIR)\
 | 
			
		||||
    ":" ALSO_TRIPLET(CONFIG_OSX_SDK1 "/usr/" CONFIG_LDDIR) \
 | 
			
		||||
    ":" ALSO_TRIPLET(CONFIG_OSX_SDK2 "/usr/" CONFIG_LDDIR)
 | 
			
		||||
#  else
 | 
			
		||||
#   define CONFIG_TCC_LIBPATHS \
 | 
			
		||||
        ALSO_TRIPLET(CONFIG_SYSROOT "/usr/" CONFIG_LDDIR) \
 | 
			
		||||
    ":" ALSO_TRIPLET(CONFIG_SYSROOT "/" CONFIG_LDDIR) \
 | 
			
		||||
    ":" ALSO_TRIPLET(CONFIG_SYSROOT "/usr/local/" CONFIG_LDDIR)
 | 
			
		||||
#  endif
 | 
			
		||||
# endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* name of ELF interpreter */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										95
									
								
								tccmacho.c
									
										
									
									
									
								
							
							
						
						
									
										95
									
								
								tccmacho.c
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -837,7 +837,78 @@ static uint32_t macho_swap32(uint32_t x)
 | 
			
		|||
}
 | 
			
		||||
#define SWAP(x) (swap ? macho_swap32(x) : (x))
 | 
			
		||||
 | 
			
		||||
ST_FUNC int macho_load_dll(TCCState *s1, int fd, const char *filename, int lev)
 | 
			
		||||
ST_FUNC int macho_add_dllref(TCCState* s1, int lev, const char* soname)
 | 
			
		||||
{
 | 
			
		||||
     /* if the dll is already loaded, do not load it */
 | 
			
		||||
    DLLReference *dllref;
 | 
			
		||||
    for(int i = 0; i < s1->nb_loaded_dlls; i++) {
 | 
			
		||||
        dllref = s1->loaded_dlls[i];
 | 
			
		||||
        if (!strcmp(soname, dllref->name)) {
 | 
			
		||||
            /* but update level if needed */
 | 
			
		||||
            if (lev < dllref->level)
 | 
			
		||||
                dllref->level = lev;
 | 
			
		||||
            return -1;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    dllref = tcc_mallocz(sizeof(DLLReference) + strlen(soname));
 | 
			
		||||
    dllref->level = lev;
 | 
			
		||||
    strcpy(dllref->name, soname);
 | 
			
		||||
    dynarray_add(&s1->loaded_dlls, &s1->nb_loaded_dlls, dllref);
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define tbd_parse_movepast(s) \
 | 
			
		||||
    (pos = (pos = strstr(pos, s)) ? pos + strlen(s) : NULL)
 | 
			
		||||
#define tbd_parse_movetoany(cs) (pos = strpbrk(pos, cs))
 | 
			
		||||
#define tbd_parse_skipws while (*pos && (*pos==' '||*pos=='\n')) ++pos
 | 
			
		||||
#define tbd_parse_tramplequote if(*pos=='\''||*pos=='"') tbd_parse_trample
 | 
			
		||||
#define tbd_parse_tramplespace if(*pos==' ') tbd_parse_trample
 | 
			
		||||
#define tbd_parse_trample *pos++=0
 | 
			
		||||
 | 
			
		||||
ST_FUNC int macho_load_tbd(TCCState* s1, int fd, const char* filename, int lev)
 | 
			
		||||
{
 | 
			
		||||
    char* soname;
 | 
			
		||||
 | 
			
		||||
    struct stat sb;
 | 
			
		||||
    fstat(fd,&sb);
 | 
			
		||||
    char* data = load_data(fd, 0, sb.st_size+1);
 | 
			
		||||
    data[sb.st_size]=0;
 | 
			
		||||
    char* pos = data;
 | 
			
		||||
 | 
			
		||||
    if (!tbd_parse_movepast("install-name: ")) return -1;
 | 
			
		||||
    tbd_parse_skipws;
 | 
			
		||||
    tbd_parse_tramplequote;
 | 
			
		||||
    soname = pos;
 | 
			
		||||
    if (!tbd_parse_movetoany("\n \"'")) return -1;
 | 
			
		||||
    tbd_parse_trample;
 | 
			
		||||
    if (macho_add_dllref(s1, lev, soname) != 0) goto the_end;
 | 
			
		||||
 | 
			
		||||
    while(pos) {
 | 
			
		||||
        char* sym = NULL;
 | 
			
		||||
        if (!tbd_parse_movepast("symbols: ")) break;
 | 
			
		||||
        if (!tbd_parse_movepast("[")) break;
 | 
			
		||||
        int cont = 1;
 | 
			
		||||
        while (cont) {
 | 
			
		||||
            tbd_parse_skipws;
 | 
			
		||||
            tbd_parse_tramplequote;
 | 
			
		||||
            sym = pos;
 | 
			
		||||
            if (!tbd_parse_movetoany(",] \"'")) break;
 | 
			
		||||
            tbd_parse_tramplequote;
 | 
			
		||||
            tbd_parse_tramplespace;
 | 
			
		||||
            tbd_parse_skipws;
 | 
			
		||||
            if (*pos==0||*pos==']') cont=0;
 | 
			
		||||
            tbd_parse_trample;
 | 
			
		||||
            set_elf_sym(s1->dynsymtab_section, 0, 0,
 | 
			
		||||
                ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, SHN_UNDEF, sym);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
the_end:
 | 
			
		||||
    tcc_free(data);
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ST_FUNC int macho_load_dylib(TCCState * s1, int fd, const char* filename, int lev)
 | 
			
		||||
{
 | 
			
		||||
    unsigned char buf[sizeof(struct mach_header_64)];
 | 
			
		||||
    void *buf2;
 | 
			
		||||
| 
						 | 
				
			
			@ -853,7 +924,6 @@ ST_FUNC int macho_load_dll(TCCState *s1, int fd, const char *filename, int lev)
 | 
			
		|||
    uint32_t strsize = 0;
 | 
			
		||||
    uint32_t iextdef = 0;
 | 
			
		||||
    uint32_t nextdef = 0;
 | 
			
		||||
    DLLReference *dllref;
 | 
			
		||||
 | 
			
		||||
  again:
 | 
			
		||||
    if (full_read(fd, buf, sizeof(buf)) != sizeof(buf))
 | 
			
		||||
| 
						 | 
				
			
			@ -934,20 +1004,8 @@ ST_FUNC int macho_load_dll(TCCState *s1, int fd, const char *filename, int lev)
 | 
			
		|||
        lc = (struct load_command*) ((char*)lc + lc->cmdsize);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* if the dll is already loaded, do not load it */
 | 
			
		||||
    for(i = 0; i < s1->nb_loaded_dlls; i++) {
 | 
			
		||||
        dllref = s1->loaded_dlls[i];
 | 
			
		||||
        if (!strcmp(soname, dllref->name)) {
 | 
			
		||||
            /* but update level if needed */
 | 
			
		||||
            if (lev < dllref->level)
 | 
			
		||||
                dllref->level = lev;
 | 
			
		||||
    if (0 != macho_add_dllref(s1, lev, soname))
 | 
			
		||||
        goto the_end;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    dllref = tcc_mallocz(sizeof(DLLReference) + strlen(soname));
 | 
			
		||||
    dllref->level = lev;
 | 
			
		||||
    strcpy(dllref->name, soname);
 | 
			
		||||
    dynarray_add(&s1->loaded_dlls, &s1->nb_loaded_dlls, dllref);
 | 
			
		||||
 | 
			
		||||
    if (!nsyms || !nextdef)
 | 
			
		||||
      tcc_warning("%s doesn't export any symbols?", filename);
 | 
			
		||||
| 
						 | 
				
			
			@ -972,3 +1030,10 @@ ST_FUNC int macho_load_dll(TCCState *s1, int fd, const char *filename, int lev)
 | 
			
		|||
    tcc_free(buf2);
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ST_FUNC int macho_load_dll(TCCState * s1, int fd, const char* filename, int lev)
 | 
			
		||||
{
 | 
			
		||||
    return strcmp(tcc_fileextension(filename), ".tbd") == 0
 | 
			
		||||
           ? macho_load_tbd(s1, fd, filename, lev)
 | 
			
		||||
           : macho_load_dylib(s1, fd, filename, lev);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		
		Reference in a new issue