diff --git a/libtcc.c b/libtcc.c index 17ecfc5..c409d80 100644 --- a/libtcc.c +++ b/libtcc.c @@ -617,6 +617,13 @@ LIBTCCAPI void tcc_set_cpp_load_func(TCCState *s, void *cpp_load_opaque, s->cpp_load_func = cpp_load_func; } +LIBTCCAPI void tcc_set_linker_resolve_func(TCCState *s, void *resolve_opaque, + void *(*resolve_func)(void *opaque, const char *name)) +{ + s->linker_resolve_opaque = resolve_opaque; + s->linker_resolve_func = resolve_func; +} + /* error without aborting current compilation */ PUB_FUNC void _tcc_error_noabort(const char *fmt, ...) { diff --git a/libtcc.h b/libtcc.h index ce86670..d55afe5 100644 --- a/libtcc.h +++ b/libtcc.h @@ -37,6 +37,10 @@ LIBTCCAPI void *tcc_get_error_opaque(TCCState *s); LIBTCCAPI void tcc_set_cpp_load_func(TCCState *s, void *cpp_load_opaque, const char *(*cpp_load_func)(void *opaque, const char *path, int *len)); +/* set linker resolver callback */ +LIBTCCAPI void tcc_set_linker_resolve_func(TCCState *s, void *resolve_opaque, + void *(*resolve_func)(void *opaque, const char *name)); + /* set options as from command line (multiple supported) */ LIBTCCAPI void tcc_set_options(TCCState *s, const char *str); diff --git a/tcc.h b/tcc.h index 3fde83a..868d47e 100644 --- a/tcc.h +++ b/tcc.h @@ -805,6 +805,10 @@ struct TCCState { void *cpp_load_opaque; const char *(*cpp_load_func)(void *opaque, const char *path, int *len); + /* linker symbol handling */ + void *linker_resolve_opaque; + void *(*linker_resolve_func)(void *opaque, const char *name); + /* output file for preprocessing (-E) */ FILE *ppfp; enum { diff --git a/tccelf.c b/tccelf.c index 36b013a..30b756e 100644 --- a/tccelf.c +++ b/tccelf.c @@ -898,20 +898,34 @@ ST_FUNC void relocate_syms(TCCState *s1, Section *symtab, int do_resolve) ElfW(Sym) *sym; int sym_bind, sh_num; const char *name; + void *addr; for_each_elem(symtab, 1, sym, ElfW(Sym)) { sh_num = sym->st_shndx; if (sh_num == SHN_UNDEF) { name = (char *) s1->symtab->link->data + sym->st_name; + + if (s1->linker_resolve_func) { + addr = s1->linker_resolve_func(s1->linker_resolve_opaque, name); + if (addr) { + sym->st_value = (addr_t) addr; +#ifdef DEBUG_RELOC + printf ("relocate_sym: %s -> 0x%lx\n", name, + sym->st_value); +#endif + goto found; + } + } + /* Use ld.so to resolve symbol for us (for tcc -run) */ if (do_resolve) { #if defined TCC_IS_NATIVE && !defined TCC_TARGET_PE #ifdef TCC_TARGET_MACHO /* The symbols in the symtables have a prepended '_' but dlsym() needs the undecorated name. */ - void *addr = dlsym(RTLD_DEFAULT, name + 1); + addr = dlsym(RTLD_DEFAULT, name + 1); #else - void *addr = dlsym(RTLD_DEFAULT, name); + addr = dlsym(RTLD_DEFAULT, name); #endif if (addr) { sym->st_value = (addr_t) addr; diff --git a/tccpe.c b/tccpe.c index 855450a..30d6161 100644 --- a/tccpe.c +++ b/tccpe.c @@ -1248,8 +1248,22 @@ static int pe_check_symbols(struct pe_info *pe) int imp_sym = pe_find_import(pe->s1, sym); struct import_symbol *is; - if (imp_sym <= 0) - goto not_found; + if (imp_sym <= 0) { + TCCState *s1 = pe->s1; + + if (s1->linker_resolve_func) { + void *addr = s1->linker_resolve_func( + s1->linker_resolve_opaque, + name); + if (addr) { + tcc_add_symbol(s1, name, addr); + imp_sym = pe_find_import(s1, sym); + } + } + + if (imp_sym <= 0) + goto not_found; + } if (type == STT_NOTYPE) { /* symbols from assembler have no type, find out which */