Beginnings of a crt0 library.
[wine.git] / tools / winebuild / import.c
blobb04be4b8a3e69976081997b996d90f57a9afacb0
1 /*
2 * DLL imports support
4 * Copyright 2000, 2004 Alexandre Julliard
5 * Copyright 2000 Eric Pouech
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.
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.
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
22 #include "config.h"
23 #include "wine/port.h"
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
38 #include "windef.h"
39 #include "winbase.h"
40 #include "build.h"
42 struct import
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 */
55 struct name_table
57 char **names;
58 unsigned int count, size;
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 */
66 static char *ld_tmp_file; /* ld temp file name */
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 */
74 /* list of symbols that are ignored by default */
75 static const char * const default_ignored_symbols[] =
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"
126 static inline const char *ppc_reg( int reg )
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' */
136 /* compare function names; helper for resolve_imports */
137 static int name_cmp( const void *name, const void *entry )
139 return strcmp( *(const char* const *)name, *(const char* const *)entry );
142 /* compare function names; helper for resolve_imports */
143 static int func_cmp( const void *func1, const void *func2 )
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 );
151 /* add a name to a name table */
152 inline static void add_name( struct name_table *table, const char *name )
154 if (table->count == table->size)
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) );
160 table->names[table->count++] = xstrdup( name );
163 /* remove a name from a name table */
164 inline static void remove_name( struct name_table *table, unsigned int idx )
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--;
173 /* make a name table empty */
174 inline static void empty_name_table( struct name_table *table )
176 unsigned int i;
178 for (i = 0; i < table->count; i++) free( table->names[i] );
179 table->count = 0;
182 /* locate a name in a (sorted) list */
183 inline static const char *find_name( const char *name, const struct name_table *table )
185 char **res = NULL;
187 if (table->count) res = bsearch( &name, table->names, table->count, sizeof(*table->names), name_cmp );
188 return res ? *res : NULL;
191 /* sort a name table */
192 inline static void sort_names( struct name_table *table )
194 if (table->count) qsort( table->names, table->count, sizeof(*table->names), name_cmp );
197 /* locate an export in a (sorted) export list */
198 inline static ORDDEF *find_export( const char *name, ORDDEF **table, int size )
200 ORDDEF func, *odp, **res = NULL;
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;
209 inline static void output_function_size( FILE *outfile, const char *name )
211 const char *size = func_size( name );
212 if (size[0]) fprintf( outfile, " \"\\t%s\\n\"\n", size );
215 /* free an import structure */
216 static void free_imports( struct import *imp )
218 free( imp->exports );
219 free( imp->imports );
220 free_dll_spec( imp->spec );
221 free( imp->full_name );
222 free( imp );
225 /* remove the temp file at exit */
226 static void remove_ld_tmp_file(void)
228 if (ld_tmp_file) unlink( ld_tmp_file );
231 /* check whether a given dll is imported in delayed mode */
232 static int is_delayed_import( const char *name )
234 int i;
236 for (i = 0; i < delayed_imports.count; i++)
238 if (!strcmp( delayed_imports.names[i], name )) return 1;
240 return 0;
243 /* check whether a given dll has already been imported */
244 static struct import *is_already_imported( const char *name )
246 int i;
248 for (i = 0; i < nb_imports; i++)
250 if (!strcmp( dll_imports[i]->spec->file_name, name )) return dll_imports[i];
252 return NULL;
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 )
258 char *buffer;
259 int fd;
261 buffer = xmalloc( strlen(path) + strlen(name) + 9 );
262 sprintf( buffer, "%s/lib%s.def", path, name );
264 /* check if the file exists */
265 if ((fd = open( buffer, O_RDONLY )) != -1)
267 close( fd );
268 return buffer;
270 free( buffer );
271 return NULL;
274 /* find the .def import library for a given dll */
275 static char *find_library( const char *name )
277 char *fullname;
278 int i;
280 for (i = 0; i < nb_lib_paths; i++)
282 if ((fullname = try_library_path( lib_path[i], name ))) return fullname;
284 fatal_error( "could not open .def file for %s\n", name );
285 return NULL;
288 /* read in the list of exported symbols of an import library */
289 static int read_import_lib( struct import *imp )
291 FILE *f;
292 int i, ret;
293 struct stat stat;
294 struct import *prev_imp;
295 DLLSPEC *spec = imp->spec;
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;
305 /* check if we already imported that library from a different file */
306 if ((prev_imp = is_already_imported( spec->file_name )))
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 */
314 if (is_delayed_import( spec->file_name ))
316 imp->delay = 1;
317 nb_delayed++;
320 imp->exports = xmalloc( spec->nb_entry_points * sizeof(*imp->exports) );
322 for (i = 0; i < spec->nb_entry_points; i++)
324 ORDDEF *odp = &spec->entry_points[i];
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;
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;
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 )
339 char *ret;
341 if (filename)
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;
351 else
353 ret = xmalloc( strlen(name) + 5 );
354 strcpy( ret, name );
356 if (!strchr( ret, '.' )) strcat( ret, ".dll" );
357 return ret;
360 /* add a dll to the list of imports */
361 void add_import_dll( const char *name, const char *filename )
363 struct import *imp = xmalloc( sizeof(*imp) );
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;
373 if (filename) imp->full_name = xstrdup( filename );
374 else imp->full_name = find_library( name );
376 if (read_import_lib( imp ))
378 dll_imports = xrealloc( dll_imports, (nb_imports+1) * sizeof(*dll_imports) );
379 dll_imports[nb_imports++] = imp;
381 else
383 free_imports( imp );
384 if (nb_errors) exit(1);
388 /* add a library to the list of delayed imports */
389 void add_delayed_import( const char *name )
391 struct import *imp;
392 char *fullname = get_dll_name( name, NULL );
394 add_name( &delayed_imports, fullname );
395 if ((imp = is_already_imported( fullname )) && !imp->delay)
397 imp->delay = 1;
398 nb_delayed++;
400 free( fullname );
403 /* remove an imported dll, based on its index in the dll_imports array */
404 static void remove_import_dll( int index )
406 struct import *imp = dll_imports[index];
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 );
414 /* initialize the list of ignored symbols */
415 static void init_ignored_symbols(void)
417 unsigned int i;
419 for (i = 0; i < sizeof(default_ignored_symbols)/sizeof(default_ignored_symbols[0]); i++)
420 add_name( &ignore_symbols, default_ignored_symbols[i] );
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 )
427 unsigned int i;
429 if (!ignore_symbols.size) init_ignored_symbols(); /* first time around, fill list with defaults */
431 if (name[0] == '-') /* remove it */
433 if (!name[1]) empty_name_table( &ignore_symbols ); /* remove everything */
434 else for (i = 0; i < ignore_symbols.count; i++)
436 if (!strcmp( ignore_symbols.names[i], name+1 )) remove_name( &ignore_symbols, i-- );
439 else add_name( &ignore_symbols, name );
442 /* add a symbol to the list of extra symbols that ld must resolve */
443 void add_extra_ld_symbol( const char *name )
445 add_name( &extra_ld_symbols, name );
448 /* add a function to the list of imports from a given dll */
449 static void add_import_func( struct import *imp, ORDDEF *func )
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++;
457 /* add a symbol to the extra list, but only if needed */
458 static int add_extra_symbol( const char **extras, int *count, const char *name, const DLLSPEC *spec )
460 int i;
462 if (!find_name( name, &undef_symbols ))
464 /* check if the symbol is being exported by this dll */
465 for (i = 0; i < spec->nb_entry_points; i++)
467 ORDDEF *odp = &spec->entry_points[i];
468 if (odp->type == TYPE_STDCALL ||
469 odp->type == TYPE_CDECL ||
470 odp->type == TYPE_VARARGS ||
471 odp->type == TYPE_EXTERN)
473 if (odp->name && !strcmp( odp->name, name )) return 0;
476 extras[*count] = name;
477 (*count)++;
479 return 1;
482 /* add the extra undefined symbols that will be contained in the generated spec file itself */
483 static void add_extra_undef_symbols( const DLLSPEC *spec )
485 const char *extras[10];
486 int i, count = 0, nb_stubs = 0;
487 int kernel_imports = 0, ntdll_imports = 0;
489 sort_names( &undef_symbols );
491 for (i = 0; i < spec->nb_entry_points; i++)
493 ORDDEF *odp = &spec->entry_points[i];
494 if (odp->type == TYPE_STUB) nb_stubs++;
497 /* add symbols that will be contained in the spec file itself */
498 if (!(spec->characteristics & IMAGE_FILE_DLL))
500 switch (spec->subsystem)
502 case IMAGE_SUBSYSTEM_WINDOWS_GUI:
503 case IMAGE_SUBSYSTEM_WINDOWS_CUI:
504 kernel_imports += add_extra_symbol( extras, &count, "GetCommandLineA", spec );
505 kernel_imports += add_extra_symbol( extras, &count, "GetStartupInfoA", spec );
506 kernel_imports += add_extra_symbol( extras, &count, "GetModuleHandleA", spec );
507 kernel_imports += add_extra_symbol( extras, &count, "ExitProcess", spec );
508 break;
511 if (nb_delayed)
513 kernel_imports += add_extra_symbol( extras, &count, "LoadLibraryA", spec );
514 kernel_imports += add_extra_symbol( extras, &count, "FreeLibrary", spec );
515 kernel_imports += add_extra_symbol( extras, &count, "GetProcAddress", spec );
516 kernel_imports += add_extra_symbol( extras, &count, "DelayLoadFailureHook", spec );
518 if (nb_stubs)
519 ntdll_imports += add_extra_symbol( extras, &count, "RtlRaiseException", spec );
521 /* make sure we import the dlls that contain these functions */
522 if (kernel_imports) add_import_dll( "kernel32", NULL );
523 if (ntdll_imports) add_import_dll( "ntdll", NULL );
525 if (count)
527 for (i = 0; i < count; i++) add_name( &undef_symbols, extras[i] );
528 sort_names( &undef_symbols );
532 /* check if a given imported dll is not needed, taking forwards into account */
533 static int check_unused( const struct import* imp, const DLLSPEC *spec )
535 int i;
536 const char *file_name = imp->spec->file_name;
537 size_t len = strlen( file_name );
538 const char *p = strchr( file_name, '.' );
539 if (p && !strcasecmp( p, ".dll" )) len = p - file_name;
541 for (i = spec->base; i <= spec->limit; i++)
543 ORDDEF *odp = spec->ordinals[i];
544 if (!odp || !(odp->flags & FLAG_FORWARD)) continue;
545 if (!strncasecmp( odp->link_name, file_name, len ) &&
546 odp->link_name[len] == '.')
547 return 0; /* found a forward, it is used */
549 return 1;
552 /* combine a list of object files with ld into a single object file */
553 /* returns the name of the combined file */
554 static const char *ldcombine_files( char **argv )
556 unsigned int i, len = 0;
557 char *cmd, *p;
558 int fd, err;
560 if (output_file_name && output_file_name[0])
562 ld_tmp_file = xmalloc( strlen(output_file_name) + 10 );
563 strcpy( ld_tmp_file, output_file_name );
564 strcat( ld_tmp_file, ".XXXXXX.o" );
566 else ld_tmp_file = xstrdup( "/tmp/winebuild.tmp.XXXXXX.o" );
568 if ((fd = mkstemps( ld_tmp_file, 2 ) == -1)) fatal_error( "could not generate a temp file\n" );
569 close( fd );
570 atexit( remove_ld_tmp_file );
572 if (!ld_command) ld_command = xstrdup("ld");
573 for (i = 0; i < extra_ld_symbols.count; i++) len += strlen(extra_ld_symbols.names[i]) + 5;
574 for (i = 0; argv[i]; i++) len += strlen(argv[i]) + 1;
575 cmd = p = xmalloc( len + strlen(ld_tmp_file) + 8 + strlen(ld_command) );
576 p += sprintf( cmd, "%s -r -o %s", ld_command, ld_tmp_file );
577 for (i = 0; i < extra_ld_symbols.count; i++)
578 p += sprintf( p, " -u %s", asm_name(extra_ld_symbols.names[i]) );
579 for (i = 0; argv[i]; i++)
580 p += sprintf( p, " %s", argv[i] );
581 err = system( cmd );
582 if (err) fatal_error( "%s -r failed with status %d\n", ld_command, err );
583 free( cmd );
584 return ld_tmp_file;
587 /* read in the list of undefined symbols */
588 void read_undef_symbols( DLLSPEC *spec, char **argv )
590 size_t prefix_len;
591 FILE *f;
592 char *cmd, buffer[1024], name_prefix[16];
593 int err;
594 const char *name;
596 if (!argv[0]) return;
598 if (spec->init_func) add_extra_ld_symbol( spec->init_func );
599 else if (spec->characteristics & IMAGE_FILE_DLL) add_extra_ld_symbol( "DllMain" );
600 else if (spec->subsystem == IMAGE_SUBSYSTEM_NATIVE) add_extra_ld_symbol( "DriverEntry ");
601 else add_extra_ld_symbol( "main" );
603 strcpy( name_prefix, asm_name("") );
604 prefix_len = strlen( name_prefix );
606 name = ldcombine_files( argv );
608 if (!nm_command) nm_command = xstrdup("nm");
609 cmd = xmalloc( strlen(nm_command) + strlen(name) + 5 );
610 sprintf( cmd, "%s -u %s", nm_command, name );
611 if (!(f = popen( cmd, "r" )))
612 fatal_error( "Cannot execute '%s'\n", cmd );
614 while (fgets( buffer, sizeof(buffer), f ))
616 char *p = buffer + strlen(buffer) - 1;
617 if (p < buffer) continue;
618 if (*p == '\n') *p-- = 0;
619 p = buffer;
620 while (*p == ' ') p++;
621 if (p[0] == 'U' && p[1] == ' ' && p[2]) p += 2;
622 if (prefix_len && !strncmp( p, name_prefix, prefix_len )) p += prefix_len;
623 add_name( &undef_symbols, p );
625 if ((err = pclose( f ))) warning( "%s failed with status %d\n", cmd, err );
626 free( cmd );
629 static void remove_ignored_symbols(void)
631 unsigned int i;
633 if (!ignore_symbols.size) init_ignored_symbols();
634 sort_names( &ignore_symbols );
635 for (i = 0; i < undef_symbols.count; i++)
637 if (find_name( undef_symbols.names[i], &ignore_symbols ))
638 remove_name( &undef_symbols, i-- );
642 /* resolve the imports for a Win32 module */
643 int resolve_imports( DLLSPEC *spec )
645 unsigned int i, j, removed;
647 add_extra_undef_symbols( spec );
648 remove_ignored_symbols();
650 for (i = 0; i < nb_imports; i++)
652 struct import *imp = dll_imports[i];
654 for (j = removed = 0; j < undef_symbols.count; j++)
656 ORDDEF *odp = find_export( undef_symbols.names[j], imp->exports, imp->nb_exports );
657 if (odp)
659 add_import_func( imp, odp );
660 remove_name( &undef_symbols, j-- );
661 removed++;
664 if (!removed && check_unused( imp, spec ))
666 /* the dll is not used, get rid of it */
667 warning( "%s imported but no symbols used\n", imp->spec->file_name );
668 remove_import_dll( i );
669 i--;
672 return 1;
675 /* output a single import thunk */
676 static void output_import_thunk( FILE *outfile, const char *name, const char *table, int pos )
678 fprintf( outfile, " \"\\t.align %d\\n\"\n", get_alignment(4) );
679 fprintf( outfile, " \"\\t%s\\n\"\n", func_declaration(name) );
680 fprintf( outfile, " \"\\t.globl %s\\n\"\n", asm_name(name) );
681 fprintf( outfile, " \"%s:\\n\"\n", asm_name(name) );
683 switch(target_cpu)
685 case CPU_x86:
686 if (!UsePIC)
688 if (strstr( name, "__wine_call_from_16" )) fprintf( outfile, " \"\\t.byte 0x2e\\n\"\n" );
689 fprintf( outfile, " \"\\tjmp *(%s+%d)\\n\"\n", asm_name(table), pos );
691 else
693 if (!strcmp( name, "__wine_call_from_32_regs" ))
695 /* special case: need to preserve all registers */
696 fprintf( outfile, " \"\\tpushl %%eax\\n\"\n" );
697 fprintf( outfile, " \"\\tcall .L__wine_spec_%s\\n\"\n", name );
698 fprintf( outfile, " \".L__wine_spec_%s:\\n\"\n", name );
699 fprintf( outfile, " \"\\tpopl %%eax\\n\"\n" );
700 if (!strcmp( name, "__wine_call_from_16_regs" ))
701 fprintf( outfile, " \"\\t.byte 0x2e\\n\"\n" );
702 fprintf( outfile, " \"\\tmovl %s+%d-.L__wine_spec_%s(%%eax),%%eax\\n\"\n",
703 asm_name(table), pos, name );
704 fprintf( outfile, " \"\\txchgl %%eax,(%%esp)\\n\"\n" );
705 fprintf( outfile, " \"\\tret\\n\"\n" );
707 else if (!strcmp( name, "__wine_call_from_16_regs" ))
709 /* special case: need to preserve all registers */
710 fprintf( outfile, " \"\\tpushl %%eax\\n\"\n" );
711 fprintf( outfile, " \"\\tpushl %%ecx\\n\"\n" );
712 fprintf( outfile, " \"\\tcall .L__wine_spec_%s\\n\"\n", name );
713 fprintf( outfile, " \".L__wine_spec_%s:\\n\"\n", name );
714 fprintf( outfile, " \"\\tpopl %%eax\\n\"\n" );
715 fprintf( outfile, " \"\\t.byte 0x2e\\n\"\n" );
716 fprintf( outfile, " \"\\tmovl %s+%d-.L__wine_spec_%s(%%eax),%%eax\\n\"\n",
717 asm_name(table), pos, name );
718 fprintf( outfile, " \"\\tmovzwl %%sp, %%ecx\\n\"\n" );
719 fprintf( outfile, " \"\\t.byte 0x36\\n\"\n" );
720 fprintf( outfile, " \"\\txchgl %%eax,4(%%ecx)\\n\"\n" );
721 fprintf( outfile, " \"\\tpopl %%ecx\\n\"\n" );
722 fprintf( outfile, " \"\\tret\\n\"\n" );
724 else
726 fprintf( outfile, " \"\\tcall .L__wine_spec_%s\\n\"\n", name );
727 fprintf( outfile, " \".L__wine_spec_%s:\\n\"\n", name );
728 fprintf( outfile, " \"\\tpopl %%eax\\n\"\n" );
729 if (strstr( name, "__wine_call_from_16" ))
730 fprintf( outfile, " \"\\t.byte 0x2e\\n\"\n" );
731 fprintf( outfile, " \"\\tjmp *%s+%d-.L__wine_spec_%s(%%eax)\\n\"\n",
732 asm_name(table), pos, name );
735 break;
736 case CPU_SPARC:
737 if ( !UsePIC )
739 fprintf( outfile, " \"\\tsethi %%hi(%s+%d), %%g1\\n\"\n", table, pos );
740 fprintf( outfile, " \"\\tld [%%g1+%%lo(%s+%d)], %%g1\\n\"\n", table, pos );
741 fprintf( outfile, " \"\\tjmp %%g1\\n\\tnop\\n\"\n" );
743 else
745 /* Hmpf. Stupid sparc assembler always interprets global variable
746 names as GOT offsets, so we have to do it the long way ... */
747 fprintf( outfile, " \"\\tsave %%sp, -96, %%sp\\n\"\n" );
748 fprintf( outfile, " \"0:\\tcall 1f\\n\\tnop\\n\"\n" );
749 fprintf( outfile, " \"1:\\tsethi %%hi(%s+%d-0b), %%g1\\n\"\n", table, pos );
750 fprintf( outfile, " \"\\tor %%g1, %%lo(%s+%d-0b), %%g1\\n\"\n", table, pos );
751 fprintf( outfile, " \"\\tld [%%g1+%%o7], %%g1\\n\"\n" );
752 fprintf( outfile, " \"\\tjmp %%g1\\n\\trestore\\n\"\n" );
754 break;
755 case CPU_ALPHA:
756 fprintf( outfile, " \"\\tlda $0,%s\\n\"\n", table );
757 fprintf( outfile, " \"\\tlda $0,%d($0)\\n\"\n", pos);
758 fprintf( outfile, " \"\\tjmp $31,($0)\\n\"\n" );
759 break;
760 case CPU_POWERPC:
761 fprintf(outfile, " \"\\taddi %s, %s, -0x4\\n\"\n", ppc_reg(1), ppc_reg(1));
762 fprintf(outfile, " \"\\tstw %s, 0(%s)\\n\"\n", ppc_reg(9), ppc_reg(1));
763 fprintf(outfile, " \"\\taddi %s, %s, -0x4\\n\"\n", ppc_reg(1), ppc_reg(1));
764 fprintf(outfile, " \"\\tstw %s, 0(%s)\\n\"\n", ppc_reg(8), ppc_reg(1));
765 fprintf(outfile, " \"\\taddi %s, %s, -0x4\\n\"\n", ppc_reg(1), ppc_reg(1));
766 fprintf(outfile, " \"\\tstw %s, 0(%s)\\n\"\n", ppc_reg(7), ppc_reg(1));
767 if (target_platform == PLATFORM_APPLE)
769 fprintf(outfile, " \"\\tlis %s, ha16(%s+%d)\\n\"\n",
770 ppc_reg(9), asm_name(table), pos);
771 fprintf(outfile, " \"\\tla %s, lo16(%s+%d)(%s)\\n\"\n",
772 ppc_reg(8), asm_name(table), pos, ppc_reg(9));
774 else
776 fprintf(outfile, " \"\\tlis %s, (%s+%d)@hi\\n\"\n",
777 ppc_reg(9), asm_name(table), pos);
778 fprintf(outfile, " \"\\tla %s, (%s+%d)@l(%s)\\n\"\n",
779 ppc_reg(8), asm_name(table), pos, ppc_reg(9));
781 fprintf(outfile, " \"\\tlwz %s, 0(%s)\\n\"\n", ppc_reg(7), ppc_reg(8));
782 fprintf(outfile, " \"\\tmtctr %s\\n\"\n", ppc_reg(7));
783 fprintf(outfile, " \"\\tlwz %s, 0(%s)\\n\"\n", ppc_reg(7), ppc_reg(1));
784 fprintf(outfile, " \"\\taddi %s, %s, 0x4\\n\"\n", ppc_reg(1), ppc_reg(1));
785 fprintf(outfile, " \"\\tlwz %s, 0(%s)\\n\"\n", ppc_reg(8), ppc_reg(1));
786 fprintf(outfile, " \"\\taddi %s, %s, 0x4\\n\"\n", ppc_reg(1), ppc_reg(1));
787 fprintf(outfile, " \"\\tlwz %s, 0(%s)\\n\"\n", ppc_reg(9), ppc_reg(1));
788 fprintf(outfile, " \"\\taddi %s, %s, 0x4\\n\"\n", ppc_reg(1), ppc_reg(1));
789 fprintf(outfile, " \"\\tbctr\\n\"\n");
790 break;
792 output_function_size( outfile, name );
795 /* output the import table of a Win32 module */
796 static int output_immediate_imports( FILE *outfile )
798 int i, j, nb_imm = nb_imports - nb_delayed;
800 if (!nb_imm) return 0;
802 /* main import header */
804 fprintf( outfile, "\nstatic struct {\n" );
805 fprintf( outfile, " struct {\n" );
806 fprintf( outfile, " void *OriginalFirstThunk;\n" );
807 fprintf( outfile, " unsigned int TimeDateStamp;\n" );
808 fprintf( outfile, " unsigned int ForwarderChain;\n" );
809 fprintf( outfile, " const char *Name;\n" );
810 fprintf( outfile, " void *FirstThunk;\n" );
811 fprintf( outfile, " } imp[%d];\n", nb_imm+1 );
812 fprintf( outfile, " const char *data[%d];\n",
813 total_imports - total_delayed + nb_imm );
814 fprintf( outfile, "} imports = {\n {\n" );
816 /* list of dlls */
818 for (i = j = 0; i < nb_imports; i++)
820 if (dll_imports[i]->delay) continue;
821 fprintf( outfile, " { 0, 0, 0, \"%s\", &imports.data[%d] },\n",
822 dll_imports[i]->spec->file_name, j );
823 j += dll_imports[i]->nb_imports + 1;
826 fprintf( outfile, " { 0, 0, 0, 0, 0 },\n" );
827 fprintf( outfile, " },\n {\n" );
829 /* list of imported functions */
831 for (i = 0; i < nb_imports; i++)
833 if (dll_imports[i]->delay) continue;
834 fprintf( outfile, " /* %s */\n", dll_imports[i]->spec->file_name );
835 for (j = 0; j < dll_imports[i]->nb_imports; j++)
837 ORDDEF *odp = dll_imports[i]->imports[j];
838 if (!(odp->flags & FLAG_NONAME))
840 unsigned short ord = odp->ordinal;
841 fprintf( outfile, " \"\\%03o\\%03o%s\",\n",
842 *(unsigned char *)&ord, *((unsigned char *)&ord + 1), odp->name );
844 else
845 fprintf( outfile, " (char *)%d,\n", odp->ordinal );
847 fprintf( outfile, " 0,\n" );
849 fprintf( outfile, " }\n};\n\n" );
851 return nb_imm;
854 /* output the import thunks of a Win32 module */
855 static void output_immediate_import_thunks( FILE *outfile )
857 int i, j, pos;
858 int nb_imm = nb_imports - nb_delayed;
859 static const char import_thunks[] = "__wine_spec_import_thunks";
861 if (!nb_imm) return;
863 pos = (sizeof(void *) + 2*sizeof(unsigned int) + sizeof(const char *) + sizeof(void *)) *
864 (nb_imm + 1); /* offset of imports.data from start of imports */
865 fprintf( outfile, "/* immediate import thunks */\n" );
866 fprintf( outfile, "asm(\".text\\n\\t.align %d\\n\"\n", get_alignment(8) );
867 fprintf( outfile, " \"%s:\\n\"\n", asm_name(import_thunks));
869 for (i = 0; i < nb_imports; i++)
871 if (dll_imports[i]->delay) continue;
872 for (j = 0; j < dll_imports[i]->nb_imports; j++, pos += sizeof(const char *))
874 ORDDEF *odp = dll_imports[i]->imports[j];
875 output_import_thunk( outfile, odp->name ? odp->name : odp->export_name,
876 "imports", pos );
878 pos += 4;
880 output_function_size( outfile, import_thunks );
881 fprintf( outfile, ");\n" );
884 /* output the delayed import table of a Win32 module */
885 static int output_delayed_imports( FILE *outfile, const DLLSPEC *spec )
887 int i, j;
889 if (!nb_delayed) return 0;
891 fprintf( outfile, "static void *__wine_delay_imp_hmod[%d];\n", nb_delayed );
892 for (i = 0; i < nb_imports; i++)
894 if (!dll_imports[i]->delay) continue;
895 for (j = 0; j < dll_imports[i]->nb_imports; j++)
897 ORDDEF *odp = dll_imports[i]->imports[j];
898 const char *name = odp->name ? odp->name : odp->export_name;
899 fprintf( outfile, "void __wine_delay_imp_%d_%s();\n", i, name );
902 fprintf( outfile, "\n" );
903 fprintf( outfile, "static struct {\n" );
904 fprintf( outfile, " struct ImgDelayDescr {\n" );
905 fprintf( outfile, " unsigned int grAttrs;\n" );
906 fprintf( outfile, " const char *szName;\n" );
907 fprintf( outfile, " void **phmod;\n" );
908 fprintf( outfile, " void **pIAT;\n" );
909 fprintf( outfile, " const char **pINT;\n" );
910 fprintf( outfile, " void* pBoundIAT;\n" );
911 fprintf( outfile, " void* pUnloadIAT;\n" );
912 fprintf( outfile, " unsigned long dwTimeStamp;\n" );
913 fprintf( outfile, " } imp[%d];\n", nb_delayed );
914 fprintf( outfile, " void *IAT[%d];\n", total_delayed );
915 fprintf( outfile, " const char *INT[%d];\n", total_delayed );
916 fprintf( outfile, "} delay_imports = {\n" );
917 fprintf( outfile, " {\n" );
918 for (i = j = 0; i < nb_imports; i++)
920 if (!dll_imports[i]->delay) continue;
921 fprintf( outfile, " { 0, \"%s\", &__wine_delay_imp_hmod[%d], &delay_imports.IAT[%d], &delay_imports.INT[%d], 0, 0, 0 },\n",
922 dll_imports[i]->spec->file_name, i, j, j );
923 j += dll_imports[i]->nb_imports;
925 fprintf( outfile, " },\n {\n" );
926 for (i = 0; i < nb_imports; i++)
928 if (!dll_imports[i]->delay) continue;
929 fprintf( outfile, " /* %s */\n", dll_imports[i]->spec->file_name );
930 for (j = 0; j < dll_imports[i]->nb_imports; j++)
932 ORDDEF *odp = dll_imports[i]->imports[j];
933 const char *name = odp->name ? odp->name : odp->export_name;
934 fprintf( outfile, " &__wine_delay_imp_%d_%s,\n", i, name );
937 fprintf( outfile, " },\n {\n" );
938 for (i = 0; i < nb_imports; i++)
940 if (!dll_imports[i]->delay) continue;
941 fprintf( outfile, " /* %s */\n", dll_imports[i]->spec->file_name );
942 for (j = 0; j < dll_imports[i]->nb_imports; j++)
944 ORDDEF *odp = dll_imports[i]->imports[j];
945 if (!odp->name)
946 fprintf( outfile, " (char *)%d,\n", odp->ordinal );
947 else
948 fprintf( outfile, " \"%s\",\n", odp->name );
951 fprintf( outfile, " }\n};\n\n" );
953 fprintf( outfile, "extern void * __stdcall LoadLibraryA(const char*);\n");
954 fprintf( outfile, "extern void * __stdcall GetProcAddress(void *, const char*);\n");
955 fprintf( outfile, "extern void * __stdcall DelayLoadFailureHook(const char *, const char*);\n");
956 fprintf( outfile, "\n" );
958 fprintf( outfile, "void *__stdcall __wine_delay_load( int idx_nr )\n" );
959 fprintf( outfile, "{\n" );
960 fprintf( outfile, " int idx = idx_nr >> 16, nr = idx_nr & 0xffff;\n" );
961 fprintf( outfile, " struct ImgDelayDescr *imd = delay_imports.imp + idx;\n" );
962 fprintf( outfile, " void **pIAT = imd->pIAT + nr;\n" );
963 fprintf( outfile, " const char** pINT = imd->pINT + nr;\n" );
964 fprintf( outfile, " void *fn;\n\n" );
966 fprintf( outfile, " if (!*imd->phmod) *imd->phmod = LoadLibraryA(imd->szName);\n" );
967 fprintf( outfile, " if (!*imd->phmod || !(fn = GetProcAddress(*imd->phmod, *pINT)))\n");
968 fprintf( outfile, " fn = DelayLoadFailureHook(imd->szName, *pINT);\n" );
969 fprintf( outfile, " /* patch IAT with final value */\n" );
970 fprintf( outfile, " return *pIAT = fn;\n" );
971 fprintf( outfile, "}\n" );
973 return nb_delayed;
976 /* output the delayed import thunks of a Win32 module */
977 static void output_delayed_import_thunks( FILE *outfile, const DLLSPEC *spec )
979 int i, idx, j, pos, extra_stack_storage = 0;
980 static const char delayed_import_loaders[] = "__wine_spec_delayed_import_loaders";
981 static const char delayed_import_thunks[] = "__wine_spec_delayed_import_thunks";
983 if (!nb_delayed) return;
985 fprintf( outfile, "/* delayed import thunks */\n" );
986 fprintf( outfile, "asm(\".text\\n\"\n" );
987 fprintf( outfile, " \"\\t.align %d\\n\"\n", get_alignment(8) );
988 fprintf( outfile, " \"%s:\\n\"\n", asm_name(delayed_import_loaders));
989 fprintf( outfile, " \"\\t%s\\n\"\n", func_declaration("__wine_delay_load_asm") );
990 fprintf( outfile, " \"%s:\\n\"\n", asm_name("__wine_delay_load_asm") );
991 switch(target_cpu)
993 case CPU_x86:
994 fprintf( outfile, " \"\\tpushl %%ecx\\n\\tpushl %%edx\\n\\tpushl %%eax\\n\"\n" );
995 fprintf( outfile, " \"\\tcall %s\\n\"\n", asm_name("__wine_delay_load") );
996 fprintf( outfile, " \"\\tpopl %%edx\\n\\tpopl %%ecx\\n\\tjmp *%%eax\\n\"\n" );
997 break;
998 case CPU_SPARC:
999 fprintf( outfile, " \"\\tsave %%sp, -96, %%sp\\n\"\n" );
1000 fprintf( outfile, " \"\\tcall %s\\n\"\n", asm_name("__wine_delay_load") );
1001 fprintf( outfile, " \"\\tmov %%g1, %%o0\\n\"\n" );
1002 fprintf( outfile, " \"\\tjmp %%o0\\n\\trestore\\n\"\n" );
1003 break;
1004 case CPU_ALPHA:
1005 fprintf( outfile, " \"\\tjsr $26,%s\\n\"\n", asm_name("__wine_delay_load") );
1006 fprintf( outfile, " \"\\tjmp $31,($0)\\n\"\n" );
1007 break;
1008 case CPU_POWERPC:
1009 if (target_platform == PLATFORM_APPLE) extra_stack_storage = 56;
1011 /* Save all callee saved registers into a stackframe. */
1012 fprintf( outfile, " \"\\tstwu %s, -%d(%s)\\n\"\n",ppc_reg(1), 48+extra_stack_storage, ppc_reg(1));
1013 fprintf( outfile, " \"\\tstw %s, %d(%s)\\n\"\n", ppc_reg(3), 4+extra_stack_storage, ppc_reg(1));
1014 fprintf( outfile, " \"\\tstw %s, %d(%s)\\n\"\n", ppc_reg(4), 8+extra_stack_storage, ppc_reg(1));
1015 fprintf( outfile, " \"\\tstw %s, %d(%s)\\n\"\n", ppc_reg(5), 12+extra_stack_storage, ppc_reg(1));
1016 fprintf( outfile, " \"\\tstw %s, %d(%s)\\n\"\n", ppc_reg(6), 16+extra_stack_storage, ppc_reg(1));
1017 fprintf( outfile, " \"\\tstw %s, %d(%s)\\n\"\n", ppc_reg(7), 20+extra_stack_storage, ppc_reg(1));
1018 fprintf( outfile, " \"\\tstw %s, %d(%s)\\n\"\n", ppc_reg(8), 24+extra_stack_storage, ppc_reg(1));
1019 fprintf( outfile, " \"\\tstw %s, %d(%s)\\n\"\n", ppc_reg(9), 28+extra_stack_storage, ppc_reg(1));
1020 fprintf( outfile, " \"\\tstw %s, %d(%s)\\n\"\n", ppc_reg(10),32+extra_stack_storage, ppc_reg(1));
1021 fprintf( outfile, " \"\\tstw %s, %d(%s)\\n\"\n", ppc_reg(11),36+extra_stack_storage, ppc_reg(1));
1022 fprintf( outfile, " \"\\tstw %s, %d(%s)\\n\"\n", ppc_reg(12),40+extra_stack_storage, ppc_reg(1));
1024 /* r0 -> r3 (arg1) */
1025 fprintf( outfile, " \"\\tmr %s, %s\\n\"\n", ppc_reg(3), ppc_reg(0));
1027 /* save return address */
1028 fprintf( outfile, " \"\\tmflr %s\\n\"\n", ppc_reg(0));
1029 fprintf( outfile, " \"\\tstw %s, %d(%s)\\n\"\n", ppc_reg(0), 44+extra_stack_storage, ppc_reg(1));
1031 /* Call the __wine_delay_load function, arg1 is arg1. */
1032 fprintf( outfile, " \"\\tbl %s\\n\"\n", asm_name("__wine_delay_load") );
1034 /* Load return value from call into ctr register */
1035 fprintf( outfile, " \"\\tmtctr %s\\n\"\n", ppc_reg(3));
1037 /* restore all saved registers and drop stackframe. */
1038 fprintf( outfile, " \"\\tlwz %s, %d(%s)\\n\"\n", ppc_reg(3), 4+extra_stack_storage, ppc_reg(1));
1039 fprintf( outfile, " \"\\tlwz %s, %d(%s)\\n\"\n", ppc_reg(4), 8+extra_stack_storage, ppc_reg(1));
1040 fprintf( outfile, " \"\\tlwz %s, %d(%s)\\n\"\n", ppc_reg(5), 12+extra_stack_storage, ppc_reg(1));
1041 fprintf( outfile, " \"\\tlwz %s, %d(%s)\\n\"\n", ppc_reg(6), 16+extra_stack_storage, ppc_reg(1));
1042 fprintf( outfile, " \"\\tlwz %s, %d(%s)\\n\"\n", ppc_reg(7), 20+extra_stack_storage, ppc_reg(1));
1043 fprintf( outfile, " \"\\tlwz %s, %d(%s)\\n\"\n", ppc_reg(8), 24+extra_stack_storage, ppc_reg(1));
1044 fprintf( outfile, " \"\\tlwz %s, %d(%s)\\n\"\n", ppc_reg(9), 28+extra_stack_storage, ppc_reg(1));
1045 fprintf( outfile, " \"\\tlwz %s, %d(%s)\\n\"\n", ppc_reg(10),32+extra_stack_storage, ppc_reg(1));
1046 fprintf( outfile, " \"\\tlwz %s, %d(%s)\\n\"\n", ppc_reg(11),36+extra_stack_storage, ppc_reg(1));
1047 fprintf( outfile, " \"\\tlwz %s, %d(%s)\\n\"\n", ppc_reg(12),40+extra_stack_storage, ppc_reg(1));
1049 /* Load return value from call into return register */
1050 fprintf( outfile, " \"\\tlwz %s, %d(%s)\\n\"\n", ppc_reg(0), 44+extra_stack_storage, ppc_reg(1));
1051 fprintf( outfile, " \"\\tmtlr %s\\n\"\n", ppc_reg(0));
1052 fprintf( outfile, " \"\\taddi %s, %s, %d\\n\"\n", ppc_reg(1), ppc_reg(1), 48+extra_stack_storage);
1054 /* branch to ctr register. */
1055 fprintf( outfile, " \"bctr\\n\"\n");
1056 break;
1058 output_function_size( outfile, "__wine_delay_load_asm" );
1060 for (i = idx = 0; i < nb_imports; i++)
1062 if (!dll_imports[i]->delay) continue;
1063 for (j = 0; j < dll_imports[i]->nb_imports; j++)
1065 char buffer[128];
1066 ORDDEF *odp = dll_imports[i]->imports[j];
1067 const char *name = odp->name ? odp->name : odp->export_name;
1069 sprintf( buffer, "__wine_delay_imp_%d_%s", i, name );
1070 fprintf( outfile, " \"\\t%s\\n\"\n", func_declaration(buffer) );
1071 fprintf( outfile, " \"%s:\\n\"\n", asm_name(buffer) );
1072 switch(target_cpu)
1074 case CPU_x86:
1075 fprintf( outfile, " \"\\tmovl $%d, %%eax\\n\"\n", (idx << 16) | j );
1076 fprintf( outfile, " \"\\tjmp %s\\n\"\n", asm_name("__wine_delay_load_asm") );
1077 break;
1078 case CPU_SPARC:
1079 fprintf( outfile, " \"\\tset %d, %%g1\\n\"\n", (idx << 16) | j );
1080 fprintf( outfile, " \"\\tb,a %s\\n\"\n", asm_name("__wine_delay_load_asm") );
1081 break;
1082 case CPU_ALPHA:
1083 fprintf( outfile, " \"\\tlda $0,%d($31)\\n\"\n", j);
1084 fprintf( outfile, " \"\\tldah $0,%d($0)\\n\"\n", idx);
1085 fprintf( outfile, " \"\\tjmp $31,%s\\n\"\n", asm_name("__wine_delay_load_asm") );
1086 break;
1087 case CPU_POWERPC:
1088 switch(target_platform)
1090 case PLATFORM_APPLE:
1091 /* On Darwin we can use r0 and r2 */
1092 /* Upper part in r2 */
1093 fprintf( outfile, " \"\\tlis %s, %d\\n\"\n", ppc_reg(2), idx);
1094 /* Lower part + r2 -> r0, Note we can't use r0 directly */
1095 fprintf( outfile, " \"\\taddi %s, %s, %d\\n\"\n", ppc_reg(0), ppc_reg(2), j);
1096 fprintf( outfile, " \"\\tb %s\\n\"\n", asm_name("__wine_delay_load_asm") );
1097 break;
1098 default:
1099 /* On linux we can't use r2 since r2 is not a scratch register (hold the TOC) */
1100 /* Save r13 on the stack */
1101 fprintf( outfile, " \"\\taddi %s, %s, -0x4\\n\"\n", ppc_reg(1), ppc_reg(1));
1102 fprintf( outfile, " \"\\tstw %s, 0(%s)\\n\"\n", ppc_reg(13), ppc_reg(1));
1103 /* Upper part in r13 */
1104 fprintf( outfile, " \"\\tlis %s, %d\\n\"\n", ppc_reg(13), idx);
1105 /* Lower part + r13 -> r0, Note we can't use r0 directly */
1106 fprintf( outfile, " \"\\taddi %s, %s, %d\\n\"\n", ppc_reg(0), ppc_reg(13), j);
1107 /* Restore r13 */
1108 fprintf( outfile, " \"\\tstw %s, 0(%s)\\n\"\n", ppc_reg(13), ppc_reg(1));
1109 fprintf( outfile, " \"\\taddic %s, %s, 0x4\\n\"\n", ppc_reg(1), ppc_reg(1));
1110 fprintf( outfile, " \"\\tb %s\\n\"\n", asm_name("__wine_delay_load_asm") );
1111 break;
1113 break;
1115 output_function_size( outfile, name );
1117 idx++;
1119 output_function_size( outfile, delayed_import_loaders );
1121 fprintf( outfile, "\n \".align %d\\n\"\n", get_alignment(8) );
1122 fprintf( outfile, " \"%s:\\n\"\n", asm_name(delayed_import_thunks));
1123 pos = nb_delayed * 32;
1124 for (i = 0; i < nb_imports; i++)
1126 if (!dll_imports[i]->delay) continue;
1127 for (j = 0; j < dll_imports[i]->nb_imports; j++, pos += 4)
1129 ORDDEF *odp = dll_imports[i]->imports[j];
1130 output_import_thunk( outfile, odp->name ? odp->name : odp->export_name,
1131 "delay_imports", pos );
1134 output_function_size( outfile, delayed_import_thunks );
1135 fprintf( outfile, ");\n" );
1138 /* output the import and delayed import tables of a Win32 module
1139 * returns number of DLLs exported in 'immediate' mode
1141 int output_imports( FILE *outfile, DLLSPEC *spec, int *nb_delayed )
1143 *nb_delayed = output_delayed_imports( outfile, spec );
1144 return output_immediate_imports( outfile );
1147 /* output the import and delayed import thunks of a Win32 module */
1148 void output_import_thunks( FILE *outfile, DLLSPEC *spec )
1150 output_delayed_import_thunks( outfile, spec );
1151 output_immediate_import_thunks( outfile );