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:
parent
980f817737
commit
a999a990fe
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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, " "));
|
||||
|
|
Loading…
Reference in New Issue