iphlpapi: Clean up memory allocation.
[wine/wine64.git] / tools / winebuild / import.c
blobd97d58d4494e66e99b81b43847f4c4ad355351db
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 */
65 static struct name_table ext_link_imports; /* list of external symbols to link to */
67 static struct import **dll_imports = NULL;
68 static int nb_imports = 0; /* number of imported dlls (delayed or not) */
69 static int nb_delayed = 0; /* number of delayed dlls */
70 static int total_imports = 0; /* total number of imported functions */
71 static int total_delayed = 0; /* total number of imported functions in delayed DLLs */
73 /* list of symbols that are ignored by default */
74 static const char * const default_ignored_symbols[] =
76 "abs",
77 "acos",
78 "asin",
79 "atan",
80 "atan2",
81 "atoi",
82 "atol",
83 "bsearch",
84 "ceil",
85 "cos",
86 "cosh",
87 "exp",
88 "fabs",
89 "floor",
90 "fmod",
91 "frexp",
92 "labs",
93 "log",
94 "log10",
95 "memchr",
96 "memcmp",
97 "memcpy",
98 "memmove",
99 "memset",
100 "modf",
101 "pow",
102 "qsort",
103 "sin",
104 "sinh",
105 "sqrt",
106 "strcat",
107 "strchr",
108 "strcmp",
109 "strcpy",
110 "strcspn",
111 "strlen",
112 "strncat",
113 "strncmp",
114 "strncpy",
115 "strpbrk",
116 "strrchr",
117 "strspn",
118 "strstr",
119 "tan",
120 "tanh"
124 static inline const char *ppc_reg( int reg )
126 static const char * const ppc_regs[32] = { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
127 "r8", "r9", "r10","r11","r12","r13","r14","r15",
128 "r16","r17","r18","r19","r20","r21","r22","r23",
129 "r24","r25","r26","r27","r28","r29","r30","r31" };
130 if (target_platform == PLATFORM_APPLE) return ppc_regs[reg];
131 return ppc_regs[reg] + 1; /* skip the 'r' */
134 /* compare function names; helper for resolve_imports */
135 static int name_cmp( const void *name, const void *entry )
137 return strcmp( *(const char* const *)name, *(const char* const *)entry );
140 /* compare function names; helper for resolve_imports */
141 static int func_cmp( const void *func1, const void *func2 )
143 const ORDDEF *odp1 = *(const ORDDEF * const *)func1;
144 const ORDDEF *odp2 = *(const ORDDEF * const *)func2;
145 return strcmp( odp1->name ? odp1->name : odp1->export_name,
146 odp2->name ? odp2->name : odp2->export_name );
149 /* add a name to a name table */
150 inline static void add_name( struct name_table *table, const char *name )
152 if (table->count == table->size)
154 table->size += (table->size / 2);
155 if (table->size < 32) table->size = 32;
156 table->names = xrealloc( table->names, table->size * sizeof(*table->names) );
158 table->names[table->count++] = xstrdup( name );
161 /* remove a name from a name table */
162 inline static void remove_name( struct name_table *table, unsigned int idx )
164 assert( idx < table->count );
165 free( table->names[idx] );
166 memmove( table->names + idx, table->names + idx + 1,
167 (table->count - idx - 1) * sizeof(*table->names) );
168 table->count--;
171 /* make a name table empty */
172 inline static void empty_name_table( struct name_table *table )
174 unsigned int i;
176 for (i = 0; i < table->count; i++) free( table->names[i] );
177 table->count = 0;
180 /* locate a name in a (sorted) list */
181 inline static const char *find_name( const char *name, const struct name_table *table )
183 char **res = NULL;
185 if (table->count) res = bsearch( &name, table->names, table->count, sizeof(*table->names), name_cmp );
186 return res ? *res : NULL;
189 /* sort a name table */
190 inline static void sort_names( struct name_table *table )
192 if (table->count) qsort( table->names, table->count, sizeof(*table->names), name_cmp );
195 /* locate an export in a (sorted) export list */
196 inline static ORDDEF *find_export( const char *name, ORDDEF **table, int size )
198 ORDDEF func, *odp, **res = NULL;
200 func.name = (char *)name;
201 func.ordinal = -1;
202 odp = &func;
203 if (table) res = bsearch( &odp, table, size, sizeof(*table), func_cmp );
204 return res ? *res : NULL;
207 /* free an import structure */
208 static void free_imports( struct import *imp )
210 free( imp->exports );
211 free( imp->imports );
212 free_dll_spec( imp->spec );
213 free( imp->full_name );
214 free( imp );
217 /* check whether a given dll is imported in delayed mode */
218 static int is_delayed_import( const char *name )
220 int i;
222 for (i = 0; i < delayed_imports.count; i++)
224 if (!strcmp( delayed_imports.names[i], name )) return 1;
226 return 0;
229 /* check whether a given dll has already been imported */
230 static struct import *is_already_imported( const char *name )
232 int i;
234 for (i = 0; i < nb_imports; i++)
236 if (!strcmp( dll_imports[i]->spec->file_name, name )) return dll_imports[i];
238 return NULL;
241 /* open the .so library for a given dll in a specified path */
242 static char *try_library_path( const char *path, const char *name )
244 char *buffer;
245 int fd;
247 buffer = xmalloc( strlen(path) + strlen(name) + 9 );
248 sprintf( buffer, "%s/lib%s.def", path, name );
250 /* check if the file exists */
251 if ((fd = open( buffer, O_RDONLY )) != -1)
253 close( fd );
254 return buffer;
256 free( buffer );
257 return NULL;
260 /* find the .def import library for a given dll */
261 static char *find_library( const char *name )
263 char *fullname;
264 int i;
266 for (i = 0; i < nb_lib_paths; i++)
268 if ((fullname = try_library_path( lib_path[i], name ))) return fullname;
270 fatal_error( "could not open .def file for %s\n", name );
271 return NULL;
274 /* read in the list of exported symbols of an import library */
275 static int read_import_lib( struct import *imp )
277 FILE *f;
278 int i, ret;
279 struct stat stat;
280 struct import *prev_imp;
281 DLLSPEC *spec = imp->spec;
283 f = open_input_file( NULL, imp->full_name );
284 fstat( fileno(f), &stat );
285 imp->dev = stat.st_dev;
286 imp->ino = stat.st_ino;
287 ret = parse_def_file( f, spec );
288 close_input_file( f );
289 if (!ret) return 0;
291 /* check if we already imported that library from a different file */
292 if ((prev_imp = is_already_imported( spec->file_name )))
294 if (prev_imp->dev != imp->dev || prev_imp->ino != imp->ino)
295 fatal_error( "%s and %s have the same export name '%s'\n",
296 prev_imp->full_name, imp->full_name, spec->file_name );
297 return 0; /* the same file was already loaded, ignore this one */
300 if (is_delayed_import( spec->file_name ))
302 imp->delay = 1;
303 nb_delayed++;
306 imp->exports = xmalloc( spec->nb_entry_points * sizeof(*imp->exports) );
308 for (i = 0; i < spec->nb_entry_points; i++)
310 ORDDEF *odp = &spec->entry_points[i];
312 if (odp->type != TYPE_STDCALL && odp->type != TYPE_CDECL) continue;
313 if (odp->flags & FLAG_PRIVATE) continue;
314 imp->exports[imp->nb_exports++] = odp;
316 imp->exports = xrealloc( imp->exports, imp->nb_exports * sizeof(*imp->exports) );
317 if (imp->nb_exports)
318 qsort( imp->exports, imp->nb_exports, sizeof(*imp->exports), func_cmp );
319 return 1;
322 /* build the dll exported name from the import lib name or path */
323 static char *get_dll_name( const char *name, const char *filename )
325 char *ret;
327 if (filename)
329 const char *basename = strrchr( filename, '/' );
330 if (!basename) basename = filename;
331 else basename++;
332 if (!strncmp( basename, "lib", 3 )) basename += 3;
333 ret = xmalloc( strlen(basename) + 5 );
334 strcpy( ret, basename );
335 if (strendswith( ret, ".def" )) ret[strlen(ret)-4] = 0;
337 else
339 ret = xmalloc( strlen(name) + 5 );
340 strcpy( ret, name );
342 if (!strchr( ret, '.' )) strcat( ret, ".dll" );
343 return ret;
346 /* add a dll to the list of imports */
347 void add_import_dll( const char *name, const char *filename )
349 struct import *imp = xmalloc( sizeof(*imp) );
351 imp->spec = alloc_dll_spec();
352 imp->spec->file_name = get_dll_name( name, filename );
353 imp->delay = 0;
354 imp->imports = NULL;
355 imp->nb_imports = 0;
356 imp->exports = NULL;
357 imp->nb_exports = 0;
359 if (filename) imp->full_name = xstrdup( filename );
360 else imp->full_name = find_library( name );
362 if (read_import_lib( imp ))
364 dll_imports = xrealloc( dll_imports, (nb_imports+1) * sizeof(*dll_imports) );
365 dll_imports[nb_imports++] = imp;
367 else
369 free_imports( imp );
370 if (nb_errors) exit(1);
374 /* add a library to the list of delayed imports */
375 void add_delayed_import( const char *name )
377 struct import *imp;
378 char *fullname = get_dll_name( name, NULL );
380 add_name( &delayed_imports, fullname );
381 if ((imp = is_already_imported( fullname )) && !imp->delay)
383 imp->delay = 1;
384 nb_delayed++;
386 free( fullname );
389 /* remove an imported dll, based on its index in the dll_imports array */
390 static void remove_import_dll( int index )
392 struct import *imp = dll_imports[index];
394 memmove( &dll_imports[index], &dll_imports[index+1], sizeof(imp) * (nb_imports - index - 1) );
395 nb_imports--;
396 if (imp->delay) nb_delayed--;
397 free_imports( imp );
400 /* initialize the list of ignored symbols */
401 static void init_ignored_symbols(void)
403 unsigned int i;
405 for (i = 0; i < sizeof(default_ignored_symbols)/sizeof(default_ignored_symbols[0]); i++)
406 add_name( &ignore_symbols, default_ignored_symbols[i] );
409 /* add a symbol to the ignored symbol list */
410 /* if the name starts with '-' the symbol is removed instead */
411 void add_ignore_symbol( const char *name )
413 unsigned int i;
415 if (!ignore_symbols.size) init_ignored_symbols(); /* first time around, fill list with defaults */
417 if (name[0] == '-') /* remove it */
419 if (!name[1]) empty_name_table( &ignore_symbols ); /* remove everything */
420 else for (i = 0; i < ignore_symbols.count; i++)
422 if (!strcmp( ignore_symbols.names[i], name+1 )) remove_name( &ignore_symbols, i-- );
425 else add_name( &ignore_symbols, name );
428 /* add a symbol to the list of extra symbols that ld must resolve */
429 void add_extra_ld_symbol( const char *name )
431 add_name( &extra_ld_symbols, name );
434 /* add a function to the list of imports from a given dll */
435 static void add_import_func( struct import *imp, ORDDEF *func )
437 imp->imports = xrealloc( imp->imports, (imp->nb_imports+1) * sizeof(*imp->imports) );
438 imp->imports[imp->nb_imports++] = func;
439 total_imports++;
440 if (imp->delay) total_delayed++;
443 /* get the default entry point for a given spec file */
444 static const char *get_default_entry_point( const DLLSPEC *spec )
446 if (spec->characteristics & IMAGE_FILE_DLL) return "__wine_spec_dll_entry";
447 if (spec->subsystem == IMAGE_SUBSYSTEM_NATIVE) return "__wine_spec_drv_entry";
448 return "__wine_spec_exe_entry";
451 /* check if the spec file exports any stubs */
452 static int has_stubs( const DLLSPEC *spec )
454 int i;
455 for (i = 0; i < spec->nb_entry_points; i++)
457 ORDDEF *odp = &spec->entry_points[i];
458 if (odp->type == TYPE_STUB) return 1;
460 return 0;
463 /* add the extra undefined symbols that will be contained in the generated spec file itself */
464 static void add_extra_undef_symbols( DLLSPEC *spec )
466 if (!spec->init_func) spec->init_func = xstrdup( get_default_entry_point(spec) );
467 add_extra_ld_symbol( spec->init_func );
468 if (has_stubs( spec )) add_extra_ld_symbol( "__wine_spec_unimplemented_stub" );
469 if (nb_delayed) add_extra_ld_symbol( "__wine_spec_delay_load" );
472 /* check if a given imported dll is not needed, taking forwards into account */
473 static int check_unused( const struct import* imp, const DLLSPEC *spec )
475 int i;
476 const char *file_name = imp->spec->file_name;
477 size_t len = strlen( file_name );
478 const char *p = strchr( file_name, '.' );
479 if (p && !strcasecmp( p, ".dll" )) len = p - file_name;
481 for (i = spec->base; i <= spec->limit; i++)
483 ORDDEF *odp = spec->ordinals[i];
484 if (!odp || !(odp->flags & FLAG_FORWARD)) continue;
485 if (!strncasecmp( odp->link_name, file_name, len ) &&
486 odp->link_name[len] == '.')
487 return 0; /* found a forward, it is used */
489 return 1;
492 /* flag the dll exports that link to an undefined symbol */
493 static void check_undefined_exports( DLLSPEC *spec )
495 int i;
497 for (i = 0; i < spec->nb_entry_points; i++)
499 ORDDEF *odp = &spec->entry_points[i];
500 if (odp->type == TYPE_STUB) continue;
501 if (odp->flags & FLAG_FORWARD) continue;
502 if (find_name( odp->link_name, &undef_symbols ))
504 odp->flags |= FLAG_EXT_LINK;
505 add_name( &ext_link_imports, odp->link_name );
510 /* create a .o file that references all the undefined symbols we want to resolve */
511 static char *create_undef_symbols_file( DLLSPEC *spec )
513 char *as_file, *obj_file;
514 unsigned int i;
515 FILE *f;
517 as_file = get_temp_file_name( output_file_name, ".s" );
518 if (!(f = fopen( as_file, "w" ))) fatal_error( "Cannot create %s\n", as_file );
519 fprintf( f, "\t.data\n" );
521 for (i = 0; i < spec->nb_entry_points; i++)
523 ORDDEF *odp = &spec->entry_points[i];
524 if (odp->type == TYPE_STUB) continue;
525 if (odp->flags & FLAG_FORWARD) continue;
526 fprintf( f, "\t%s %s\n", get_asm_ptr_keyword(), asm_name(odp->link_name) );
528 for (i = 0; i < extra_ld_symbols.count; i++)
529 fprintf( f, "\t%s %s\n", get_asm_ptr_keyword(), asm_name(extra_ld_symbols.names[i]) );
530 fclose( f );
532 obj_file = get_temp_file_name( output_file_name, ".o" );
533 assemble_file( as_file, obj_file );
534 return obj_file;
537 /* combine a list of object files with ld into a single object file */
538 /* returns the name of the combined file */
539 static const char *ldcombine_files( DLLSPEC *spec, char **argv )
541 unsigned int i, len = 0;
542 char *cmd, *p, *ld_tmp_file, *undef_file;
543 int err;
545 undef_file = create_undef_symbols_file( spec );
546 len += strlen(undef_file) + 1;
547 ld_tmp_file = get_temp_file_name( output_file_name, ".o" );
548 if (!ld_command) ld_command = xstrdup("ld");
549 for (i = 0; argv[i]; i++) len += strlen(argv[i]) + 1;
550 cmd = p = xmalloc( len + strlen(ld_tmp_file) + 8 + strlen(ld_command) );
551 p += sprintf( cmd, "%s -r -o %s %s", ld_command, ld_tmp_file, undef_file );
552 for (i = 0; argv[i]; i++)
553 p += sprintf( p, " %s", argv[i] );
554 if (verbose) fprintf( stderr, "%s\n", cmd );
555 err = system( cmd );
556 if (err) fatal_error( "%s -r failed with status %d\n", ld_command, err );
557 free( cmd );
558 return ld_tmp_file;
561 /* read in the list of undefined symbols */
562 void read_undef_symbols( DLLSPEC *spec, char **argv )
564 size_t prefix_len;
565 FILE *f;
566 char *cmd, buffer[1024], name_prefix[16];
567 int err;
568 const char *name;
570 if (!argv[0]) return;
572 add_extra_undef_symbols( spec );
574 strcpy( name_prefix, asm_name("") );
575 prefix_len = strlen( name_prefix );
577 name = ldcombine_files( spec, argv );
579 if (!nm_command) nm_command = xstrdup("nm");
580 cmd = xmalloc( strlen(nm_command) + strlen(name) + 5 );
581 sprintf( cmd, "%s -u %s", nm_command, name );
582 if (!(f = popen( cmd, "r" )))
583 fatal_error( "Cannot execute '%s'\n", cmd );
585 while (fgets( buffer, sizeof(buffer), f ))
587 char *p = buffer + strlen(buffer) - 1;
588 if (p < buffer) continue;
589 if (*p == '\n') *p-- = 0;
590 p = buffer;
591 while (*p == ' ') p++;
592 if (p[0] == 'U' && p[1] == ' ' && p[2]) p += 2;
593 if (prefix_len && !strncmp( p, name_prefix, prefix_len )) p += prefix_len;
594 add_name( &undef_symbols, p );
596 if ((err = pclose( f ))) warning( "%s failed with status %d\n", cmd, err );
597 free( cmd );
600 /* resolve the imports for a Win32 module */
601 int resolve_imports( DLLSPEC *spec )
603 unsigned int i, j, removed;
604 ORDDEF *odp;
606 if (!ignore_symbols.size) init_ignored_symbols();
607 sort_names( &ignore_symbols );
609 for (i = 0; i < nb_imports; i++)
611 struct import *imp = dll_imports[i];
613 for (j = removed = 0; j < undef_symbols.count; j++)
615 if (find_name( undef_symbols.names[j], &ignore_symbols )) continue;
616 odp = find_export( undef_symbols.names[j], imp->exports, imp->nb_exports );
617 if (odp)
619 add_import_func( imp, odp );
620 remove_name( &undef_symbols, j-- );
621 removed++;
624 if (!removed && check_unused( imp, spec ))
626 /* the dll is not used, get rid of it */
627 warning( "%s imported but no symbols used\n", imp->spec->file_name );
628 remove_import_dll( i );
629 i--;
633 sort_names( &undef_symbols );
634 check_undefined_exports( spec );
636 return 1;
639 /* output the get_pc thunk if needed */
640 void output_get_pc_thunk( FILE *outfile )
642 if (target_cpu != CPU_x86) return;
643 if (!UsePIC) return;
644 fprintf( outfile, "\n\t.text\n" );
645 fprintf( outfile, "\t.align %d\n", get_alignment(4) );
646 fprintf( outfile, "\t%s\n", func_declaration("__wine_spec_get_pc_thunk_eax") );
647 fprintf( outfile, "%s:\n", asm_name("__wine_spec_get_pc_thunk_eax") );
648 fprintf( outfile, "\tpopl %%eax\n" );
649 fprintf( outfile, "\tpushl %%eax\n" );
650 fprintf( outfile, "\tret\n" );
651 output_function_size( outfile, "__wine_spec_get_pc_thunk_eax" );
654 /* output a single import thunk */
655 static void output_import_thunk( FILE *outfile, const char *name, const char *table, int pos )
657 fprintf( outfile, "\n\t.align %d\n", get_alignment(4) );
658 fprintf( outfile, "\t%s\n", func_declaration(name) );
659 fprintf( outfile, "%s\n", asm_globl(name) );
661 switch(target_cpu)
663 case CPU_x86:
664 if (!UsePIC)
666 fprintf( outfile, "\tjmp *(%s+%d)\n", table, pos );
668 else
670 fprintf( outfile, "\tcall %s\n", asm_name("__wine_spec_get_pc_thunk_eax") );
671 fprintf( outfile, "1:\tjmp *%s+%d-1b(%%eax)\n", table, pos );
673 break;
674 case CPU_x86_64:
675 fprintf( outfile, "\tjmpq *%s+%d(%%rip)\n", table, pos );
676 break;
677 case CPU_SPARC:
678 if ( !UsePIC )
680 fprintf( outfile, "\tsethi %%hi(%s+%d), %%g1\n", table, pos );
681 fprintf( outfile, "\tld [%%g1+%%lo(%s+%d)], %%g1\n", table, pos );
682 fprintf( outfile, "\tjmp %%g1\n" );
683 fprintf( outfile, "\tnop\n" );
685 else
687 /* Hmpf. Stupid sparc assembler always interprets global variable
688 names as GOT offsets, so we have to do it the long way ... */
689 fprintf( outfile, "\tsave %%sp, -96, %%sp\n" );
690 fprintf( outfile, "0:\tcall 1f\n" );
691 fprintf( outfile, "\tnop\n" );
692 fprintf( outfile, "1:\tsethi %%hi(%s+%d-0b), %%g1\n", table, pos );
693 fprintf( outfile, "\tor %%g1, %%lo(%s+%d-0b), %%g1\n", table, pos );
694 fprintf( outfile, "\tld [%%g1+%%o7], %%g1\n" );
695 fprintf( outfile, "\tjmp %%g1\n" );
696 fprintf( outfile, "\trestore\n" );
698 break;
699 case CPU_ALPHA:
700 fprintf( outfile, "\tlda $0,%s\n", table );
701 fprintf( outfile, "\tlda $0,%d($0)\n", pos );
702 fprintf( outfile, "\tjmp $31,($0)\n" );
703 break;
704 case CPU_POWERPC:
705 fprintf( outfile, "\taddi %s, %s, -0x4\n", ppc_reg(1), ppc_reg(1) );
706 fprintf( outfile, "\tstw %s, 0(%s)\n", ppc_reg(9), ppc_reg(1) );
707 fprintf( outfile, "\taddi %s, %s, -0x4\n", ppc_reg(1), ppc_reg(1) );
708 fprintf( outfile, "\tstw %s, 0(%s)\n", ppc_reg(8), ppc_reg(1) );
709 fprintf( outfile, "\taddi %s, %s, -0x4\n", ppc_reg(1), ppc_reg(1) );
710 fprintf( outfile, "\tstw %s, 0(%s)\n", ppc_reg(7), ppc_reg(1) );
711 if (target_platform == PLATFORM_APPLE)
713 fprintf( outfile, "\tlis %s, ha16(%s+%d)\n", ppc_reg(9), table, pos );
714 fprintf( outfile, "\tla %s, lo16(%s+%d)(%s)\n", ppc_reg(8), table, pos, ppc_reg(9) );
716 else
718 fprintf( outfile, "\tlis %s, (%s+%d)@h\n", ppc_reg(9), table, pos );
719 fprintf( outfile, "\tla %s, (%s+%d)@l(%s)\n", ppc_reg(8), table, pos, ppc_reg(9) );
721 fprintf( outfile, "\tlwz %s, 0(%s)\n", ppc_reg(7), ppc_reg(8) );
722 fprintf( outfile, "\tmtctr %s\n", ppc_reg(7) );
723 fprintf( outfile, "\tlwz %s, 0(%s)\n", ppc_reg(7), ppc_reg(1) );
724 fprintf( outfile, "\taddi %s, %s, 0x4\n", ppc_reg(1), ppc_reg(1) );
725 fprintf( outfile, "\tlwz %s, 0(%s)\n", ppc_reg(8), ppc_reg(1) );
726 fprintf( outfile, "\taddi %s, %s, 0x4\n", ppc_reg(1), ppc_reg(1) );
727 fprintf( outfile, "\tlwz %s, 0(%s)\n", ppc_reg(9), ppc_reg(1) );
728 fprintf( outfile, "\taddi %s, %s, 0x4\n", ppc_reg(1), ppc_reg(1) );
729 fprintf( outfile, "\tbctr\n" );
730 break;
732 output_function_size( outfile, name );
735 /* check if we need an import directory */
736 int has_imports(void)
738 return (nb_imports - nb_delayed) > 0;
741 /* output the import table of a Win32 module */
742 static void output_immediate_imports( FILE *outfile )
744 int i, j;
745 const char *dll_name;
747 if (nb_imports == nb_delayed) return; /* no immediate imports */
749 /* main import header */
751 fprintf( outfile, "\n/* import table */\n" );
752 fprintf( outfile, "\n\t.data\n" );
753 fprintf( outfile, "\t.align %d\n", get_alignment(4) );
754 fprintf( outfile, ".L__wine_spec_imports:\n" );
756 /* list of dlls */
758 for (i = j = 0; i < nb_imports; i++)
760 if (dll_imports[i]->delay) continue;
761 dll_name = make_c_identifier( dll_imports[i]->spec->file_name );
762 fprintf( outfile, "\t.long 0\n" ); /* OriginalFirstThunk */
763 fprintf( outfile, "\t.long 0\n" ); /* TimeDateStamp */
764 fprintf( outfile, "\t.long 0\n" ); /* ForwarderChain */
765 fprintf( outfile, "\t.long .L__wine_spec_import_name_%s-.L__wine_spec_rva_base\n", /* Name */
766 dll_name );
767 fprintf( outfile, "\t.long .L__wine_spec_import_data_ptrs+%d-.L__wine_spec_rva_base\n", /* FirstThunk */
768 j * get_ptr_size() );
769 j += dll_imports[i]->nb_imports + 1;
771 fprintf( outfile, "\t.long 0\n" ); /* OriginalFirstThunk */
772 fprintf( outfile, "\t.long 0\n" ); /* TimeDateStamp */
773 fprintf( outfile, "\t.long 0\n" ); /* ForwarderChain */
774 fprintf( outfile, "\t.long 0\n" ); /* Name */
775 fprintf( outfile, "\t.long 0\n" ); /* FirstThunk */
777 fprintf( outfile, "\n\t.align %d\n", get_alignment(get_ptr_size()) );
778 fprintf( outfile, ".L__wine_spec_import_data_ptrs:\n" );
779 for (i = 0; i < nb_imports; i++)
781 if (dll_imports[i]->delay) continue;
782 dll_name = make_c_identifier( dll_imports[i]->spec->file_name );
783 for (j = 0; j < dll_imports[i]->nb_imports; j++)
785 ORDDEF *odp = dll_imports[i]->imports[j];
786 if (!(odp->flags & FLAG_NONAME))
787 fprintf( outfile, "\t%s .L__wine_spec_import_data_%s_%s-.L__wine_spec_rva_base\n",
788 get_asm_ptr_keyword(), dll_name, odp->name );
789 else
791 if (get_ptr_size() == 8)
792 fprintf( outfile, "\t.quad 0x800000000000%04x\n", odp->ordinal );
793 else
794 fprintf( outfile, "\t.long 0x8000%04x\n", odp->ordinal );
797 fprintf( outfile, "\t%s 0\n", get_asm_ptr_keyword() );
799 fprintf( outfile, ".L__wine_spec_imports_end:\n" );
801 for (i = 0; i < nb_imports; i++)
803 if (dll_imports[i]->delay) continue;
804 dll_name = make_c_identifier( dll_imports[i]->spec->file_name );
805 for (j = 0; j < dll_imports[i]->nb_imports; j++)
807 ORDDEF *odp = dll_imports[i]->imports[j];
808 if (!(odp->flags & FLAG_NONAME))
810 fprintf( outfile, "\t.align %d\n", get_alignment(2) );
811 fprintf( outfile, ".L__wine_spec_import_data_%s_%s:\n", dll_name, odp->name );
812 fprintf( outfile, "\t%s %d\n", get_asm_short_keyword(), odp->ordinal );
813 fprintf( outfile, "\t%s \"%s\"\n", get_asm_string_keyword(), odp->name );
818 for (i = 0; i < nb_imports; i++)
820 if (dll_imports[i]->delay) continue;
821 dll_name = make_c_identifier( dll_imports[i]->spec->file_name );
822 fprintf( outfile, ".L__wine_spec_import_name_%s:\n\t%s \"%s\"\n",
823 dll_name, get_asm_string_keyword(), dll_imports[i]->spec->file_name );
827 /* output the import thunks of a Win32 module */
828 static void output_immediate_import_thunks( FILE *outfile )
830 int i, j, pos;
831 int nb_imm = nb_imports - nb_delayed;
832 static const char import_thunks[] = "__wine_spec_import_thunks";
834 if (!nb_imm) return;
836 fprintf( outfile, "\n/* immediate import thunks */\n\n" );
837 fprintf( outfile, "\t.text\n" );
838 fprintf( outfile, "\t.align %d\n", get_alignment(8) );
839 fprintf( outfile, "%s:\n", asm_name(import_thunks));
841 for (i = pos = 0; i < nb_imports; i++)
843 if (dll_imports[i]->delay) continue;
844 for (j = 0; j < dll_imports[i]->nb_imports; j++, pos += get_ptr_size())
846 ORDDEF *odp = dll_imports[i]->imports[j];
847 output_import_thunk( outfile, odp->name ? odp->name : odp->export_name,
848 ".L__wine_spec_import_data_ptrs", pos );
850 pos += get_ptr_size();
852 output_function_size( outfile, import_thunks );
855 /* output the delayed import table of a Win32 module */
856 static void output_delayed_imports( FILE *outfile, const DLLSPEC *spec )
858 int i, j;
860 if (!nb_delayed) return;
862 fprintf( outfile, "\n/* delayed imports */\n\n" );
863 fprintf( outfile, "\t.data\n" );
864 fprintf( outfile, "\t.align %d\n", get_alignment(get_ptr_size()) );
865 fprintf( outfile, "%s\n", asm_globl("__wine_spec_delay_imports") );
867 /* list of dlls */
869 for (i = j = 0; i < nb_imports; i++)
871 if (!dll_imports[i]->delay) continue;
872 fprintf( outfile, "\t%s 0\n", get_asm_ptr_keyword() ); /* grAttrs */
873 fprintf( outfile, "\t%s .L__wine_delay_name_%d\n", /* szName */
874 get_asm_ptr_keyword(), i );
875 fprintf( outfile, "\t%s .L__wine_delay_modules+%d\n", /* phmod */
876 get_asm_ptr_keyword(), i * get_ptr_size() );
877 fprintf( outfile, "\t%s .L__wine_delay_IAT+%d\n", /* pIAT */
878 get_asm_ptr_keyword(), j * get_ptr_size() );
879 fprintf( outfile, "\t%s .L__wine_delay_INT+%d\n", /* pINT */
880 get_asm_ptr_keyword(), j * get_ptr_size() );
881 fprintf( outfile, "\t%s 0\n", get_asm_ptr_keyword() ); /* pBoundIAT */
882 fprintf( outfile, "\t%s 0\n", get_asm_ptr_keyword() ); /* pUnloadIAT */
883 fprintf( outfile, "\t%s 0\n", get_asm_ptr_keyword() ); /* dwTimeStamp */
884 j += dll_imports[i]->nb_imports;
886 fprintf( outfile, "\t%s 0\n", get_asm_ptr_keyword() ); /* grAttrs */
887 fprintf( outfile, "\t%s 0\n", get_asm_ptr_keyword() ); /* szName */
888 fprintf( outfile, "\t%s 0\n", get_asm_ptr_keyword() ); /* phmod */
889 fprintf( outfile, "\t%s 0\n", get_asm_ptr_keyword() ); /* pIAT */
890 fprintf( outfile, "\t%s 0\n", get_asm_ptr_keyword() ); /* pINT */
891 fprintf( outfile, "\t%s 0\n", get_asm_ptr_keyword() ); /* pBoundIAT */
892 fprintf( outfile, "\t%s 0\n", get_asm_ptr_keyword() ); /* pUnloadIAT */
893 fprintf( outfile, "\t%s 0\n", get_asm_ptr_keyword() ); /* dwTimeStamp */
895 fprintf( outfile, "\n.L__wine_delay_IAT:\n" );
896 for (i = 0; i < nb_imports; i++)
898 if (!dll_imports[i]->delay) continue;
899 for (j = 0; j < dll_imports[i]->nb_imports; j++)
901 ORDDEF *odp = dll_imports[i]->imports[j];
902 const char *name = odp->name ? odp->name : odp->export_name;
903 fprintf( outfile, "\t%s .L__wine_delay_imp_%d_%s\n",
904 get_asm_ptr_keyword(), i, name );
908 fprintf( outfile, "\n.L__wine_delay_INT:\n" );
909 for (i = 0; i < nb_imports; i++)
911 if (!dll_imports[i]->delay) continue;
912 for (j = 0; j < dll_imports[i]->nb_imports; j++)
914 ORDDEF *odp = dll_imports[i]->imports[j];
915 if (!odp->name)
916 fprintf( outfile, "\t%s %d\n", get_asm_ptr_keyword(), odp->ordinal );
917 else
918 fprintf( outfile, "\t%s .L__wine_delay_data_%d_%s\n",
919 get_asm_ptr_keyword(), i, odp->name );
923 fprintf( outfile, "\n.L__wine_delay_modules:\n" );
924 for (i = 0; i < nb_imports; i++)
926 if (dll_imports[i]->delay) fprintf( outfile, "\t%s 0\n", get_asm_ptr_keyword() );
929 for (i = 0; i < nb_imports; i++)
931 if (!dll_imports[i]->delay) continue;
932 fprintf( outfile, ".L__wine_delay_name_%d:\n", i );
933 fprintf( outfile, "\t%s \"%s\"\n",
934 get_asm_string_keyword(), dll_imports[i]->spec->file_name );
937 for (i = 0; i < nb_imports; i++)
939 if (!dll_imports[i]->delay) continue;
940 for (j = 0; j < dll_imports[i]->nb_imports; j++)
942 ORDDEF *odp = dll_imports[i]->imports[j];
943 if (!odp->name) continue;
944 fprintf( outfile, ".L__wine_delay_data_%d_%s:\n", i, odp->name );
945 fprintf( outfile, "\t%s \"%s\"\n", get_asm_string_keyword(), odp->name );
948 output_function_size( outfile, "__wine_spec_delay_imports" );
951 /* output the delayed import thunks of a Win32 module */
952 static void output_delayed_import_thunks( FILE *outfile, const DLLSPEC *spec )
954 int i, idx, j, pos, extra_stack_storage = 0;
955 static const char delayed_import_loaders[] = "__wine_spec_delayed_import_loaders";
956 static const char delayed_import_thunks[] = "__wine_spec_delayed_import_thunks";
958 if (!nb_delayed) return;
960 fprintf( outfile, "\n/* delayed import thunks */\n\n" );
961 fprintf( outfile, "\t.text\n" );
962 fprintf( outfile, "\t.align %d\n", get_alignment(8) );
963 fprintf( outfile, "%s:\n", asm_name(delayed_import_loaders));
964 fprintf( outfile, "\t%s\n", func_declaration("__wine_delay_load_asm") );
965 fprintf( outfile, "%s:\n", asm_name("__wine_delay_load_asm") );
966 switch(target_cpu)
968 case CPU_x86:
969 fprintf( outfile, "\tpushl %%ecx\n" );
970 fprintf( outfile, "\tpushl %%edx\n" );
971 fprintf( outfile, "\tpushl %%eax\n" );
972 fprintf( outfile, "\tcall %s\n", asm_name("__wine_spec_delay_load") );
973 fprintf( outfile, "\tpopl %%edx\n" );
974 fprintf( outfile, "\tpopl %%ecx\n" );
975 fprintf( outfile, "\tjmp *%%eax\n" );
976 break;
977 case CPU_x86_64:
978 fprintf( outfile, "\tpushq %%rdi\n" );
979 fprintf( outfile, "\tsubq $8,%%rsp\n" );
980 fprintf( outfile, "\tmovq %%r11,%%rdi\n" );
981 fprintf( outfile, "\tcall %s\n", asm_name("__wine_spec_delay_load") );
982 fprintf( outfile, "\taddq $8,%%rsp\n" );
983 fprintf( outfile, "\tpopq %%rdi\n" );
984 fprintf( outfile, "\tjmp *%%rax\n" );
985 break;
986 case CPU_SPARC:
987 fprintf( outfile, "\tsave %%sp, -96, %%sp\n" );
988 fprintf( outfile, "\tcall %s\n", asm_name("__wine_spec_delay_load") );
989 fprintf( outfile, "\tmov %%g1, %%o0\n" );
990 fprintf( outfile, "\tjmp %%o0\n" );
991 fprintf( outfile, "\trestore\n" );
992 break;
993 case CPU_ALPHA:
994 fprintf( outfile, "\tjsr $26,%s\n", asm_name("__wine_spec_delay_load") );
995 fprintf( outfile, "\tjmp $31,($0)\n" );
996 break;
997 case CPU_POWERPC:
998 if (target_platform == PLATFORM_APPLE) extra_stack_storage = 56;
1000 /* Save all callee saved registers into a stackframe. */
1001 fprintf( outfile, "\tstwu %s, -%d(%s)\n",ppc_reg(1), 48+extra_stack_storage, ppc_reg(1));
1002 fprintf( outfile, "\tstw %s, %d(%s)\n", ppc_reg(3), 4+extra_stack_storage, ppc_reg(1));
1003 fprintf( outfile, "\tstw %s, %d(%s)\n", ppc_reg(4), 8+extra_stack_storage, ppc_reg(1));
1004 fprintf( outfile, "\tstw %s, %d(%s)\n", ppc_reg(5), 12+extra_stack_storage, ppc_reg(1));
1005 fprintf( outfile, "\tstw %s, %d(%s)\n", ppc_reg(6), 16+extra_stack_storage, ppc_reg(1));
1006 fprintf( outfile, "\tstw %s, %d(%s)\n", ppc_reg(7), 20+extra_stack_storage, ppc_reg(1));
1007 fprintf( outfile, "\tstw %s, %d(%s)\n", ppc_reg(8), 24+extra_stack_storage, ppc_reg(1));
1008 fprintf( outfile, "\tstw %s, %d(%s)\n", ppc_reg(9), 28+extra_stack_storage, ppc_reg(1));
1009 fprintf( outfile, "\tstw %s, %d(%s)\n", ppc_reg(10),32+extra_stack_storage, ppc_reg(1));
1010 fprintf( outfile, "\tstw %s, %d(%s)\n", ppc_reg(11),36+extra_stack_storage, ppc_reg(1));
1011 fprintf( outfile, "\tstw %s, %d(%s)\n", ppc_reg(12),40+extra_stack_storage, ppc_reg(1));
1013 /* r0 -> r3 (arg1) */
1014 fprintf( outfile, "\tmr %s, %s\n", ppc_reg(3), ppc_reg(0));
1016 /* save return address */
1017 fprintf( outfile, "\tmflr %s\n", ppc_reg(0));
1018 fprintf( outfile, "\tstw %s, %d(%s)\n", ppc_reg(0), 44+extra_stack_storage, ppc_reg(1));
1020 /* Call the __wine_delay_load function, arg1 is arg1. */
1021 fprintf( outfile, "\tbl %s\n", asm_name("__wine_spec_delay_load") );
1023 /* Load return value from call into ctr register */
1024 fprintf( outfile, "\tmtctr %s\n", ppc_reg(3));
1026 /* restore all saved registers and drop stackframe. */
1027 fprintf( outfile, "\tlwz %s, %d(%s)\n", ppc_reg(3), 4+extra_stack_storage, ppc_reg(1));
1028 fprintf( outfile, "\tlwz %s, %d(%s)\n", ppc_reg(4), 8+extra_stack_storage, ppc_reg(1));
1029 fprintf( outfile, "\tlwz %s, %d(%s)\n", ppc_reg(5), 12+extra_stack_storage, ppc_reg(1));
1030 fprintf( outfile, "\tlwz %s, %d(%s)\n", ppc_reg(6), 16+extra_stack_storage, ppc_reg(1));
1031 fprintf( outfile, "\tlwz %s, %d(%s)\n", ppc_reg(7), 20+extra_stack_storage, ppc_reg(1));
1032 fprintf( outfile, "\tlwz %s, %d(%s)\n", ppc_reg(8), 24+extra_stack_storage, ppc_reg(1));
1033 fprintf( outfile, "\tlwz %s, %d(%s)\n", ppc_reg(9), 28+extra_stack_storage, ppc_reg(1));
1034 fprintf( outfile, "\tlwz %s, %d(%s)\n", ppc_reg(10),32+extra_stack_storage, ppc_reg(1));
1035 fprintf( outfile, "\tlwz %s, %d(%s)\n", ppc_reg(11),36+extra_stack_storage, ppc_reg(1));
1036 fprintf( outfile, "\tlwz %s, %d(%s)\n", ppc_reg(12),40+extra_stack_storage, ppc_reg(1));
1038 /* Load return value from call into return register */
1039 fprintf( outfile, "\tlwz %s, %d(%s)\n", ppc_reg(0), 44+extra_stack_storage, ppc_reg(1));
1040 fprintf( outfile, "\tmtlr %s\n", ppc_reg(0));
1041 fprintf( outfile, "\taddi %s, %s, %d\n", ppc_reg(1), ppc_reg(1), 48+extra_stack_storage);
1043 /* branch to ctr register. */
1044 fprintf( outfile, "\tbctr\n");
1045 break;
1047 output_function_size( outfile, "__wine_delay_load_asm" );
1048 fprintf( outfile, "\n" );
1050 for (i = idx = 0; i < nb_imports; i++)
1052 if (!dll_imports[i]->delay) continue;
1053 for (j = 0; j < dll_imports[i]->nb_imports; j++)
1055 ORDDEF *odp = dll_imports[i]->imports[j];
1056 const char *name = odp->name ? odp->name : odp->export_name;
1058 fprintf( outfile, ".L__wine_delay_imp_%d_%s:\n", i, name );
1059 switch(target_cpu)
1061 case CPU_x86:
1062 fprintf( outfile, "\tmovl $%d, %%eax\n", (idx << 16) | j );
1063 fprintf( outfile, "\tjmp %s\n", asm_name("__wine_delay_load_asm") );
1064 break;
1065 case CPU_x86_64:
1066 fprintf( outfile, "\tmovq $%d,%%r11\n", (idx << 16) | j );
1067 fprintf( outfile, "\tjmp %s\n", asm_name("__wine_delay_load_asm") );
1068 break;
1069 case CPU_SPARC:
1070 fprintf( outfile, "\tset %d, %%g1\n", (idx << 16) | j );
1071 fprintf( outfile, "\tb,a %s\n", asm_name("__wine_delay_load_asm") );
1072 break;
1073 case CPU_ALPHA:
1074 fprintf( outfile, "\tlda $0,%d($31)\n", j);
1075 fprintf( outfile, "\tldah $0,%d($0)\n", idx);
1076 fprintf( outfile, "\tjmp $31,%s\n", asm_name("__wine_delay_load_asm") );
1077 break;
1078 case CPU_POWERPC:
1079 switch(target_platform)
1081 case PLATFORM_APPLE:
1082 /* On Darwin we can use r0 and r2 */
1083 /* Upper part in r2 */
1084 fprintf( outfile, "\tlis %s, %d\n", ppc_reg(2), idx);
1085 /* Lower part + r2 -> r0, Note we can't use r0 directly */
1086 fprintf( outfile, "\taddi %s, %s, %d\n", ppc_reg(0), ppc_reg(2), j);
1087 fprintf( outfile, "\tb %s\n", asm_name("__wine_delay_load_asm") );
1088 break;
1089 default:
1090 /* On linux we can't use r2 since r2 is not a scratch register (hold the TOC) */
1091 /* Save r13 on the stack */
1092 fprintf( outfile, "\taddi %s, %s, -0x4\n", ppc_reg(1), ppc_reg(1));
1093 fprintf( outfile, "\tstw %s, 0(%s)\n", ppc_reg(13), ppc_reg(1));
1094 /* Upper part in r13 */
1095 fprintf( outfile, "\tlis %s, %d\n", ppc_reg(13), idx);
1096 /* Lower part + r13 -> r0, Note we can't use r0 directly */
1097 fprintf( outfile, "\taddi %s, %s, %d\n", ppc_reg(0), ppc_reg(13), j);
1098 /* Restore r13 */
1099 fprintf( outfile, "\tstw %s, 0(%s)\n", ppc_reg(13), ppc_reg(1));
1100 fprintf( outfile, "\taddic %s, %s, 0x4\n", ppc_reg(1), ppc_reg(1));
1101 fprintf( outfile, "\tb %s\n", asm_name("__wine_delay_load_asm") );
1102 break;
1104 break;
1107 idx++;
1109 output_function_size( outfile, delayed_import_loaders );
1111 fprintf( outfile, "\n\t.align %d\n", get_alignment(get_ptr_size()) );
1112 fprintf( outfile, "%s:\n", asm_name(delayed_import_thunks));
1113 for (i = pos = 0; i < nb_imports; i++)
1115 if (!dll_imports[i]->delay) continue;
1116 for (j = 0; j < dll_imports[i]->nb_imports; j++, pos += get_ptr_size())
1118 ORDDEF *odp = dll_imports[i]->imports[j];
1119 output_import_thunk( outfile, odp->name ? odp->name : odp->export_name,
1120 ".L__wine_delay_IAT", pos );
1123 output_function_size( outfile, delayed_import_thunks );
1126 /* output import stubs for exported entry points that link to external symbols */
1127 static void output_external_link_imports( FILE *outfile, DLLSPEC *spec )
1129 unsigned int i, pos;
1131 if (!ext_link_imports.count) return; /* nothing to do */
1133 sort_names( &ext_link_imports );
1135 /* get rid of duplicate names */
1136 for (i = 1; i < ext_link_imports.count; i++)
1138 if (!strcmp( ext_link_imports.names[i-1], ext_link_imports.names[i] ))
1139 remove_name( &ext_link_imports, i-- );
1142 fprintf( outfile, "\n/* external link thunks */\n\n" );
1143 fprintf( outfile, "\t.data\n" );
1144 fprintf( outfile, "\t.align %d\n", get_alignment(get_ptr_size()) );
1145 fprintf( outfile, ".L__wine_spec_external_links:\n" );
1146 for (i = 0; i < ext_link_imports.count; i++)
1147 fprintf( outfile, "\t%s %s\n", get_asm_ptr_keyword(), asm_name(ext_link_imports.names[i]) );
1149 fprintf( outfile, "\n\t.text\n" );
1150 fprintf( outfile, "\t.align %d\n", get_alignment(get_ptr_size()) );
1151 fprintf( outfile, "%s:\n", asm_name("__wine_spec_external_link_thunks") );
1153 for (i = pos = 0; i < ext_link_imports.count; i++)
1155 char buffer[256];
1156 sprintf( buffer, "__wine_spec_ext_link_%s", ext_link_imports.names[i] );
1157 output_import_thunk( outfile, buffer, ".L__wine_spec_external_links", pos );
1158 pos += get_ptr_size();
1160 output_function_size( outfile, "__wine_spec_external_link_thunks" );
1163 /*******************************************************************
1164 * output_stubs
1166 * Output the functions for stub entry points
1168 void output_stubs( FILE *outfile, DLLSPEC *spec )
1170 const char *name, *exp_name;
1171 int i, pos;
1173 if (!has_stubs( spec )) return;
1175 fprintf( outfile, "\n/* stub functions */\n\n" );
1176 fprintf( outfile, "\t.text\n" );
1178 for (i = pos = 0; i < spec->nb_entry_points; i++)
1180 ORDDEF *odp = &spec->entry_points[i];
1181 if (odp->type != TYPE_STUB) continue;
1183 name = get_stub_name( odp, spec );
1184 exp_name = odp->name ? odp->name : odp->export_name;
1185 fprintf( outfile, "\t.align %d\n", get_alignment(4) );
1186 fprintf( outfile, "\t%s\n", func_declaration(name) );
1187 fprintf( outfile, "%s:\n", asm_name(name) );
1188 fprintf( outfile, "\tsubl $4,%%esp\n" );
1190 if (UsePIC)
1192 fprintf( outfile, "\tcall %s\n", asm_name("__wine_spec_get_pc_thunk_eax") );
1193 fprintf( outfile, "1:" );
1194 if (exp_name)
1196 fprintf( outfile, "\tleal .L__wine_stub_strings+%d-1b(%%eax),%%ecx\n", pos );
1197 fprintf( outfile, "\tpushl %%ecx\n" );
1198 pos += strlen(exp_name) + 1;
1200 else
1201 fprintf( outfile, "\tpushl $%d\n", odp->ordinal );
1202 fprintf( outfile, "\tleal .L__wine_spec_file_name-1b(%%eax),%%ecx\n" );
1203 fprintf( outfile, "\tpushl %%ecx\n" );
1205 else
1207 if (exp_name)
1209 fprintf( outfile, "\tpushl $.L__wine_stub_strings+%d\n", pos );
1210 pos += strlen(exp_name) + 1;
1212 else
1213 fprintf( outfile, "\tpushl $%d\n", odp->ordinal );
1214 fprintf( outfile, "\tpushl $.L__wine_spec_file_name\n" );
1216 fprintf( outfile, "\tcall %s\n", asm_name("__wine_spec_unimplemented_stub") );
1217 output_function_size( outfile, name );
1220 if (pos)
1222 fprintf( outfile, "\t%s\n", get_asm_string_section() );
1223 fprintf( outfile, ".L__wine_stub_strings:\n" );
1224 for (i = 0; i < spec->nb_entry_points; i++)
1226 ORDDEF *odp = &spec->entry_points[i];
1227 if (odp->type != TYPE_STUB) continue;
1228 exp_name = odp->name ? odp->name : odp->export_name;
1229 if (exp_name)
1230 fprintf( outfile, "\t%s \"%s\"\n", get_asm_string_keyword(), exp_name );
1235 /* output the import and delayed import tables of a Win32 module */
1236 void output_imports( FILE *outfile, DLLSPEC *spec )
1238 output_immediate_imports( outfile );
1239 output_delayed_imports( outfile, spec );
1240 output_immediate_import_thunks( outfile );
1241 output_delayed_import_thunks( outfile, spec );
1242 output_external_link_imports( outfile, spec );
1243 if (nb_imports || ext_link_imports.count || has_stubs(spec) || has_relays(spec))
1244 output_get_pc_thunk( outfile );