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