Moved all 16-bit relay code to the text section.
[wine] / tools / winebuild / import.c
1 /*
2  * DLL imports support
3  *
4  * Copyright 2000, 2004 Alexandre Julliard
5  * Copyright 2000 Eric Pouech
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 #include "config.h"
23 #include "wine/port.h"
24
25 #include <ctype.h>
26 #include <fcntl.h>
27 #include <stdio.h>
28 #include <string.h>
29 #include <stdarg.h>
30 #ifdef HAVE_SYS_STAT_H
31 # include <sys/stat.h>
32 #endif
33 #ifdef HAVE_UNISTD_H
34 # include <unistd.h>
35 #endif
36
37 #include "windef.h"
38 #include "winbase.h"
39 #include "wine/exception.h"
40 #include "build.h"
41
42 struct import
43 {
44     DLLSPEC     *spec;        /* description of the imported dll */
45     char        *full_name;   /* full name of the input file */
46     dev_t        dev;         /* device/inode of the input file */
47     ino_t        ino;
48     int          delay;       /* delay or not dll loading ? */
49     ORDDEF     **exports;     /* functions exported from this dll */
50     int          nb_exports;  /* number of exported functions */
51     ORDDEF     **imports;     /* functions we want to import from this dll */
52     int          nb_imports;  /* number of imported functions */
53 };
54
55 static char **undef_symbols;  /* list of undefined symbols */
56 static int nb_undef_symbols = -1;
57 static int undef_size;
58
59 static char **ignore_symbols; /* list of symbols to ignore */
60 static int nb_ignore_symbols;
61 static int ignore_size;
62
63 static char *ld_tmp_file;  /* ld temp file name */
64
65 static struct import **dll_imports = NULL;
66 static int nb_imports = 0;      /* number of imported dlls (delayed or not) */
67 static int nb_delayed = 0;      /* number of delayed dlls */
68 static int total_imports = 0;   /* total number of imported functions */
69 static int total_delayed = 0;   /* total number of imported functions in delayed DLLs */
70 static char **delayed_imports;  /* names of delayed import dlls */
71 static int nb_delayed_imports;  /* size of the delayed_imports array */
72
73 /* list of symbols that are ignored by default */
74 static const char * const default_ignored_symbols[] =
75 {
76     "abs",
77     "acos",
78     "asin",
79     "atan",
80     "atan2",
81     "atof",
82     "atoi",
83     "atol",
84     "bsearch",
85     "ceil",
86     "cos",
87     "cosh",
88     "exp",
89     "fabs",
90     "floor",
91     "fmod",
92     "frexp",
93     "labs",
94     "log",
95     "log10",
96     "memchr",
97     "memcmp",
98     "memcpy",
99     "memmove",
100     "memset",
101     "modf",
102     "pow",
103     "qsort",
104     "sin",
105     "sinh",
106     "sqrt",
107     "strcat",
108     "strchr",
109     "strcmp",
110     "strcpy",
111     "strcspn",
112     "strlen",
113     "strncat",
114     "strncmp",
115     "strncpy",
116     "strpbrk",
117     "strrchr",
118     "strspn",
119     "strstr",
120     "tan",
121     "tanh"
122 };
123
124
125 static inline const char *ppc_reg( int reg )
126 {
127     static const char * const ppc_regs[32] = { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
128                                                "r8", "r9", "r10","r11","r12","r13","r14","r15",
129                                                "r16","r17","r18","r19","r20","r21","r22","r23",
130                                                "r24","r25","r26","r27","r28","r29","r30","r31" };
131     if (target_platform == PLATFORM_APPLE) return ppc_regs[reg];
132     return ppc_regs[reg] + 1;  /* skip the 'r' */
133 }
134
135 /* compare function names; helper for resolve_imports */
136 static int name_cmp( const void *name, const void *entry )
137 {
138     return strcmp( *(const char* const *)name, *(const char* const *)entry );
139 }
140
141 /* compare function names; helper for resolve_imports */
142 static int func_cmp( const void *func1, const void *func2 )
143 {
144     const ORDDEF *odp1 = *(const ORDDEF * const *)func1;
145     const ORDDEF *odp2 = *(const ORDDEF * const *)func2;
146     return strcmp( odp1->name ? odp1->name : odp1->export_name,
147                    odp2->name ? odp2->name : odp2->export_name );
148 }
149
150 /* locate a symbol in a (sorted) list */
151 inline static const char *find_symbol( const char *name, char **table, int size )
152 {
153     char **res = NULL;
154
155     if (table) {
156         res = bsearch( &name, table, size, sizeof(*table), name_cmp );
157     }
158
159     return res ? *res : NULL;
160 }
161
162 /* locate an export in a (sorted) export list */
163 inline static ORDDEF *find_export( const char *name, ORDDEF **table, int size )
164 {
165     ORDDEF func, *odp, **res = NULL;
166
167     func.name = (char *)name;
168     func.ordinal = -1;
169     odp = &func;
170     if (table) res = bsearch( &odp, table, size, sizeof(*table), func_cmp );
171     return res ? *res : NULL;
172 }
173
174 /* sort a symbol table */
175 inline static void sort_symbols( char **table, int size )
176 {
177     if (table )
178         qsort( table, size, sizeof(*table), name_cmp );
179 }
180
181 inline static void output_function_size( FILE *outfile, const char *name )
182 {
183     const char *size = func_size( name );
184     if (size[0]) fprintf( outfile, "    \"\\t%s\\n\"\n", size );
185 }
186
187 /* free an import structure */
188 static void free_imports( struct import *imp )
189 {
190     free( imp->exports );
191     free( imp->imports );
192     free_dll_spec( imp->spec );
193     free( imp->full_name );
194     free( imp );
195 }
196
197 /* remove the temp file at exit */
198 static void remove_ld_tmp_file(void)
199 {
200     if (ld_tmp_file) unlink( ld_tmp_file );
201 }
202
203 /* check whether a given dll is imported in delayed mode */
204 static int is_delayed_import( const char *name )
205 {
206     int i;
207
208     for (i = 0; i < nb_delayed_imports; i++)
209     {
210         if (!strcmp( delayed_imports[i], name )) return 1;
211     }
212     return 0;
213 }
214
215 /* check whether a given dll has already been imported */
216 static struct import *is_already_imported( const char *name )
217 {
218     int i;
219
220     for (i = 0; i < nb_imports; i++)
221     {
222         if (!strcmp( dll_imports[i]->spec->file_name, name )) return dll_imports[i];
223     }
224     return NULL;
225 }
226
227 /* open the .so library for a given dll in a specified path */
228 static char *try_library_path( const char *path, const char *name )
229 {
230     char *buffer;
231     int fd;
232
233     buffer = xmalloc( strlen(path) + strlen(name) + 9 );
234     sprintf( buffer, "%s/lib%s.def", path, name );
235
236     /* check if the file exists */
237     if ((fd = open( buffer, O_RDONLY )) != -1)
238     {
239         close( fd );
240         return buffer;
241     }
242     free( buffer );
243     return NULL;
244 }
245
246 /* find the .def import library for a given dll */
247 static char *find_library( const char *name )
248 {
249     char *fullname;
250     int i;
251
252     for (i = 0; i < nb_lib_paths; i++)
253     {
254         if ((fullname = try_library_path( lib_path[i], name ))) return fullname;
255     }
256     fatal_error( "could not open .def file for %s\n", name );
257     return NULL;
258 }
259
260 /* read in the list of exported symbols of an import library */
261 static int read_import_lib( struct import *imp )
262 {
263     FILE *f;
264     int i, ret;
265     struct stat stat;
266     struct import *prev_imp;
267     DLLSPEC *spec = imp->spec;
268
269     f = open_input_file( NULL, imp->full_name );
270     fstat( fileno(f), &stat );
271     imp->dev = stat.st_dev;
272     imp->ino = stat.st_ino;
273     ret = parse_def_file( f, spec );
274     close_input_file( f );
275     if (!ret) return 0;
276
277     /* check if we already imported that library from a different file */
278     if ((prev_imp = is_already_imported( spec->file_name )))
279     {
280         if (prev_imp->dev != imp->dev || prev_imp->ino != imp->ino)
281             fatal_error( "%s and %s have the same export name '%s'\n",
282                          prev_imp->full_name, imp->full_name, spec->file_name );
283         return 0;  /* the same file was already loaded, ignore this one */
284     }
285
286     if (is_delayed_import( spec->file_name ))
287     {
288         imp->delay = 1;
289         nb_delayed++;
290     }
291
292     imp->exports = xmalloc( spec->nb_entry_points * sizeof(*imp->exports) );
293
294     for (i = 0; i < spec->nb_entry_points; i++)
295     {
296         ORDDEF *odp = &spec->entry_points[i];
297
298         if (odp->type != TYPE_STDCALL && odp->type != TYPE_CDECL) continue;
299         if (odp->flags & FLAG_PRIVATE) continue;
300         imp->exports[imp->nb_exports++] = odp;
301     }
302     imp->exports = xrealloc( imp->exports, imp->nb_exports * sizeof(*imp->exports) );
303     if (imp->nb_exports)
304         qsort( imp->exports, imp->nb_exports, sizeof(*imp->exports), func_cmp );
305     return 1;
306 }
307
308 /* build the dll exported name from the import lib name or path */
309 static char *get_dll_name( const char *name, const char *filename )
310 {
311     char *ret;
312
313     if (filename)
314     {
315         const char *basename = strrchr( filename, '/' );
316         if (!basename) basename = filename;
317         else basename++;
318         if (!strncmp( basename, "lib", 3 )) basename += 3;
319         ret = xmalloc( strlen(basename) + 5 );
320         strcpy( ret, basename );
321         if (strendswith( ret, ".def" )) ret[strlen(ret)-4] = 0;
322     }
323     else
324     {
325         ret = xmalloc( strlen(name) + 5 );
326         strcpy( ret, name );
327     }
328     if (!strchr( ret, '.' )) strcat( ret, ".dll" );
329     return ret;
330 }
331
332 /* add a dll to the list of imports */
333 void add_import_dll( const char *name, const char *filename )
334 {
335     struct import *imp = xmalloc( sizeof(*imp) );
336
337     imp->spec            = alloc_dll_spec();
338     imp->spec->file_name = get_dll_name( name, filename );
339     imp->delay           = 0;
340     imp->imports         = NULL;
341     imp->nb_imports      = 0;
342     imp->exports         = NULL;
343     imp->nb_exports      = 0;
344
345     if (filename) imp->full_name = xstrdup( filename );
346     else imp->full_name = find_library( name );
347
348     if (read_import_lib( imp ))
349     {
350         dll_imports = xrealloc( dll_imports, (nb_imports+1) * sizeof(*dll_imports) );
351         dll_imports[nb_imports++] = imp;
352     }
353     else
354     {
355         free_imports( imp );
356         if (nb_errors) exit(1);
357     }
358 }
359
360 /* add a library to the list of delayed imports */
361 void add_delayed_import( const char *name )
362 {
363     struct import *imp;
364     char *fullname = get_dll_name( name, NULL );
365
366     delayed_imports = xrealloc( delayed_imports, (nb_delayed_imports+1) * sizeof(*delayed_imports) );
367     delayed_imports[nb_delayed_imports++] = fullname;
368     if ((imp = is_already_imported( fullname )) && !imp->delay)
369     {
370         imp->delay = 1;
371         nb_delayed++;
372     }
373 }
374
375 /* remove an imported dll, based on its index in the dll_imports array */
376 static void remove_import_dll( int index )
377 {
378     struct import *imp = dll_imports[index];
379
380     memmove( &dll_imports[index], &dll_imports[index+1], sizeof(imp) * (nb_imports - index - 1) );
381     nb_imports--;
382     if (imp->delay) nb_delayed--;
383     free_imports( imp );
384 }
385
386 /* initialize the list of ignored symbols */
387 static void init_ignored_symbols(void)
388 {
389     int i;
390
391     nb_ignore_symbols = sizeof(default_ignored_symbols)/sizeof(default_ignored_symbols[0]);
392     ignore_size = nb_ignore_symbols + 32;
393     ignore_symbols = xmalloc( ignore_size * sizeof(*ignore_symbols) );
394     for (i = 0; i < nb_ignore_symbols; i++)
395         ignore_symbols[i] = xstrdup( default_ignored_symbols[i] );
396 }
397
398 /* add a symbol to the ignored symbol list */
399 /* if the name starts with '-' the symbol is removed instead */
400 void add_ignore_symbol( const char *name )
401 {
402     int i;
403
404     if (!ignore_symbols) init_ignored_symbols();  /* first time around, fill list with defaults */
405
406     if (name[0] == '-')  /* remove it */
407     {
408         if (!name[1])  /* remove everything */
409         {
410             for (i = 0; i < nb_ignore_symbols; i++) free( ignore_symbols[i] );
411             nb_ignore_symbols = 0;
412         }
413         else
414         {
415             for (i = 0; i < nb_ignore_symbols; i++)
416             {
417                 if (!strcmp( ignore_symbols[i], name+1 ))
418                 {
419                     free( ignore_symbols[i] );
420                     memmove( &ignore_symbols[i], &ignore_symbols[i+1], nb_ignore_symbols - i - 1 );
421                     nb_ignore_symbols--;
422                 }
423             }
424         }
425     }
426     else
427     {
428         if (nb_ignore_symbols == ignore_size)
429         {
430             ignore_size += 32;
431             ignore_symbols = xrealloc( ignore_symbols, ignore_size * sizeof(*ignore_symbols) );
432         }
433         ignore_symbols[nb_ignore_symbols++] = xstrdup( name );
434     }
435 }
436
437 /* add a function to the list of imports from a given dll */
438 static void add_import_func( struct import *imp, ORDDEF *func )
439 {
440     imp->imports = xrealloc( imp->imports, (imp->nb_imports+1) * sizeof(*imp->imports) );
441     imp->imports[imp->nb_imports++] = func;
442     total_imports++;
443     if (imp->delay) total_delayed++;
444 }
445
446 /* add a symbol to the undef list */
447 inline static void add_undef_symbol( const char *name )
448 {
449     if (nb_undef_symbols == undef_size)
450     {
451         undef_size += 128;
452         undef_symbols = xrealloc( undef_symbols, undef_size * sizeof(*undef_symbols) );
453     }
454     undef_symbols[nb_undef_symbols++] = xstrdup( name );
455 }
456
457 /* remove all the holes in the undefined symbol list; return the number of removed symbols */
458 static int remove_symbol_holes(void)
459 {
460     int i, off;
461     for (i = off = 0; i < nb_undef_symbols; i++)
462     {
463         if (!undef_symbols[i]) off++;
464         else undef_symbols[i - off] = undef_symbols[i];
465     }
466     nb_undef_symbols -= off;
467     return off;
468 }
469
470 /* add a symbol to the extra list, but only if needed */
471 static int add_extra_symbol( const char **extras, int *count, const char *name, const DLLSPEC *spec )
472 {
473     int i;
474
475     if (!find_symbol( name, undef_symbols, nb_undef_symbols ))
476     {
477         /* check if the symbol is being exported by this dll */
478         for (i = 0; i < spec->nb_entry_points; i++)
479         {
480             ORDDEF *odp = &spec->entry_points[i];
481             if (odp->type == TYPE_STDCALL ||
482                 odp->type == TYPE_CDECL ||
483                 odp->type == TYPE_VARARGS ||
484                 odp->type == TYPE_EXTERN)
485             {
486                 if (odp->name && !strcmp( odp->name, name )) return 0;
487             }
488         }
489         extras[*count] = name;
490         (*count)++;
491     }
492     return 1;
493 }
494
495 /* add the extra undefined symbols that will be contained in the generated spec file itself */
496 static void add_extra_undef_symbols( const DLLSPEC *spec )
497 {
498     const char *extras[10];
499     int i, count = 0, nb_stubs = 0;
500     int kernel_imports = 0, ntdll_imports = 0;
501
502     sort_symbols( undef_symbols, nb_undef_symbols );
503
504     for (i = 0; i < spec->nb_entry_points; i++)
505     {
506         ORDDEF *odp = &spec->entry_points[i];
507         if (odp->type == TYPE_STUB) nb_stubs++;
508     }
509
510     /* add symbols that will be contained in the spec file itself */
511     if (!(spec->characteristics & IMAGE_FILE_DLL))
512     {
513         switch (spec->subsystem)
514         {
515         case IMAGE_SUBSYSTEM_WINDOWS_GUI:
516         case IMAGE_SUBSYSTEM_WINDOWS_CUI:
517             kernel_imports += add_extra_symbol( extras, &count, "GetCommandLineA", spec );
518             kernel_imports += add_extra_symbol( extras, &count, "GetStartupInfoA", spec );
519             kernel_imports += add_extra_symbol( extras, &count, "GetModuleHandleA", spec );
520             kernel_imports += add_extra_symbol( extras, &count, "ExitProcess", spec );
521             break;
522         }
523     }
524     if (nb_delayed)
525     {
526         kernel_imports += add_extra_symbol( extras, &count, "LoadLibraryA", spec );
527         kernel_imports += add_extra_symbol( extras, &count, "FreeLibrary", spec );
528         kernel_imports += add_extra_symbol( extras, &count, "GetProcAddress", spec );
529         kernel_imports += add_extra_symbol( extras, &count, "RaiseException", spec );
530     }
531     if (nb_stubs)
532         ntdll_imports += add_extra_symbol( extras, &count, "RtlRaiseException", spec );
533
534     /* make sure we import the dlls that contain these functions */
535     if (kernel_imports) add_import_dll( "kernel32", NULL );
536     if (ntdll_imports) add_import_dll( "ntdll", NULL );
537
538     if (count)
539     {
540         for (i = 0; i < count; i++) add_undef_symbol( extras[i] );
541         sort_symbols( undef_symbols, nb_undef_symbols );
542     }
543 }
544
545 /* check if a given imported dll is not needed, taking forwards into account */
546 static int check_unused( const struct import* imp, const DLLSPEC *spec )
547 {
548     int i;
549     const char *file_name = imp->spec->file_name;
550     size_t len = strlen( file_name );
551     const char *p = strchr( file_name, '.' );
552     if (p && !strcasecmp( p, ".dll" )) len = p - file_name;
553
554     for (i = spec->base; i <= spec->limit; i++)
555     {
556         ORDDEF *odp = spec->ordinals[i];
557         if (!odp || !(odp->flags & FLAG_FORWARD)) continue;
558         if (!strncasecmp( odp->link_name, file_name, len ) &&
559             odp->link_name[len] == '.')
560             return 0;  /* found a forward, it is used */
561     }
562     return 1;
563 }
564
565 /* combine a list of object files with ld into a single object file */
566 /* returns the name of the combined file */
567 static const char *ldcombine_files( char **argv )
568 {
569     int i, len = 0;
570     char *cmd;
571     int fd, err;
572
573     if (output_file_name && output_file_name[0])
574     {
575         ld_tmp_file = xmalloc( strlen(output_file_name) + 10 );
576         strcpy( ld_tmp_file, output_file_name );
577         strcat( ld_tmp_file, ".XXXXXX.o" );
578     }
579     else ld_tmp_file = xstrdup( "/tmp/winebuild.tmp.XXXXXX.o" );
580
581     if ((fd = mkstemps( ld_tmp_file, 2 ) == -1)) fatal_error( "could not generate a temp file\n" );
582     close( fd );
583     atexit( remove_ld_tmp_file );
584
585     if (!ld_command) ld_command = xstrdup("ld");
586     for (i = 0; argv[i]; i++) len += strlen(argv[i]) + 1;
587     cmd = xmalloc( len + strlen(ld_tmp_file) + 8 + strlen(ld_command)  );
588     sprintf( cmd, "%s -r -o %s", ld_command, ld_tmp_file );
589     for (i = 0; argv[i]; i++) sprintf( cmd + strlen(cmd), " %s", argv[i] );
590     err = system( cmd );
591     if (err) fatal_error( "%s -r failed with status %d\n", ld_command, err );
592     free( cmd );
593     return ld_tmp_file;
594 }
595
596 /* read in the list of undefined symbols */
597 void read_undef_symbols( char **argv )
598 {
599     size_t prefix_len;
600     FILE *f;
601     char *cmd, buffer[1024], name_prefix[16];
602     int err;
603     const char *name;
604
605     if (!argv[0]) return;
606
607     strcpy( name_prefix, asm_name("") );
608     prefix_len = strlen( name_prefix );
609
610     undef_size = nb_undef_symbols = 0;
611
612     /* if we have multiple object files, link them together */
613     if (argv[1]) name = ldcombine_files( argv );
614     else name = argv[0];
615
616     if (!nm_command) nm_command = xstrdup("nm");
617     cmd = xmalloc( strlen(nm_command) + strlen(name) + 5 );
618     sprintf( cmd, "%s -u %s", nm_command, name );
619     if (!(f = popen( cmd, "r" )))
620         fatal_error( "Cannot execute '%s'\n", cmd );
621
622     while (fgets( buffer, sizeof(buffer), f ))
623     {
624         char *p = buffer + strlen(buffer) - 1;
625         if (p < buffer) continue;
626         if (*p == '\n') *p-- = 0;
627         p = buffer;
628         while (*p == ' ') p++;
629         if (p[0] == 'U' && p[1] == ' ' && p[2]) p += 2;
630         if (prefix_len && !strncmp( p, name_prefix, prefix_len )) p += prefix_len;
631         add_undef_symbol( p );
632     }
633     if ((err = pclose( f ))) warning( "%s failed with status %d\n", cmd, err );
634     free( cmd );
635 }
636
637 static void remove_ignored_symbols(void)
638 {
639     int i;
640
641     if (!ignore_symbols) init_ignored_symbols();
642     sort_symbols( ignore_symbols, nb_ignore_symbols );
643     for (i = 0; i < nb_undef_symbols; i++)
644     {
645         if (find_symbol( undef_symbols[i], ignore_symbols, nb_ignore_symbols ))
646         {
647             free( undef_symbols[i] );
648             undef_symbols[i] = NULL;
649         }
650     }
651     remove_symbol_holes();
652 }
653
654 /* resolve the imports for a Win32 module */
655 int resolve_imports( DLLSPEC *spec )
656 {
657     int i, j;
658
659     if (nb_undef_symbols == -1) return 0; /* no symbol file specified */
660
661     add_extra_undef_symbols( spec );
662     remove_ignored_symbols();
663
664     for (i = 0; i < nb_imports; i++)
665     {
666         struct import *imp = dll_imports[i];
667
668         for (j = 0; j < nb_undef_symbols; j++)
669         {
670             ORDDEF *odp = find_export( undef_symbols[j], imp->exports, imp->nb_exports );
671             if (odp)
672             {
673                 add_import_func( imp, odp );
674                 free( undef_symbols[j] );
675                 undef_symbols[j] = NULL;
676             }
677         }
678         /* remove all the holes in the undef symbols list */
679         if (!remove_symbol_holes() && check_unused( imp, spec ))
680         {
681             /* the dll is not used, get rid of it */
682             warning( "%s imported but no symbols used\n", imp->spec->file_name );
683             remove_import_dll( i );
684             i--;
685         }
686     }
687     return 1;
688 }
689
690 /* output a single import thunk */
691 static void output_import_thunk( FILE *outfile, const char *name, const char *table, int pos )
692 {
693     fprintf( outfile, "    \"\\t.align %d\\n\"\n", get_alignment(4) );
694     fprintf( outfile, "    \"\\t%s\\n\"\n", func_declaration(name) );
695     fprintf( outfile, "    \"\\t.globl %s\\n\"\n", asm_name(name) );
696     fprintf( outfile, "    \"%s:\\n\"\n", asm_name(name) );
697
698     switch(target_cpu)
699     {
700     case CPU_x86:
701         if (!UsePIC)
702         {
703             if (strstr( name, "__wine_call_from_16" )) fprintf( outfile, "    \"\\t.byte 0x2e\\n\"\n" );
704             fprintf( outfile, "    \"\\tjmp *(imports+%d)\\n\"\n", pos );
705         }
706         else
707         {
708             if (!strcmp( name, "__wine_call_from_32_regs" ))
709             {
710                 /* special case: need to preserve all registers */
711                 fprintf( outfile, "    \"\\tpushl %%eax\\n\"\n" );
712                 fprintf( outfile, "    \"\\tcall .L__wine_spec_%s\\n\"\n", name );
713                 fprintf( outfile, "    \".L__wine_spec_%s:\\n\"\n", name );
714                 fprintf( outfile, "    \"\\tpopl %%eax\\n\"\n" );
715                 if (!strcmp( name, "__wine_call_from_16_regs" ))
716                     fprintf( outfile, "    \"\\t.byte 0x2e\\n\"\n" );
717                 fprintf( outfile, "    \"\\tmovl %s+%d-.L__wine_spec_%s(%%eax),%%eax\\n\"\n",
718                          asm_name(table), pos, name );
719                 fprintf( outfile, "    \"\\txchgl %%eax,(%%esp)\\n\"\n" );
720                 fprintf( outfile, "    \"\\tret\\n\"\n" );
721             }
722             else if (!strcmp( name, "__wine_call_from_16_regs" ))
723             {
724                 /* special case: need to preserve all registers */
725                 fprintf( outfile, "    \"\\tpushl %%eax\\n\"\n" );
726                 fprintf( outfile, "    \"\\tpushl %%ecx\\n\"\n" );
727                 fprintf( outfile, "    \"\\tcall .L__wine_spec_%s\\n\"\n", name );
728                 fprintf( outfile, "    \".L__wine_spec_%s:\\n\"\n", name );
729                 fprintf( outfile, "    \"\\tpopl %%eax\\n\"\n" );
730                 fprintf( outfile, "    \"\\t.byte 0x2e\\n\"\n" );
731                 fprintf( outfile, "    \"\\tmovl %s+%d-.L__wine_spec_%s(%%eax),%%eax\\n\"\n",
732                          asm_name(table), pos, name );
733                 fprintf( outfile, "    \"\\tmovzwl %%sp, %%ecx\\n\"\n" );
734                 fprintf( outfile, "    \"\\t.byte 0x36\\n\"\n" );
735                 fprintf( outfile, "    \"\\txchgl %%eax,4(%%ecx)\\n\"\n" );
736                 fprintf( outfile, "    \"\\tpopl %%ecx\\n\"\n" );
737                 fprintf( outfile, "    \"\\tret\\n\"\n" );
738             }
739             else
740             {
741                 fprintf( outfile, "    \"\\tcall .L__wine_spec_%s\\n\"\n", name );
742                 fprintf( outfile, "    \".L__wine_spec_%s:\\n\"\n", name );
743                 fprintf( outfile, "    \"\\tpopl %%eax\\n\"\n" );
744                 if (strstr( name, "__wine_call_from_16" ))
745                     fprintf( outfile, "    \"\\t.byte 0x2e\\n\"\n" );
746                 fprintf( outfile, "    \"\\tjmp *%s+%d-.L__wine_spec_%s(%%eax)\\n\"\n",
747                          asm_name(table), pos, name );
748             }
749         }
750         break;
751     case CPU_SPARC:
752         if ( !UsePIC )
753         {
754             fprintf( outfile, "    \"\\tsethi %%hi(%s+%d), %%g1\\n\"\n", table, pos );
755             fprintf( outfile, "    \"\\tld [%%g1+%%lo(%s+%d)], %%g1\\n\"\n", table, pos );
756             fprintf( outfile, "    \"\\tjmp %%g1\\n\\tnop\\n\"\n" );
757         }
758         else
759         {
760             /* Hmpf.  Stupid sparc assembler always interprets global variable
761                names as GOT offsets, so we have to do it the long way ... */
762             fprintf( outfile, "    \"\\tsave %%sp, -96, %%sp\\n\"\n" );
763             fprintf( outfile, "    \"0:\\tcall 1f\\n\\tnop\\n\"\n" );
764             fprintf( outfile, "    \"1:\\tsethi %%hi(%s+%d-0b), %%g1\\n\"\n", table, pos );
765             fprintf( outfile, "    \"\\tor %%g1, %%lo(%s+%d-0b), %%g1\\n\"\n", table, pos );
766             fprintf( outfile, "    \"\\tld [%%g1+%%o7], %%g1\\n\"\n" );
767             fprintf( outfile, "    \"\\tjmp %%g1\\n\\trestore\\n\"\n" );
768         }
769         break;
770     case CPU_ALPHA:
771         fprintf( outfile, "    \"\\tlda $0,%s\\n\"\n", table );
772         fprintf( outfile, "    \"\\tlda $0,%d($0)\\n\"\n", pos);
773         fprintf( outfile, "    \"\\tjmp $31,($0)\\n\"\n" );
774         break;
775     case CPU_POWERPC:
776         fprintf(outfile, "    \"\\taddi %s, %s, -0x4\\n\"\n", ppc_reg(1), ppc_reg(1));
777         fprintf(outfile, "    \"\\tstw  %s, 0(%s)\\n\"\n",    ppc_reg(9), ppc_reg(1));
778         fprintf(outfile, "    \"\\taddi %s, %s, -0x4\\n\"\n", ppc_reg(1), ppc_reg(1));
779         fprintf(outfile, "    \"\\tstw  %s, 0(%s)\\n\"\n",    ppc_reg(8), ppc_reg(1));
780         fprintf(outfile, "    \"\\taddi %s, %s, -0x4\\n\"\n", ppc_reg(1), ppc_reg(1));
781         fprintf(outfile, "    \"\\tstw  %s, 0(%s)\\n\"\n",    ppc_reg(7), ppc_reg(1));
782         if (target_platform == PLATFORM_APPLE)
783         {
784             fprintf(outfile, "    \"\\tlis %s, ha16(%s+%d)\\n\"\n",
785                     ppc_reg(9), asm_name(table), pos);
786             fprintf(outfile, "    \"\\tla  %s, lo16(%s+%d)(%s)\\n\"\n",
787                     ppc_reg(8), asm_name(table), pos, ppc_reg(9));
788         }
789         else
790         {
791             fprintf(outfile, "    \"\\tlis %s, (%s+%d)@hi\\n\"\n",
792                     ppc_reg(9), asm_name(table), pos);
793             fprintf(outfile, "    \"\\tla  %s, (%s+%d)@l(%s)\\n\"\n",
794                     ppc_reg(8), asm_name(table), pos, ppc_reg(9));
795         }
796         fprintf(outfile, "    \"\\tlwz  %s, 0(%s)\\n\"\n", ppc_reg(7), ppc_reg(8));
797         fprintf(outfile, "    \"\\tmtctr %s\\n\"\n", ppc_reg(7));
798         fprintf(outfile, "    \"\\tlwz  %s, 0(%s)\\n\"\n",   ppc_reg(7), ppc_reg(1));
799         fprintf(outfile, "    \"\\taddi %s, %s, 0x4\\n\"\n", ppc_reg(1), ppc_reg(1));
800         fprintf(outfile, "    \"\\tlwz  %s, 0(%s)\\n\"\n",   ppc_reg(8), ppc_reg(1));
801         fprintf(outfile, "    \"\\taddi %s, %s, 0x4\\n\"\n", ppc_reg(1), ppc_reg(1));
802         fprintf(outfile, "    \"\\tlwz  %s, 0(%s)\\n\"\n",   ppc_reg(9), ppc_reg(1));
803         fprintf(outfile, "    \"\\taddi %s, %s, 0x4\\n\"\n", ppc_reg(1), ppc_reg(1));
804         fprintf(outfile, "    \"\\tbctr\\n\"\n");
805         break;
806     }
807     output_function_size( outfile, name );
808 }
809
810 /* output the import table of a Win32 module */
811 static int output_immediate_imports( FILE *outfile )
812 {
813     int i, j, nb_imm = nb_imports - nb_delayed;
814
815     if (!nb_imm) return 0;
816
817     /* main import header */
818
819     fprintf( outfile, "\nstatic struct {\n" );
820     fprintf( outfile, "  struct {\n" );
821     fprintf( outfile, "    void        *OriginalFirstThunk;\n" );
822     fprintf( outfile, "    unsigned int TimeDateStamp;\n" );
823     fprintf( outfile, "    unsigned int ForwarderChain;\n" );
824     fprintf( outfile, "    const char  *Name;\n" );
825     fprintf( outfile, "    void        *FirstThunk;\n" );
826     fprintf( outfile, "  } imp[%d];\n", nb_imm+1 );
827     fprintf( outfile, "  const char *data[%d];\n",
828              total_imports - total_delayed + nb_imm );
829     fprintf( outfile, "} imports = {\n  {\n" );
830
831     /* list of dlls */
832
833     for (i = j = 0; i < nb_imports; i++)
834     {
835         if (dll_imports[i]->delay) continue;
836         fprintf( outfile, "    { 0, 0, 0, \"%s\", &imports.data[%d] },\n",
837                  dll_imports[i]->spec->file_name, j );
838         j += dll_imports[i]->nb_imports + 1;
839     }
840
841     fprintf( outfile, "    { 0, 0, 0, 0, 0 },\n" );
842     fprintf( outfile, "  },\n  {\n" );
843
844     /* list of imported functions */
845
846     for (i = 0; i < nb_imports; i++)
847     {
848         if (dll_imports[i]->delay) continue;
849         fprintf( outfile, "    /* %s */\n", dll_imports[i]->spec->file_name );
850         for (j = 0; j < dll_imports[i]->nb_imports; j++)
851         {
852             ORDDEF *odp = dll_imports[i]->imports[j];
853             if (!(odp->flags & FLAG_NONAME))
854             {
855                 unsigned short ord = odp->ordinal;
856                 fprintf( outfile, "    \"\\%03o\\%03o%s\",\n",
857                          *(unsigned char *)&ord, *((unsigned char *)&ord + 1), odp->name );
858             }
859             else
860                 fprintf( outfile, "    (char *)%d,\n", odp->ordinal );
861         }
862         fprintf( outfile, "    0,\n" );
863     }
864     fprintf( outfile, "  }\n};\n\n" );
865
866     return nb_imm;
867 }
868
869 /* output the import thunks of a Win32 module */
870 static void output_immediate_import_thunks( FILE *outfile )
871 {
872     int i, j, pos;
873     int nb_imm = nb_imports - nb_delayed;
874     static const char import_thunks[] = "__wine_spec_import_thunks";
875
876     if (!nb_imm) return;
877
878     pos = (sizeof(void *) + 2*sizeof(unsigned int) + sizeof(const char *) + sizeof(void *)) *
879             (nb_imm + 1);  /* offset of imports.data from start of imports */
880     fprintf( outfile, "/* immediate import thunks */\n" );
881     fprintf( outfile, "asm(\".text\\n\\t.align %d\\n\"\n", get_alignment(8) );
882     fprintf( outfile, "    \"%s:\\n\"\n", asm_name(import_thunks));
883
884     for (i = 0; i < nb_imports; i++)
885     {
886         if (dll_imports[i]->delay) continue;
887         for (j = 0; j < dll_imports[i]->nb_imports; j++, pos += sizeof(const char *))
888         {
889             ORDDEF *odp = dll_imports[i]->imports[j];
890             output_import_thunk( outfile, odp->name ? odp->name : odp->export_name,
891                                  "imports", pos );
892         }
893         pos += 4;
894     }
895     output_function_size( outfile, import_thunks );
896     fprintf( outfile, ");\n" );
897 }
898
899 /* output the delayed import table of a Win32 module */
900 static int output_delayed_imports( FILE *outfile, const DLLSPEC *spec )
901 {
902     int i, j;
903
904     if (!nb_delayed) return 0;
905
906     fprintf( outfile, "static void *__wine_delay_imp_hmod[%d];\n", nb_delayed );
907     for (i = 0; i < nb_imports; i++)
908     {
909         if (!dll_imports[i]->delay) continue;
910         for (j = 0; j < dll_imports[i]->nb_imports; j++)
911         {
912             ORDDEF *odp = dll_imports[i]->imports[j];
913             const char *name = odp->name ? odp->name : odp->export_name;
914             fprintf( outfile, "void __wine_delay_imp_%d_%s();\n", i, name );
915         }
916     }
917     fprintf( outfile, "\n" );
918     fprintf( outfile, "static struct {\n" );
919     fprintf( outfile, "  struct ImgDelayDescr {\n" );
920     fprintf( outfile, "    unsigned int  grAttrs;\n" );
921     fprintf( outfile, "    const char   *szName;\n" );
922     fprintf( outfile, "    void        **phmod;\n" );
923     fprintf( outfile, "    void        **pIAT;\n" );
924     fprintf( outfile, "    const char  **pINT;\n" );
925     fprintf( outfile, "    void*         pBoundIAT;\n" );
926     fprintf( outfile, "    void*         pUnloadIAT;\n" );
927     fprintf( outfile, "    unsigned long dwTimeStamp;\n" );
928     fprintf( outfile, "  } imp[%d];\n", nb_delayed );
929     fprintf( outfile, "  void         *IAT[%d];\n", total_delayed );
930     fprintf( outfile, "  const char   *INT[%d];\n", total_delayed );
931     fprintf( outfile, "} delay_imports = {\n" );
932     fprintf( outfile, "  {\n" );
933     for (i = j = 0; i < nb_imports; i++)
934     {
935         if (!dll_imports[i]->delay) continue;
936         fprintf( outfile, "    { 0, \"%s\", &__wine_delay_imp_hmod[%d], &delay_imports.IAT[%d], &delay_imports.INT[%d], 0, 0, 0 },\n",
937                  dll_imports[i]->spec->file_name, i, j, j );
938         j += dll_imports[i]->nb_imports;
939     }
940     fprintf( outfile, "  },\n  {\n" );
941     for (i = 0; i < nb_imports; i++)
942     {
943         if (!dll_imports[i]->delay) continue;
944         fprintf( outfile, "    /* %s */\n", dll_imports[i]->spec->file_name );
945         for (j = 0; j < dll_imports[i]->nb_imports; j++)
946         {
947             ORDDEF *odp = dll_imports[i]->imports[j];
948             const char *name = odp->name ? odp->name : odp->export_name;
949             fprintf( outfile, "    &__wine_delay_imp_%d_%s,\n", i, name );
950         }
951     }
952     fprintf( outfile, "  },\n  {\n" );
953     for (i = 0; i < nb_imports; i++)
954     {
955         if (!dll_imports[i]->delay) continue;
956         fprintf( outfile, "    /* %s */\n", dll_imports[i]->spec->file_name );
957         for (j = 0; j < dll_imports[i]->nb_imports; j++)
958         {
959             ORDDEF *odp = dll_imports[i]->imports[j];
960             if (!odp->name)
961                 fprintf( outfile, "    (char *)%d,\n", odp->ordinal );
962             else
963                 fprintf( outfile, "    \"%s\",\n", odp->name );
964         }
965     }
966     fprintf( outfile, "  }\n};\n\n" );
967
968     fprintf( outfile, "extern void __stdcall RaiseException(unsigned int, unsigned int, unsigned int, const void *args[]);\n" );
969     fprintf( outfile, "extern void * __stdcall LoadLibraryA(const char*);\n");
970     fprintf( outfile, "extern void * __stdcall GetProcAddress(void *, const char*);\n");
971     fprintf( outfile, "\n" );
972
973     fprintf( outfile, "void *__stdcall __wine_delay_load( int idx_nr )\n" );
974     fprintf( outfile, "{\n" );
975     fprintf( outfile, "  int idx = idx_nr >> 16, nr = idx_nr & 0xffff;\n" );
976     fprintf( outfile, "  struct ImgDelayDescr *imd = delay_imports.imp + idx;\n" );
977     fprintf( outfile, "  void **pIAT = imd->pIAT + nr;\n" );
978     fprintf( outfile, "  const char** pINT = imd->pINT + nr;\n" );
979     fprintf( outfile, "  void *fn;\n\n" );
980
981     fprintf( outfile, "  if (!*imd->phmod) *imd->phmod = LoadLibraryA(imd->szName);\n" );
982     fprintf( outfile, "  if (*imd->phmod && (fn = GetProcAddress(*imd->phmod, *pINT)))\n");
983     fprintf( outfile, "    /* patch IAT with final value */\n" );
984     fprintf( outfile, "    return *pIAT = fn;\n" );
985     fprintf( outfile, "  else {\n");
986     fprintf( outfile, "    const void *args[2];\n" );
987     fprintf( outfile, "    args[0] = imd->szName;\n" );
988     fprintf( outfile, "    args[1] = *pINT;\n" );
989     fprintf( outfile, "    RaiseException( 0x%08x, %d, 2, args );\n",
990              EXCEPTION_WINE_STUB, EH_NONCONTINUABLE );
991     fprintf( outfile, "    return 0;\n" );
992     fprintf( outfile, "  }\n}\n" );
993
994     return nb_delayed;
995 }
996
997 /* output the delayed import thunks of a Win32 module */
998 static void output_delayed_import_thunks( FILE *outfile, const DLLSPEC *spec )
999 {
1000     int i, idx, j, pos, extra_stack_storage = 0;
1001     static const char delayed_import_loaders[] = "__wine_spec_delayed_import_loaders";
1002     static const char delayed_import_thunks[] = "__wine_spec_delayed_import_thunks";
1003
1004     if (!nb_delayed) return;
1005
1006     fprintf( outfile, "/* delayed import thunks */\n" );
1007     fprintf( outfile, "asm(\".text\\n\"\n" );
1008     fprintf( outfile, "    \"\\t.align %d\\n\"\n", get_alignment(8) );
1009     fprintf( outfile, "    \"%s:\\n\"\n", asm_name(delayed_import_loaders));
1010     fprintf( outfile, "    \"\\t%s\\n\"\n", func_declaration("__wine_delay_load_asm") );
1011     fprintf( outfile, "    \"%s:\\n\"\n", asm_name("__wine_delay_load_asm") );
1012     switch(target_cpu)
1013     {
1014     case CPU_x86:
1015         fprintf( outfile, "    \"\\tpushl %%ecx\\n\\tpushl %%edx\\n\\tpushl %%eax\\n\"\n" );
1016         fprintf( outfile, "    \"\\tcall %s\\n\"\n", asm_name("__wine_delay_load") );
1017         fprintf( outfile, "    \"\\tpopl %%edx\\n\\tpopl %%ecx\\n\\tjmp *%%eax\\n\"\n" );
1018         break;
1019     case CPU_SPARC:
1020         fprintf( outfile, "    \"\\tsave %%sp, -96, %%sp\\n\"\n" );
1021         fprintf( outfile, "    \"\\tcall %s\\n\"\n", asm_name("__wine_delay_load") );
1022         fprintf( outfile, "    \"\\tmov %%g1, %%o0\\n\"\n" );
1023         fprintf( outfile, "    \"\\tjmp %%o0\\n\\trestore\\n\"\n" );
1024         break;
1025     case CPU_ALPHA:
1026         fprintf( outfile, "    \"\\tjsr $26,%s\\n\"\n", asm_name("__wine_delay_load") );
1027         fprintf( outfile, "    \"\\tjmp $31,($0)\\n\"\n" );
1028         break;
1029     case CPU_POWERPC:
1030         if (target_platform == PLATFORM_APPLE) extra_stack_storage = 56;
1031
1032         /* Save all callee saved registers into a stackframe. */
1033         fprintf( outfile, "    \"\\tstwu %s, -%d(%s)\\n\"\n",ppc_reg(1), 48+extra_stack_storage, ppc_reg(1));
1034         fprintf( outfile, "    \"\\tstw  %s, %d(%s)\\n\"\n", ppc_reg(3),  4+extra_stack_storage, ppc_reg(1));
1035         fprintf( outfile, "    \"\\tstw  %s, %d(%s)\\n\"\n", ppc_reg(4),  8+extra_stack_storage, ppc_reg(1));
1036         fprintf( outfile, "    \"\\tstw  %s, %d(%s)\\n\"\n", ppc_reg(5), 12+extra_stack_storage, ppc_reg(1));
1037         fprintf( outfile, "    \"\\tstw  %s, %d(%s)\\n\"\n", ppc_reg(6), 16+extra_stack_storage, ppc_reg(1));
1038         fprintf( outfile, "    \"\\tstw  %s, %d(%s)\\n\"\n", ppc_reg(7), 20+extra_stack_storage, ppc_reg(1));
1039         fprintf( outfile, "    \"\\tstw  %s, %d(%s)\\n\"\n", ppc_reg(8), 24+extra_stack_storage, ppc_reg(1));
1040         fprintf( outfile, "    \"\\tstw  %s, %d(%s)\\n\"\n", ppc_reg(9), 28+extra_stack_storage, ppc_reg(1));
1041         fprintf( outfile, "    \"\\tstw  %s, %d(%s)\\n\"\n", ppc_reg(10),32+extra_stack_storage, ppc_reg(1));
1042         fprintf( outfile, "    \"\\tstw  %s, %d(%s)\\n\"\n", ppc_reg(11),36+extra_stack_storage, ppc_reg(1));
1043         fprintf( outfile, "    \"\\tstw  %s, %d(%s)\\n\"\n", ppc_reg(12),40+extra_stack_storage, ppc_reg(1));
1044
1045         /* r0 -> r3 (arg1) */
1046         fprintf( outfile, "    \"\\tmr %s, %s\\n\"\n", ppc_reg(3), ppc_reg(0));
1047
1048         /* save return address */
1049         fprintf( outfile, "    \"\\tmflr %s\\n\"\n", ppc_reg(0));
1050         fprintf( outfile, "    \"\\tstw  %s, %d(%s)\\n\"\n", ppc_reg(0), 44+extra_stack_storage, ppc_reg(1));
1051
1052         /* Call the __wine_delay_load function, arg1 is arg1. */
1053         fprintf( outfile, "    \"\\tbl %s\\n\"\n", asm_name("__wine_delay_load") );
1054
1055         /* Load return value from call into ctr register */
1056         fprintf( outfile, "    \"\\tmtctr %s\\n\"\n", ppc_reg(3));
1057
1058         /* restore all saved registers and drop stackframe. */
1059         fprintf( outfile, "    \"\\tlwz  %s, %d(%s)\\n\"\n", ppc_reg(3),  4+extra_stack_storage, ppc_reg(1));
1060         fprintf( outfile, "    \"\\tlwz  %s, %d(%s)\\n\"\n", ppc_reg(4),  8+extra_stack_storage, ppc_reg(1));
1061         fprintf( outfile, "    \"\\tlwz  %s, %d(%s)\\n\"\n", ppc_reg(5), 12+extra_stack_storage, ppc_reg(1));
1062         fprintf( outfile, "    \"\\tlwz  %s, %d(%s)\\n\"\n", ppc_reg(6), 16+extra_stack_storage, ppc_reg(1));
1063         fprintf( outfile, "    \"\\tlwz  %s, %d(%s)\\n\"\n", ppc_reg(7), 20+extra_stack_storage, ppc_reg(1));
1064         fprintf( outfile, "    \"\\tlwz  %s, %d(%s)\\n\"\n", ppc_reg(8), 24+extra_stack_storage, ppc_reg(1));
1065         fprintf( outfile, "    \"\\tlwz  %s, %d(%s)\\n\"\n", ppc_reg(9), 28+extra_stack_storage, ppc_reg(1));
1066         fprintf( outfile, "    \"\\tlwz  %s, %d(%s)\\n\"\n", ppc_reg(10),32+extra_stack_storage, ppc_reg(1));
1067         fprintf( outfile, "    \"\\tlwz  %s, %d(%s)\\n\"\n", ppc_reg(11),36+extra_stack_storage, ppc_reg(1));
1068         fprintf( outfile, "    \"\\tlwz  %s, %d(%s)\\n\"\n", ppc_reg(12),40+extra_stack_storage, ppc_reg(1));
1069
1070         /* Load return value from call into return register */
1071         fprintf( outfile, "    \"\\tlwz  %s,  %d(%s)\\n\"\n", ppc_reg(0), 44+extra_stack_storage, ppc_reg(1));
1072         fprintf( outfile, "    \"\\tmtlr %s\\n\"\n", ppc_reg(0));
1073         fprintf( outfile, "    \"\\taddi %s, %s, %d\\n\"\n", ppc_reg(1), ppc_reg(1),  48+extra_stack_storage);
1074
1075         /* branch to ctr register. */
1076         fprintf( outfile, "    \"bctr\\n\"\n");
1077         break;
1078     }
1079     output_function_size( outfile, "__wine_delay_load_asm" );
1080
1081     for (i = idx = 0; i < nb_imports; i++)
1082     {
1083         if (!dll_imports[i]->delay) continue;
1084         for (j = 0; j < dll_imports[i]->nb_imports; j++)
1085         {
1086             char buffer[128];
1087             ORDDEF *odp = dll_imports[i]->imports[j];
1088             const char *name = odp->name ? odp->name : odp->export_name;
1089
1090             sprintf( buffer, "__wine_delay_imp_%d_%s", i, name );
1091             fprintf( outfile, "    \"\\t%s\\n\"\n", func_declaration(buffer) );
1092             fprintf( outfile, "    \"%s:\\n\"\n", asm_name(buffer) );
1093             switch(target_cpu)
1094             {
1095             case CPU_x86:
1096                 fprintf( outfile, "    \"\\tmovl $%d, %%eax\\n\"\n", (idx << 16) | j );
1097                 fprintf( outfile, "    \"\\tjmp %s\\n\"\n", asm_name("__wine_delay_load_asm") );
1098                 break;
1099             case CPU_SPARC:
1100                 fprintf( outfile, "    \"\\tset %d, %%g1\\n\"\n", (idx << 16) | j );
1101                 fprintf( outfile, "    \"\\tb,a %s\\n\"\n", asm_name("__wine_delay_load_asm") );
1102                 break;
1103             case CPU_ALPHA:
1104                 fprintf( outfile, "    \"\\tlda $0,%d($31)\\n\"\n", j);
1105                 fprintf( outfile, "    \"\\tldah $0,%d($0)\\n\"\n", idx);
1106                 fprintf( outfile, "    \"\\tjmp $31,%s\\n\"\n", asm_name("__wine_delay_load_asm") );
1107                 break;
1108             case CPU_POWERPC:
1109                 switch(target_platform)
1110                 {
1111                 case PLATFORM_APPLE:
1112                     /* On Darwin we can use r0 and r2 */
1113                     /* Upper part in r2 */
1114                     fprintf( outfile, "    \"\\tlis %s, %d\\n\"\n", ppc_reg(2), idx);
1115                     /* Lower part + r2 -> r0, Note we can't use r0 directly */
1116                     fprintf( outfile, "    \"\\taddi %s, %s, %d\\n\"\n", ppc_reg(0), ppc_reg(2), j);
1117                     fprintf( outfile, "    \"\\tb %s\\n\"\n", asm_name("__wine_delay_load_asm") );
1118                     break;
1119                 default:
1120                     /* On linux we can't use r2 since r2 is not a scratch register (hold the TOC) */
1121                     /* Save r13 on the stack */
1122                     fprintf( outfile, "    \"\\taddi %s, %s, -0x4\\n\"\n", ppc_reg(1), ppc_reg(1));
1123                     fprintf( outfile, "    \"\\tstw  %s, 0(%s)\\n\"\n",    ppc_reg(13), ppc_reg(1));
1124                     /* Upper part in r13 */
1125                     fprintf( outfile, "    \"\\tlis %s, %d\\n\"\n", ppc_reg(13), idx);
1126                     /* Lower part + r13 -> r0, Note we can't use r0 directly */
1127                     fprintf( outfile, "    \"\\taddi %s, %s, %d\\n\"\n", ppc_reg(0), ppc_reg(13), j);
1128                     /* Restore r13 */
1129                     fprintf( outfile, "    \"\\tstw  %s, 0(%s)\\n\"\n",    ppc_reg(13), ppc_reg(1));
1130                     fprintf( outfile, "    \"\\taddic %s, %s, 0x4\\n\"\n", ppc_reg(1), ppc_reg(1));
1131                     fprintf( outfile, "    \"\\tb %s\\n\"\n", asm_name("__wine_delay_load_asm") );
1132                     break;
1133                 }
1134                 break;
1135             }
1136             output_function_size( outfile, name );
1137         }
1138         idx++;
1139     }
1140     output_function_size( outfile, delayed_import_loaders );
1141
1142     fprintf( outfile, "\n    \".align %d\\n\"\n", get_alignment(8) );
1143     fprintf( outfile, "    \"%s:\\n\"\n", asm_name(delayed_import_thunks));
1144     pos = nb_delayed * 32;
1145     for (i = 0; i < nb_imports; i++)
1146     {
1147         if (!dll_imports[i]->delay) continue;
1148         for (j = 0; j < dll_imports[i]->nb_imports; j++, pos += 4)
1149         {
1150             ORDDEF *odp = dll_imports[i]->imports[j];
1151             output_import_thunk( outfile, odp->name ? odp->name : odp->export_name,
1152                                  "delay_imports", pos );
1153         }
1154     }
1155     output_function_size( outfile, delayed_import_thunks );
1156     fprintf( outfile, ");\n" );
1157 }
1158
1159 /* output the import and delayed import tables of a Win32 module
1160  * returns number of DLLs exported in 'immediate' mode
1161  */
1162 int output_imports( FILE *outfile, DLLSPEC *spec, int *nb_delayed )
1163 {
1164     *nb_delayed = output_delayed_imports( outfile, spec );
1165     return output_immediate_imports( outfile );
1166 }
1167
1168 /* output the import and delayed import thunks of a Win32 module */
1169 void output_import_thunks( FILE *outfile, DLLSPEC *spec )
1170 {
1171     output_delayed_import_thunks( outfile, spec );
1172     output_immediate_import_thunks( outfile );
1173 }