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