From 2341ee5142c184e06964f66696ebf88931953e7d Mon Sep 17 00:00:00 2001 From: grischka Date: Thu, 14 Jan 2010 20:55:51 +0100 Subject: [PATCH] tccpe: improve dllimport/export and use for tcc_add_symbol --- i386-gen.c | 10 +-- libtcc.c | 44 ++++++------ tcc.h | 10 +-- tccgen.c | 26 +++---- tccpe.c | 172 ++++++++++++++++++++++++++++------------------ win32/tools/tiny_impdef.c | 40 ++++++----- x86_64-gen.c | 8 +-- 7 files changed, 177 insertions(+), 133 deletions(-) diff --git a/i386-gen.c b/i386-gen.c index 9a8ceeeb..5ea70dfe 100644 --- a/i386-gen.c +++ b/i386-gen.c @@ -215,9 +215,10 @@ ST_FUNC void load(int r, SValue *sv) SValue v1; #ifdef TCC_TARGET_PE - if (pe_dllimport(r, sv, load)) - return; + SValue v2; + sv = pe_getimport(sv, &v2); #endif + fr = sv->r; ft = sv->type.t; fc = sv->c.ul; @@ -283,9 +284,10 @@ ST_FUNC void store(int r, SValue *v) int fr, bt, ft, fc; #ifdef TCC_TARGET_PE - if (pe_dllimport(r, v, store)) - return; + SValue v2; + v = pe_getimport(v, &v2); #endif + ft = v->type.t; fc = v->c.ul; fr = v->r & VT_VALMASK; diff --git a/libtcc.c b/libtcc.c index cc1c6af6..ae80bc64 100644 --- a/libtcc.c +++ b/libtcc.c @@ -393,7 +393,7 @@ ST_FUNC void put_extern_sym2(Sym *sym, Section *section, unsigned long value, unsigned long size, int can_add_underscore) { - int sym_type, sym_bind, sh_num, info, other, attr; + int sym_type, sym_bind, sh_num, info, other; ElfW(Sym) *esym; const char *name; char buf1[256]; @@ -405,26 +405,12 @@ ST_FUNC void put_extern_sym2(Sym *sym, Section *section, else sh_num = section->sh_num; - other = attr = 0; - if ((sym->type.t & VT_BTYPE) == VT_FUNC) { sym_type = STT_FUNC; -#ifdef TCC_TARGET_PE - if (sym->type.ref) - attr = sym->type.ref->r; - if (FUNC_EXPORT(attr)) - other |= 1; - if (FUNC_CALL(attr) == FUNC_STDCALL) - other |= 2; -#endif } else if ((sym->type.t & VT_BTYPE) == VT_VOID) { sym_type = STT_NOTYPE; } else { sym_type = STT_OBJECT; -#ifdef TCC_TARGET_PE - if (sym->type.t & VT_EXPORT) - other |= 1; -#endif } if (sym->type.t & VT_STATIC) @@ -463,12 +449,27 @@ ST_FUNC void put_extern_sym2(Sym *sym, Section *section, } } #endif + other = 0; #ifdef TCC_TARGET_PE - if ((other & 2) && can_add_underscore) { - sprintf(buf1, "_%s@%d", name, FUNC_ARGS(attr)); - name = buf1; - } else + if (sym->type.t & VT_EXPORT) + other |= 1; + if (sym_type == STT_FUNC && sym->type.ref) { + int attr = sym->type.ref->r; + if (FUNC_EXPORT(attr)) + other |= 1; + if (FUNC_CALL(attr) == FUNC_STDCALL && can_add_underscore) { + sprintf(buf1, "_%s@%d", name, FUNC_ARGS(attr) * PTR_SIZE); + name = buf1; + other |= 2; + can_add_underscore = 0; + } + } else { + if (find_elf_sym(tcc_state->dynsymtab_section, name)) + other |= 4; + if (sym->type.t & VT_IMPORT) + other |= 4; + } #endif if (tcc_state->leading_underscore && can_add_underscore) { buf1[0] = '_'; @@ -482,7 +483,6 @@ ST_FUNC void put_extern_sym2(Sym *sym, Section *section, esym->st_value = value; esym->st_size = size; esym->st_shndx = sh_num; - esym->st_other |= other; } } @@ -1215,9 +1215,13 @@ LIBTCCAPI int tcc_add_library(TCCState *s, const char *libraryname) LIBTCCAPI int tcc_add_symbol(TCCState *s, const char *name, void *val) { +#ifdef TCC_TARGET_PE + pe_putimport(s, 0, name, val); +#else add_elf_sym(symtab_section, (uplong)val, 0, ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0, SHN_ABS, name); +#endif return 0; } diff --git a/tcc.h b/tcc.h index 700d0c54..780c18e8 100644 --- a/tcc.h +++ b/tcc.h @@ -261,12 +261,13 @@ typedef struct DLLReference { /* GNUC attribute definition */ typedef struct AttributeDef { unsigned - packed : 1, - aligned : 5, /* alignement (0..16) */ func_call : 3, /* calling convention (0..5), see below */ + aligned : 5, /* alignement (0..16) */ + packed : 1, func_export : 1, func_import : 1, - func_args : 8; + func_args : 5, + fill : 16; struct Section *section; } AttributeDef; @@ -1176,7 +1177,8 @@ ST_FUNC void asm_clobber(uint8_t *clobber_regs, const char *str); ST_FUNC int pe_load_file(struct TCCState *s1, const char *filename, int fd); ST_FUNC int pe_add_dll(struct TCCState *s, const char *libraryname); ST_FUNC int pe_output_file(TCCState * s1, const char *filename); -ST_FUNC int pe_dllimport(int r, SValue *sv, void (*fn)(int r, SValue *sv)); +ST_FUNC int pe_putimport(TCCState *s1, int dllindex, const char *name, const void *value); +ST_FUNC SValue *pe_getimport(SValue *sv, SValue *v2); /* tiny_impdef.c */ ST_FUNC char *get_export_names(FILE *fp); #ifdef TCC_TARGET_X86_64 diff --git a/tccgen.c b/tccgen.c index b608c1fb..be8d80f9 100644 --- a/tccgen.c +++ b/tccgen.c @@ -1343,10 +1343,8 @@ static void gen_opic(int op) } goto general_case; } else if (c2 && (op == '+' || op == '-') && - (((vtop[-1].r & (VT_VALMASK | VT_LVAL | VT_SYM)) == (VT_CONST | VT_SYM) - && !(vtop[-1].sym->type.t & VT_IMPORT)) - || - (vtop[-1].r & (VT_VALMASK | VT_LVAL)) == VT_LOCAL)) { + (((vtop[-1].r & (VT_VALMASK | VT_LVAL | VT_SYM)) == (VT_CONST | VT_SYM)) + || (vtop[-1].r & (VT_VALMASK | VT_LVAL)) == VT_LOCAL)) { /* symbol + constant case */ if (op == '-') l2 = -l2; @@ -2973,7 +2971,7 @@ static void post_type(CType *type, AttributeDef *ad) type_decl(&pt, &ad1, &n, TYPE_DIRECT | TYPE_ABSTRACT); if ((pt.t & VT_BTYPE) == VT_VOID) error("parameter declared as void"); - arg_size += (type_size(&pt, &align) + 3) & ~3; + arg_size += (type_size(&pt, &align) + PTR_SIZE - 1) / PTR_SIZE; } else { old_proto: n = tok; @@ -5284,6 +5282,12 @@ ST_FUNC void decl(int l) func_decl_list(sym); } +#ifdef TCC_TARGET_PE + if (ad.func_import) + type.t |= VT_IMPORT; + if (ad.func_export) + type.t |= VT_EXPORT; +#endif if (tok == '{') { if (l == VT_LOCAL) error("cannot use local functions"); @@ -5402,10 +5406,6 @@ ST_FUNC void decl(int l) /* NOTE: as GCC, uninitialized global static arrays of null size are considered as extern */ -#ifdef TCC_TARGET_PE - if (ad.func_import) - type.t |= VT_IMPORT; -#endif external_sym(v, &type, r); } else { type.t |= (btype.t & VT_STATIC); /* Retain "static". */ @@ -5415,12 +5415,7 @@ ST_FUNC void decl(int l) r |= l; if (has_init) next(); -#ifdef TCC_TARGET_PE - if (ad.func_export) - type.t |= VT_EXPORT; -#endif - decl_initializer_alloc(&type, &ad, r, - has_init, v, l); + decl_initializer_alloc(&type, &ad, r, has_init, v, l); } } if (tok != ',') { @@ -5432,4 +5427,3 @@ ST_FUNC void decl(int l) } } } - diff --git a/tccpe.c b/tccpe.c index 536f4cdb..e8321dc3 100644 --- a/tccpe.c +++ b/tccpe.c @@ -753,10 +753,10 @@ static struct import_symbol *pe_add_import(struct pe_info *pe, int sym_index) int dll_index; struct pe_import_info *p; struct import_symbol *s; + ElfW(Sym) *isym; - dll_index = ((ElfW(Sym) *)pe->s1->dynsymtab_section->data + sym_index)->st_value; - if (0 == dll_index) - return NULL; + isym = (ElfW(Sym) *)pe->s1->dynsymtab_section->data + sym_index; + dll_index = isym->st_size; i = dynarray_assoc ((void**)pe->imp_info, pe->imp_count, dll_index); if (-1 != i) { @@ -804,14 +804,20 @@ static void pe_build_imports(struct pe_info *pe) for (i = 0; i < pe->imp_count; ++i) { IMAGE_IMPORT_DESCRIPTOR *hdr; - int k, n; + int k, n, dllindex; ADDR3264 v; struct pe_import_info *p = pe->imp_info[i]; - const char *name = pe->s1->loaded_dlls[p->dll_index-1]->name; + const char *name; + DLLReference *dllref; + + dllindex = p->dll_index; + if (dllindex) + name = (dllref = pe->s1->loaded_dlls[dllindex-1])->name; + else + name = "", dllref = NULL; /* put the dll name into the import header */ v = put_elf_str(pe->thunk, name); - hdr = (IMAGE_IMPORT_DESCRIPTOR*)(pe->thunk->data + dll_ptr); hdr->FirstThunk = thk_ptr + rva_base; hdr->OriginalFirstThunk = ent_ptr + rva_base; @@ -832,10 +838,12 @@ static void pe_build_imports(struct pe_info *pe) put_elf_str(pe->thunk, name); #ifdef TCC_IS_NATIVE if (pe->type == PE_RUN) { - DLLReference *dllref = pe->s1->loaded_dlls[imp_sym->st_value-1]; - if ( !dllref->handle ) - dllref->handle = LoadLibrary(dllref->name); - v = (ADDR3264)GetProcAddress(dllref->handle, name); + v = imp_sym->st_value; + if (dllref) { + if ( !dllref->handle ) + dllref->handle = LoadLibrary(dllref->name); + v = (ADDR3264)GetProcAddress(dllref->handle, name); + } if (!v) error_noabort("undefined symbol '%s'", name); } @@ -1214,9 +1222,6 @@ static int pe_check_symbols(struct pe_info *pe) if (0 == imp_sym) goto not_found; - is = pe_add_import(pe, imp_sym); - if (!is) - goto not_found; if (type == STT_NOTYPE) { /* symbols from assembler have no type, find out which */ @@ -1226,6 +1231,8 @@ static int pe_check_symbols(struct pe_info *pe) type = STT_OBJECT; } + is = pe_add_import(pe, imp_sym); + if (type == STT_FUNC) { unsigned long offset = is->thk_offset; if (offset) { @@ -1425,6 +1432,75 @@ static void pe_print_sections(TCCState *s1, const char *fname) #endif /* ------------------------------------------------------------- */ +/* helper function for load/store to insert one more indirection */ + +ST_FUNC SValue *pe_getimport(SValue *sv, SValue *v2) +{ + Sym *sym; + ElfW(Sym) *esym; + int r2; + + if ((sv->r & (VT_VALMASK|VT_SYM)) != (VT_CONST|VT_SYM) || (sv->r2 != VT_CONST)) + return sv; + sym = sv->sym; + if ((sym->type.t & (VT_EXTERN|VT_STATIC)) != VT_EXTERN) + return sv; + if (!sym->c) + put_extern_sym(sym, NULL, 0, 0); + esym = &((ElfW(Sym) *)symtab_section->data)[sym->c]; + if (!(esym->st_other & 4)) + return sv; + + // printf("import %04x %04x %04x %s\n", sv->type.t, sym->type.t, sv->r, get_tok_str(sv->sym->v, NULL)); + + memset(v2, 0, sizeof *v2); + v2->type.t = VT_PTR; + v2->r = VT_CONST | VT_SYM | VT_LVAL; + v2->sym = sv->sym; + + r2 = get_reg(RC_INT); + load(r2, v2); + v2->r = r2; + + if (sv->c.ui) { + vpushv(v2); + vpushi(sv->c.ui); + gen_opi('+'); + *v2 = *vtop--; + } + + v2->type.t = sv->type.t; + v2->r |= sv->r & VT_LVAL; + return v2; +} + +ST_FUNC int pe_putimport(TCCState *s1, int dllindex, const char *name, const void *value) +{ + return add_elf_sym( + s1->dynsymtab_section, + (uplong)value, + dllindex, /* st_size */ + ELFW_ST_INFO(STB_GLOBAL, STT_NOTYPE), + 0, + value ? SHN_ABS : SHN_UNDEF, + name + ); +} + +static int add_dllref(TCCState *s1, const char *dllname) +{ + DLLReference *dllref; + int i; + for (i = 0; i < s1->nb_loaded_dlls; ++i) + if (0 == strcmp(s1->loaded_dlls[i]->name, dllname)) + return i + 1; + dllref = tcc_mallocz(sizeof(DLLReference) + strlen(dllname)); + strcpy(dllref->name, dllname); + dynarray_add((void ***) &s1->loaded_dlls, &s1->nb_loaded_dlls, dllref); + return s1->nb_loaded_dlls; +} + +/* ------------------------------------------------------------- */ static int read_mem(FILE *fp, unsigned offset, void *buffer, unsigned len) { @@ -1503,8 +1579,7 @@ static char *get_line(char *line, int size, FILE *fp) /* ------------------------------------------------------------- */ static int pe_load_def(TCCState *s1, FILE *fp) { - DLLReference *dllref; - int state = 0, ret = -1; + int state = 0, ret = -1, dllindex = 0; char line[400], dllname[80], *p; for (;;) { @@ -1528,16 +1603,11 @@ static int pe_load_def(TCCState *s1, FILE *fp) continue; case 2: - dllref = tcc_mallocz(sizeof(DLLReference) + strlen(dllname)); - strcpy(dllref->name, dllname); - dynarray_add((void ***) &s1->loaded_dlls, &s1->nb_loaded_dlls, dllref); + dllindex = add_dllref(s1, dllname); ++state; default: - add_elf_sym(s1->dynsymtab_section, - s1->nb_loaded_dlls, 0, - ELFW_ST_INFO(STB_GLOBAL, STT_FUNC), 0, - text_section->sh_num, p); + pe_putimport(s1, dllindex, p, NULL); continue; } } @@ -1552,24 +1622,16 @@ quit: static int pe_load_dll(TCCState *s1, const char *dllname, FILE *fp) { - int i = 0; char *p, *q; + int index; p = get_export_names(fp); - if (p) { - DLLReference *dllref; - dllref = tcc_mallocz(sizeof(DLLReference) + strlen(dllname)); - strcpy(dllref->name, dllname); - dynarray_add((void ***) &s1->loaded_dlls, &s1->nb_loaded_dlls, dllref); - for (q = p, i = 0; *q; ++i) { - add_elf_sym(s1->dynsymtab_section, - s1->nb_loaded_dlls, 0, - ELFW_ST_INFO(STB_GLOBAL, STT_FUNC), 0, - text_section->sh_num, q); - q += 1 + strlen(q); - } - tcc_free(p); - } - return i ? 0 : -1; + if (!p) + return -1; + index = add_dllref(s1, dllname); + for (q = p; *q; q += 1 + strlen(q)) + pe_putimport(s1, index, q, NULL); + tcc_free(p); + return 0; } /* ------------------------------------------------------------- */ @@ -1606,32 +1668,6 @@ ST_FUNC int pe_add_dll(struct TCCState *s, const char *libname) } /* ------------------------------------------------------------- */ -/* helper function for load/store to insert one more indirection */ - -ST_FUNC int pe_dllimport(int r, SValue *sv, void (*fn)(int r, SValue *sv)) -{ - int t; - if ((sv->r & (VT_VALMASK|VT_SYM|VT_CONST)) != (VT_SYM|VT_CONST)) - return 0; - t = sv->sym->type.t; - if (0 == (t & VT_IMPORT)) - return 0; - - sv->sym->type.t = t & ~VT_IMPORT; - //printf("import %x %04x %s\n", t, ind, get_tok_str(sv->sym->v, NULL)); - - vpushv(sv); - vtop->type.t &= ~(VT_ARRAY|VT_IMPORT); - mk_pointer(&vtop->type); - indir(); - fn(r, vtop); - --vtop; - - sv->sym->type.t = t; - return 1; -} - -/* ------------------------------------------------------------- */ #ifdef TCC_TARGET_X86_64 ST_FUNC void pe_add_unwind_data(unsigned start, unsigned end, unsigned stack) { @@ -1702,6 +1738,8 @@ static void pe_add_runtime_ex(TCCState *s1, struct pe_info *pe) /* need this for 'tccelf.c:relocate_section()' */ s1->output_type = TCC_OUTPUT_EXE; } + else + pe_type = PE_EXE; start_symbol = TCC_OUTPUT_MEMORY == s1->output_type @@ -1731,9 +1769,12 @@ static void pe_add_runtime_ex(TCCState *s1, struct pe_info *pe) } } + if (TCC_OUTPUT_MEMORY == s1->output_type) + pe_type = PE_RUN; + if (start_symbol) { addr = (uplong)tcc_get_symbol_err(s1, start_symbol); - if (s1->output_type == TCC_OUTPUT_MEMORY && addr) + if (PE_RUN == pe_type && addr) /* for -run GUI's, put '_runwinmain' instead of 'main' */ add_elf_sym(symtab_section, addr, 0, @@ -1823,7 +1864,6 @@ ST_FUNC int pe_output_file(TCCState * s1, const char *filename) #ifndef TCC_IS_NATIVE error_noabort("-run supported only on native platform"); #endif - pe.type = PE_RUN; pe.thunk = data_section; pe_build_imports(&pe); } diff --git a/win32/tools/tiny_impdef.c b/win32/tools/tiny_impdef.c index b024a900..f801e0b5 100644 --- a/win32/tools/tiny_impdef.c +++ b/win32/tools/tiny_impdef.c @@ -60,6 +60,7 @@ int main(int argc, char **argv) fp = op = NULL; v = 0; ret = 1; + p = NULL; for (i = 1; i < argc; ++i) { const char *a = argv[i]; @@ -90,19 +91,20 @@ usage: if (0 == outfile[0]) { strcpy(outfile, file_basename(infile)); - p = strrchr(outfile, '.'); - if (NULL == p) - p = strchr(outfile, 0); - strcpy(p, ".def"); + q = strrchr(outfile, '.'); + if (NULL == q) + q = strchr(outfile, 0); + strcpy(q, ".def"); } file = infile; + #ifdef _WIN32 - for (pp = ext; *pp; ++pp) - if (SearchPath(NULL, file, *pp, sizeof path, path, NULL)) { - file = path; - break; - } + pp = ext; + do if (SearchPath(NULL, file, *pp, sizeof path, path, NULL)) { + file = path; + break; + } while (*pp++); #endif fp = fopen(file, "rb"); @@ -110,28 +112,26 @@ usage: fprintf(stderr, "tiny_impdef: no such file: %s\n", infile); goto the_end; } - - op = fopen(outfile, "w"); - if (NULL == op) { - fprintf(stderr, "tiny_impdef: could not create output file: %s\n", outfile); - goto the_end; - } - if (v) - printf("--> %s\n", infile); + printf("--> %s\n", file); - fprintf(op, "LIBRARY %s\n\nEXPORTS\n", file_basename(infile)); p = get_export_names(fp); if (NULL == p) { fprintf(stderr, "tiny_impdef: could not get exported function names.\n"); goto the_end; } + op = fopen(outfile, "w"); + if (NULL == op) { + fprintf(stderr, "tiny_impdef: could not create output file: %s\n", outfile); + goto the_end; + } + + fprintf(op, "LIBRARY %s\n\nEXPORTS\n", file_basename(file)); for (q = p, i = 0; *q; ++i) { fprintf(op, "%s\n", q); q += strlen(q) + 1; } - free(p); if (v) { printf("<-- %s\n", outfile); @@ -141,6 +141,8 @@ usage: ret = 0; the_end: + if (p) + free(p); if (fp) fclose(fp); if (op) diff --git a/x86_64-gen.c b/x86_64-gen.c index a80020fb..10003d16 100644 --- a/x86_64-gen.c +++ b/x86_64-gen.c @@ -335,8 +335,8 @@ void load(int r, SValue *sv) SValue v1; #ifdef TCC_TARGET_PE - if (pe_dllimport(r, sv, load)) - return; + SValue v2; + sv = pe_getimport(sv, &v2); #endif fr = sv->r; @@ -469,8 +469,8 @@ void store(int r, SValue *v) int pic = 0; #ifdef TCC_TARGET_PE - if (pe_dllimport(r, v, store)) - return; + SValue v2; + v = pe_getimport(v, &v2); #endif ft = v->type.t; -- 2.11.4.GIT