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