Create an assembly file with all undefined symbols and add it to the

link command so that the symbols show up in the final undefined list.
Use that list to create thunks for all exported but undefined symbols,
to make sure all export RVAs point somewhere inside the module.
This commit is contained in:
Alexandre Julliard 2005-09-19 17:04:43 +00:00
parent 980f817737
commit a999a990fe
7 changed files with 142 additions and 21 deletions

View File

@ -131,6 +131,7 @@ extern enum target_platform target_platform;
#define FLAG_PRIVATE 0x40 /* function is private (cannot be imported) */
#define FLAG_FORWARD 0x80 /* function is a forwarded name */
#define FLAG_EXT_LINK 0x100 /* function links to an external symbol */
/* Offset of a structure field relative to the start of the struct */
#define STRUCTOFFSET(type,field) ((int)&((type *)0)->field)
@ -239,6 +240,7 @@ extern const char *output_file_name;
extern char **debug_channels;
extern char **lib_path;
extern char *as_command;
extern char *ld_command;
extern char *nm_command;

View File

@ -62,6 +62,7 @@ static struct name_table undef_symbols; /* list of undefined symbols */
static struct name_table ignore_symbols; /* list of symbols to ignore */
static struct name_table extra_ld_symbols; /* list of extra symbols that ld should resolve */
static struct name_table delayed_imports; /* list of delayed import dlls */
static struct name_table ext_link_imports; /* list of external symbols to link to */
static struct import **dll_imports = NULL;
static int nb_imports = 0; /* number of imported dlls (delayed or not) */
@ -483,22 +484,73 @@ static int check_unused( const struct import* imp, const DLLSPEC *spec )
return 1;
}
/* combine a list of object files with ld into a single object file */
/* returns the name of the combined file */
static const char *ldcombine_files( char **argv )
/* flag the dll exports that link to an undefined symbol */
static void check_undefined_exports( DLLSPEC *spec )
{
unsigned int i, len = 0;
char *cmd, *p, *ld_tmp_file;
int i;
for (i = 0; i < spec->nb_entry_points; i++)
{
ORDDEF *odp = &spec->entry_points[i];
if (odp->type == TYPE_STUB) continue;
if (odp->flags & FLAG_FORWARD) continue;
if (find_name( odp->link_name, &undef_symbols ))
{
odp->flags |= FLAG_EXT_LINK;
add_name( &ext_link_imports, odp->link_name );
}
}
}
/* create a .o file that references all the undefined symbols we want to resolve */
static char *create_undef_symbols_file( DLLSPEC *spec )
{
char *cmd, *as_file, *obj_file;
unsigned int i;
FILE *f;
int err;
if (!as_command) as_command = xstrdup("as");
as_file = get_temp_file_name( output_file_name, ".s" );
if (!(f = fopen( as_file, "w" ))) fatal_error( "Cannot create %s\n", as_file );
fprintf( f, "\t.data\n" );
for (i = 0; i < spec->nb_entry_points; i++)
{
ORDDEF *odp = &spec->entry_points[i];
if (odp->type == TYPE_STUB) continue;
if (odp->flags & FLAG_FORWARD) continue;
fprintf( f, "\t%s %s\n", get_asm_ptr_keyword(), asm_name(odp->link_name) );
}
for (i = 0; i < extra_ld_symbols.count; i++)
fprintf( f, "\t%s %s\n", get_asm_ptr_keyword(), asm_name(extra_ld_symbols.names[i]) );
fclose( f );
obj_file = get_temp_file_name( output_file_name, ".o" );
cmd = xmalloc( strlen(as_command) + strlen(obj_file) + strlen(as_file) + 6 );
sprintf( cmd, "%s -o %s %s", as_command, obj_file, as_file );
err = system( cmd );
if (err) fatal_error( "%s failed with status %d\n", as_command, err );
free( cmd );
return obj_file;
}
/* combine a list of object files with ld into a single object file */
/* returns the name of the combined file */
static const char *ldcombine_files( DLLSPEC *spec, char **argv )
{
unsigned int i, len = 0;
char *cmd, *p, *ld_tmp_file, *undef_file;
int err;
undef_file = create_undef_symbols_file( spec );
len += strlen(undef_file) + 1;
ld_tmp_file = get_temp_file_name( output_file_name, ".o" );
if (!ld_command) ld_command = xstrdup("ld");
for (i = 0; i < extra_ld_symbols.count; i++) len += strlen(extra_ld_symbols.names[i]) + 5;
for (i = 0; argv[i]; i++) len += strlen(argv[i]) + 1;
cmd = p = xmalloc( len + strlen(ld_tmp_file) + 8 + strlen(ld_command) );
p += sprintf( cmd, "%s -r -o %s", ld_command, ld_tmp_file );
for (i = 0; i < extra_ld_symbols.count; i++)
p += sprintf( p, " -u %s", asm_name(extra_ld_symbols.names[i]) );
p += sprintf( cmd, "%s -r -o %s %s", ld_command, ld_tmp_file, undef_file );
for (i = 0; argv[i]; i++)
p += sprintf( p, " %s", argv[i] );
err = system( cmd );
@ -523,7 +575,7 @@ void read_undef_symbols( DLLSPEC *spec, char **argv )
strcpy( name_prefix, asm_name("") );
prefix_len = strlen( name_prefix );
name = ldcombine_files( argv );
name = ldcombine_files( spec, argv );
if (!nm_command) nm_command = xstrdup("nm");
cmd = xmalloc( strlen(nm_command) + strlen(name) + 5 );
@ -578,6 +630,10 @@ int resolve_imports( DLLSPEC *spec )
i--;
}
}
sort_names( &undef_symbols );
check_undefined_exports( spec );
return 1;
}
@ -1068,6 +1124,43 @@ static void output_delayed_import_thunks( FILE *outfile, const DLLSPEC *spec )
output_function_size( outfile, delayed_import_thunks );
}
/* output import stubs for exported entry points that link to external symbols */
static void output_external_link_imports( FILE *outfile, DLLSPEC *spec )
{
unsigned int i, pos;
if (!ext_link_imports.count) return; /* nothing to do */
sort_names( &ext_link_imports );
/* get rid of duplicate names */
for (i = 1; i < ext_link_imports.count; i++)
{
if (!strcmp( ext_link_imports.names[i-1], ext_link_imports.names[i] ))
remove_name( &ext_link_imports, i-- );
}
fprintf( outfile, "\n/* external link thunks */\n\n" );
fprintf( outfile, "\t.data\n" );
fprintf( outfile, "\t.align %d\n", get_alignment(get_ptr_size()) );
fprintf( outfile, ".L__wine_spec_external_links:\n" );
for (i = 0; i < ext_link_imports.count; i++)
fprintf( outfile, "\t%s %s\n", get_asm_ptr_keyword(), asm_name(ext_link_imports.names[i]) );
fprintf( outfile, "\n\t.text\n" );
fprintf( outfile, "\t.align %d\n", get_alignment(get_ptr_size()) );
fprintf( outfile, "%s:\n", asm_name("__wine_spec_external_link_thunks") );
for (i = pos = 0; i < ext_link_imports.count; i++)
{
char buffer[256];
sprintf( buffer, "__wine_spec_ext_link_%s", ext_link_imports.names[i] );
output_import_thunk( outfile, buffer, ".L__wine_spec_external_links", pos );
pos += get_ptr_size();
}
output_function_size( outfile, "__wine_spec_external_link_thunks" );
}
/* output the import and delayed import tables of a Win32 module */
void output_imports( FILE *outfile, DLLSPEC *spec )
{
@ -1075,5 +1168,6 @@ void output_imports( FILE *outfile, DLLSPEC *spec )
output_delayed_imports( outfile, spec );
output_immediate_import_thunks( outfile );
output_delayed_import_thunks( outfile, spec );
if (nb_imports || has_stubs(spec)) output_get_pc_thunk( outfile );
output_external_link_imports( outfile, spec );
if (nb_imports || ext_link_imports.count || has_stubs(spec)) output_get_pc_thunk( outfile );
}

View File

@ -78,6 +78,7 @@ char *input_file_name = NULL;
char *spec_file_name = NULL;
const char *output_file_name = NULL;
char *as_command = NULL;
char *ld_command = NULL;
char *nm_command = NULL;
@ -205,6 +206,12 @@ static void set_target( const char *target )
free( spec );
if (!as_command)
{
as_command = xmalloc( strlen(target) + sizeof("-as") );
strcpy( as_command, target );
strcat( as_command, "-as" );
}
if (!ld_command)
{
ld_command = xmalloc( strlen(target) + sizeof("-ld") );
@ -237,6 +244,7 @@ static void exit_on_signal( int sig )
static const char usage_str[] =
"Usage: winebuild [OPTIONS] [FILES]\n\n"
"Options:\n"
" --as-cmd=AS Command to use for assembling (default: as)\n"
" -C, --source-dir=DIR Look for source files in DIR\n"
" -d, --delay-lib=LIB Import the specified library in delayed mode\n"
" -D SYM Ignored for C flags compatibility\n"
@ -278,6 +286,7 @@ enum long_options_values
LONG_OPT_DEF,
LONG_OPT_EXE,
LONG_OPT_DEBUG,
LONG_OPT_ASCMD,
LONG_OPT_LDCMD,
LONG_OPT_NMCMD,
LONG_OPT_RELAY16,
@ -295,6 +304,7 @@ static const struct option long_options[] =
{ "def", 0, 0, LONG_OPT_DEF },
{ "exe", 0, 0, LONG_OPT_EXE },
{ "debug", 0, 0, LONG_OPT_DEBUG },
{ "as-cmd", 1, 0, LONG_OPT_ASCMD },
{ "ld-cmd", 1, 0, LONG_OPT_LDCMD },
{ "nm-cmd", 1, 0, LONG_OPT_NMCMD },
{ "relay16", 0, 0, LONG_OPT_RELAY16 },
@ -444,6 +454,9 @@ static char **parse_options( int argc, char **argv, DLLSPEC *spec )
case LONG_OPT_DEBUG:
set_exec_mode( MODE_DEBUG );
break;
case LONG_OPT_ASCMD:
as_command = xstrdup( optarg );
break;
case LONG_OPT_LDCMD:
ld_command = xstrdup( optarg );
break;

View File

@ -274,7 +274,8 @@ static int parse_spec_export( ORDDEF *odp, DLLSPEC *spec )
else if (!strcmp(token, "double"))
{
odp->u.func.arg_types[i++] = 'l';
if (i < sizeof(odp->u.func.arg_types)) 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
{

View File

@ -146,18 +146,23 @@ static void output_exports( FILE *outfile, DLLSPEC *spec )
case TYPE_STDCALL:
case TYPE_VARARGS:
case TYPE_CDECL:
if (!(odp->flags & FLAG_FORWARD))
if (odp->flags & FLAG_FORWARD)
{
fprintf( outfile, "\t.long %s\n", asm_name(odp->link_name) );
fprintf( outfile, "\t%s .L__wine_spec_forwards+%u\n", get_asm_ptr_keyword(), fwd_size );
fwd_size += strlen(odp->link_name) + 1;
}
else if (odp->flags & FLAG_EXT_LINK)
{
fprintf( outfile, "\t%s %s_%s\n",
get_asm_ptr_keyword(), asm_name("__wine_spec_ext_link"), odp->link_name );
}
else
{
fprintf( outfile, "\t.long .L__wine_spec_forwards+%d\n", fwd_size );
fwd_size += strlen(odp->link_name) + 1;
fprintf( outfile, "\t%s %s\n", get_asm_ptr_keyword(), asm_name(odp->link_name) );
}
break;
case TYPE_STUB:
fprintf( outfile, "\t.long %s\n",
fprintf( outfile, "\t%s %s\n", get_asm_ptr_keyword(),
asm_name( make_internal_name( odp, spec, "stub" )) );
break;
default:

View File

@ -64,6 +64,10 @@ Generate the assembly code for the 32-bit relay routines. This is for
Wine internal usage only, you should never need to use this option.
.SH OPTIONS
.TP
.BI \--as-cmd= as-command
Specify the command to use to compile assembly files; the default is
\fBas\fR.
.TP
.BI \-C,\ --source-dir= directory
Change to the specified directory before reading source files. Only
meaningful in
@ -131,10 +135,6 @@ Ignored for compatibility with the C compiler.
Specify the command to use to link the object files; the default is
\fBld\fR.
.TP
.BI \--nm-cmd= nm-command
Specify the command to use to get the list of undefined symbols; the
default is \fBnm\fR.
.TP
.BI \-L,\ --library-path= directory
Append the specified directory to the list of directories that are
searched for import libraries.
@ -155,6 +155,10 @@ modules. The default is to use the base name of the spec file (without
any extension). This is used for KERNEL, since it lives in
KRNL386.EXE. It shouldn't be needed otherwise.
.TP
.BI \--nm-cmd= nm-command
Specify the command to use to get the list of undefined symbols; the
default is \fBnm\fR.
.TP
.BI \-o,\ --output= file
Set the name of the output file (default is standard output).
.TP

View File

@ -590,6 +590,8 @@ static void build(struct options* opts)
spec_args = strarray_alloc();
spec_s_name = get_temp_file(output_name, ".spec.s");
strarray_add(spec_args, winebuild);
strarray_add(spec_args, "--as-cmd");
strarray_add(spec_args, AS);
strarray_add(spec_args, "--ld-cmd");
strarray_add(spec_args, LD);
strarray_addall(spec_args, strarray_fromstring(DLLFLAGS, " "));