diff --git a/tools/winebuild/build.h b/tools/winebuild/build.h index ef9196193f0..7ec9997856a 100644 --- a/tools/winebuild/build.h +++ b/tools/winebuild/build.h @@ -58,6 +58,22 @@ typedef enum SPEC_WIN32 } SPEC_TYPE; +enum arg_type +{ + ARG_WORD, /* 16-bit word */ + ARG_SWORD, /* 16-bit signed word */ + ARG_SEGPTR, /* segmented pointer */ + ARG_SEGSTR, /* segmented pointer to Ansi string */ + ARG_LONG, /* long */ + ARG_PTR, /* pointer */ + ARG_STR, /* pointer to Ansi string */ + ARG_WSTR, /* pointer to Unicode string */ + ARG_DOUBLE, /* floating point double */ + ARG_MAXARG = ARG_DOUBLE +}; + +#define MAX_ARGUMENTS 32 + typedef struct { int n_values; @@ -66,7 +82,8 @@ typedef struct typedef struct { - char arg_types[21]; + unsigned int nb_args; + enum arg_type args[MAX_ARGUMENTS]; } ORD_FUNCTION; typedef struct @@ -244,6 +261,7 @@ extern enum target_cpu get_cpu_from_name( const char *name ); extern unsigned int get_alignment(unsigned int align); extern unsigned int get_page_size(void); extern unsigned int get_ptr_size(void); +extern unsigned int get_args_size( const ORDDEF *odp ); extern const char *asm_name( const char *func ); extern const char *func_declaration( const char *func ); extern const char *asm_globl( const char *func ); diff --git a/tools/winebuild/parser.c b/tools/winebuild/parser.c index ce17a3f7cca..8ace7052772 100644 --- a/tools/winebuild/parser.c +++ b/tools/winebuild/parser.c @@ -72,6 +72,19 @@ static const char * const FlagNames[] = NULL }; +static const char * const ArgNames[ARG_MAXARG + 1] = +{ + "word", /* ARG_WORD */ + "s_word", /* ARG_SWORD */ + "segptr", /* ARG_SEGPTR */ + "segstr", /* ARG_SEGSTR */ + "long", /* ARG_LONG */ + "ptr", /* ARG_PTR */ + "str", /* ARG_STR */ + "wstr", /* ARG_WSTR */ + "double" /* ARG_DOUBLE */ +}; + static int IsNumberString(const char *s) { while (*s) if (!isdigit(*s++)) return 0; @@ -228,7 +241,7 @@ static int parse_spec_variable( ORDDEF *odp, DLLSPEC *spec ) static int parse_spec_export( ORDDEF *odp, DLLSPEC *spec ) { const char *token; - unsigned int i; + unsigned int i, arg; int is_win32 = (spec->type == SPEC_WIN32) || (odp->flags & FLAG_EXPORT32); if (!is_win32 && odp->type == TYPE_STDCALL) @@ -254,61 +267,42 @@ static int parse_spec_export( ORDDEF *odp, DLLSPEC *spec ) return 0; } - for (i = 0; i < sizeof(odp->u.func.arg_types); i++) + odp->u.func.nb_args = 0; + for (i = 0; i < MAX_ARGUMENTS; i++) { if (!(token = GetToken(0))) return 0; if (*token == ')') break; - if (!strcmp(token, "word")) - odp->u.func.arg_types[i] = 'w'; - else if (!strcmp(token, "s_word")) - odp->u.func.arg_types[i] = 's'; - else if (!strcmp(token, "long") || !strcmp(token, "segptr")) - odp->u.func.arg_types[i] = 'l'; - else if (!strcmp(token, "ptr")) - odp->u.func.arg_types[i] = 'p'; - else if (!strcmp(token, "str")) - odp->u.func.arg_types[i] = 't'; - else if (!strcmp(token, "wstr")) - odp->u.func.arg_types[i] = 'W'; - else if (!strcmp(token, "segstr")) - odp->u.func.arg_types[i] = 'T'; - else if (!strcmp(token, "double")) - { - odp->u.func.arg_types[i++] = 'l'; - if (get_ptr_size() == 4 && i < sizeof(odp->u.func.arg_types)) - odp->u.func.arg_types[i] = 'l'; - } - else + for (arg = 0; arg <= ARG_MAXARG; arg++) + if (!strcmp( ArgNames[arg], token )) break; + + if (arg > ARG_MAXARG) { error( "Unknown argument type '%s'\n", token ); return 0; } - - if (is_win32) + if (is_win32) switch (arg) { - if (strcmp(token, "long") && - strcmp(token, "ptr") && - strcmp(token, "str") && - strcmp(token, "wstr") && - strcmp(token, "double")) - { - error( "Type '%s' not supported for Win32 function\n", token ); - return 0; - } + case ARG_WORD: + case ARG_SWORD: + case ARG_SEGPTR: + case ARG_SEGSTR: + error( "Argument type '%s' only allowed for Win16\n", token ); + return 0; } + odp->u.func.args[i] = arg; } - if ((*token != ')') || (i >= sizeof(odp->u.func.arg_types))) + if (*token != ')') { error( "Too many arguments\n" ); return 0; } - odp->u.func.arg_types[i] = '\0'; + odp->u.func.nb_args = i; if (odp->type == TYPE_VARARGS) odp->flags |= FLAG_NORELAY; /* no relay debug possible for varags entry point */ - if (odp->type == TYPE_THISCALL && odp->u.func.arg_types[0] != 'p') + if (odp->type == TYPE_THISCALL && (!i || odp->u.func.args[0] != ARG_PTR)) { error( "First argument of a thiscall function must be a pointer\n" ); return 0; @@ -386,7 +380,7 @@ static int parse_spec_equate( ORDDEF *odp, DLLSPEC *spec ) */ static int parse_spec_stub( ORDDEF *odp, DLLSPEC *spec ) { - odp->u.func.arg_types[0] = '\0'; + odp->u.func.nb_args = 0; odp->link_name = xstrdup(""); odp->flags |= FLAG_CPU(CPU_x86) | FLAG_CPU(CPU_x86_64); /* don't bother generating stubs for Winelib */ return 1; @@ -806,7 +800,8 @@ void add_16bit_exports( DLLSPEC *spec32, DLLSPEC *spec16 ) odp->lineno = odp16->lineno; odp->ordinal = -1; odp->link_name = xstrdup( odp16->link_name ); - strcpy( odp->u.func.arg_types, odp16->u.func.arg_types ); + odp->u.func.nb_args = odp16->u.func.nb_args; + memcpy( odp->u.func.args, odp16->u.func.args, odp->u.func.nb_args * sizeof(odp->u.func.args[0]) ); } assign_names( spec32 ); @@ -936,18 +931,23 @@ static int parse_def_export( char *name, DLLSPEC *spec ) odp->ordinal = -1; odp->name = name; args = remove_stdcall_decoration( odp->name ); - if (args == -1) odp->type = TYPE_CDECL; + if (args == -1) + { + odp->type = TYPE_CDECL; + args = 0; + } else { odp->type = TYPE_STDCALL; args /= get_ptr_size(); - if (args >= sizeof(odp->u.func.arg_types)) + if (args >= MAX_ARGUMENTS) { error( "Too many arguments in stdcall function '%s'\n", odp->name ); return 0; } - for (i = 0; i < args; i++) odp->u.func.arg_types[i] = 'l'; + for (i = 0; i < args; i++) odp->u.func.args[i] = ARG_LONG; } + odp->u.func.nb_args = args; /* check for optional internal name */ diff --git a/tools/winebuild/spec16.c b/tools/winebuild/spec16.c index 22ec7b6d3b0..82ff9f18994 100644 --- a/tools/winebuild/spec16.c +++ b/tools/winebuild/spec16.c @@ -36,14 +36,14 @@ /* argument type flags for relay debugging */ enum arg_types { - ARG_NONE = 0, /* indicates end of arg list */ - ARG_WORD, /* unsigned word */ - ARG_SWORD, /* signed word */ - ARG_LONG, /* long or segmented pointer */ - ARG_PTR, /* linear pointer */ - ARG_STR, /* linear pointer to null-terminated string */ - ARG_SEGSTR, /* segmented pointer to null-terminated string */ - ARG_VARARG /* start of varargs */ + ARG16_NONE = 0, /* indicates end of arg list */ + ARG16_WORD, /* unsigned word */ + ARG16_SWORD, /* signed word */ + ARG16_LONG, /* long or segmented pointer */ + ARG16_PTR, /* linear pointer */ + ARG16_STR, /* linear pointer to null-terminated string */ + ARG16_SEGSTR, /* segmented pointer to null-terminated string */ + ARG16_VARARG /* start of varargs */ }; /* sequences of nops to fill a certain number of words */ @@ -64,6 +64,30 @@ static inline int is_function( const ORDDEF *odp ) odp->type == TYPE_STUB); } +static const char *get_args_str( const ORDDEF *odp ) +{ + static char buffer[MAX_ARGUMENTS*2+1]; + unsigned int i; + + buffer[0] = 0; + for (i = 0; i < odp->u.func.nb_args; i++) + { + switch (odp->u.func.args[i]) + { + case ARG_WORD: strcat( buffer, "w" ); break; + case ARG_SWORD: strcat( buffer, "s" ); break; + case ARG_SEGSTR: strcat( buffer, "T" ); break; + case ARG_STR: strcat( buffer, "t" ); break; + case ARG_DOUBLE: strcat( buffer, "ll" ); break; + case ARG_LONG: + case ARG_SEGPTR: strcat( buffer, "l" ); break; + case ARG_PTR: + case ARG_WSTR: strcat( buffer, "p" ); break; + } + } + return buffer; +} + /******************************************************************* * output_entries * @@ -203,7 +227,7 @@ static const char *get_callfrom16_name( const ORDDEF *odp ) (odp->type == TYPE_VARARGS) ? "v" : "c", (odp->flags & FLAG_REGISTER) ? "regs" : (odp->flags & FLAG_RET16) ? "word" : "long", - odp->u.func.arg_types ); + get_args_str(odp) ); return buffer; } @@ -231,7 +255,7 @@ static const char *get_relay_name( const ORDDEF *odp ) default: assert(0); } - strcat( buffer, odp->u.func.arg_types ); + strcat( buffer, get_args_str(odp) ); for (p = buffer + 2; *p; p++) { /* map string types to the corresponding plain pointer type */ @@ -248,25 +272,27 @@ static const char *get_relay_name( const ORDDEF *odp ) */ static int get_function_argsize( const ORDDEF *odp ) { - const char *args; - int argsize = 0; + unsigned int i, argsize = 0; - for (args = odp->u.func.arg_types; *args; args++) + for (i = 0; i < odp->u.func.nb_args; i++) { - switch (*args) + switch (odp->u.func.args[i]) { - case 'w': /* word */ - case 's': /* s_word */ + case ARG_WORD: + case ARG_SWORD: argsize += 2; break; - case 'l': /* long or segmented pointer */ - case 'T': /* segmented pointer to null-terminated string */ - case 'p': /* linear pointer */ - case 't': /* linear pointer to null-terminated string */ + case ARG_SEGPTR: + case ARG_SEGSTR: + case ARG_LONG: + case ARG_PTR: + case ARG_STR: + case ARG_WSTR: argsize += 4; break; - default: - assert(0); + case ARG_DOUBLE: + argsize += 8; + break; } } return argsize; @@ -304,9 +330,8 @@ static void output_call16_function( ORDDEF *odp ) { char *name; int i, pos, stack_words; - const char *args = odp->u.func.arg_types; int argsize = get_function_argsize( odp ); - int needs_ldt = strchr( args, 'p' ) || strchr( args, 't' ); + int needs_ldt = (strpbrk( get_args_str( odp ), "pt" ) != NULL); name = strmake( ".L__wine_spec_call16_%s", get_relay_name(odp) ); @@ -335,11 +360,13 @@ static void output_call16_function( ORDDEF *odp ) } /* preserve 16-byte stack alignment */ - stack_words += strlen(args); + stack_words += odp->u.func.nb_args; + for (i = 0; i < odp->u.func.nb_args; i++) + if (odp->u.func.args[i] == ARG_DOUBLE) stack_words++; if ((odp->flags & FLAG_REGISTER) || (odp->type == TYPE_VARARGS)) stack_words++; if (stack_words % 4) output( "\tsubl $%d,%%esp\n", 16 - 4 * (stack_words % 4) ); - if (args[0] || odp->type == TYPE_VARARGS) + if (odp->u.func.nb_args || odp->type == TYPE_VARARGS) output( "\tmovl 12(%%ebp),%%ecx\n" ); /* args */ if (odp->flags & FLAG_REGISTER) @@ -353,33 +380,40 @@ static void output_call16_function( ORDDEF *odp ) } pos = (odp->type == TYPE_PASCAL) ? 0 : argsize; - for (i = strlen(args) - 1; i >= 0; i--) + for (i = odp->u.func.nb_args - 1; i >= 0; i--) { - switch (args[i]) + switch (odp->u.func.args[i]) { - case 'w': /* word */ + case ARG_WORD: if (odp->type != TYPE_PASCAL) pos -= 2; output( "\tmovzwl %d(%%ecx),%%eax\n", pos ); output( "\tpushl %%eax\n" ); if (odp->type == TYPE_PASCAL) pos += 2; break; - case 's': /* s_word */ + case ARG_SWORD: if (odp->type != TYPE_PASCAL) pos -= 2; output( "\tmovswl %d(%%ecx),%%eax\n", pos ); output( "\tpushl %%eax\n" ); if (odp->type == TYPE_PASCAL) pos += 2; break; - case 'l': /* long or segmented pointer */ - case 'T': /* segmented pointer to null-terminated string */ + case ARG_DOUBLE: + if (odp->type != TYPE_PASCAL) pos -= 4; + output( "\tpushl %d(%%ecx)\n", pos ); + if (odp->type == TYPE_PASCAL) pos += 4; + /* fall through */ + case ARG_LONG: + case ARG_SEGPTR: + case ARG_SEGSTR: if (odp->type != TYPE_PASCAL) pos -= 4; output( "\tpushl %d(%%ecx)\n", pos ); if (odp->type == TYPE_PASCAL) pos += 4; break; - case 'p': /* linear pointer */ - case 't': /* linear pointer to null-terminated string */ + case ARG_PTR: + case ARG_STR: + case ARG_WSTR: if (odp->type != TYPE_PASCAL) pos -= 4; output( "\tmovzwl %d(%%ecx),%%edx\n", pos + 2 ); /* sel */ output( "\tshr $3,%%edx\n" ); @@ -388,9 +422,6 @@ static void output_call16_function( ORDDEF *odp ) output( "\tpushl %%eax\n" ); if (odp->type == TYPE_PASCAL) pos += 4; break; - - default: - assert(0); } } @@ -423,6 +454,7 @@ static int callfrom16_type_compare( const void *e1, const void *e2 ) int retval; int type1 = odp1->type; int type2 = odp2->type; + char args1[80]; if (type1 == TYPE_STUB) type1 = TYPE_CDECL; if (type2 == TYPE_STUB) type2 = TYPE_CDECL; @@ -434,7 +466,8 @@ static int callfrom16_type_compare( const void *e1, const void *e2 ) if ((retval = type1 - type2) != 0) return retval; - return strcmp( odp1->u.func.arg_types, odp2->u.func.arg_types ); + strcpy( args1, get_args_str( odp1 )); + return strcmp( args1, get_args_str( odp2 )); } @@ -504,7 +537,7 @@ static void output_module16( DLLSPEC *spec ) entry_point->name = NULL; entry_point->link_name = xstrdup( spec->init_func ); entry_point->export_name = NULL; - entry_point->u.func.arg_types[0] = 0; + entry_point->u.func.nb_args = 0; assert( !spec->ordinals[0] ); spec->ordinals[0] = entry_point; } @@ -654,28 +687,36 @@ static void output_module16( DLLSPEC *spec ) for ( i = 0; i < nb_funcs; i++ ) { unsigned int arg_types[2]; - int nop_words, argsize = 0; + int nop_words, pos, argsize = 0; if ( typelist[i]->type == TYPE_PASCAL ) argsize = get_function_argsize( typelist[i] ); /* build the arg types bit fields */ arg_types[0] = arg_types[1] = 0; - for (j = 0; typelist[i]->u.func.arg_types[j]; j++) + for (j = pos = 0; j < typelist[i]->u.func.nb_args && pos < 20; j++, pos++) { int type = 0; - switch(typelist[i]->u.func.arg_types[j]) + switch (typelist[i]->u.func.args[j]) { - case 'w': type = ARG_WORD; break; - case 's': type = ARG_SWORD; break; - case 'l': type = ARG_LONG; break; - case 'p': type = ARG_PTR; break; - case 't': type = ARG_STR; break; - case 'T': type = ARG_SEGSTR; break; + case ARG_WORD: type = ARG16_WORD; break; + case ARG_SWORD: type = ARG16_SWORD; break; + case ARG_SEGPTR: type = ARG16_LONG; break; + case ARG_SEGSTR: type = ARG16_SEGSTR; break; + case ARG_LONG: type = ARG16_LONG; break; + case ARG_PTR: type = ARG16_PTR; break; + case ARG_STR: type = ARG16_STR; break; + case ARG_WSTR: type = ARG16_PTR; break; + case ARG_DOUBLE: + type = ARG16_LONG; + arg_types[pos / 10] |= type << (3 * (pos % 10)); + pos++; + break; } - arg_types[j / 10] |= type << (3 * (j % 10)); + if (pos < 20) arg_types[pos / 10] |= type << (3 * (pos % 10)); } - if (typelist[i]->type == TYPE_VARARGS) arg_types[j / 10] |= ARG_VARARG << (3 * (j % 10)); + if (typelist[i]->type == TYPE_VARARGS && pos < 20) + arg_types[pos / 10] |= ARG16_VARARG << (3 * (pos % 10)); output( ".L__wine_spec_callfrom16_%s:\n", get_callfrom16_name(typelist[i]) ); output( "\tpushl $.L__wine_spec_call16_%s\n", get_relay_name(typelist[i]) ); diff --git a/tools/winebuild/spec32.c b/tools/winebuild/spec32.c index 330db30ae36..20a1ed85e18 100644 --- a/tools/winebuild/spec32.c +++ b/tools/winebuild/spec32.c @@ -81,7 +81,7 @@ int has_relays( DLLSPEC *spec ) static void output_relay_debug( DLLSPEC *spec ) { int i; - unsigned int j, args, flags; + unsigned int j, pos, args, flags; /* first the table of entry point offsets */ @@ -111,10 +111,15 @@ static void output_relay_debug( DLLSPEC *spec ) if (needs_relay( odp )) { - for (j = 0; j < 16 && odp->u.func.arg_types[j]; j++) + for (j = pos = 0; pos < 16 && j < odp->u.func.nb_args; j++) { - if (odp->u.func.arg_types[j] == 't') mask |= 1<< (j*2); - if (odp->u.func.arg_types[j] == 'W') mask |= 2<< (j*2); + switch (odp->u.func.args[j]) + { + case ARG_STR: mask |= 1 << (2 * pos++); break; + case ARG_WSTR: mask |= 2 << (2 * pos++); break; + case ARG_DOUBLE: pos += 8 / get_ptr_size(); break; + default: pos++; break; + } } } output( "\t.long 0x%08x\n", mask ); @@ -135,7 +140,7 @@ static void output_relay_debug( DLLSPEC *spec ) output( "\t.align %d\n", get_alignment(4) ); output( ".L__wine_spec_relay_entry_point_%d:\n", i ); - args = strlen(odp->u.func.arg_types); + args = get_args_size(odp) / get_ptr_size(); flags = 0; switch (target_cpu) @@ -831,7 +836,7 @@ void output_def_file( DLLSPEC *spec, int include_private ) break; case TYPE_STDCALL: { - int at_param = strlen(odp->u.func.arg_types) * get_ptr_size(); + int at_param = get_args_size( odp ); if (!kill_at && target_cpu == CPU_x86) output( "@%d", at_param ); if (odp->flags & FLAG_FORWARD) { diff --git a/tools/winebuild/utils.c b/tools/winebuild/utils.c index 251ab00f997..a85683119f3 100644 --- a/tools/winebuild/utils.c +++ b/tools/winebuild/utils.c @@ -890,6 +890,26 @@ unsigned int get_ptr_size(void) return 0; } +/* return the total size in bytes of the arguments on the stack */ +unsigned int get_args_size( const ORDDEF *odp ) +{ + unsigned int i, size; + + for (i = size = 0; i < odp->u.func.nb_args; i++) + { + switch (odp->u.func.args[i]) + { + case ARG_DOUBLE: + size += 8; + break; + default: + size += get_ptr_size(); + break; + } + } + return size; +} + /* return the assembly name for a C symbol */ const char *asm_name( const char *sym ) {