Sync to Wine-0_9_2:
[reactos.git] / reactos / tools / winebuild / import.c
index f1aa28f..6f8bd28 100644 (file)
@@ -1,8 +1,8 @@
 /*
  * 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) */
@@ -120,95 +125,122 @@ static const char * const default_ignored_symbols[] =
     "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 */
@@ -230,8 +262,8 @@ static char *try_library_path( const char *path, const char *name )
     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;
@@ -240,185 +272,99 @@ static char *open_library( const char *name )
     {
         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;
@@ -430,6 +376,21 @@ void add_import_dll( const char *name, int delay )
     }
 }
 
+/* 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 )
 {
@@ -444,253 +405,187 @@ 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 ))
     {
@@ -700,476 +595,655 @@ void read_undef_symbols( char **argv )
         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 );
 }