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.
This commit is contained in:
Michael Matz 2018-12-31 22:00:31 +01:00
parent 325241c0de
commit 3e007193a2
3 changed files with 79 additions and 25 deletions

View File

@ -846,6 +846,52 @@ ST_FUNC Sym *external_global_sym(int v, CType *type, int r)
return s; 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. */ /* Merge some type attributes. */
static void patch_type(Sym *sym, CType *type) 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) if (sym->a.dllimport != ad->a.dllimport)
tcc_error("incompatible dll linkage for redefinition of '%s'", tcc_error("incompatible dll linkage for redefinition of '%s'",
get_tok_str(sym->v, NULL)); get_tok_str(sym->v, NULL));
sym->a.dllexport |= ad->a.dllexport;
#endif #endif
sym->a.weak |= ad->a.weak; merge_symattr(&sym->a, &ad->a);
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;
if (ad->asm_label) if (ad->asm_label)
sym->asm_label = ad->asm_label; sym->asm_label = ad->asm_label;
update_storage(sym); update_storage(sym);
@ -4000,14 +4034,8 @@ do_decl:
static void sym_to_attr(AttributeDef *ad, Sym *s) static void sym_to_attr(AttributeDef *ad, Sym *s)
{ {
if (s->a.aligned && 0 == ad->a.aligned) merge_symattr(&ad->a, &s->a);
ad->a.aligned = s->a.aligned; merge_funcattr(&ad->f, &s->f);
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;
} }
/* Add type qualifiers to a type. If the type is an array then the qualifiers /* 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; l = 0;
else if (parse_btype(&pt, &ad1)) else if (parse_btype(&pt, &ad1))
l = FUNC_NEW; l = FUNC_NEW;
else if (td) else if (td) {
return 0; merge_attr (ad, &ad1);
else return 0;
} else
l = FUNC_OLD; l = FUNC_OLD;
first = NULL; first = NULL;
plast = &first; plast = &first;

View File

@ -1747,7 +1747,7 @@ ST_FUNC int pe_load_file(struct TCCState *s1, const char *filename, int fd)
ret = pe_load_def(s1, fd); ret = pe_load_def(s1, fd);
else if (pe_load_res(s1, fd) == 0) else if (pe_load_res(s1, fd) == 0)
ret = 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); ret = pe_load_dll(s1, filename);
return ret; return ret;
} }

View File

@ -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 /* The actual attribute isn't important, must just be
parsable. */ parsable. */
#define ATTR __attribute__((__noinline__)) #define ATTR __attribute__((__noinline__))
@ -24,9 +31,11 @@ int ATTR actual_function() {
} }
extern int printf (const char *, ...); extern int printf (const char *, ...);
static int globalvar;
int main() int main()
{ {
void *function_pointer = &actual_function; void *function_pointer = &actual_function;
int localvar = 42, i;
int a = ((ATTR int(*) (void)) function_pointer)(); int a = ((ATTR int(*) (void)) function_pointer)();
printf("%i\n", a); printf("%i\n", a);
@ -36,5 +45,21 @@ int main()
int b = ( (int(ATTR *)(void)) function_pointer)(); int b = ( (int(ATTR *)(void)) function_pointer)();
printf("%i\n", b); 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; return 0;
} }