/*
* DLL imports support
*
- * Copyright 2000 Alexandre Julliard
- * 2000 Eric Pouech
+ * Copyright 2000, 2004 Alexandre Julliard
+ * Copyright 2000 Eric Pouech
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
*/
#include "config.h"
-#include "wine/port.h"
+#include <assert.h>
#include <ctype.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
+#include <stdarg.h>
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
-#if defined(WIN32)
-#include <windows.h>
-#endif
-
+#include "winglue.h"
#include "build.h"
-struct func
-{
- char *name; /* function name */
- int ordinal; /* function ordinal */
- int ord_only; /* non-zero if function is imported by ordinal */
-};
+#ifndef EXCEPTION_NONCONTINUABLE
+#define EXCEPTION_NONCONTINUABLE 1
+#endif
+
+#define EXCEPTION_WINE_STUB 0x80000100 /* stub entry point called */
struct import
{
- char *dll; /* dll name */
+ DLLSPEC *spec; /* description of the imported dll */
+ char *full_name; /* full name of the input file */
+ dev_t dev; /* device/inode of the input file */
+ ino_t ino;
int delay; /* delay or not dll loading ? */
- struct func *exports; /* functions exported from this dll */
+ ORDDEF **exports; /* functions exported from this dll */
int nb_exports; /* number of exported functions */
- struct func *imports; /* functions we want to import from this dll */
+ ORDDEF **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 = -1;
-static int undef_size;
-
-static char **ignore_symbols; /* list of symbols to ignore */
-static int nb_ignore_symbols;
-static int ignore_size;
+struct name_table
+{
+ char **names;
+ unsigned int count, size;
+};
-static char *ld_tmp_file; /* ld temp file name */
+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) */
"tanh"
};
-#ifdef __powerpc__
-# ifdef __APPLE__
-# define ppc_high(mem) "ha16(" mem ")"
-# define ppc_low(mem) "lo16(" mem ")"
-static const char * const ppc_reg[32] = { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
- "r8", "r9", "r10","r11","r12","r13","r14","r15",
- "r16","r17","r18","r19","r20","r21","r22","r23",
- "r24","r25","r26","r27","r28","r29","r30","r31" };
-# else /* __APPLE__ */
-# define ppc_high(mem) "(" mem ")@hi"
-# define ppc_low(mem) "(" mem ")@l"
-static const char * const ppc_reg[32] = { "0", "1", "2", "3", "4", "5", "6", "7",
- "8", "9", "10","11","12","13","14","15",
- "16","17","18","19","20","21","22","23",
- "24","25","26","27","28","29","30","31" };
-# endif /* __APPLE__ */
-#endif /* __powerpc__ */
+
+static inline const char *ppc_reg( int reg )
+{
+ static const char * const ppc_regs[32] = { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
+ "r8", "r9", "r10","r11","r12","r13","r14","r15",
+ "r16","r17","r18","r19","r20","r21","r22","r23",
+ "r24","r25","r26","r27","r28","r29","r30","r31" };
+ if (target_platform == PLATFORM_APPLE) return ppc_regs[reg];
+ return ppc_regs[reg] + 1; /* skip the 'r' */
+}
/* compare function names; helper for resolve_imports */
static int name_cmp( const void *name, const void *entry )
{
- return strcmp( *(char **)name, *(char **)entry );
+ return strcmp( *(const char* const *)name, *(const char* const *)entry );
}
/* compare function names; helper for resolve_imports */
static int func_cmp( const void *func1, const void *func2 )
{
- return strcmp( ((struct func *)func1)->name, ((struct func *)func2)->name );
+ const ORDDEF *odp1 = *(const ORDDEF * const *)func1;
+ const ORDDEF *odp2 = *(const ORDDEF * const *)func2;
+ return strcmp( odp1->name ? odp1->name : odp1->export_name,
+ odp2->name ? odp2->name : odp2->export_name );
}
-/* locate a symbol in a (sorted) list */
-inline static const char *find_symbol( const char *name, char **table, int size )
+/* add a name to a name table */
+inline static void add_name( struct name_table *table, const char *name )
{
- char **res = NULL;
-
- if (table) {
- res = bsearch( &name, table, size, sizeof(*table), name_cmp );
+ if (table->count == table->size)
+ {
+ table->size += (table->size / 2);
+ if (table->size < 32) table->size = 32;
+ table->names = xrealloc( table->names, table->size * sizeof(*table->names) );
}
+ table->names[table->count++] = xstrdup( name );
+}
+
+/* remove a name from a name table */
+inline static void remove_name( struct name_table *table, unsigned int idx )
+{
+ assert( idx < table->count );
+ free( table->names[idx] );
+ memmove( table->names + idx, table->names + idx + 1,
+ (table->count - idx - 1) * sizeof(*table->names) );
+ table->count--;
+}
+
+/* make a name table empty */
+inline static void empty_name_table( struct name_table *table )
+{
+ unsigned int i;
+ for (i = 0; i < table->count; i++) free( table->names[i] );
+ table->count = 0;
+}
+
+/* locate a name in a (sorted) list */
+inline static const char *find_name( const char *name, const struct name_table *table )
+{
+ char **res = NULL;
+
+ if (table->count) res = bsearch( &name, table->names, table->count, sizeof(*table->names), name_cmp );
return res ? *res : NULL;
}
+/* sort a name table */
+inline static void sort_names( struct name_table *table )
+{
+ if (table->count) qsort( table->names, table->count, sizeof(*table->names), name_cmp );
+}
+
/* locate an export in a (sorted) export list */
-inline static struct func *find_export( const char *name, struct func *table, int size )
+inline static ORDDEF *find_export( const char *name, ORDDEF **table, int size )
{
- struct func func, *res = NULL;
+ ORDDEF func, *odp, **res = NULL;
func.name = (char *)name;
func.ordinal = -1;
- if (table) res = bsearch( &func, table, size, sizeof(*table), func_cmp );
- return res;
-}
-
-/* sort a symbol table */
-inline static void sort_symbols( char **table, int size )
-{
- if (table )
- qsort( table, size, sizeof(*table), name_cmp );
+ odp = &func;
+ if (table) res = bsearch( &odp, table, size, sizeof(*table), func_cmp );
+ return res ? *res : NULL;
}
/* free an import structure */
static void free_imports( struct import *imp )
{
- int i;
-
- for (i = 0; i < imp->nb_exports; i++) free( imp->exports[i].name );
- for (i = 0; i < imp->nb_imports; i++) free( imp->imports[i].name );
free( imp->exports );
free( imp->imports );
- free( imp->dll );
+ free_dll_spec( imp->spec );
+ free( imp->full_name );
free( imp );
}
-/* remove the temp file at exit */
-static void remove_ld_tmp_file(void)
+/* check whether a given dll is imported in delayed mode */
+static int is_delayed_import( const char *name )
{
- if (ld_tmp_file) unlink( ld_tmp_file );
+ int i;
+
+ for (i = 0; i < delayed_imports.count; i++)
+ {
+ if (!strcmp( delayed_imports.names[i], name )) return 1;
+ }
+ return 0;
}
/* check whether a given dll has already been imported */
-static int is_already_imported( const char *name )
+static struct import *is_already_imported( const char *name )
{
int i;
for (i = 0; i < nb_imports; i++)
{
- if (!strcmp( dll_imports[i]->dll, name )) return 1;
+ if (!strcmp( dll_imports[i]->spec->file_name, name )) return dll_imports[i];
}
- return 0;
+ return NULL;
}
/* open the .so library for a given dll in a specified path */
return NULL;
}
-/* open the .so library for a given dll */
-static char *open_library( const char *name )
+/* find the .def import library for a given dll */
+static char *find_library( const char *name )
{
char *fullname;
int i;
{
if ((fullname = try_library_path( lib_path[i], name ))) return fullname;
}
- if (!(fullname = try_library_path( ".", name )))
- fatal_error( "could not open .def file for %s\n", name );
- return fullname;
-}
-
-/* skip whitespace until the next token */
-static char *skip_whitespace( char *p )
-{
- while (*p && isspace(*p)) p++;
- if (!*p || *p == ';') p = NULL;
- return p;
-}
-
-/* skip to the start of the next token, null terminating the current one */
-static char *next_token( char *p )
-{
- while (*p && !isspace(*p)) p++;
- if (*p) *p++ = 0;
- return skip_whitespace( p );
-}
-
-/* remove the @nn suffix from stdcall names */
-static char *remove_stdcall_decoration( char *buffer )
-{
- char *p = buffer + strlen(buffer) - 1;
- while (p > buffer && isdigit(*p)) p--;
- if (p > buffer && *p == '@') *p = 0;
- return buffer;
+ fatal_error( "could not open .def file for %s\n", name );
+ return NULL;
}
/* read in the list of exported symbols of an import library */
-static int read_import_lib( const char *name, struct import *imp )
+static int read_import_lib( struct import *imp )
{
FILE *f;
- char buffer[1024];
- char *fullname;
- int size;
-
- imp->exports = NULL;
- imp->nb_exports = size = 0;
-
- fullname = open_library( name );
- f = open_input_file( NULL, fullname );
- free( fullname );
+ int i, ret;
+ struct stat stat;
+ struct import *prev_imp;
+ DLLSPEC *spec = imp->spec;
+
+ f = open_input_file( NULL, imp->full_name );
+ fstat( fileno(f), &stat );
+ imp->dev = stat.st_dev;
+ imp->ino = stat.st_ino;
+ ret = parse_def_file( f, spec );
+ close_input_file( f );
+ if (!ret) return 0;
- while (fgets( buffer, sizeof(buffer), f ))
+ /* check if we already imported that library from a different file */
+ if ((prev_imp = is_already_imported( spec->file_name )))
{
- char *name, *flags;
- int ordinal = 0, ord_only = 0;
-
- char *p = buffer + strlen(buffer) - 1;
- if (p < buffer) goto next;
- if (*p == '\n') *p-- = 0;
-
- p = buffer;
- if (!(p = skip_whitespace(p))) goto next;
- name = p;
- p = next_token( name );
+ if (prev_imp->dev != imp->dev || prev_imp->ino != imp->ino)
+ fatal_error( "%s and %s have the same export name '%s'\n",
+ prev_imp->full_name, imp->full_name, spec->file_name );
+ return 0; /* the same file was already loaded, ignore this one */
+ }
- if (!strcmp( name, "LIBRARY" ))
- {
- if (!p)
- {
- error( "Expected name after LIBRARY\n" );
- goto next;
- }
- name = p;
- p = next_token( name );
- if (p)
- {
- error( "Garbage after LIBRARY statement\n" );
- goto next;
- }
- if (is_already_imported( name ))
- {
- close_input_file( f );
- return 0; /* ignore this dll */
- }
- free( imp->dll );
- imp->dll = xstrdup( name );
- goto next;
- }
- if (!strcmp( name, "EXPORTS" )) goto next;
+ if (is_delayed_import( spec->file_name ))
+ {
+ imp->delay = 1;
+ nb_delayed++;
+ }
- /* check for ordinal */
- if (!p)
- {
- error( "Expected ordinal after function name\n" );
- goto next;
- }
- if (*p != '@' || !isdigit(p[1]))
- {
- error( "Expected ordinal after function name '%s'\n", name );
- goto next;
- }
- ordinal = strtol( p+1, &p, 10 );
- if (ordinal >= MAX_ORDINALS)
- {
- error( "Invalid ordinal number %d\n", ordinal );
- goto next;
- }
+ imp->exports = xmalloc( spec->nb_entry_points * sizeof(*imp->exports) );
- /* check for optional flags */
- while (p && (p = skip_whitespace(p)))
- {
- flags = p;
- p = next_token( flags );
- if (!strcmp( flags, "NONAME" ))
- {
- ord_only = 1;
- if (!ordinal)
- {
- error( "Invalid ordinal number %d\n", ordinal );
- goto next;
- }
- }
- else if (!strcmp( flags, "CONSTANT" ) || !strcmp( flags, "DATA" ))
- {
- /* we don't support importing non-function entry points */
- goto next;
- }
- else if (!strcmp( flags, "PRIVATE" ))
- {
- /* function must not be imported */
- goto next;
- }
- else
- {
- error( "Garbage after ordinal declaration\n" );
- goto next;
- }
- }
+ for (i = 0; i < spec->nb_entry_points; i++)
+ {
+ ORDDEF *odp = &spec->entry_points[i];
- if (imp->nb_exports == size)
- {
- size += 128;
- imp->exports = xrealloc( imp->exports, size * sizeof(*imp->exports) );
- }
- if ((p = strchr( name, '=' ))) *p = 0;
- remove_stdcall_decoration( name );
- imp->exports[imp->nb_exports].name = xstrdup( name );
- imp->exports[imp->nb_exports].ordinal = ordinal;
- imp->exports[imp->nb_exports].ord_only = ord_only;
- imp->nb_exports++;
- next:
- current_line++;
+ if (odp->type != TYPE_STDCALL && odp->type != TYPE_CDECL) continue;
+ if (odp->flags & FLAG_PRIVATE) continue;
+ imp->exports[imp->nb_exports++] = odp;
}
- close_input_file( f );
+ imp->exports = xrealloc( imp->exports, imp->nb_exports * sizeof(*imp->exports) );
if (imp->nb_exports)
qsort( imp->exports, imp->nb_exports, sizeof(*imp->exports), func_cmp );
- return !nb_errors;
+ return 1;
}
-/* add a dll to the list of imports */
-void add_import_dll( const char *name, int delay )
+/* build the dll exported name from the import lib name or path */
+static char *get_dll_name( const char *name, const char *filename )
{
- struct import *imp;
- char *fullname;
-
- fullname = xmalloc( strlen(name) + 5 );
- strcpy( fullname, name );
- if (!strchr( fullname, '.' )) strcat( fullname, ".dll" );
+ char *ret;
- /* check if we already imported it */
- if (is_already_imported( fullname ))
+ if (filename)
{
- free( fullname );
- return;
+ const char *basename = strrchr( filename, '/' );
+ if (!basename) basename = filename;
+ else basename++;
+ if (!strncmp( basename, "lib", 3 )) basename += 3;
+ ret = xmalloc( strlen(basename) + 5 );
+ strcpy( ret, basename );
+ if (strendswith( ret, ".def" )) ret[strlen(ret)-4] = 0;
}
+ else
+ {
+ ret = xmalloc( strlen(name) + 5 );
+ strcpy( ret, name );
+ }
+ if (!strchr( ret, '.' )) strcat( ret, ".dll" );
+ return ret;
+}
- imp = xmalloc( sizeof(*imp) );
- imp->dll = fullname;
- imp->delay = delay;
- imp->imports = NULL;
- imp->nb_imports = 0;
+/* add a dll to the list of imports */
+void add_import_dll( const char *name, const char *filename )
+{
+ struct import *imp = xmalloc( sizeof(*imp) );
- if (delay) nb_delayed++;
+ imp->spec = alloc_dll_spec();
+ imp->spec->file_name = get_dll_name( name, filename );
+ imp->delay = 0;
+ imp->imports = NULL;
+ imp->nb_imports = 0;
+ imp->exports = NULL;
+ imp->nb_exports = 0;
- if (read_import_lib( name, imp ))
+ if (filename) imp->full_name = xstrdup( filename );
+ else imp->full_name = find_library( name );
+
+ if (read_import_lib( imp ))
{
dll_imports = xrealloc( dll_imports, (nb_imports+1) * sizeof(*dll_imports) );
dll_imports[nb_imports++] = imp;
}
}
+/* add a library to the list of delayed imports */
+void add_delayed_import( const char *name )
+{
+ struct import *imp;
+ char *fullname = get_dll_name( name, NULL );
+
+ add_name( &delayed_imports, fullname );
+ if ((imp = is_already_imported( fullname )) && !imp->delay)
+ {
+ imp->delay = 1;
+ nb_delayed++;
+ }
+ free( fullname );
+}
+
/* remove an imported dll, based on its index in the dll_imports array */
static void remove_import_dll( int index )
{
/* initialize the list of ignored symbols */
static void init_ignored_symbols(void)
{
- int i;
+ unsigned int i;
- nb_ignore_symbols = sizeof(default_ignored_symbols)/sizeof(default_ignored_symbols[0]);
- ignore_size = nb_ignore_symbols + 32;
- ignore_symbols = xmalloc( ignore_size * sizeof(*ignore_symbols) );
- for (i = 0; i < nb_ignore_symbols; i++)
- ignore_symbols[i] = xstrdup( default_ignored_symbols[i] );
+ for (i = 0; i < sizeof(default_ignored_symbols)/sizeof(default_ignored_symbols[0]); i++)
+ add_name( &ignore_symbols, default_ignored_symbols[i] );
}
/* add a symbol to the ignored symbol list */
/* if the name starts with '-' the symbol is removed instead */
void add_ignore_symbol( const char *name )
{
- int i;
+ unsigned int i;
- if (!ignore_symbols) init_ignored_symbols(); /* first time around, fill list with defaults */
+ if (!ignore_symbols.size) init_ignored_symbols(); /* first time around, fill list with defaults */
if (name[0] == '-') /* remove it */
{
- if (!name[1]) /* remove everything */
- {
- for (i = 0; i < nb_ignore_symbols; i++) free( ignore_symbols[i] );
- nb_ignore_symbols = 0;
- }
- else
- {
- for (i = 0; i < nb_ignore_symbols; i++)
- {
- if (!strcmp( ignore_symbols[i], name+1 ))
- {
- free( ignore_symbols[i] );
- memmove( &ignore_symbols[i], &ignore_symbols[i+1], nb_ignore_symbols - i - 1 );
- nb_ignore_symbols--;
- }
- }
- }
- }
- else
- {
- if (nb_ignore_symbols == ignore_size)
+ if (!name[1]) empty_name_table( &ignore_symbols ); /* remove everything */
+ else for (i = 0; i < ignore_symbols.count; i++)
{
- ignore_size += 32;
- ignore_symbols = xrealloc( ignore_symbols, ignore_size * sizeof(*ignore_symbols) );
+ if (!strcmp( ignore_symbols.names[i], name+1 )) remove_name( &ignore_symbols, i-- );
}
- ignore_symbols[nb_ignore_symbols++] = xstrdup( name );
}
+ else add_name( &ignore_symbols, name );
+}
+
+/* add a symbol to the list of extra symbols that ld must resolve */
+void add_extra_ld_symbol( const char *name )
+{
+ add_name( &extra_ld_symbols, name );
}
/* add a function to the list of imports from a given dll */
-static void add_import_func( struct import *imp, const struct func *func )
+static void add_import_func( struct import *imp, ORDDEF *func )
{
imp->imports = xrealloc( imp->imports, (imp->nb_imports+1) * sizeof(*imp->imports) );
- imp->imports[imp->nb_imports].name = xstrdup( func->name );
- imp->imports[imp->nb_imports].ordinal = func->ordinal;
- imp->imports[imp->nb_imports].ord_only = func->ord_only;
- imp->nb_imports++;
+ imp->imports[imp->nb_imports++] = func;
total_imports++;
if (imp->delay) total_delayed++;
}
-/* add a symbol to the undef list */
-inline static void add_undef_symbol( const char *name )
+/* get the default entry point for a given spec file */
+static const char *get_default_entry_point( const DLLSPEC *spec )
{
- 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 );
+ if (spec->characteristics & IMAGE_FILE_DLL) return "__wine_spec_dll_entry";
+ if (spec->subsystem == IMAGE_SUBSYSTEM_NATIVE) return "__wine_spec_drv_entry";
+ return "__wine_spec_exe_entry";
}
-/* remove all the holes in the undefined symbol list; return the number of removed symbols */
-static int remove_symbol_holes(void)
+/* check if the spec file exports any stubs */
+static int has_stubs( const DLLSPEC *spec )
{
- int i, off;
- for (i = off = 0; i < nb_undef_symbols; i++)
+ int i;
+ for (i = 0; i < spec->nb_entry_points; i++)
{
- if (!undef_symbols[i]) off++;
- else undef_symbols[i - off] = undef_symbols[i];
+ ORDDEF *odp = &spec->entry_points[i];
+ if (odp->type == TYPE_STUB) return 1;
}
- nb_undef_symbols -= off;
- return off;
+ return 0;
+}
+
+/* add the extra undefined symbols that will be contained in the generated spec file itself */
+static void add_extra_undef_symbols( DLLSPEC *spec )
+{
+ if (!spec->init_func) spec->init_func = xstrdup( get_default_entry_point(spec) );
+ add_extra_ld_symbol( spec->init_func );
+ if (has_stubs( spec )) add_extra_ld_symbol( "__wine_spec_unimplemented_stub" );
+ if (nb_delayed) add_extra_ld_symbol( "__wine_spec_delay_load" );
}
-/* add a symbol to the extra list, but only if needed */
-static int add_extra_symbol( const char **extras, int *count, const char *name )
+/* check if a given imported dll is not needed, taking forwards into account */
+static int check_unused( const struct import* imp, const DLLSPEC *spec )
{
int i;
+ const char *file_name = imp->spec->file_name;
+ size_t len = strlen( file_name );
+ const char *p = strchr( file_name, '.' );
+ if (p && !strcasecmp( p, ".dll" )) len = p - file_name;
- if (!find_symbol( name, undef_symbols, nb_undef_symbols ))
+ for (i = spec->base; i <= spec->limit; i++)
{
- /* check if the symbol is being exported by this dll */
- for (i = 0; i < nb_entry_points; i++)
- {
- ORDDEF *odp = EntryPoints[i];
- if (odp->type == TYPE_STDCALL ||
- odp->type == TYPE_CDECL ||
- odp->type == TYPE_VARARGS ||
- odp->type == TYPE_EXTERN)
- {
- if (odp->name && !strcmp( odp->name, name )) return 0;
- }
- }
- extras[*count] = name;
- (*count)++;
+ ORDDEF *odp = spec->ordinals[i];
+ if (!odp || !(odp->flags & FLAG_FORWARD)) continue;
+ if (!strncasecmp( odp->link_name, file_name, len ) &&
+ odp->link_name[len] == '.')
+ return 0; /* found a forward, it is used */
}
return 1;
}
-/* add the extra undefined symbols that will be contained in the generated spec file itself */
-static void add_extra_undef_symbols(void)
+/* flag the dll exports that link to an undefined symbol */
+static void check_undefined_exports( DLLSPEC *spec )
{
- const char *extras[10];
- int i, count = 0, nb_stubs = 0, nb_regs = 0;
- int kernel_imports = 0, ntdll_imports = 0;
-
- sort_symbols( undef_symbols, nb_undef_symbols );
-
- for (i = 0; i < nb_entry_points; i++)
- {
- ORDDEF *odp = EntryPoints[i];
- if (odp->type == TYPE_STUB) nb_stubs++;
- if (odp->flags & FLAG_REGISTER) nb_regs++;
- }
-
- /* add symbols that will be contained in the spec file itself */
- switch (SpecMode)
- {
- case SPEC_MODE_DLL:
- break;
- case SPEC_MODE_GUIEXE:
- kernel_imports += add_extra_symbol( extras, &count, "GetCommandLineA" );
- kernel_imports += add_extra_symbol( extras, &count, "GetStartupInfoA" );
- kernel_imports += add_extra_symbol( extras, &count, "GetModuleHandleA" );
- /* fall through */
- case SPEC_MODE_CUIEXE:
- kernel_imports += add_extra_symbol( extras, &count, "ExitProcess" );
- break;
- case SPEC_MODE_GUIEXE_UNICODE:
- kernel_imports += add_extra_symbol( extras, &count, "GetCommandLineA" );
- kernel_imports += add_extra_symbol( extras, &count, "GetStartupInfoA" );
- kernel_imports += add_extra_symbol( extras, &count, "GetModuleHandleA" );
- /* fall through */
- case SPEC_MODE_CUIEXE_UNICODE:
- kernel_imports += add_extra_symbol( extras, &count, "ExitProcess" );
- break;
- }
- if (nb_delayed)
- {
- kernel_imports += add_extra_symbol( extras, &count, "LoadLibraryA" );
- kernel_imports += add_extra_symbol( extras, &count, "GetProcAddress" );
- }
- if (nb_regs)
- ntdll_imports += add_extra_symbol( extras, &count, "__wine_call_from_32_regs" );
- if (nb_delayed || nb_stubs)
- ntdll_imports += add_extra_symbol( extras, &count, "RtlRaiseException" );
-
- /* make sure we import the dlls that contain these functions */
- if (kernel_imports) add_import_dll( "kernel32", 0 );
- if (ntdll_imports) add_import_dll( "ntdll", 0 );
+ int i;
- if (count)
+ for (i = 0; i < spec->nb_entry_points; i++)
{
- for (i = 0; i < count; i++) add_undef_symbol( extras[i] );
- sort_symbols( undef_symbols, nb_undef_symbols );
+ 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 );
+ }
}
}
-/* check if a given imported dll is not needed, taking forwards into account */
-static int check_unused( const struct import* imp )
+/* create a .o file that references all the undefined symbols we want to resolve */
+static char *create_undef_symbols_file( DLLSPEC *spec )
{
- int i;
- size_t len = strlen(imp->dll);
- const char *p = strchr( imp->dll, '.' );
- if (p && !strcasecmp( p, ".dll" )) len = p - imp->dll;
+ char *as_file, *obj_file;
+ unsigned int i;
+ FILE *f;
- for (i = Base; i <= Limit; i++)
+ 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 = Ordinals[i];
- if (!odp || !(odp->flags & FLAG_FORWARD)) continue;
- if (!strncasecmp( odp->link_name, imp->dll, len ) &&
- odp->link_name[len] == '.')
- return 0; /* found a forward, it is used */
+ 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) );
}
- return 1;
+ 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" );
+ assemble_file( as_file, obj_file );
+ 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( char **argv )
+static const char *ldcombine_files( DLLSPEC *spec, char **argv )
{
- int i, len = 0;
- char *cmd;
- int fd, err;
-#if defined(WIN32)
- char tmppath[MAX_PATH];
- char tmpfile[MAX_PATH];
-#endif
-
-#if defined(WIN32)
- if (GetTempPathA(MAX_PATH, tmppath) == 0) return NULL;
- if (GetTempFileNameA(tmppath, "WNB", 0, tmpfile) == 0) fatal_error( "could not generate a temp file\n" );
- ld_tmp_file = xstrdup( tmpfile );
- if ((fd = open( ld_tmp_file, O_RDONLY )) == -1)
-#else
- if (output_file_name && output_file_name[0])
- {
- ld_tmp_file = xmalloc( MAX_PATH);
- strcpy( ld_tmp_file, output_file_name );
- strcat( ld_tmp_file, ".XXXXXX.o" );
- }
- else ld_tmp_file = xstrdup( "/tmp/winebuild.tmp.XXXXXX.o" );
- if ((fd = mkstemps( ld_tmp_file, 2 ) == -1)) fatal_error( "could not generate a temp file\n" );
-#endif
-
- close( fd );
- atexit( remove_ld_tmp_file );
+ 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; argv[i]; i++) len += strlen(argv[i]) + 1;
- cmd = xmalloc( len + strlen(ld_tmp_file) + 10 );
- sprintf( cmd, "ld -r -o %s", ld_tmp_file );
- for (i = 0; argv[i]; i++) sprintf( cmd + strlen(cmd), " %s", argv[i] );
+ cmd = p = xmalloc( len + strlen(ld_tmp_file) + 8 + strlen(ld_command) );
+ 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] );
+ if (verbose) fprintf( stderr, "%s\n", cmd );
err = system( cmd );
- if (err) fatal_error( "ld -r failed with status %d\n", err );
+ if (err) fatal_error( "%s -r failed with status %d\n", ld_command, err );
free( cmd );
return ld_tmp_file;
}
/* read in the list of undefined symbols */
-void read_undef_symbols( char **argv )
+void read_undef_symbols( DLLSPEC *spec, char **argv )
{
+ size_t prefix_len;
FILE *f;
- char buffer[1024];
+ char *cmd, buffer[1024], name_prefix[16];
int err;
const char *name;
if (!argv[0]) return;
- undef_size = nb_undef_symbols = 0;
+ add_extra_undef_symbols( spec );
- /* if we have multiple object files, link them together */
- if (argv[1]) name = ldcombine_files( argv );
- else name = argv[0];
+ strcpy( name_prefix, asm_name("") );
+ prefix_len = strlen( name_prefix );
- sprintf( buffer, "nm -u %s", name );
- if (!(f = popen( buffer, "r" )))
- fatal_error( "Cannot execute '%s'\n", buffer );
+ name = ldcombine_files( spec, argv );
+
+ if (!nm_command) nm_command = xstrdup("nm");
+ cmd = xmalloc( strlen(nm_command) + strlen(name) + 5 );
+ sprintf( cmd, "%s -u %s", nm_command, name );
+ if (!(f = popen( cmd, "r" )))
+ fatal_error( "Cannot execute '%s'\n", cmd );
while (fgets( buffer, sizeof(buffer), f ))
{
p = buffer;
while (*p == ' ') p++;
if (p[0] == 'U' && p[1] == ' ' && p[2]) p += 2;
- add_undef_symbol( p );
+ if (prefix_len && !strncmp( p, name_prefix, prefix_len )) p += prefix_len;
+ add_name( &undef_symbols, p );
}
- if ((err = pclose( f ))) warning( "nm -u %s error %d\n", name, err );
-}
-
-static void remove_ignored_symbols(void)
-{
- int i;
-
- if (!ignore_symbols) init_ignored_symbols();
- sort_symbols( ignore_symbols, nb_ignore_symbols );
- for (i = 0; i < nb_undef_symbols; i++)
- {
- if (find_symbol( undef_symbols[i], ignore_symbols, nb_ignore_symbols ))
- {
- free( undef_symbols[i] );
- undef_symbols[i] = NULL;
- }
- }
- remove_symbol_holes();
+ if ((err = pclose( f ))) warning( "%s failed with status %d\n", cmd, err );
+ free( cmd );
}
/* resolve the imports for a Win32 module */
-int resolve_imports( void )
+int resolve_imports( DLLSPEC *spec )
{
- int i, j;
-
- if (nb_undef_symbols == -1) return 0; /* no symbol file specified */
+ unsigned int i, j, removed;
+ ORDDEF *odp;
- add_extra_undef_symbols();
- remove_ignored_symbols();
+ if (!ignore_symbols.size) init_ignored_symbols();
+ sort_names( &ignore_symbols );
for (i = 0; i < nb_imports; i++)
{
struct import *imp = dll_imports[i];
- for (j = 0; j < nb_undef_symbols; j++)
+ for (j = removed = 0; j < undef_symbols.count; j++)
{
- struct func *func = find_export( undef_symbols[j], imp->exports, imp->nb_exports );
- if (func)
+ if (find_name( undef_symbols.names[j], &ignore_symbols )) continue;
+ odp = find_export( undef_symbols.names[j], imp->exports, imp->nb_exports );
+ if (odp)
{
- add_import_func( imp, func );
- free( undef_symbols[j] );
- undef_symbols[j] = NULL;
+ add_import_func( imp, odp );
+ remove_name( &undef_symbols, j-- );
+ removed++;
}
}
- /* remove all the holes in the undef symbols list */
- if (!remove_symbol_holes() && check_unused( imp ))
+ if (!removed && check_unused( imp, spec ))
{
/* the dll is not used, get rid of it */
- warning( "%s imported but no symbols used\n", imp->dll );
+ warning( "%s imported but no symbols used\n", imp->spec->file_name );
remove_import_dll( i );
i--;
}
}
+
+ sort_names( &undef_symbols );
+ check_undefined_exports( spec );
+
return 1;
}
+/* output the get_pc thunk if needed */
+void output_get_pc_thunk( FILE *outfile )
+{
+ if (target_cpu != CPU_x86) return;
+ if (!UsePIC) return;
+ fprintf( outfile, "\n\t.text\n" );
+ fprintf( outfile, "\t.align %d\n", get_alignment(4) );
+ fprintf( outfile, "\t%s\n", func_declaration("__wine_spec_get_pc_thunk_eax") );
+ fprintf( outfile, "%s:\n", asm_name("__wine_spec_get_pc_thunk_eax") );
+ fprintf( outfile, "\tpopl %%eax\n" );
+ fprintf( outfile, "\tpushl %%eax\n" );
+ fprintf( outfile, "\tret\n" );
+ output_function_size( outfile, "__wine_spec_get_pc_thunk_eax" );
+}
+
+/* output a single import thunk */
+static void output_import_thunk( FILE *outfile, const char *name, const char *table, int pos )
+{
+ fprintf( outfile, "\n\t.align %d\n", get_alignment(4) );
+ fprintf( outfile, "\t%s\n", func_declaration(name) );
+ fprintf( outfile, "%s\n", asm_globl(name) );
+
+ switch(target_cpu)
+ {
+ case CPU_x86:
+ if (!UsePIC)
+ {
+ fprintf( outfile, "\tjmp *(%s+%d)\n", table, pos );
+ }
+ else
+ {
+ fprintf( outfile, "\tcall %s\n", asm_name("__wine_spec_get_pc_thunk_eax") );
+ fprintf( outfile, "1:\tjmp *%s+%d-1b(%%eax)\n", table, pos );
+ }
+ break;
+ case CPU_x86_64:
+ fprintf( outfile, "\tjmpq *%s+%d(%%rip)\n", table, pos );
+ break;
+ case CPU_SPARC:
+ if ( !UsePIC )
+ {
+ fprintf( outfile, "\tsethi %%hi(%s+%d), %%g1\n", table, pos );
+ fprintf( outfile, "\tld [%%g1+%%lo(%s+%d)], %%g1\n", table, pos );
+ fprintf( outfile, "\tjmp %%g1\n" );
+ fprintf( outfile, "\tnop\n" );
+ }
+ else
+ {
+ /* Hmpf. Stupid sparc assembler always interprets global variable
+ names as GOT offsets, so we have to do it the long way ... */
+ fprintf( outfile, "\tsave %%sp, -96, %%sp\n" );
+ fprintf( outfile, "0:\tcall 1f\n" );
+ fprintf( outfile, "\tnop\n" );
+ fprintf( outfile, "1:\tsethi %%hi(%s+%d-0b), %%g1\n", table, pos );
+ fprintf( outfile, "\tor %%g1, %%lo(%s+%d-0b), %%g1\n", table, pos );
+ fprintf( outfile, "\tld [%%g1+%%o7], %%g1\n" );
+ fprintf( outfile, "\tjmp %%g1\n" );
+ fprintf( outfile, "\trestore\n" );
+ }
+ break;
+ case CPU_ALPHA:
+ fprintf( outfile, "\tlda $0,%s\n", table );
+ fprintf( outfile, "\tlda $0,%d($0)\n", pos );
+ fprintf( outfile, "\tjmp $31,($0)\n" );
+ break;
+ case CPU_POWERPC:
+ fprintf( outfile, "\taddi %s, %s, -0x4\n", ppc_reg(1), ppc_reg(1) );
+ fprintf( outfile, "\tstw %s, 0(%s)\n", ppc_reg(9), ppc_reg(1) );
+ fprintf( outfile, "\taddi %s, %s, -0x4\n", ppc_reg(1), ppc_reg(1) );
+ fprintf( outfile, "\tstw %s, 0(%s)\n", ppc_reg(8), ppc_reg(1) );
+ fprintf( outfile, "\taddi %s, %s, -0x4\n", ppc_reg(1), ppc_reg(1) );
+ fprintf( outfile, "\tstw %s, 0(%s)\n", ppc_reg(7), ppc_reg(1) );
+ if (target_platform == PLATFORM_APPLE)
+ {
+ fprintf( outfile, "\tlis %s, ha16(%s+%d)\n", ppc_reg(9), table, pos );
+ fprintf( outfile, "\tla %s, lo16(%s+%d)(%s)\n", ppc_reg(8), table, pos, ppc_reg(9) );
+ }
+ else
+ {
+ fprintf( outfile, "\tlis %s, (%s+%d)@h\n", ppc_reg(9), table, pos );
+ fprintf( outfile, "\tla %s, (%s+%d)@l(%s)\n", ppc_reg(8), table, pos, ppc_reg(9) );
+ }
+ fprintf( outfile, "\tlwz %s, 0(%s)\n", ppc_reg(7), ppc_reg(8) );
+ fprintf( outfile, "\tmtctr %s\n", ppc_reg(7) );
+ fprintf( outfile, "\tlwz %s, 0(%s)\n", ppc_reg(7), ppc_reg(1) );
+ fprintf( outfile, "\taddi %s, %s, 0x4\n", ppc_reg(1), ppc_reg(1) );
+ fprintf( outfile, "\tlwz %s, 0(%s)\n", ppc_reg(8), ppc_reg(1) );
+ fprintf( outfile, "\taddi %s, %s, 0x4\n", ppc_reg(1), ppc_reg(1) );
+ fprintf( outfile, "\tlwz %s, 0(%s)\n", ppc_reg(9), ppc_reg(1) );
+ fprintf( outfile, "\taddi %s, %s, 0x4\n", ppc_reg(1), ppc_reg(1) );
+ fprintf( outfile, "\tbctr\n" );
+ break;
+ }
+ output_function_size( outfile, name );
+}
+
+/* check if we need an import directory */
+int has_imports(void)
+{
+ return (nb_imports - nb_delayed) > 0;
+}
+
/* output the import table of a Win32 module */
-static int output_immediate_imports( FILE *outfile )
+static void output_immediate_imports( FILE *outfile )
{
- int i, j, pos;
- int nb_imm = nb_imports - nb_delayed;
+ int i, j;
+ const char *dll_name;
- if (!nb_imm) goto done;
+ if (nb_imports == nb_delayed) return; /* no immediate imports */
/* main import header */
- fprintf( outfile, "\nstatic struct {\n" );
- fprintf( outfile, " struct {\n" );
- fprintf( outfile, " void *OriginalFirstThunk;\n" );
- fprintf( outfile, " unsigned int TimeDateStamp;\n" );
- fprintf( outfile, " unsigned int ForwarderChain;\n" );
- fprintf( outfile, " const char *Name;\n" );
- fprintf( outfile, " void *FirstThunk;\n" );
- fprintf( outfile, " } imp[%d];\n", nb_imm+1 );
- fprintf( outfile, " const char *data[%d];\n",
- total_imports - total_delayed + nb_imm );
- fprintf( outfile, "} imports = {\n {\n" );
+ fprintf( outfile, "\n/* import table */\n" );
+ fprintf( outfile, "\n\t.data\n" );
+ fprintf( outfile, "\t.align %d\n", get_alignment(4) );
+ fprintf( outfile, ".L__wine_spec_imports:\n" );
/* list of dlls */
for (i = j = 0; i < nb_imports; i++)
{
if (dll_imports[i]->delay) continue;
- fprintf( outfile, " { 0, 0, 0, \"%s\", &imports.data[%d] },\n",
- dll_imports[i]->dll, j );
+ dll_name = make_c_identifier( dll_imports[i]->spec->file_name );
+ fprintf( outfile, "\t.long 0\n" ); /* OriginalFirstThunk */
+ fprintf( outfile, "\t.long 0\n" ); /* TimeDateStamp */
+ fprintf( outfile, "\t.long 0\n" ); /* ForwarderChain */
+ fprintf( outfile, "\t.long .L__wine_spec_import_name_%s-.L__wine_spec_rva_base\n", /* Name */
+ dll_name );
+ fprintf( outfile, "\t.long .L__wine_spec_import_data_ptrs+%d-.L__wine_spec_rva_base\n", /* FirstThunk */
+ j * get_ptr_size() );
j += dll_imports[i]->nb_imports + 1;
}
-
- fprintf( outfile, " { 0, 0, 0, 0, 0 },\n" );
- fprintf( outfile, " },\n {\n" );
-
- /* list of imported functions */
-
+ fprintf( outfile, "\t.long 0\n" ); /* OriginalFirstThunk */
+ fprintf( outfile, "\t.long 0\n" ); /* TimeDateStamp */
+ fprintf( outfile, "\t.long 0\n" ); /* ForwarderChain */
+ fprintf( outfile, "\t.long 0\n" ); /* Name */
+ fprintf( outfile, "\t.long 0\n" ); /* FirstThunk */
+
+ fprintf( outfile, "\n\t.align %d\n", get_alignment(get_ptr_size()) );
+ fprintf( outfile, ".L__wine_spec_import_data_ptrs:\n" );
for (i = 0; i < nb_imports; i++)
{
if (dll_imports[i]->delay) continue;
- fprintf( outfile, " /* %s */\n", dll_imports[i]->dll );
+ dll_name = make_c_identifier( dll_imports[i]->spec->file_name );
for (j = 0; j < dll_imports[i]->nb_imports; j++)
{
- struct func *import = &dll_imports[i]->imports[j];
- if (!import->ord_only)
+ ORDDEF *odp = dll_imports[i]->imports[j];
+ if (!(odp->flags & FLAG_NONAME))
+ fprintf( outfile, "\t%s .L__wine_spec_import_data_%s_%s-.L__wine_spec_rva_base\n",
+ get_asm_ptr_keyword(), dll_name, odp->name );
+ else
{
- unsigned short ord = import->ordinal;
- fprintf( outfile, " \"\\%03o\\%03o%s\",\n",
- *(unsigned char *)&ord, *((unsigned char *)&ord + 1), import->name );
+ if (get_ptr_size() == 8)
+ fprintf( outfile, "\t.quad 0x800000000000%04x\n", odp->ordinal );
+ else
+ fprintf( outfile, "\t.long 0x8000%04x\n", odp->ordinal );
}
- else
- fprintf( outfile, " (char *)%d,\n", import->ordinal );
}
- fprintf( outfile, " 0,\n" );
+ fprintf( outfile, "\t%s 0\n", get_asm_ptr_keyword() );
}
- fprintf( outfile, " }\n};\n\n" );
-
- /* thunks for imported functions */
+ fprintf( outfile, ".L__wine_spec_imports_end:\n" );
- fprintf( outfile, "#ifndef __GNUC__\nstatic void __asm__dummy_import(void) {\n#endif\n\n" );
- pos = 20 * (nb_imm + 1); /* offset of imports.data from start of imports */
- fprintf( outfile, "asm(\".data\\n\\t.align %d\\n\"\n", get_alignment(8) );
for (i = 0; i < nb_imports; i++)
{
if (dll_imports[i]->delay) continue;
- for (j = 0; j < dll_imports[i]->nb_imports; j++, pos += 4)
+ dll_name = make_c_identifier( dll_imports[i]->spec->file_name );
+ for (j = 0; j < dll_imports[i]->nb_imports; j++)
{
- struct func *import = &dll_imports[i]->imports[j];
- fprintf( outfile, " \"\\t" __ASM_FUNC("%s") "\\n\"\n", import->name );
- fprintf( outfile, " \"\\t.globl " __ASM_NAME("%s") "\\n\"\n", import->name );
- fprintf( outfile, " \"" __ASM_NAME("%s") ":\\n\\t", import->name);
-
-#if defined(__i386__)
- if (strstr( import->name, "__wine_call_from_16" ))
- fprintf( outfile, ".byte 0x2e\\n\\tjmp *(imports+%d)\\n\\tnop\\n", pos );
- else
- fprintf( outfile, "jmp *(imports+%d)\\n\\tmovl %%esi,%%esi\\n", pos );
-#elif defined(__sparc__)
- if ( !UsePIC )
+ ORDDEF *odp = dll_imports[i]->imports[j];
+ if (!(odp->flags & FLAG_NONAME))
{
- fprintf( outfile, "sethi %%hi(imports+%d), %%g1\\n\\t", pos );
- fprintf( outfile, "ld [%%g1+%%lo(imports+%d)], %%g1\\n\\t", pos );
- fprintf( outfile, "jmp %%g1\\n\\tnop\\n" );
+ fprintf( outfile, "\t.align %d\n", get_alignment(2) );
+ fprintf( outfile, ".L__wine_spec_import_data_%s_%s:\n", dll_name, odp->name );
+ fprintf( outfile, "\t%s %d\n", get_asm_short_keyword(), odp->ordinal );
+ fprintf( outfile, "\t%s \"%s\"\n", get_asm_string_keyword(), odp->name );
}
- else
- {
- /* Hmpf. Stupid sparc assembler always interprets global variable
- names as GOT offsets, so we have to do it the long way ... */
- fprintf( outfile, "save %%sp, -96, %%sp\\n" );
- fprintf( outfile, "0:\\tcall 1f\\n\\tnop\\n" );
- fprintf( outfile, "1:\\tsethi %%hi(imports+%d-0b), %%g1\\n\\t", pos );
- fprintf( outfile, "or %%g1, %%lo(imports+%d-0b), %%g1\\n\\t", pos );
- fprintf( outfile, "ld [%%g1+%%o7], %%g1\\n\\t" );
- fprintf( outfile, "jmp %%g1\\n\\trestore\\n" );
- }
-
-#elif defined(__powerpc__)
- fprintf(outfile, "\taddi %s, %s, -0x4\\n\"\n", ppc_reg[1], ppc_reg[1]);
- fprintf(outfile, "\t\"\\tstw %s, 0(%s)\\n\"\n", ppc_reg[9], ppc_reg[1]);
- fprintf(outfile, "\t\"\\taddi %s, %s, -0x4\\n\"\n", ppc_reg[1], ppc_reg[1]);
- fprintf(outfile, "\t\"\\tstw %s, 0(%s)\\n\"\n", ppc_reg[8], ppc_reg[1]);
- fprintf(outfile, "\t\"\\taddi %s, %s, -0x4\\n\"\n", ppc_reg[1], ppc_reg[1]);
- fprintf(outfile, "\t\"\\tstw %s, 0(%s)\\n\"\n", ppc_reg[7], ppc_reg[1]);
-
- fprintf(outfile, "\t\"\\tlis %s, " ppc_high(__ASM_NAME("imports") "+ %d") "\\n\"\n", ppc_reg[9], pos);
- fprintf(outfile, "\t\"\\tla %s, " ppc_low (__ASM_NAME("imports") "+ %d") "(%s)\\n\"\n", ppc_reg[8], pos, ppc_reg[9]);
- fprintf(outfile, "\t\"\\tlwz %s, 0(%s)\\n\"\n", ppc_reg[7], ppc_reg[8]);
- fprintf(outfile, "\t\"\\tmtctr %s\\n\"\n", ppc_reg[7]);
-
- fprintf(outfile, "\t\"\\tlwz %s, 0(%s)\\n\"\n", ppc_reg[7], ppc_reg[1]);
- fprintf(outfile, "\t\"\\taddi %s, %s, 0x4\\n\"\n", ppc_reg[1], ppc_reg[1]);
- fprintf(outfile, "\t\"\\tlwz %s, 0(%s)\\n\"\n", ppc_reg[8], ppc_reg[1]);
- fprintf(outfile, "\t\"\\taddi %s, %s, 0x4\\n\"\n", ppc_reg[1], ppc_reg[1]);
- fprintf(outfile, "\t\"\\tlwz %s, 0(%s)\\n\"\n", ppc_reg[9], ppc_reg[1]);
- fprintf(outfile, "\t\"\\taddi %s, %s, 0x4\\n\"\n", ppc_reg[1], ppc_reg[1]);
- fprintf(outfile, "\t\"\\tbctr\\n");
-#else
-#error You need to define import thunks for your architecture!
-#endif
- fprintf( outfile, "\"\n" );
}
- pos += 4;
}
- fprintf( outfile, "\".text\");\n#ifndef __GNUC__\n}\n#endif\n\n" );
- done:
- return nb_imm;
+ for (i = 0; i < nb_imports; i++)
+ {
+ if (dll_imports[i]->delay) continue;
+ dll_name = make_c_identifier( dll_imports[i]->spec->file_name );
+ fprintf( outfile, ".L__wine_spec_import_name_%s:\n\t%s \"%s\"\n",
+ dll_name, get_asm_string_keyword(), dll_imports[i]->spec->file_name );
+ }
}
-/* output the delayed import table of a Win32 module */
-static int output_delayed_imports( FILE *outfile )
+/* output the import thunks of a Win32 module */
+static void output_immediate_import_thunks( FILE *outfile )
{
- int i, idx, j, pos;
+ int i, j, pos;
+ int nb_imm = nb_imports - nb_delayed;
+ static const char import_thunks[] = "__wine_spec_import_thunks";
- if (!nb_delayed) goto done;
+ if (!nb_imm) return;
- for (i = 0; i < nb_imports; i++)
+ fprintf( outfile, "\n/* immediate import thunks */\n\n" );
+ fprintf( outfile, "\t.text\n" );
+ fprintf( outfile, "\t.align %d\n", get_alignment(8) );
+ fprintf( outfile, "%s:\n", asm_name(import_thunks));
+
+ for (i = pos = 0; i < nb_imports; i++)
{
- if (!dll_imports[i]->delay) continue;
- fprintf( outfile, "static void *__wine_delay_imp_%d_hmod;\n", i);
- for (j = 0; j < dll_imports[i]->nb_imports; j++)
+ if (dll_imports[i]->delay) continue;
+ for (j = 0; j < dll_imports[i]->nb_imports; j++, pos += get_ptr_size())
{
- fprintf( outfile, "void __wine_delay_imp_%d_%s();\n",
- i, dll_imports[i]->imports[j].name );
+ ORDDEF *odp = dll_imports[i]->imports[j];
+ output_import_thunk( outfile, odp->name ? odp->name : odp->export_name,
+ ".L__wine_spec_import_data_ptrs", pos );
}
+ pos += get_ptr_size();
}
- fprintf( outfile, "\n" );
- fprintf( outfile, "static struct {\n" );
- fprintf( outfile, " struct ImgDelayDescr {\n" );
- fprintf( outfile, " unsigned int grAttrs;\n" );
- fprintf( outfile, " const char *szName;\n" );
- fprintf( outfile, " void **phmod;\n" );
- fprintf( outfile, " void **pIAT;\n" );
- fprintf( outfile, " const char **pINT;\n" );
- fprintf( outfile, " void* pBoundIAT;\n" );
- fprintf( outfile, " void* pUnloadIAT;\n" );
- fprintf( outfile, " unsigned long dwTimeStamp;\n" );
- fprintf( outfile, " } imp[%d];\n", nb_delayed );
- fprintf( outfile, " void *IAT[%d];\n", total_delayed );
- fprintf( outfile, " const char *INT[%d];\n", total_delayed );
- fprintf( outfile, "} delay_imports = {\n" );
- fprintf( outfile, " {\n" );
+ output_function_size( outfile, import_thunks );
+}
+
+/* output the delayed import table of a Win32 module */
+static void output_delayed_imports( FILE *outfile, const DLLSPEC *spec )
+{
+ int i, j;
+
+ if (!nb_delayed) return;
+
+ fprintf( outfile, "\n/* delayed imports */\n\n" );
+ fprintf( outfile, "\t.data\n" );
+ fprintf( outfile, "\t.align %d\n", get_alignment(get_ptr_size()) );
+ fprintf( outfile, "%s\n", asm_globl("__wine_spec_delay_imports") );
+
+ /* list of dlls */
+
for (i = j = 0; i < nb_imports; i++)
{
if (!dll_imports[i]->delay) continue;
- fprintf( outfile, " { 0, \"%s\", &__wine_delay_imp_%d_hmod, &delay_imports.IAT[%d], &delay_imports.INT[%d], 0, 0, 0 },\n",
- dll_imports[i]->dll, i, j, j );
+ fprintf( outfile, "\t%s 0\n", get_asm_ptr_keyword() ); /* grAttrs */
+ fprintf( outfile, "\t%s .L__wine_delay_name_%d\n", /* szName */
+ get_asm_ptr_keyword(), i );
+ fprintf( outfile, "\t%s .L__wine_delay_modules+%d\n", /* phmod */
+ get_asm_ptr_keyword(), i * get_ptr_size() );
+ fprintf( outfile, "\t%s .L__wine_delay_IAT+%d\n", /* pIAT */
+ get_asm_ptr_keyword(), j * get_ptr_size() );
+ fprintf( outfile, "\t%s .L__wine_delay_INT+%d\n", /* pINT */
+ get_asm_ptr_keyword(), j * get_ptr_size() );
+ fprintf( outfile, "\t%s 0\n", get_asm_ptr_keyword() ); /* pBoundIAT */
+ fprintf( outfile, "\t%s 0\n", get_asm_ptr_keyword() ); /* pUnloadIAT */
+ fprintf( outfile, "\t%s 0\n", get_asm_ptr_keyword() ); /* dwTimeStamp */
j += dll_imports[i]->nb_imports;
}
- fprintf( outfile, " },\n {\n" );
+ fprintf( outfile, "\t%s 0\n", get_asm_ptr_keyword() ); /* grAttrs */
+ fprintf( outfile, "\t%s 0\n", get_asm_ptr_keyword() ); /* szName */
+ fprintf( outfile, "\t%s 0\n", get_asm_ptr_keyword() ); /* phmod */
+ fprintf( outfile, "\t%s 0\n", get_asm_ptr_keyword() ); /* pIAT */
+ fprintf( outfile, "\t%s 0\n", get_asm_ptr_keyword() ); /* pINT */
+ fprintf( outfile, "\t%s 0\n", get_asm_ptr_keyword() ); /* pBoundIAT */
+ fprintf( outfile, "\t%s 0\n", get_asm_ptr_keyword() ); /* pUnloadIAT */
+ fprintf( outfile, "\t%s 0\n", get_asm_ptr_keyword() ); /* dwTimeStamp */
+
+ fprintf( outfile, "\n.L__wine_delay_IAT:\n" );
for (i = 0; i < nb_imports; i++)
{
if (!dll_imports[i]->delay) continue;
- fprintf( outfile, " /* %s */\n", dll_imports[i]->dll );
for (j = 0; j < dll_imports[i]->nb_imports; j++)
{
- fprintf( outfile, " &__wine_delay_imp_%d_%s,\n", i, dll_imports[i]->imports[j].name);
+ ORDDEF *odp = dll_imports[i]->imports[j];
+ const char *name = odp->name ? odp->name : odp->export_name;
+ fprintf( outfile, "\t%s .L__wine_delay_imp_%d_%s\n",
+ get_asm_ptr_keyword(), i, name );
}
}
- fprintf( outfile, " },\n {\n" );
+
+ fprintf( outfile, "\n.L__wine_delay_INT:\n" );
for (i = 0; i < nb_imports; i++)
{
if (!dll_imports[i]->delay) continue;
- fprintf( outfile, " /* %s */\n", dll_imports[i]->dll );
for (j = 0; j < dll_imports[i]->nb_imports; j++)
{
- struct func *import = &dll_imports[i]->imports[j];
- if (import->ord_only)
- fprintf( outfile, " (char *)%d,\n", import->ordinal );
+ ORDDEF *odp = dll_imports[i]->imports[j];
+ if (!odp->name)
+ fprintf( outfile, "\t%s %d\n", get_asm_ptr_keyword(), odp->ordinal );
else
- fprintf( outfile, " \"%s\",\n", import->name );
+ fprintf( outfile, "\t%s .L__wine_delay_data_%d_%s\n",
+ get_asm_ptr_keyword(), i, odp->name );
}
}
- fprintf( outfile, " }\n};\n\n" );
-
- /* check if there's some stub defined. if so, exception struct
- * is already defined, so don't emit it twice
- */
- for (i = 0; i < nb_entry_points; i++) if (EntryPoints[i]->type == TYPE_STUB) break;
-
- if (i == nb_entry_points) {
- fprintf( outfile, "struct exc_record {\n" );
- fprintf( outfile, " unsigned int code, flags;\n" );
- fprintf( outfile, " void *rec, *addr;\n" );
- fprintf( outfile, " unsigned int params;\n" );
- fprintf( outfile, " const void *info[15];\n" );
- fprintf( outfile, "};\n\n" );
- fprintf( outfile, "extern void __stdcall RtlRaiseException( struct exc_record * );\n" );
+
+ fprintf( outfile, "\n.L__wine_delay_modules:\n" );
+ for (i = 0; i < nb_imports; i++)
+ {
+ if (dll_imports[i]->delay) fprintf( outfile, "\t%s 0\n", get_asm_ptr_keyword() );
}
- fprintf( outfile, "extern void * __stdcall LoadLibraryA(const char*);\n");
- fprintf( outfile, "extern void * __stdcall GetProcAddress(void *, const char*);\n");
- fprintf( outfile, "\n" );
+ for (i = 0; i < nb_imports; i++)
+ {
+ if (!dll_imports[i]->delay) continue;
+ fprintf( outfile, ".L__wine_delay_name_%d:\n", i );
+ fprintf( outfile, "\t%s \"%s\"\n",
+ get_asm_string_keyword(), dll_imports[i]->spec->file_name );
+ }
- fprintf( outfile, "void *__stdcall __wine_delay_load( int idx_nr )\n" );
- fprintf( outfile, "{\n" );
- fprintf( outfile, " int idx = idx_nr >> 16, nr = idx_nr & 0xffff;\n" );
- fprintf( outfile, " struct ImgDelayDescr *imd = delay_imports.imp + idx;\n" );
- fprintf( outfile, " void **pIAT = imd->pIAT + nr;\n" );
- fprintf( outfile, " const char** pINT = imd->pINT + nr;\n" );
- fprintf( outfile, " void *fn;\n\n" );
-
- fprintf( outfile, " if (!*imd->phmod) *imd->phmod = LoadLibraryA(imd->szName);\n" );
- fprintf( outfile, " if (*imd->phmod && (fn = GetProcAddress(*imd->phmod, *pINT)))\n");
- fprintf( outfile, " /* patch IAT with final value */\n" );
- fprintf( outfile, " return *pIAT = fn;\n" );
- fprintf( outfile, " else {\n");
- fprintf( outfile, " struct exc_record rec;\n" );
- fprintf( outfile, " rec.code = 0x80000100;\n" );
- fprintf( outfile, " rec.flags = 1;\n" );
- fprintf( outfile, " rec.rec = 0;\n" );
- fprintf( outfile, " rec.params = 2;\n" );
- fprintf( outfile, " rec.info[0] = imd->szName;\n" );
- fprintf( outfile, " rec.info[1] = *pINT + 2;\n" );
- fprintf( outfile, "#ifdef __GNUC__\n" );
- fprintf( outfile, " rec.addr = __builtin_return_address(1);\n" );
- fprintf( outfile, "#else\n" );
- fprintf( outfile, " rec.addr = 0;\n" );
- fprintf( outfile, "#endif\n" );
- fprintf( outfile, " for (;;) RtlRaiseException( &rec );\n" );
- fprintf( outfile, " return 0; /* shouldn't go here */\n" );
- fprintf( outfile, " }\n}\n\n" );
-
- fprintf( outfile, "#ifndef __GNUC__\n" );
- fprintf( outfile, "static void __asm__dummy_delay_import(void) {\n" );
- fprintf( outfile, "#endif\n" );
-
- fprintf( outfile, "asm(\".align %d\\n\"\n", get_alignment(8) );
- fprintf( outfile, " \"\\t" __ASM_FUNC("__wine_delay_load_asm") "\\n\"\n" );
- fprintf( outfile, " \"" __ASM_NAME("__wine_delay_load_asm") ":\\n\"\n" );
-#if defined(__i386__)
- fprintf( outfile, " \"\\tpushl %%ecx\\n\\tpushl %%edx\\n\\tpushl %%eax\\n\"\n" );
- fprintf( outfile, " \"\\tcall __wine_delay_load\\n\"\n" );
- fprintf( outfile, " \"\\tpopl %%edx\\n\\tpopl %%ecx\\n\\tjmp *%%eax\\n\"\n" );
-#elif defined(__sparc__)
- fprintf( outfile, " \"\\tsave %%sp, -96, %%sp\\n\"\n" );
- fprintf( outfile, " \"\\tcall __wine_delay_load\\n\"\n" );
- fprintf( outfile, " \"\\tmov %%g1, %%o0\\n\"\n" );
- fprintf( outfile, " \"\\tjmp %%o0\\n\\trestore\\n\"\n" );
-#elif defined(__powerpc__)
- /* Save all callee saved registers into a stackframe. */
- fprintf( outfile, " \"\\tstwu %s, -48(%s)\\n\"\n", ppc_reg[1], ppc_reg[1]);
- fprintf( outfile, " \"\\tstw %s, 4(%s)\\n\"\n", ppc_reg[3], ppc_reg[1]);
- fprintf( outfile, " \"\\tstw %s, 8(%s)\\n\"\n", ppc_reg[4], ppc_reg[1]);
- fprintf( outfile, " \"\\tstw %s, 12(%s)\\n\"\n", ppc_reg[5], ppc_reg[1]);
- fprintf( outfile, " \"\\tstw %s, 16(%s)\\n\"\n", ppc_reg[6], ppc_reg[1]);
- fprintf( outfile, " \"\\tstw %s, 20(%s)\\n\"\n", ppc_reg[7], ppc_reg[1]);
- fprintf( outfile, " \"\\tstw %s, 24(%s)\\n\"\n", ppc_reg[8], ppc_reg[1]);
- fprintf( outfile, " \"\\tstw %s, 28(%s)\\n\"\n", ppc_reg[9], ppc_reg[1]);
- fprintf( outfile, " \"\\tstw %s, 32(%s)\\n\"\n", ppc_reg[10], ppc_reg[1]);
- fprintf( outfile, " \"\\tstw %s, 36(%s)\\n\"\n", ppc_reg[11], ppc_reg[1]);
- fprintf( outfile, " \"\\tstw %s, 40(%s)\\n\"\n", ppc_reg[12], ppc_reg[1]);
-
- /* r0 -> r3 (arg1) */
- fprintf( outfile, " \"\\tmr %s, %s\\n\"\n", ppc_reg[3], ppc_reg[0]);
-
- /* save return address */
- fprintf( outfile, " \"\\tmflr %s\\n\"\n", ppc_reg[0]);
- fprintf( outfile, " \"\\tstw %s, 44(%s)\\n\"\n", ppc_reg[0], ppc_reg[1]);
-
- /* Call the __wine_delay_load function, arg1 is arg1. */
- fprintf( outfile, " \"\\tbl " __ASM_NAME("__wine_delay_load") "\\n\"\n");
-
- /* Load return value from call into ctr register */
- fprintf( outfile, " \"\\tmtctr %s\\n\"\n", ppc_reg[3]);
-
- /* restore all saved registers and drop stackframe. */
- fprintf( outfile, " \"\\tlwz %s, 4(%s)\\n\"\n", ppc_reg[3], ppc_reg[1]);
- fprintf( outfile, " \"\\tlwz %s, 8(%s)\\n\"\n", ppc_reg[4], ppc_reg[1]);
- fprintf( outfile, " \"\\tlwz %s, 12(%s)\\n\"\n", ppc_reg[5], ppc_reg[1]);
- fprintf( outfile, " \"\\tlwz %s, 16(%s)\\n\"\n", ppc_reg[6], ppc_reg[1]);
- fprintf( outfile, " \"\\tlwz %s, 20(%s)\\n\"\n", ppc_reg[7], ppc_reg[1]);
- fprintf( outfile, " \"\\tlwz %s, 24(%s)\\n\"\n", ppc_reg[8], ppc_reg[1]);
- fprintf( outfile, " \"\\tlwz %s, 28(%s)\\n\"\n", ppc_reg[9], ppc_reg[1]);
- fprintf( outfile, " \"\\tlwz %s, 32(%s)\\n\"\n", ppc_reg[10], ppc_reg[1]);
- fprintf( outfile, " \"\\tlwz %s, 36(%s)\\n\"\n", ppc_reg[11], ppc_reg[1]);
- fprintf( outfile, " \"\\tlwz %s, 40(%s)\\n\"\n", ppc_reg[12], ppc_reg[1]);
-
- /* Load return value from call into return register */
- fprintf( outfile, " \"\\tlwz %s, 44(%s)\\n\"\n", ppc_reg[0], ppc_reg[1]);
- fprintf( outfile, " \"\\tmtlr %s\\n\"\n", ppc_reg[0]);
- fprintf( outfile, " \"\\taddi %s, %s, 48\\n\"\n", ppc_reg[1], ppc_reg[1]);
-
- /* branch to ctr register. */
- fprintf( outfile, "\"bctr\\n\"\n");
-#else
-#error You need to defined delayed import thunks for your architecture!
-#endif
+ for (i = 0; i < nb_imports; i++)
+ {
+ if (!dll_imports[i]->delay) continue;
+ for (j = 0; j < dll_imports[i]->nb_imports; j++)
+ {
+ ORDDEF *odp = dll_imports[i]->imports[j];
+ if (!odp->name) continue;
+ fprintf( outfile, ".L__wine_delay_data_%d_%s:\n", i, odp->name );
+ fprintf( outfile, "\t%s \"%s\"\n", get_asm_string_keyword(), odp->name );
+ }
+ }
+ output_function_size( outfile, "__wine_spec_delay_imports" );
+}
+
+/* output the delayed import thunks of a Win32 module */
+static void output_delayed_import_thunks( FILE *outfile, const DLLSPEC *spec )
+{
+ int i, idx, j, pos, extra_stack_storage = 0;
+ static const char delayed_import_loaders[] = "__wine_spec_delayed_import_loaders";
+ static const char delayed_import_thunks[] = "__wine_spec_delayed_import_thunks";
+
+ if (!nb_delayed) return;
+
+ fprintf( outfile, "\n/* delayed import thunks */\n\n" );
+ fprintf( outfile, "\t.text\n" );
+ fprintf( outfile, "\t.align %d\n", get_alignment(8) );
+ fprintf( outfile, "%s:\n", asm_name(delayed_import_loaders));
+ fprintf( outfile, "\t%s\n", func_declaration("__wine_delay_load_asm") );
+ fprintf( outfile, "%s:\n", asm_name("__wine_delay_load_asm") );
+ switch(target_cpu)
+ {
+ case CPU_x86:
+ fprintf( outfile, "\tpushl %%ecx\n" );
+ fprintf( outfile, "\tpushl %%edx\n" );
+ fprintf( outfile, "\tpushl %%eax\n" );
+ fprintf( outfile, "\tcall %s\n", asm_name("__wine_spec_delay_load") );
+ fprintf( outfile, "\tpopl %%edx\n" );
+ fprintf( outfile, "\tpopl %%ecx\n" );
+ fprintf( outfile, "\tjmp *%%eax\n" );
+ break;
+ case CPU_x86_64:
+ fprintf( outfile, "\tpushq %%rdi\n" );
+ fprintf( outfile, "\tsubq $8,%%rsp\n" );
+ fprintf( outfile, "\tmovq %%r11,%%rdi\n" );
+ fprintf( outfile, "\tcall %s\n", asm_name("__wine_spec_delay_load") );
+ fprintf( outfile, "\taddq $8,%%rsp\n" );
+ fprintf( outfile, "\tpopq %%rdi\n" );
+ fprintf( outfile, "\tjmp *%%rax\n" );
+ break;
+ case CPU_SPARC:
+ fprintf( outfile, "\tsave %%sp, -96, %%sp\n" );
+ fprintf( outfile, "\tcall %s\n", asm_name("__wine_spec_delay_load") );
+ fprintf( outfile, "\tmov %%g1, %%o0\n" );
+ fprintf( outfile, "\tjmp %%o0\n" );
+ fprintf( outfile, "\trestore\n" );
+ break;
+ case CPU_ALPHA:
+ fprintf( outfile, "\tjsr $26,%s\n", asm_name("__wine_spec_delay_load") );
+ fprintf( outfile, "\tjmp $31,($0)\n" );
+ break;
+ case CPU_POWERPC:
+ if (target_platform == PLATFORM_APPLE) extra_stack_storage = 56;
+
+ /* Save all callee saved registers into a stackframe. */
+ fprintf( outfile, "\tstwu %s, -%d(%s)\n",ppc_reg(1), 48+extra_stack_storage, ppc_reg(1));
+ fprintf( outfile, "\tstw %s, %d(%s)\n", ppc_reg(3), 4+extra_stack_storage, ppc_reg(1));
+ fprintf( outfile, "\tstw %s, %d(%s)\n", ppc_reg(4), 8+extra_stack_storage, ppc_reg(1));
+ fprintf( outfile, "\tstw %s, %d(%s)\n", ppc_reg(5), 12+extra_stack_storage, ppc_reg(1));
+ fprintf( outfile, "\tstw %s, %d(%s)\n", ppc_reg(6), 16+extra_stack_storage, ppc_reg(1));
+ fprintf( outfile, "\tstw %s, %d(%s)\n", ppc_reg(7), 20+extra_stack_storage, ppc_reg(1));
+ fprintf( outfile, "\tstw %s, %d(%s)\n", ppc_reg(8), 24+extra_stack_storage, ppc_reg(1));
+ fprintf( outfile, "\tstw %s, %d(%s)\n", ppc_reg(9), 28+extra_stack_storage, ppc_reg(1));
+ fprintf( outfile, "\tstw %s, %d(%s)\n", ppc_reg(10),32+extra_stack_storage, ppc_reg(1));
+ fprintf( outfile, "\tstw %s, %d(%s)\n", ppc_reg(11),36+extra_stack_storage, ppc_reg(1));
+ fprintf( outfile, "\tstw %s, %d(%s)\n", ppc_reg(12),40+extra_stack_storage, ppc_reg(1));
+
+ /* r0 -> r3 (arg1) */
+ fprintf( outfile, "\tmr %s, %s\n", ppc_reg(3), ppc_reg(0));
+
+ /* save return address */
+ fprintf( outfile, "\tmflr %s\n", ppc_reg(0));
+ fprintf( outfile, "\tstw %s, %d(%s)\n", ppc_reg(0), 44+extra_stack_storage, ppc_reg(1));
+
+ /* Call the __wine_delay_load function, arg1 is arg1. */
+ fprintf( outfile, "\tbl %s\n", asm_name("__wine_spec_delay_load") );
+
+ /* Load return value from call into ctr register */
+ fprintf( outfile, "\tmtctr %s\n", ppc_reg(3));
+
+ /* restore all saved registers and drop stackframe. */
+ fprintf( outfile, "\tlwz %s, %d(%s)\n", ppc_reg(3), 4+extra_stack_storage, ppc_reg(1));
+ fprintf( outfile, "\tlwz %s, %d(%s)\n", ppc_reg(4), 8+extra_stack_storage, ppc_reg(1));
+ fprintf( outfile, "\tlwz %s, %d(%s)\n", ppc_reg(5), 12+extra_stack_storage, ppc_reg(1));
+ fprintf( outfile, "\tlwz %s, %d(%s)\n", ppc_reg(6), 16+extra_stack_storage, ppc_reg(1));
+ fprintf( outfile, "\tlwz %s, %d(%s)\n", ppc_reg(7), 20+extra_stack_storage, ppc_reg(1));
+ fprintf( outfile, "\tlwz %s, %d(%s)\n", ppc_reg(8), 24+extra_stack_storage, ppc_reg(1));
+ fprintf( outfile, "\tlwz %s, %d(%s)\n", ppc_reg(9), 28+extra_stack_storage, ppc_reg(1));
+ fprintf( outfile, "\tlwz %s, %d(%s)\n", ppc_reg(10),32+extra_stack_storage, ppc_reg(1));
+ fprintf( outfile, "\tlwz %s, %d(%s)\n", ppc_reg(11),36+extra_stack_storage, ppc_reg(1));
+ fprintf( outfile, "\tlwz %s, %d(%s)\n", ppc_reg(12),40+extra_stack_storage, ppc_reg(1));
+
+ /* Load return value from call into return register */
+ fprintf( outfile, "\tlwz %s, %d(%s)\n", ppc_reg(0), 44+extra_stack_storage, ppc_reg(1));
+ fprintf( outfile, "\tmtlr %s\n", ppc_reg(0));
+ fprintf( outfile, "\taddi %s, %s, %d\n", ppc_reg(1), ppc_reg(1), 48+extra_stack_storage);
+
+ /* branch to ctr register. */
+ fprintf( outfile, "\tbctr\n");
+ break;
+ }
+ output_function_size( outfile, "__wine_delay_load_asm" );
+ fprintf( outfile, "\n" );
for (i = idx = 0; i < nb_imports; i++)
{
if (!dll_imports[i]->delay) continue;
for (j = 0; j < dll_imports[i]->nb_imports; j++)
{
- char buffer[128];
- sprintf( buffer, "__wine_delay_imp_%d_%s", i, dll_imports[i]->imports[j].name );
- fprintf( outfile, " \"\\t" __ASM_FUNC("%s") "\\n\"\n", buffer );
- fprintf( outfile, " \"" __ASM_NAME("%s") ":\\n\"\n", buffer );
-#if defined(__i386__)
- fprintf( outfile, " \"\\tmovl $%d, %%eax\\n\"\n", (idx << 16) | j );
- fprintf( outfile, " \"\\tjmp __wine_delay_load_asm\\n\"\n" );
-#elif defined(__sparc__)
- fprintf( outfile, " \"\\tset %d, %%g1\\n\"\n", (idx << 16) | j );
- fprintf( outfile, " \"\\tb,a __wine_delay_load_asm\\n\"\n" );
-#elif defined(__powerpc__)
- /* g0 is a function scratch register or so I understand. */
- /* First load the upper half-word, and then the lower part */
- fprintf( outfile, " \"\\tlis %s, %d\\n\"\n", ppc_reg[0], idx);
- fprintf( outfile, " \"\\tli %s, %d\\n\"\n", ppc_reg[0], j);
- fprintf( outfile, " \"\\tb " __ASM_NAME("__wine_delay_load_asm") "\\n\"\n");
-#else
-#error You need to defined delayed import thunks for your architecture!
-#endif
+ ORDDEF *odp = dll_imports[i]->imports[j];
+ const char *name = odp->name ? odp->name : odp->export_name;
+
+ fprintf( outfile, ".L__wine_delay_imp_%d_%s:\n", i, name );
+ switch(target_cpu)
+ {
+ case CPU_x86:
+ fprintf( outfile, "\tmovl $%d, %%eax\n", (idx << 16) | j );
+ fprintf( outfile, "\tjmp %s\n", asm_name("__wine_delay_load_asm") );
+ break;
+ case CPU_x86_64:
+ fprintf( outfile, "\tmovq $%d,%%r11\n", (idx << 16) | j );
+ fprintf( outfile, "\tjmp %s\n", asm_name("__wine_delay_load_asm") );
+ break;
+ case CPU_SPARC:
+ fprintf( outfile, "\tset %d, %%g1\n", (idx << 16) | j );
+ fprintf( outfile, "\tb,a %s\n", asm_name("__wine_delay_load_asm") );
+ break;
+ case CPU_ALPHA:
+ fprintf( outfile, "\tlda $0,%d($31)\n", j);
+ fprintf( outfile, "\tldah $0,%d($0)\n", idx);
+ fprintf( outfile, "\tjmp $31,%s\n", asm_name("__wine_delay_load_asm") );
+ break;
+ case CPU_POWERPC:
+ switch(target_platform)
+ {
+ case PLATFORM_APPLE:
+ /* On Darwin we can use r0 and r2 */
+ /* Upper part in r2 */
+ fprintf( outfile, "\tlis %s, %d\n", ppc_reg(2), idx);
+ /* Lower part + r2 -> r0, Note we can't use r0 directly */
+ fprintf( outfile, "\taddi %s, %s, %d\n", ppc_reg(0), ppc_reg(2), j);
+ fprintf( outfile, "\tb %s\n", asm_name("__wine_delay_load_asm") );
+ break;
+ default:
+ /* On linux we can't use r2 since r2 is not a scratch register (hold the TOC) */
+ /* Save r13 on the stack */
+ fprintf( outfile, "\taddi %s, %s, -0x4\n", ppc_reg(1), ppc_reg(1));
+ fprintf( outfile, "\tstw %s, 0(%s)\n", ppc_reg(13), ppc_reg(1));
+ /* Upper part in r13 */
+ fprintf( outfile, "\tlis %s, %d\n", ppc_reg(13), idx);
+ /* Lower part + r13 -> r0, Note we can't use r0 directly */
+ fprintf( outfile, "\taddi %s, %s, %d\n", ppc_reg(0), ppc_reg(13), j);
+ /* Restore r13 */
+ fprintf( outfile, "\tstw %s, 0(%s)\n", ppc_reg(13), ppc_reg(1));
+ fprintf( outfile, "\taddic %s, %s, 0x4\n", ppc_reg(1), ppc_reg(1));
+ fprintf( outfile, "\tb %s\n", asm_name("__wine_delay_load_asm") );
+ break;
+ }
+ break;
+ }
}
idx++;
}
+ output_function_size( outfile, delayed_import_loaders );
- fprintf( outfile, "\n \".data\\n\\t.align %d\\n\"\n", get_alignment(8) );
- pos = nb_delayed * 32;
- for (i = 0; i < nb_imports; i++)
+ fprintf( outfile, "\n\t.align %d\n", get_alignment(get_ptr_size()) );
+ fprintf( outfile, "%s:\n", asm_name(delayed_import_thunks));
+ for (i = pos = 0; i < nb_imports; i++)
{
if (!dll_imports[i]->delay) continue;
- for (j = 0; j < dll_imports[i]->nb_imports; j++, pos += 4)
+ for (j = 0; j < dll_imports[i]->nb_imports; j++, pos += get_ptr_size())
{
- struct func *import = &dll_imports[i]->imports[j];
- fprintf( outfile, " \"\\t" __ASM_FUNC("%s") "\\n\"\n", import->name );
- fprintf( outfile, " \"\\t.globl " __ASM_NAME("%s") "\\n\"\n", import->name );
- fprintf( outfile, " \"" __ASM_NAME("%s") ":\\n\\t\"", import->name);
-#if defined(__i386__)
- if (strstr( import->name, "__wine_call_from_16" ))
- fprintf( outfile, "\".byte 0x2e\\n\\tjmp *(delay_imports+%d)\\n\\tnop\\n\"", pos );
- else
- fprintf( outfile, "\"jmp *(delay_imports+%d)\\n\\tmovl %%esi,%%esi\\n\"", pos );
-#elif defined(__sparc__)
- if ( !UsePIC )
+ ORDDEF *odp = dll_imports[i]->imports[j];
+ output_import_thunk( outfile, odp->name ? odp->name : odp->export_name,
+ ".L__wine_delay_IAT", pos );
+ }
+ }
+ 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_stubs
+ *
+ * Output the functions for stub entry points
+ */
+void output_stubs( FILE *outfile, DLLSPEC *spec )
+{
+ const char *name, *exp_name;
+ int i, pos;
+
+ if (!has_stubs( spec )) return;
+
+ fprintf( outfile, "\n/* stub functions */\n\n" );
+ fprintf( outfile, "\t.text\n" );
+
+ for (i = pos = 0; i < spec->nb_entry_points; i++)
+ {
+ ORDDEF *odp = &spec->entry_points[i];
+ if (odp->type != TYPE_STUB) continue;
+
+ name = get_stub_name( odp, spec );
+ exp_name = odp->name ? odp->name : odp->export_name;
+ fprintf( outfile, "\t.align %d\n", get_alignment(4) );
+ fprintf( outfile, "\t%s\n", func_declaration(name) );
+ fprintf( outfile, "%s:\n", asm_name(name) );
+ fprintf( outfile, "\tsubl $4,%%esp\n" );
+
+ if (UsePIC)
+ {
+ fprintf( outfile, "\tcall %s\n", asm_name("__wine_spec_get_pc_thunk_eax") );
+ fprintf( outfile, "1:" );
+ if (exp_name)
{
- fprintf( outfile, "\"sethi %%hi(delay_imports+%d), %%g1\\n\\t\"", pos );
- fprintf( outfile, "\"ld [%%g1+%%lo(delay_imports+%d)], %%g1\\n\\t\"", pos );
- fprintf( outfile, "\"jmp %%g1\\n\\tnop\\n\"" );
+ fprintf( outfile, "\tleal .L__wine_stub_strings+%d-1b(%%eax),%%ecx\n", pos );
+ fprintf( outfile, "\tpushl %%ecx\n" );
+ pos += strlen(exp_name) + 1;
}
else
+ fprintf( outfile, "\tpushl $%d\n", odp->ordinal );
+ fprintf( outfile, "\tleal .L__wine_spec_file_name-1b(%%eax),%%ecx\n" );
+ fprintf( outfile, "\tpushl %%ecx\n" );
+ }
+ else
+ {
+ if (exp_name)
{
- /* Hmpf. Stupid sparc assembler always interprets global variable
- names as GOT offsets, so we have to do it the long way ... */
- fprintf( outfile, "\"save %%sp, -96, %%sp\\n\"" );
- fprintf( outfile, "\"0:\\tcall 1f\\n\\tnop\\n\"" );
- fprintf( outfile, "\"1:\\tsethi %%hi(delay_imports+%d-0b), %%g1\\n\\t\"", pos );
- fprintf( outfile, "\"or %%g1, %%lo(delay_imports+%d-0b), %%g1\\n\\t\"", pos );
- fprintf( outfile, "\"ld [%%g1+%%o7], %%g1\\n\\t\"" );
- fprintf( outfile, "\"jmp %%g1\\n\\trestore\\n\"" );
+ fprintf( outfile, "\tpushl $.L__wine_stub_strings+%d\n", pos );
+ pos += strlen(exp_name) + 1;
}
-
-#elif defined(__powerpc__)
- fprintf( outfile, "\t\"addi %s, %s, -0x4\\n\"\n", ppc_reg[1], ppc_reg[1]);
- fprintf( outfile, "\t\"\\tstw %s, 0(%s)\\n\"\n", ppc_reg[9], ppc_reg[1]);
- fprintf( outfile, "\t\"\\taddi %s, %s, -0x4\\n\"\n", ppc_reg[1], ppc_reg[1]);
- fprintf( outfile, "\t\"\\tstw %s, 0(%s)\\n\"\n", ppc_reg[8], ppc_reg[1]);
- fprintf( outfile, "\t\"\\taddi %s, %s, -0x4\\n\"\n", ppc_reg[1], ppc_reg[1]);
- fprintf( outfile, "\t\"\\tstw %s, 0(%s)\\n\"\n", ppc_reg[7], ppc_reg[1]);
- fprintf( outfile, "\t\"\\tlis %s, " ppc_high(__ASM_NAME("imports") "+ %d") "\\n\"\n", ppc_reg[9], pos);
- fprintf( outfile, "\t\"\\tla %s, " ppc_low (__ASM_NAME("imports") "+ %d") "(%s)\\n\"\n", ppc_reg[8], pos, ppc_reg[9]);
- fprintf( outfile, "\t\"\\tlwz %s, 0(%s)\\n\"\n", ppc_reg[7], ppc_reg[8]);
- fprintf( outfile, "\t\"\\tmtctr %s\\n\"\n", ppc_reg[7]);
-
- fprintf( outfile, "\t\"\\tlwz %s, 0(%s)\\n\"\n", ppc_reg[7], ppc_reg[1]);
- fprintf( outfile, "\t\"\\taddi %s, %s, 0x4\\n\"\n", ppc_reg[1], ppc_reg[1]);
- fprintf( outfile, "\t\"\\tlwz %s, 0(%s)\\n\"\n", ppc_reg[8], ppc_reg[1]);
- fprintf( outfile, "\t\"\\taddi %s, %s, 0x4\\n\"\n", ppc_reg[1], ppc_reg[1]);
- fprintf( outfile, "\t\"\\tlwz %s, 0(%s)\\n\"\n", ppc_reg[9], ppc_reg[1]);
- fprintf( outfile, "\t\"\\taddi %s, %s, 0x4\\n\"\n", ppc_reg[1], ppc_reg[1]);
- fprintf( outfile, "\t\"\\tbctr\\n\"");
-#else
-#error You need to define delayed import thunks for your architecture!
-#endif
- fprintf( outfile, "\n" );
+ else
+ fprintf( outfile, "\tpushl $%d\n", odp->ordinal );
+ fprintf( outfile, "\tpushl $.L__wine_spec_file_name\n" );
}
+ fprintf( outfile, "\tcall %s\n", asm_name("__wine_spec_unimplemented_stub") );
+ output_function_size( outfile, name );
}
- fprintf( outfile, "\".text\");\n" );
- fprintf( outfile, "#ifndef __GNUC__\n" );
- fprintf( outfile, "}\n" );
- fprintf( outfile, "#endif\n" );
- fprintf( outfile, "\n" );
- done:
- return nb_delayed;
+ if (pos)
+ {
+ fprintf( outfile, "\t%s\n", get_asm_string_section() );
+ fprintf( outfile, ".L__wine_stub_strings:\n" );
+ for (i = 0; i < spec->nb_entry_points; i++)
+ {
+ ORDDEF *odp = &spec->entry_points[i];
+ if (odp->type != TYPE_STUB) continue;
+ exp_name = odp->name ? odp->name : odp->export_name;
+ if (exp_name)
+ fprintf( outfile, "\t%s \"%s\"\n", get_asm_string_keyword(), exp_name );
+ }
+ }
}
-/* output the import and delayed import tables of a Win32 module
- * returns number of DLLs exported in 'immediate' mode
- */
-int output_imports( FILE *outfile )
+/* output the import and delayed import tables of a Win32 module */
+void output_imports( FILE *outfile, DLLSPEC *spec )
{
- output_delayed_imports( outfile );
- return output_immediate_imports( outfile );
+ output_immediate_imports( outfile );
+ output_delayed_imports( outfile, spec );
+ output_immediate_import_thunks( outfile );
+ output_delayed_import_thunks( outfile, spec );
+ output_external_link_imports( outfile, spec );
+ if (nb_imports || ext_link_imports.count || has_stubs(spec)) output_get_pc_thunk( outfile );
}