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