Commit 000c13a0 authored by Alexandre Julliard's avatar Alexandre Julliard

Added support in winebuild for resolving function imports (-sym option).

Added -L option for locating imported dlls. Changed generated exe init code to use __wine_get_main_args.
parent b1e70285
......@@ -157,14 +157,11 @@ DLLS = \
# Implicit rules
.SUFFIXES: .mc .rc .mc.rc .res .spec .spec.c .spec.o .glue.c
.SUFFIXES: .mc .rc .mc.rc .res .spec .spec.c .glue.c
.c.o:
$(CC) -c $(ALLCFLAGS) -o $*.o $<
.spec.c.spec.o:
$(CC) -c $(ALLCFLAGS) @GCC_NO_BUILTIN@ -o $*.spec.o $<
.s.o:
$(AS) -o $*.o $<
......@@ -178,7 +175,7 @@ DLLS = \
$(LDPATH) $(WRC) $(WRCFLAGS) $(DIVINCL) -o $@ -r $<
.spec.spec.c:
$(LDPATH) $(WINEBUILD) @DLLFLAGS@ -o $@ -spec $<
$(LDPATH) $(WINEBUILD) @DLLFLAGS@ -L $(DLLDIR) -o $@ -spec $<
.c.glue.c:
$(LDPATH) $(WINEBUILD) @DLLFLAGS@ -o $@ -glue $<
......@@ -192,6 +189,16 @@ DLLS = \
all: Makefile
# Rule for main module intermediate object
$(MODULE).tmp.o: $(OBJS) Makefile.in
$(LDCOMBINE) $(OBJS) -o $@
# Rule for main module spec file
$(MODULE).spec.c: $(MODULE).spec $(RC_SRCS:.rc=.res) $(SYMBOLFILE) $(WINEBUILD)
$(LDPATH) $(WINEBUILD) @DLLFLAGS@ -L $(DLLDIR) $(SYMBOLFILE:%=-sym %) -o $@ -spec $(MODULE).spec
# Rule to rebuild the resource compiler
$(WRC):
......@@ -212,10 +219,6 @@ $(MAKEDEP):
$(WINEBUILD):
cd $(TOPOBJDIR)/tools/winebuild && $(MAKE) winebuild
# Rule for main module spec file
$(MODULE).spec.c: $(RC_SRCS:.rc=.res)
# Rules for makefile
Makefile: Makefile.in $(TOPSRCDIR)/configure
......
......@@ -99,7 +99,9 @@ libwine_unicode.$(LIBEXT): unicode/libwine_unicode.$(LIBEXT)
# Dependencies between directories
$(EMUOBJS) $(DLLOBJS) $(PROGRAMS): tools
$(DLLOBJS) $(PROGRAMS): tools
$(EMUOBJS): tools dlls
$(LIBPROGRAMS): tools dlls libwine.$(LIBEXT) libwine_unicode.$(LIBEXT)
......
......@@ -142,7 +142,7 @@ extern void warning( const char *msg, ... );
extern void dump_bytes( FILE *outfile, const unsigned char *data, int len,
const char *label, int constant );
extern void add_import_dll( const char *name );
extern void resolve_imports( FILE *outfile );
extern int resolve_imports( FILE *outfile );
extern int output_imports( FILE *outfile );
extern void load_res32_file( const char *name );
extern int output_resources( FILE *outfile );
......@@ -153,7 +153,7 @@ extern int output_res16_directory( unsigned char *buffer );
extern void BuildGlue( FILE *outfile, FILE *infile );
extern void BuildRelays( FILE *outfile );
extern void BuildSpec16File( FILE *outfile );
extern void BuildSpec32File( FILE *outfile );
extern void BuildSpec32File( FILE *outfile, int output_main );
extern SPEC_TYPE ParseTopLevel( FILE *file );
/* global variables */
......@@ -167,6 +167,7 @@ extern int DLLHeapSize;
extern int UsePIC;
extern int debugging;
extern int nb_debug_channels;
extern int nb_lib_paths;
extern char DLLName[80];
extern char DLLFileName[80];
......@@ -175,6 +176,7 @@ extern char owner_name[80];
extern const char *input_file_name;
extern const char *output_file_name;
extern char **debug_channels;
extern char **lib_path;
extern ORDDEF EntryPoints[MAX_ORDINALS];
extern ORDDEF *Ordinals[MAX_ORDINALS];
......
......@@ -14,16 +14,116 @@
struct import
{
char *dll; /* dll name */
char **exports; /* functions exported from this dll */
int nb_exports; /* number of exported functions */
char **imports; /* functions we want to import from this dll */
int nb_imports; /* number of imported functions */
};
static char **undef_symbols; /* list of undefined symbols */
static int nb_undef_symbols, undef_size;
static struct import **dll_imports = NULL;
static int nb_imports = 0; /* number of imported dlls */
static int total_imports = 0; /* total number of imported functions */
/* compare function names; helper for resolve_imports */
static int name_cmp( const void *name, const void *entry )
{
return strcmp( *(char **)name, *(char **)entry );
}
/* locate a symbol in a (sorted) list */
inline static const char *find_symbol( const char *name, char **table, int size )
{
char **res = bsearch( &name, table, size, sizeof(*table), name_cmp );
return res ? *res : NULL;
}
/* sort a symbol table */
inline static void sort_symbols( char **table, int size )
{
qsort( table, size, sizeof(*table), name_cmp );
}
/* open the .so library for a given dll in a specified path */
static char *try_library_path( const char *path, const char *name )
{
char *buffer, *p;
int fd;
buffer = xmalloc( strlen(path) + strlen(name) + 8 );
sprintf( buffer, "%s/lib%s", path, name );
p = buffer + strlen(buffer) - 4;
if (!strcmp( p, ".dll" )) *p = 0;
strcat( buffer, ".so" );
/* check if the file exists */
if ((fd = open( buffer, O_RDONLY )) == -1) return NULL;
close( fd );
return buffer;
}
/* open the .so library for a given dll */
static char *open_library( const char *name )
{
char *fullname;
int i;
for (i = 0; i < nb_lib_paths; i++)
{
if ((fullname = try_library_path( lib_path[i], name ))) return fullname;
}
if (!(fullname = try_library_path( ".", name )))
fatal_error( "could not open .so file for %s\n", name );
return fullname;
}
/* read in the list of exported symbols of a .so */
static void read_exported_symbols( const char *name, struct import *imp )
{
FILE *f;
char buffer[1024];
char *fullname, *cmdline;
const char *ext;
int size, err;
imp->exports = NULL;
imp->nb_exports = size = 0;
if (!(ext = strrchr( name, '.' ))) ext = name + strlen(name);
if (!(fullname = open_library( name ))) return;
cmdline = xmalloc( strlen(fullname) + 4 );
sprintf( cmdline, "nm %s", fullname );
free( fullname );
if (!(f = popen( cmdline, "r" )))
fatal_error( "Cannot execute '%s'\n", cmdline );
while (fgets( buffer, sizeof(buffer), f ))
{
char *p = buffer + strlen(buffer) - 1;
if (p < buffer) continue;
if (*p == '\n') *p-- = 0;
if (!(p = strstr( buffer, "__wine_dllexport_" ))) continue;
p += 17;
if (strncmp( p, name, ext - name )) continue;
p += ext - name;
if (*p++ != '_') continue;
if (imp->nb_exports == size)
{
size += 128;
imp->exports = xrealloc( imp->exports, size * sizeof(*imp->exports) );
}
imp->exports[imp->nb_exports++] = xstrdup( p );
}
if ((err = pclose( f ))) fatal_error( "%s error %d\n", cmdline, err );
free( cmdline );
sort_symbols( imp->exports, imp->nb_exports );
}
/* add a dll to the list of imports */
void add_import_dll( const char *name )
{
......@@ -32,11 +132,12 @@ void add_import_dll( const char *name )
imp->imports = NULL;
imp->nb_imports = 0;
read_exported_symbols( name, imp );
dll_imports = xrealloc( dll_imports, (nb_imports+1) * sizeof(*dll_imports) );
dll_imports[nb_imports++] = imp;
}
#ifdef notyet
/* add a function to the list of imports from a given dll */
static void add_import_func( struct import *imp, const char *name )
{
......@@ -44,7 +145,113 @@ static void add_import_func( struct import *imp, const char *name )
imp->imports[imp->nb_imports++] = xstrdup( name );
total_imports++;
}
#endif
/* add a symbol to the undef list */
inline static void add_undef_symbol( const char *name )
{
if (nb_undef_symbols == undef_size)
{
undef_size += 128;
undef_symbols = xrealloc( undef_symbols, undef_size * sizeof(*undef_symbols) );
}
undef_symbols[nb_undef_symbols++] = xstrdup( name );
}
/* add the extra undefined symbols that will be contained in the generated spec file itself */
static void add_extra_undef_symbols(void)
{
const char *extras[8];
int i, count = 0;
#define ADD_SYM(name) \
do { if (!find_symbol( extras[count] = (name), undef_symbols, \
nb_undef_symbols )) count++; } while(0)
sort_symbols( undef_symbols, nb_undef_symbols );
/* add symbols that will be contained in the spec file itself */
switch (SpecMode)
{
case SPEC_MODE_GUIEXE:
ADD_SYM( "GetCommandLineA" );
ADD_SYM( "GetStartupInfoA" );
ADD_SYM( "GetModuleHandleA" );
/* fall through */
case SPEC_MODE_CUIEXE:
ADD_SYM( "__wine_get_main_args" );
ADD_SYM( "ExitProcess" );
/* fall through */
case SPEC_MODE_DLL:
case SPEC_MODE_GUIEXE_NO_MAIN:
case SPEC_MODE_CUIEXE_NO_MAIN:
ADD_SYM( "RtlRaiseException" );
break;
}
if (count)
{
for (i = 0; i < count; i++) add_undef_symbol( extras[i] );
sort_symbols( undef_symbols, nb_undef_symbols );
}
}
/* read in the list of undefined symbols */
void read_undef_symbols( const char *name )
{
FILE *f;
char buffer[1024];
int err;
undef_size = nb_undef_symbols = 0;
sprintf( buffer, "nm -u %s", name );
if (!(f = popen( buffer, "r" )))
fatal_error( "Cannot execute '%s'\n", buffer );
while (fgets( buffer, sizeof(buffer), f ))
{
char *p = buffer + strlen(buffer) - 1;
if (p < buffer) continue;
if (*p == '\n') *p-- = 0;
add_undef_symbol( buffer );
}
if ((err = pclose( f ))) fatal_error( "nm -u %s error %d\n", name, err );
}
/* resolve the imports for a Win32 module */
int resolve_imports( FILE *outfile )
{
int i, j, off;
char **p;
if (!nb_undef_symbols) return 0; /* no symbol file specified */
add_extra_undef_symbols();
for (i = 0; i < nb_imports; i++)
{
struct import *imp = dll_imports[i];
for (j = 0; j < nb_undef_symbols; j++)
{
const char *res = find_symbol( undef_symbols[j], imp->exports, imp->nb_exports );
if (res)
{
add_import_func( imp, res );
undef_symbols[j] = NULL;
}
}
/* remove all the holes in the undef symbols list */
p = undef_symbols;
for (j = off = 0; j < nb_undef_symbols; j++)
{
if (!undef_symbols[j]) off++;
else undef_symbols[j - off] = undef_symbols[j];
}
nb_undef_symbols -= off;
if (!off) warning( "%s imported but no symbols used\n", imp->dll );
}
return 1;
}
/* output the import table of a Win32 module */
int output_imports( FILE *outfile )
......@@ -93,21 +300,21 @@ int output_imports( FILE *outfile )
fprintf( outfile, "#ifndef __GNUC__\nstatic void __asm__dummy_import(void) {\n#endif\n\n" );
pos = 20 * (nb_imports + 1); /* offset of imports.data from start of imports */
fprintf( outfile, "asm(\".align 4\");\n" );
fprintf( outfile, "asm(\".align 4\\n\"\n" );
for (i = 0; i < nb_imports; i++, pos += 4)
{
for (j = 0; j < dll_imports[i]->nb_imports; j++, pos += 4)
{
fprintf( outfile,
"asm(\".type " PREFIX "%s,@function\\n\\t"
".globl " PREFIX "%s\\n"
PREFIX "%s:\\tjmp *(imports+%d)\\n\\t"
"movl %%esi,%%esi\");\n",
dll_imports[i]->imports[j], dll_imports[i]->imports[j],
fprintf( outfile, " \"\\t.type " PREFIX "%s,@function\\n\"\n",
dll_imports[i]->imports[j] );
fprintf( outfile, " \"\\t.globl " PREFIX "%s\\n\"\n",
dll_imports[i]->imports[j] );
fprintf( outfile, " \"" PREFIX "%s:\\tjmp *(imports+%d)\\n\"\n",
dll_imports[i]->imports[j], pos );
fprintf( outfile, " \"\\tmovl %%esi,%%esi\\n\"\n" );
}
}
fprintf( outfile, "#ifndef __GNUC__\n}\n#endif\n\n" );
fprintf( outfile, ");\n#ifndef __GNUC__\n}\n#endif\n\n" );
done:
return nb_imports;
......
......@@ -30,12 +30,14 @@ int nb_entry_points = 0;
int nb_names = 0;
int debugging = 1;
int nb_debug_channels = 0;
int nb_lib_paths = 0;
char DLLName[80];
char DLLFileName[80];
char DLLInitFunc[80];
char owner_name[80];
char **debug_channels;
char **debug_channels = NULL;
char **lib_path = NULL;
const char *input_file_name;
const char *output_file_name;
......@@ -82,12 +84,16 @@ static void do_usage(void);
static void do_spec( const char *arg );
static void do_glue( const char *arg );
static void do_relay(void);
static void do_sym( const char *arg );
static void do_lib( const char *arg );
static const struct option option_table[] =
{
{ "-fPIC", 0, do_pic, "-fPIC Generate PIC code" },
{ "-h", 0, do_usage, "-h Display this help message" },
{ "-L", 1, do_lib, "-L directory Look for imports libraries in 'directory'" },
{ "-o", 1, do_output, "-o name Set the output file name (default: stdout)" },
{ "-sym", 1, do_sym, "-sym file.o Read the list of undefined symbols from 'file.o'" },
{ "-spec", 1, do_spec, "-spec file.spec Build a .c file from a spec file" },
{ "-glue", 1, do_glue, "-glue file.c Build the 16-bit glue for a .c file" },
{ "-relay", 0, do_relay, "-relay Build the relay assembly routines" },
......@@ -145,6 +151,17 @@ static void do_relay(void)
exec_mode = MODE_RELAY;
}
static void do_sym( const char *arg )
{
extern void read_undef_symbols( const char *name );
read_undef_symbols( arg );
}
static void do_lib( const char *arg )
{
lib_path = xrealloc( lib_path, (nb_lib_paths+1) * sizeof(*lib_path) );
lib_path[nb_lib_paths++] = xstrdup( arg );
}
/* parse options from the argv array and remove all the recognized ones */
static void parse_options( char *argv[] )
......@@ -186,7 +203,7 @@ int main(int argc, char **argv)
BuildSpec16File( output_file );
break;
case SPEC_WIN32:
BuildSpec32File( output_file );
BuildSpec32File( output_file, !resolve_imports( output_file ) );
break;
default: assert(0);
}
......
......@@ -9,6 +9,7 @@
*/
#include <assert.h>
#include <ctype.h>
#include <unistd.h>
#include "winbase.h"
......@@ -300,6 +301,19 @@ static void output_exports( FILE *outfile, int nr_exports, int nr_names, int fwd
#endif /* __i386__ */
fprintf( outfile, " }\n};\n\n" );
/* output __wine_dllexport symbols */
for (i = 0; i < nb_names; i++)
{
char *p;
/* 'extern' definitions are not available for implicit import */
if (Names[i]->type == TYPE_EXTERN) continue;
/* check for invalid characters in the name */
for (p = Names[i]->name; *p; p++) if (!isalnum(*p) && *p != '_') break;
if (!*p) fprintf( outfile, "const char __wine_dllexport_%s_%s = 0;\n",
DLLName, Names[i]->name );
}
}
......@@ -308,7 +322,7 @@ static void output_exports( FILE *outfile, int nr_exports, int nr_names, int fwd
*
* Build a Win32 C file from a spec file.
*/
void BuildSpec32File( FILE *outfile )
void BuildSpec32File( FILE *outfile, int output_main )
{
ORDDEF *odp;
int i, fwd_size = 0, have_regs = FALSE;
......@@ -468,46 +482,54 @@ void BuildSpec32File( FILE *outfile )
if (!init_func) init_func = "WinMain";
fprintf( outfile,
"\n#include <winbase.h>\n"
"static void exe_main(void)\n"
"int _ARGC;\n"
"char **_ARGV;\n"
"static void __wine_exe_main(void)\n"
"{\n"
" extern int PASCAL %s(HINSTANCE,HINSTANCE,LPSTR,INT);\n"
" extern int __wine_get_main_args( char ***argv );\n"
" STARTUPINFOA info;\n"
" LPSTR cmdline = GetCommandLineA();\n"
" while (*cmdline && *cmdline != ' ') cmdline++;\n"
" if (*cmdline) cmdline++;\n"
" GetStartupInfoA( &info );\n"
" if (!(info.dwFlags & STARTF_USESHOWWINDOW)) info.wShowWindow = 1;\n"
" _ARGC = __wine_get_main_args( &_ARGV );\n"
" ExitProcess( %s( GetModuleHandleA(0), 0, cmdline, info.wShowWindow ) );\n"
"}\n\n", init_func, init_func );
fprintf( outfile,
"int main( int argc, char *argv[] )\n"
"{\n"
" extern void PROCESS_InitWinelib( int, char ** );\n"
" PROCESS_InitWinelib( argc, argv );\n"
" return 1;\n"
"}\n\n" );
init_func = "exe_main";
if (output_main)
fprintf( outfile,
"int main( int argc, char *argv[] )\n"
"{\n"
" extern void PROCESS_InitWinelib( int, char ** );\n"
" PROCESS_InitWinelib( argc, argv );\n"
" return 1;\n"
"}\n\n" );
init_func = "__wine_exe_main";
subsystem = IMAGE_SUBSYSTEM_WINDOWS_GUI;
break;
case SPEC_MODE_CUIEXE:
if (!init_func) init_func = "wine_main";
if (!init_func) init_func = output_main ? "wine_main" : "main";
fprintf( outfile,
"\n#include <winbase.h>\n"
"static void exe_main(void)\n"
"int _ARGC;\n"
"char **_ARGV;\n"
"static void __wine_exe_main(void)\n"
"{\n"
" extern int %s( int argc, char *argv[] );\n"
" extern int _ARGC;\n"
" extern char **_ARGV;\n"
" extern int __wine_get_main_args( char ***argv );\n"
" _ARGC = __wine_get_main_args( &_ARGV );\n"
" ExitProcess( %s( _ARGC, _ARGV ) );\n"
"}\n\n", init_func, init_func );
fprintf( outfile,
"int main( int argc, char *argv[] )\n"
"{\n"
" extern void PROCESS_InitWinelib( int, char ** );\n"
" PROCESS_InitWinelib( argc, argv );\n"
" return 1;\n"
"}\n\n" );
init_func = "exe_main";
if (output_main)
fprintf( outfile,
"int main( int argc, char *argv[] )\n"
"{\n"
" extern void PROCESS_InitWinelib( int, char ** );\n"
" PROCESS_InitWinelib( argc, argv );\n"
" return 1;\n"
"}\n\n" );
init_func = "__wine_exe_main";
subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI;
break;
case SPEC_MODE_GUIEXE_NO_MAIN:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment