From 3e007193a2a83540a9c7bbc21261940f0326a02f Mon Sep 17 00:00:00 2001 From: Michael Matz Date: Mon, 31 Dec 2018 22:00:31 +0100 Subject: [PATCH] Fix more attribute placements when parsing the type in this cast: (int (__attribute__(X) *)(int))foo we ignored the attribute, which matters if it's e.g. a 'stdcall' attribute on the function pointer. Only this particular placement was misparsed. Putting the attribute after the '*' or outside the inner parens worked. This idiom seems to be used on SQLite, perhaps this fixes a compilation problem on win32 with that. --- tccgen.c | 77 ++++++++++++++++++++---------- tccpe.c | 2 +- tests/tests2/82_attribs_position.c | 25 ++++++++++ 3 files changed, 79 insertions(+), 25 deletions(-) diff --git a/tccgen.c b/tccgen.c index 1d74f6f4..9f671e09 100644 --- a/tccgen.c +++ b/tccgen.c @@ -846,6 +846,52 @@ ST_FUNC Sym *external_global_sym(int v, CType *type, int r) return s; } +/* Merge symbol attributes. */ +static void merge_symattr(struct SymAttr *sa, struct SymAttr *sa1) +{ + if (sa1->aligned && !sa->aligned) + sa->aligned = sa1->aligned; + sa->packed |= sa1->packed; + sa->weak |= sa1->weak; + if (sa1->visibility != STV_DEFAULT) { + int vis = sa->visibility; + if (vis == STV_DEFAULT + || vis > sa1->visibility) + vis = sa1->visibility; + sa->visibility = vis; + } + sa->dllexport |= sa1->dllexport; + sa->nodecorate |= sa1->nodecorate; + sa->dllimport |= sa1->dllimport; +} + +/* Merge function attributes. */ +static void merge_funcattr(struct FuncAttr *fa, struct FuncAttr *fa1) +{ + if (fa1->func_call && !fa->func_call) + fa->func_call = fa1->func_call; + if (fa1->func_type && !fa->func_type) + fa->func_type = fa1->func_type; + if (fa1->func_args && !fa->func_args) + fa->func_args = fa1->func_args; +} + +/* Merge attributes. */ +static void merge_attr(AttributeDef *ad, AttributeDef *ad1) +{ + merge_symattr(&ad->a, &ad1->a); + merge_funcattr(&ad->f, &ad1->f); + + if (ad1->section) + ad->section = ad1->section; + if (ad1->alias_target) + ad->alias_target = ad1->alias_target; + if (ad1->asm_label) + ad->asm_label = ad1->asm_label; + if (ad1->attr_mode) + ad->attr_mode = ad1->attr_mode; +} + /* Merge some type attributes. */ static void patch_type(Sym *sym, CType *type) { @@ -905,20 +951,8 @@ static void patch_storage(Sym *sym, AttributeDef *ad, CType *type) if (sym->a.dllimport != ad->a.dllimport) tcc_error("incompatible dll linkage for redefinition of '%s'", get_tok_str(sym->v, NULL)); - sym->a.dllexport |= ad->a.dllexport; #endif - sym->a.weak |= ad->a.weak; - if (ad->a.visibility) { - int vis = sym->a.visibility; - int vis2 = ad->a.visibility; - if (vis == STV_DEFAULT) - vis = vis2; - else if (vis2 != STV_DEFAULT) - vis = (vis < vis2) ? vis : vis2; - sym->a.visibility = vis; - } - if (ad->a.aligned) - sym->a.aligned = ad->a.aligned; + merge_symattr(&sym->a, &ad->a); if (ad->asm_label) sym->asm_label = ad->asm_label; update_storage(sym); @@ -4000,14 +4034,8 @@ do_decl: static void sym_to_attr(AttributeDef *ad, Sym *s) { - if (s->a.aligned && 0 == ad->a.aligned) - ad->a.aligned = s->a.aligned; - if (s->f.func_call && 0 == ad->f.func_call) - ad->f.func_call = s->f.func_call; - if (s->f.func_type && 0 == ad->f.func_type) - ad->f.func_type = s->f.func_type; - if (s->a.packed) - ad->a.packed = 1; + merge_symattr(&ad->a, &s->a); + merge_funcattr(&ad->f, &s->f); } /* Add type qualifiers to a type. If the type is an array then the qualifiers @@ -4294,9 +4322,10 @@ static int post_type(CType *type, AttributeDef *ad, int storage, int td) l = 0; else if (parse_btype(&pt, &ad1)) l = FUNC_NEW; - else if (td) - return 0; - else + else if (td) { + merge_attr (ad, &ad1); + return 0; + } else l = FUNC_OLD; first = NULL; plast = &first; diff --git a/tccpe.c b/tccpe.c index 40894d50..dfe14454 100644 --- a/tccpe.c +++ b/tccpe.c @@ -1747,7 +1747,7 @@ ST_FUNC int pe_load_file(struct TCCState *s1, const char *filename, int fd) ret = pe_load_def(s1, fd); else if (pe_load_res(s1, fd) == 0) ret = 0; - else if (read_mem(fd, 0, buf, 4) && 0 == memcmp(buf, "MZ\220", 4)) + else if (read_mem(fd, 0, buf, 4) && 0 == memcmp(buf, "MZ", 2)) ret = pe_load_dll(s1, filename); return ret; } diff --git a/tests/tests2/82_attribs_position.c b/tests/tests2/82_attribs_position.c index 7faeaf51..fd3f2c4e 100644 --- a/tests/tests2/82_attribs_position.c +++ b/tests/tests2/82_attribs_position.c @@ -16,6 +16,13 @@ void __attribute__((stdcall)) foo (void) { } +#define __stdcall __attribute__((stdcall)) +extern int some_stdcall_func (int, int, int) __stdcall; +__stdcall int __stdcall some_stdcall_func(int foo, int bar, int baz) { + //printf("Hello from stdcall: %i %i %i\n", foo, bar, baz); + return 43; +} + /* The actual attribute isn't important, must just be parsable. */ #define ATTR __attribute__((__noinline__)) @@ -24,9 +31,11 @@ int ATTR actual_function() { } extern int printf (const char *, ...); +static int globalvar; int main() { void *function_pointer = &actual_function; + int localvar = 42, i; int a = ((ATTR int(*) (void)) function_pointer)(); printf("%i\n", a); @@ -36,5 +45,21 @@ int main() int b = ( (int(ATTR *)(void)) function_pointer)(); printf("%i\n", b); + /* All these should work and leave the stack pointer in its original + position. */ + some_stdcall_func(1, 10, 100); + ((int __stdcall (*)(int, int, int))some_stdcall_func) (2, 20, 200); + ((int(*__stdcall)(int, int, int))some_stdcall_func) (3, 30, 300); + for (i = 0; i < 1024; i++) { + globalvar = i; + /* This was once misparsed at <= gitrev 325241c0, forgetting + the stdcall attribute on the function pointer leading to + stack increment being done twice (in callee and caller). + This will clobber 'i' and 'localvar' which is how we detect + this. */ + ((int(__stdcall*)(int, int, int))some_stdcall_func) (4, 40, 400); + if (localvar != 42 || globalvar != i) + printf("error, localvar=%d i=%d globalvar=%d\n", localvar, i, globalvar); + } return 0; }