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