winebuild: Use a proper enum for function arguments instead of storing them in a string.

This commit is contained in:
Alexandre Julliard 2010-08-30 12:06:19 +02:00
parent 2a5b375580
commit e0188c8340
5 changed files with 183 additions and 99 deletions

View File

@ -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 );

View File

@ -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 */

View File

@ -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]) );

View File

@ -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)
{

View File

@ -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 )
{