Added support for defining forward functions as stdcall so that we can
[wine/multimedia.git] / tools / winebuild / import.c
blobea4d291e3d7357b339c3e51b2db46ccce0dfa2ee
1 /*
2 * DLL imports support
4 * Copyright 2000 Alexandre Julliard
5 * 2000 Eric Pouech
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "config.h"
23 #include "wine/port.h"
25 #include <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
33 #include "build.h"
35 struct func
37 char *name; /* function name */
38 int ordinal; /* function ordinal */
39 int ord_only; /* non-zero if function is imported by ordinal */
42 struct import
44 char *dll; /* dll name */
45 int delay; /* delay or not dll loading ? */
46 struct func *exports; /* functions exported from this dll */
47 int nb_exports; /* number of exported functions */
48 struct func *imports; /* functions we want to import from this dll */
49 int nb_imports; /* number of imported functions */
52 static char **undef_symbols; /* list of undefined symbols */
53 static int nb_undef_symbols = -1;
54 static int undef_size;
56 static char **ignore_symbols; /* list of symbols to ignore */
57 static int nb_ignore_symbols;
58 static int ignore_size;
60 static char *ld_tmp_file; /* ld temp file name */
62 static struct import **dll_imports = NULL;
63 static int nb_imports = 0; /* number of imported dlls (delayed or not) */
64 static int nb_delayed = 0; /* number of delayed dlls */
65 static int total_imports = 0; /* total number of imported functions */
66 static int total_delayed = 0; /* total number of imported functions in delayed DLLs */
68 /* list of symbols that are ignored by default */
69 static const char * const default_ignored_symbols[] =
71 "abs",
72 "acos",
73 "asin",
74 "atan",
75 "atan2",
76 "atof",
77 "atoi",
78 "atol",
79 "bsearch",
80 "ceil",
81 "cos",
82 "cosh",
83 "div",
84 "exp",
85 "fabs",
86 "floor",
87 "fmod",
88 "frexp",
89 "labs",
90 "ldiv",
91 "log",
92 "log10",
93 "memchr",
94 "memcmp",
95 "memcpy",
96 "memmove",
97 "memset",
98 "modf",
99 "pow",
100 "qsort",
101 "sin",
102 "sinh",
103 "sprintf",
104 "sqrt",
105 "sscanf",
106 "strcat",
107 "strchr",
108 "strcmp",
109 "strcpy",
110 "strcspn",
111 "strlen",
112 "strncat",
113 "strncmp",
114 "strncpy",
115 "strpbrk",
116 "strrchr",
117 "strspn",
118 "strstr",
119 "tan",
120 "tanh",
121 "vsprintf"
124 /* compare function names; helper for resolve_imports */
125 static int name_cmp( const void *name, const void *entry )
127 return strcmp( *(char **)name, *(char **)entry );
130 /* compare function names; helper for resolve_imports */
131 static int func_cmp( const void *func1, const void *func2 )
133 return strcmp( ((struct func *)func1)->name, ((struct func *)func2)->name );
136 /* locate a symbol in a (sorted) list */
137 inline static const char *find_symbol( const char *name, char **table, int size )
139 char **res = NULL;
141 if (table) {
142 res = bsearch( &name, table, size, sizeof(*table), name_cmp );
145 return res ? *res : NULL;
148 /* locate an export in a (sorted) export list */
149 inline static struct func *find_export( const char *name, struct func *table, int size )
151 struct func func, *res = NULL;
153 func.name = (char *)name;
154 func.ordinal = -1;
155 if (table) res = bsearch( &func, table, size, sizeof(*table), func_cmp );
156 return res;
159 /* sort a symbol table */
160 inline static void sort_symbols( char **table, int size )
162 if (table )
163 qsort( table, size, sizeof(*table), name_cmp );
166 /* free an import structure */
167 static void free_imports( struct import *imp )
169 int i;
171 for (i = 0; i < imp->nb_exports; i++) free( imp->exports[i].name );
172 for (i = 0; i < imp->nb_imports; i++) free( imp->imports[i].name );
173 free( imp->exports );
174 free( imp->imports );
175 free( imp->dll );
176 free( imp );
179 /* remove the temp file at exit */
180 static void remove_ld_tmp_file(void)
182 if (ld_tmp_file) unlink( ld_tmp_file );
185 /* check whether a given dll has already been imported */
186 static int is_already_imported( const char *name )
188 int i;
190 for (i = 0; i < nb_imports; i++)
192 if (!strcmp( dll_imports[i]->dll, name )) return 1;
194 return 0;
197 /* open the .so library for a given dll in a specified path */
198 static char *try_library_path( const char *path, const char *name )
200 char *buffer;
201 int fd;
203 buffer = xmalloc( strlen(path) + strlen(name) + 9 );
204 sprintf( buffer, "%s/lib%s.def", path, name );
206 /* check if the file exists */
207 if ((fd = open( buffer, O_RDONLY )) != -1)
209 close( fd );
210 return buffer;
212 free( buffer );
213 return NULL;
216 /* open the .so library for a given dll */
217 static char *open_library( const char *name )
219 char *fullname;
220 int i;
222 for (i = 0; i < nb_lib_paths; i++)
224 if ((fullname = try_library_path( lib_path[i], name ))) return fullname;
226 if (!(fullname = try_library_path( ".", name )))
227 fatal_error( "could not open .def file for %s\n", name );
228 return fullname;
231 /* skip whitespace until the next token */
232 static char *skip_whitespace( char *p )
234 while (*p && isspace(*p)) p++;
235 if (!*p || *p == ';') p = NULL;
236 return p;
239 /* skip to the start of the next token, null terminating the current one */
240 static char *next_token( char *p )
242 while (*p && !isspace(*p)) p++;
243 if (*p) *p++ = 0;
244 return skip_whitespace( p );
247 /* remove the @nn suffix from stdcall names */
248 static char *remove_stdcall_decoration( char *buffer )
250 char *p = buffer + strlen(buffer) - 1;
251 while (p > buffer && isdigit(*p)) p--;
252 if (p > buffer && *p == '@') *p = 0;
253 return buffer;
256 /* read in the list of exported symbols of an import library */
257 static int read_import_lib( const char *name, struct import *imp )
259 FILE *f;
260 char buffer[1024];
261 char *fullname;
262 int size;
264 imp->exports = NULL;
265 imp->nb_exports = size = 0;
267 fullname = open_library( name );
268 f = open_input_file( NULL, fullname );
269 free( fullname );
271 while (fgets( buffer, sizeof(buffer), f ))
273 char *name, *flags;
274 int ordinal = 0, ord_only = 0;
276 char *p = buffer + strlen(buffer) - 1;
277 if (p < buffer) goto next;
278 if (*p == '\n') *p-- = 0;
280 p = buffer;
281 if (!(p = skip_whitespace(p))) goto next;
282 name = p;
283 p = next_token( name );
285 if (!strcmp( name, "LIBRARY" ))
287 if (!p) fatal_error( "Expected name after LIBRARY\n" );
288 name = p;
289 p = next_token( name );
290 if (p) fatal_error( "Garbage after LIBRARY statement\n" );
291 if (is_already_imported( name ))
293 close_input_file( f );
294 return 0; /* ignore this dll */
296 free( imp->dll );
297 imp->dll = xstrdup( name );
298 goto next;
300 if (!strcmp( name, "EXPORTS" )) goto next;
302 /* check for ordinal */
303 if (!p) fatal_error( "Expected ordinal after function name\n" );
304 if (*p != '@' || !isdigit(p[1]))
305 fatal_error( "Expected ordinal after function name '%s'\n", name );
306 ordinal = strtol( p+1, &p, 10 );
307 if (ordinal >= MAX_ORDINALS) fatal_error( "Invalid ordinal number %d\n", ordinal );
309 /* check for optional flags */
310 while (p && (p = skip_whitespace(p)))
312 flags = p;
313 p = next_token( flags );
314 if (!strcmp( flags, "NONAME" ))
316 ord_only = 1;
317 if (!ordinal) fatal_error( "Invalid ordinal number %d\n", ordinal );
319 else if (!strcmp( flags, "CONSTANT" ) || !strcmp( flags, "DATA" ))
321 /* we don't support importing non-function entry points */
322 goto next;
324 else fatal_error( "Garbage after ordinal declaration\n" );
327 if (imp->nb_exports == size)
329 size += 128;
330 imp->exports = xrealloc( imp->exports, size * sizeof(*imp->exports) );
332 if ((p = strchr( name, '=' ))) *p = 0;
333 remove_stdcall_decoration( name );
334 imp->exports[imp->nb_exports].name = xstrdup( name );
335 imp->exports[imp->nb_exports].ordinal = ordinal;
336 imp->exports[imp->nb_exports].ord_only = ord_only;
337 imp->nb_exports++;
338 next:
339 current_line++;
341 close_input_file( f );
342 if (imp->nb_exports)
343 qsort( imp->exports, imp->nb_exports, sizeof(*imp->exports), func_cmp );
344 return 1;
347 /* add a dll to the list of imports */
348 void add_import_dll( const char *name, int delay )
350 struct import *imp;
351 char *fullname;
353 fullname = xmalloc( strlen(name) + 5 );
354 strcpy( fullname, name );
355 if (!strchr( fullname, '.' )) strcat( fullname, ".dll" );
357 /* check if we already imported it */
358 if (is_already_imported( fullname ))
360 free( fullname );
361 return;
364 imp = xmalloc( sizeof(*imp) );
365 imp->dll = fullname;
366 imp->delay = delay;
367 imp->imports = NULL;
368 imp->nb_imports = 0;
370 if (delay) nb_delayed++;
372 if (read_import_lib( name, imp ))
374 dll_imports = xrealloc( dll_imports, (nb_imports+1) * sizeof(*dll_imports) );
375 dll_imports[nb_imports++] = imp;
377 else free_imports( imp );
380 /* initialize the list of ignored symbols */
381 static void init_ignored_symbols(void)
383 int i;
385 nb_ignore_symbols = sizeof(default_ignored_symbols)/sizeof(default_ignored_symbols[0]);
386 ignore_size = nb_ignore_symbols + 32;
387 ignore_symbols = xmalloc( ignore_size * sizeof(*ignore_symbols) );
388 for (i = 0; i < nb_ignore_symbols; i++)
389 ignore_symbols[i] = xstrdup( default_ignored_symbols[i] );
392 /* add a symbol to the ignored symbol list */
393 /* if the name starts with '-' the symbol is removed instead */
394 void add_ignore_symbol( const char *name )
396 int i;
398 if (!ignore_symbols) init_ignored_symbols(); /* first time around, fill list with defaults */
400 if (name[0] == '-') /* remove it */
402 if (!name[1]) /* remove everything */
404 for (i = 0; i < nb_ignore_symbols; i++) free( ignore_symbols[i] );
405 nb_ignore_symbols = 0;
407 else
409 for (i = 0; i < nb_ignore_symbols; i++)
411 if (!strcmp( ignore_symbols[i], name+1 ))
413 free( ignore_symbols[i] );
414 memmove( &ignore_symbols[i], &ignore_symbols[i+1], nb_ignore_symbols - i - 1 );
415 nb_ignore_symbols--;
420 else
422 if (nb_ignore_symbols == ignore_size)
424 ignore_size += 32;
425 ignore_symbols = xrealloc( ignore_symbols, ignore_size * sizeof(*ignore_symbols) );
427 ignore_symbols[nb_ignore_symbols++] = xstrdup( name );
431 /* add a function to the list of imports from a given dll */
432 static void add_import_func( struct import *imp, const struct func *func )
434 imp->imports = xrealloc( imp->imports, (imp->nb_imports+1) * sizeof(*imp->imports) );
435 imp->imports[imp->nb_imports].name = xstrdup( func->name );
436 imp->imports[imp->nb_imports].ordinal = func->ordinal;
437 imp->imports[imp->nb_imports].ord_only = func->ord_only;
438 imp->nb_imports++;
439 total_imports++;
440 if (imp->delay) total_delayed++;
443 /* add a symbol to the undef list */
444 inline static void add_undef_symbol( const char *name )
446 if (nb_undef_symbols == undef_size)
448 undef_size += 128;
449 undef_symbols = xrealloc( undef_symbols, undef_size * sizeof(*undef_symbols) );
451 undef_symbols[nb_undef_symbols++] = xstrdup( name );
454 /* remove all the holes in the undefined symbol list; return the number of removed symbols */
455 static int remove_symbol_holes(void)
457 int i, off;
458 for (i = off = 0; i < nb_undef_symbols; i++)
460 if (!undef_symbols[i]) off++;
461 else undef_symbols[i - off] = undef_symbols[i];
463 nb_undef_symbols -= off;
464 return off;
467 /* add a symbol to the extra list, but only if needed */
468 static int add_extra_symbol( const char **extras, int *count, const char *name )
470 int i;
472 if (!find_symbol( name, undef_symbols, nb_undef_symbols ))
474 /* check if the symbol is being exported by this dll */
475 for (i = 0; i < nb_entry_points; i++)
477 ORDDEF *odp = EntryPoints[i];
478 if (odp->type == TYPE_STDCALL ||
479 odp->type == TYPE_CDECL ||
480 odp->type == TYPE_VARARGS ||
481 odp->type == TYPE_EXTERN)
483 if (odp->name && !strcmp( odp->name, name )) return 0;
486 extras[*count] = name;
487 (*count)++;
489 return 1;
492 /* add the extra undefined symbols that will be contained in the generated spec file itself */
493 static void add_extra_undef_symbols(void)
495 const char *extras[10];
496 int i, count = 0, nb_stubs = 0, nb_regs = 0;
497 int kernel_imports = 0, ntdll_imports = 0;
499 sort_symbols( undef_symbols, nb_undef_symbols );
501 for (i = 0; i < nb_entry_points; i++)
503 ORDDEF *odp = EntryPoints[i];
504 if (odp->type == TYPE_STUB) nb_stubs++;
505 if (odp->flags & FLAG_REGISTER) nb_regs++;
508 /* add symbols that will be contained in the spec file itself */
509 switch (SpecMode)
511 case SPEC_MODE_DLL:
512 break;
513 case SPEC_MODE_GUIEXE:
514 kernel_imports += add_extra_symbol( extras, &count, "GetCommandLineA" );
515 kernel_imports += add_extra_symbol( extras, &count, "GetStartupInfoA" );
516 kernel_imports += add_extra_symbol( extras, &count, "GetModuleHandleA" );
517 /* fall through */
518 case SPEC_MODE_CUIEXE:
519 kernel_imports += add_extra_symbol( extras, &count, "ExitProcess" );
520 break;
521 case SPEC_MODE_GUIEXE_UNICODE:
522 kernel_imports += add_extra_symbol( extras, &count, "GetCommandLineA" );
523 kernel_imports += add_extra_symbol( extras, &count, "GetStartupInfoA" );
524 kernel_imports += add_extra_symbol( extras, &count, "GetModuleHandleA" );
525 /* fall through */
526 case SPEC_MODE_CUIEXE_UNICODE:
527 kernel_imports += add_extra_symbol( extras, &count, "ExitProcess" );
528 break;
530 if (nb_delayed)
532 kernel_imports += add_extra_symbol( extras, &count, "LoadLibraryA" );
533 kernel_imports += add_extra_symbol( extras, &count, "GetProcAddress" );
535 if (nb_regs)
536 ntdll_imports += add_extra_symbol( extras, &count, "__wine_call_from_32_regs" );
537 if (nb_delayed || nb_stubs)
538 ntdll_imports += add_extra_symbol( extras, &count, "RtlRaiseException" );
540 /* make sure we import the dlls that contain these functions */
541 if (kernel_imports) add_import_dll( "kernel32", 0 );
542 if (ntdll_imports) add_import_dll( "ntdll", 0 );
544 if (count)
546 for (i = 0; i < count; i++) add_undef_symbol( extras[i] );
547 sort_symbols( undef_symbols, nb_undef_symbols );
551 /* warn if a given dll is not used, but check forwards first */
552 static void warn_unused( const struct import* imp )
554 int i;
555 size_t len = strlen(imp->dll);
556 const char *p = strchr( imp->dll, '.' );
557 if (p && !strcasecmp( p, ".dll" )) len = p - imp->dll;
559 for (i = Base; i <= Limit; i++)
561 ORDDEF *odp = Ordinals[i];
562 if (!odp || !(odp->flags & FLAG_FORWARD)) continue;
563 if (!strncasecmp( odp->link_name, imp->dll, len ) &&
564 odp->link_name[len] == '.')
565 return; /* found an import, do not warn */
567 warning( "%s imported but no symbols used\n", imp->dll );
570 /* combine a list of object files with ld into a single object file */
571 /* returns the name of the combined file */
572 static const char *ldcombine_files( char **argv )
574 int i, len = 0;
575 char *cmd;
576 int fd, err;
578 if (output_file_name && output_file_name[0])
580 ld_tmp_file = xmalloc( strlen(output_file_name) + 8 );
581 strcpy( ld_tmp_file, output_file_name );
582 strcat( ld_tmp_file, ".XXXXXX" );
584 else ld_tmp_file = xstrdup( "/tmp/winebuild.tmp.XXXXXX" );
586 if ((fd = mkstemp( ld_tmp_file ) == -1)) fatal_error( "could not generate a temp file\n" );
587 close( fd );
588 atexit( remove_ld_tmp_file );
590 for (i = 0; argv[i]; i++) len += strlen(argv[i]) + 1;
591 cmd = xmalloc( len + strlen(ld_tmp_file) + 10 );
592 sprintf( cmd, "ld -r -o %s", ld_tmp_file );
593 for (i = 0; argv[i]; i++) sprintf( cmd + strlen(cmd), " %s", argv[i] );
594 err = system( cmd );
595 if (err) fatal_error( "ld -r failed with status %d\n", err );
596 free( cmd );
597 return ld_tmp_file;
600 /* read in the list of undefined symbols */
601 void read_undef_symbols( char **argv )
603 FILE *f;
604 char buffer[1024];
605 int err;
606 const char *name;
608 if (!argv[0]) return;
610 undef_size = nb_undef_symbols = 0;
612 /* if we have multiple object files, link them together */
613 if (argv[1]) name = ldcombine_files( argv );
614 else name = argv[0];
616 sprintf( buffer, "nm -u %s", name );
617 if (!(f = popen( buffer, "r" )))
618 fatal_error( "Cannot execute '%s'\n", buffer );
620 while (fgets( buffer, sizeof(buffer), f ))
622 char *p = buffer + strlen(buffer) - 1;
623 if (p < buffer) continue;
624 if (*p == '\n') *p-- = 0;
625 p = buffer; while (*p == ' ') p++;
626 add_undef_symbol( p );
628 if ((err = pclose( f ))) fatal_error( "nm -u %s error %d\n", name, err );
631 static void remove_ignored_symbols(void)
633 int i;
635 if (!ignore_symbols) init_ignored_symbols();
636 sort_symbols( ignore_symbols, nb_ignore_symbols );
637 for (i = 0; i < nb_undef_symbols; i++)
639 if (find_symbol( undef_symbols[i], ignore_symbols, nb_ignore_symbols ))
641 free( undef_symbols[i] );
642 undef_symbols[i] = NULL;
645 remove_symbol_holes();
648 /* resolve the imports for a Win32 module */
649 int resolve_imports( void )
651 int i, j;
653 if (nb_undef_symbols == -1) return 0; /* no symbol file specified */
655 add_extra_undef_symbols();
656 remove_ignored_symbols();
658 for (i = 0; i < nb_imports; i++)
660 struct import *imp = dll_imports[i];
662 for (j = 0; j < nb_undef_symbols; j++)
664 struct func *func = find_export( undef_symbols[j], imp->exports, imp->nb_exports );
665 if (func)
667 add_import_func( imp, func );
668 free( undef_symbols[j] );
669 undef_symbols[j] = NULL;
672 /* remove all the holes in the undef symbols list */
673 if (!remove_symbol_holes()) warn_unused( imp );
675 return 1;
678 /* output the import table of a Win32 module */
679 static int output_immediate_imports( FILE *outfile )
681 int i, j, pos;
682 int nb_imm = nb_imports - nb_delayed;
684 if (!nb_imm) goto done;
686 /* main import header */
688 fprintf( outfile, "\nstatic struct {\n" );
689 fprintf( outfile, " struct {\n" );
690 fprintf( outfile, " void *OriginalFirstThunk;\n" );
691 fprintf( outfile, " unsigned int TimeDateStamp;\n" );
692 fprintf( outfile, " unsigned int ForwarderChain;\n" );
693 fprintf( outfile, " const char *Name;\n" );
694 fprintf( outfile, " void *FirstThunk;\n" );
695 fprintf( outfile, " } imp[%d];\n", nb_imm+1 );
696 fprintf( outfile, " const char *data[%d];\n",
697 total_imports - total_delayed + nb_imm );
698 fprintf( outfile, "} imports = {\n {\n" );
700 /* list of dlls */
702 for (i = j = 0; i < nb_imports; i++)
704 if (dll_imports[i]->delay) continue;
705 fprintf( outfile, " { 0, 0, 0, \"%s\", &imports.data[%d] },\n",
706 dll_imports[i]->dll, j );
707 j += dll_imports[i]->nb_imports + 1;
710 fprintf( outfile, " { 0, 0, 0, 0, 0 },\n" );
711 fprintf( outfile, " },\n {\n" );
713 /* list of imported functions */
715 for (i = 0; i < nb_imports; i++)
717 if (dll_imports[i]->delay) continue;
718 fprintf( outfile, " /* %s */\n", dll_imports[i]->dll );
719 for (j = 0; j < dll_imports[i]->nb_imports; j++)
721 struct func *import = &dll_imports[i]->imports[j];
722 if (!import->ord_only)
724 unsigned short ord = import->ordinal;
725 fprintf( outfile, " \"\\%03o\\%03o%s\",\n",
726 *(unsigned char *)&ord, *((unsigned char *)&ord + 1), import->name );
728 else
729 fprintf( outfile, " (char *)%d,\n", import->ordinal );
731 fprintf( outfile, " 0,\n" );
733 fprintf( outfile, " }\n};\n\n" );
735 /* thunks for imported functions */
737 fprintf( outfile, "#ifndef __GNUC__\nstatic void __asm__dummy_import(void) {\n#endif\n\n" );
738 pos = 20 * (nb_imm + 1); /* offset of imports.data from start of imports */
739 fprintf( outfile, "asm(\".data\\n\\t.align %d\\n\"\n", get_alignment(8) );
740 for (i = 0; i < nb_imports; i++)
742 if (dll_imports[i]->delay) continue;
743 for (j = 0; j < dll_imports[i]->nb_imports; j++, pos += 4)
745 struct func *import = &dll_imports[i]->imports[j];
746 fprintf( outfile, " \"\\t" __ASM_FUNC("%s") "\\n\"\n", import->name );
747 fprintf( outfile, " \"\\t.globl " __ASM_NAME("%s") "\\n\"\n", import->name );
748 fprintf( outfile, " \"" __ASM_NAME("%s") ":\\n\\t", import->name);
750 #if defined(__i386__)
751 if (strstr( import->name, "__wine_call_from_16" ))
752 fprintf( outfile, ".byte 0x2e\\n\\tjmp *(imports+%d)\\n\\tnop\\n", pos );
753 else
754 fprintf( outfile, "jmp *(imports+%d)\\n\\tmovl %%esi,%%esi\\n", pos );
755 #elif defined(__sparc__)
756 if ( !UsePIC )
758 fprintf( outfile, "sethi %%hi(imports+%d), %%g1\\n\\t", pos );
759 fprintf( outfile, "ld [%%g1+%%lo(imports+%d)], %%g1\\n\\t", pos );
760 fprintf( outfile, "jmp %%g1\\n\\tnop\\n" );
762 else
764 /* Hmpf. Stupid sparc assembler always interprets global variable
765 names as GOT offsets, so we have to do it the long way ... */
766 fprintf( outfile, "save %%sp, -96, %%sp\\n" );
767 fprintf( outfile, "0:\\tcall 1f\\n\\tnop\\n" );
768 fprintf( outfile, "1:\\tsethi %%hi(imports+%d-0b), %%g1\\n\\t", pos );
769 fprintf( outfile, "or %%g1, %%lo(imports+%d-0b), %%g1\\n\\t", pos );
770 fprintf( outfile, "ld [%%g1+%%o7], %%g1\\n\\t" );
771 fprintf( outfile, "jmp %%g1\\n\\trestore\\n" );
774 #elif defined(__PPC__)
775 fprintf(outfile, "\taddi 1, 1, -0x4\\n\"\n");
776 fprintf(outfile, "\t\"\\tstw 9, 0(1)\\n\"\n");
777 fprintf(outfile, "\t\"\\taddi 1, 1, -0x4\\n\"\n");
778 fprintf(outfile, "\t\"\\tstw 8, 0(1)\\n\"\n");
779 fprintf(outfile, "\t\"\\taddi 1, 1, -0x4\\n\"\n");
780 fprintf(outfile, "\t\"\\tstw 7, 0(1)\\n\"\n");
782 fprintf(outfile, "\t\"\\tlis 9,imports+%d@ha\\n\"\n", pos);
783 fprintf(outfile, "\t\"\\tla 8,imports+%d@l(9)\\n\"\n", pos);
784 fprintf(outfile, "\t\"\\tlwz 7, 0(8)\\n\"\n");
785 fprintf(outfile, "\t\"\\tmtctr 7\\n\"\n");
787 fprintf(outfile, "\t\"\\tlwz 7, 0(1)\\n\"\n");
788 fprintf(outfile, "\t\"\\taddi 1, 1, 0x4\\n\"\n");
789 fprintf(outfile, "\t\"\\tlwz 8, 0(1)\\n\"\n");
790 fprintf(outfile, "\t\"\\taddi 1, 1, 0x4\\n\"\n");
791 fprintf(outfile, "\t\"\\tlwz 9, 0(1)\\n\"\n");
792 fprintf(outfile, "\t\"\\taddi 1, 1, 0x4\\n\"\n");
793 fprintf(outfile, "\t\"\\tbctr\\n");
794 #else
795 #error You need to define import thunks for your architecture!
796 #endif
797 fprintf( outfile, "\"\n" );
799 pos += 4;
801 fprintf( outfile, "\".section\\t\\\".text\\\"\");\n#ifndef __GNUC__\n}\n#endif\n\n" );
803 done:
804 return nb_imm;
807 /* output the delayed import table of a Win32 module */
808 static int output_delayed_imports( FILE *outfile )
810 int i, idx, j, pos;
812 if (!nb_delayed) goto done;
814 for (i = 0; i < nb_imports; i++)
816 if (!dll_imports[i]->delay) continue;
817 fprintf( outfile, "static void *__wine_delay_imp_%d_hmod;\n", i);
818 for (j = 0; j < dll_imports[i]->nb_imports; j++)
820 fprintf( outfile, "void __wine_delay_imp_%d_%s();\n",
821 i, dll_imports[i]->imports[j].name );
824 fprintf( outfile, "\n" );
825 fprintf( outfile, "static struct {\n" );
826 fprintf( outfile, " struct ImgDelayDescr {\n" );
827 fprintf( outfile, " unsigned int grAttrs;\n" );
828 fprintf( outfile, " const char *szName;\n" );
829 fprintf( outfile, " void **phmod;\n" );
830 fprintf( outfile, " void **pIAT;\n" );
831 fprintf( outfile, " const char **pINT;\n" );
832 fprintf( outfile, " void* pBoundIAT;\n" );
833 fprintf( outfile, " void* pUnloadIAT;\n" );
834 fprintf( outfile, " unsigned long dwTimeStamp;\n" );
835 fprintf( outfile, " } imp[%d];\n", nb_delayed );
836 fprintf( outfile, " void *IAT[%d];\n", total_delayed );
837 fprintf( outfile, " const char *INT[%d];\n", total_delayed );
838 fprintf( outfile, "} delay_imports = {\n" );
839 fprintf( outfile, " {\n" );
840 for (i = j = 0; i < nb_imports; i++)
842 if (!dll_imports[i]->delay) continue;
843 fprintf( outfile, " { 0, \"%s\", &__wine_delay_imp_%d_hmod, &delay_imports.IAT[%d], &delay_imports.INT[%d], 0, 0, 0 },\n",
844 dll_imports[i]->dll, i, j, j );
845 j += dll_imports[i]->nb_imports;
847 fprintf( outfile, " },\n {\n" );
848 for (i = 0; i < nb_imports; i++)
850 if (!dll_imports[i]->delay) continue;
851 fprintf( outfile, " /* %s */\n", dll_imports[i]->dll );
852 for (j = 0; j < dll_imports[i]->nb_imports; j++)
854 fprintf( outfile, " &__wine_delay_imp_%d_%s,\n", i, dll_imports[i]->imports[j].name);
857 fprintf( outfile, " },\n {\n" );
858 for (i = 0; i < nb_imports; i++)
860 if (!dll_imports[i]->delay) continue;
861 fprintf( outfile, " /* %s */\n", dll_imports[i]->dll );
862 for (j = 0; j < dll_imports[i]->nb_imports; j++)
864 struct func *import = &dll_imports[i]->imports[j];
865 if (import->ord_only)
866 fprintf( outfile, " (char *)%d,\n", import->ordinal );
867 else
868 fprintf( outfile, " \"%s\",\n", import->name );
871 fprintf( outfile, " }\n};\n\n" );
873 /* check if there's some stub defined. if so, exception struct
874 * is already defined, so don't emit it twice
876 for (i = 0; i < nb_entry_points; i++) if (EntryPoints[i]->type == TYPE_STUB) break;
878 if (i == nb_entry_points) {
879 fprintf( outfile, "struct exc_record {\n" );
880 fprintf( outfile, " unsigned int code, flags;\n" );
881 fprintf( outfile, " void *rec, *addr;\n" );
882 fprintf( outfile, " unsigned int params;\n" );
883 fprintf( outfile, " const void *info[15];\n" );
884 fprintf( outfile, "};\n\n" );
885 fprintf( outfile, "extern void __stdcall RtlRaiseException( struct exc_record * );\n" );
888 fprintf( outfile, "extern void * __stdcall LoadLibraryA(const char*);\n");
889 fprintf( outfile, "extern void * __stdcall GetProcAddress(void *, const char*);\n");
890 fprintf( outfile, "\n" );
892 fprintf( outfile, "void *__stdcall __wine_delay_load( int idx_nr )\n" );
893 fprintf( outfile, "{\n" );
894 fprintf( outfile, " int idx = idx_nr >> 16, nr = idx_nr & 0xffff;\n" );
895 fprintf( outfile, " struct ImgDelayDescr *imd = delay_imports.imp + idx;\n" );
896 fprintf( outfile, " void **pIAT = imd->pIAT + nr;\n" );
897 fprintf( outfile, " const char** pINT = imd->pINT + nr;\n" );
898 fprintf( outfile, " void *fn;\n\n" );
900 fprintf( outfile, " if (!*imd->phmod) *imd->phmod = LoadLibraryA(imd->szName);\n" );
901 fprintf( outfile, " if (*imd->phmod && (fn = GetProcAddress(*imd->phmod, *pINT)))\n");
902 fprintf( outfile, " /* patch IAT with final value */\n" );
903 fprintf( outfile, " return *pIAT = fn;\n" );
904 fprintf( outfile, " else {\n");
905 fprintf( outfile, " struct exc_record rec;\n" );
906 fprintf( outfile, " rec.code = 0x80000100;\n" );
907 fprintf( outfile, " rec.flags = 1;\n" );
908 fprintf( outfile, " rec.rec = 0;\n" );
909 fprintf( outfile, " rec.params = 2;\n" );
910 fprintf( outfile, " rec.info[0] = imd->szName;\n" );
911 fprintf( outfile, " rec.info[1] = *pINT + 2;\n" );
912 fprintf( outfile, "#ifdef __GNUC__\n" );
913 fprintf( outfile, " rec.addr = __builtin_return_address(1);\n" );
914 fprintf( outfile, "#else\n" );
915 fprintf( outfile, " rec.addr = 0;\n" );
916 fprintf( outfile, "#endif\n" );
917 fprintf( outfile, " for (;;) RtlRaiseException( &rec );\n" );
918 fprintf( outfile, " return 0; /* shouldn't go here */\n" );
919 fprintf( outfile, " }\n}\n\n" );
921 fprintf( outfile, "#ifndef __GNUC__\n" );
922 fprintf( outfile, "static void __asm__dummy_delay_import(void) {\n" );
923 fprintf( outfile, "#endif\n" );
925 fprintf( outfile, "asm(\".align %d\\n\"\n", get_alignment(8) );
926 fprintf( outfile, " \"\\t" __ASM_FUNC("__wine_delay_load_asm") "\\n\"\n" );
927 fprintf( outfile, " \"" __ASM_NAME("__wine_delay_load_asm") ":\\n\"\n" );
928 #if defined(__i386__)
929 fprintf( outfile, " \"\\tpushl %%ecx\\n\\tpushl %%edx\\n\\tpushl %%eax\\n\"\n" );
930 fprintf( outfile, " \"\\tcall __wine_delay_load\\n\"\n" );
931 fprintf( outfile, " \"\\tpopl %%edx\\n\\tpopl %%ecx\\n\\tjmp *%%eax\\n\"\n" );
932 #elif defined(__sparc__)
933 fprintf( outfile, " \"\\tsave %%sp, -96, %%sp\\n\"\n" );
934 fprintf( outfile, " \"\\tcall __wine_delay_load\\n\"\n" );
935 fprintf( outfile, " \"\\tmov %%g1, %%o0\\n\"\n" );
936 fprintf( outfile, " \"\\tjmp %%o0\\n\\trestore\\n\"\n" );
937 #elif defined(__PPC__)
938 /* Save all callee saved registers into a stackframe. */
939 fprintf( outfile, " \"\\tstwu %%r1, -48(%%r1)\\n\"\n" );
940 fprintf( outfile, " \"\\tstw %%r3, 4(%%r1)\\n\"\n" );
941 fprintf( outfile, " \"\\tstw %%r4, 8(%%r1)\\n\"\n" );
942 fprintf( outfile, " \"\\tstw %%r5, 12(%%r1)\\n\"\n" );
943 fprintf( outfile, " \"\\tstw %%r6, 16(%%r1)\\n\"\n" );
944 fprintf( outfile, " \"\\tstw %%r7, 20(%%r1)\\n\"\n" );
945 fprintf( outfile, " \"\\tstw %%r8, 24(%%r1)\\n\"\n" );
946 fprintf( outfile, " \"\\tstw %%r9, 28(%%r1)\\n\"\n" );
947 fprintf( outfile, " \"\\tstw %%r10, 32(%%r1)\\n\"\n" );
948 fprintf( outfile, " \"\\tstw %%r11, 36(%%r1)\\n\"\n" );
949 fprintf( outfile, " \"\\tstw %%r12, 40(%%r1)\\n\"\n" );
951 /* r0 -> r3 (arg1) */
952 fprintf( outfile, " \"\\tmr %%r3, %%r0\\n\"\n" );
954 /* save return address */
955 fprintf( outfile, " \"\\tmflr %%r0\\n\"\n" );
956 fprintf( outfile, " \"\\tstw %%r0, 44(%%r1)\\n\"\n" );
958 /* Call the __wine_delay_load function, arg1 is arg1. */
959 fprintf( outfile, " \"\\tbl __wine_delay_load\\n\"\n" );
961 /* Load return value from call into ctr register */
962 fprintf( outfile, " \"\\tmtctr %%r3\\n\"\n" );
964 /* restore all saved registers and drop stackframe. */
965 fprintf( outfile, " \"\\tlwz %%r3, 4(%%r1)\\n\"\n" );
966 fprintf( outfile, " \"\\tlwz %%r4, 8(%%r1)\\n\"\n" );
967 fprintf( outfile, " \"\\tlwz %%r5, 12(%%r1)\\n\"\n" );
968 fprintf( outfile, " \"\\tlwz %%r6, 16(%%r1)\\n\"\n" );
969 fprintf( outfile, " \"\\tlwz %%r7, 20(%%r1)\\n\"\n" );
970 fprintf( outfile, " \"\\tlwz %%r8, 24(%%r1)\\n\"\n" );
971 fprintf( outfile, " \"\\tlwz %%r9, 28(%%r1)\\n\"\n" );
972 fprintf( outfile, " \"\\tlwz %%r10, 32(%%r1)\\n\"\n" );
973 fprintf( outfile, " \"\\tlwz %%r11, 36(%%r1)\\n\"\n" );
974 fprintf( outfile, " \"\\tlwz %%r12, 40(%%r1)\\n\"\n" );
975 /* Load return value from call into return register */
976 fprintf( outfile, " \"\\tlwz %%r0, 44(%%r1)\\n\"\n" );
977 fprintf( outfile, " \"\\tmtlr %%r0\\n\"\n" );
978 fprintf( outfile, " \"\\taddi %%r1, %%r1, 48\\n\"\n" );
979 /* branch to ctr register. */
980 fprintf( outfile, " \"\\tbctr\\n\"\n" );
982 #else
983 #error You need to defined delayed import thunks for your architecture!
984 #endif
986 for (i = idx = 0; i < nb_imports; i++)
988 if (!dll_imports[i]->delay) continue;
989 for (j = 0; j < dll_imports[i]->nb_imports; j++)
991 char buffer[128];
992 sprintf( buffer, "__wine_delay_imp_%d_%s", i, dll_imports[i]->imports[j].name );
993 fprintf( outfile, " \"\\t" __ASM_FUNC("%s") "\\n\"\n", buffer );
994 fprintf( outfile, " \"" __ASM_NAME("%s") ":\\n\"\n", buffer );
995 #if defined(__i386__)
996 fprintf( outfile, " \"\\tmovl $%d, %%eax\\n\"\n", (idx << 16) | j );
997 fprintf( outfile, " \"\\tjmp __wine_delay_load_asm\\n\"\n" );
998 #elif defined(__sparc__)
999 fprintf( outfile, " \"\\tset %d, %%g1\\n\"\n", (idx << 16) | j );
1000 fprintf( outfile, " \"\\tb,a __wine_delay_load_asm\\n\"\n" );
1001 #elif defined(__PPC__)
1002 /* g0 is a function scratch register or so I understand. */
1003 fprintf( outfile, " \"\\tli %%r0, %d\\n\"\n", (idx << 16) | j );
1004 fprintf( outfile, " \"\\tb __wine_delay_load_asm\\n\"\n" );
1005 #else
1006 #error You need to defined delayed import thunks for your architecture!
1007 #endif
1009 idx++;
1012 fprintf( outfile, "\n \".data\\n\\t.align %d\\n\"\n", get_alignment(8) );
1013 pos = nb_delayed * 32;
1014 for (i = 0; i < nb_imports; i++)
1016 if (!dll_imports[i]->delay) continue;
1017 for (j = 0; j < dll_imports[i]->nb_imports; j++, pos += 4)
1019 struct func *import = &dll_imports[i]->imports[j];
1020 fprintf( outfile, " \"\\t" __ASM_FUNC("%s") "\\n\"\n", import->name );
1021 fprintf( outfile, " \"\\t.globl " __ASM_NAME("%s") "\\n\"\n", import->name );
1022 fprintf( outfile, " \"" __ASM_NAME("%s") ":\\n\\t\"", import->name);
1023 #if defined(__i386__)
1024 if (strstr( import->name, "__wine_call_from_16" ))
1025 fprintf( outfile, "\".byte 0x2e\\n\\tjmp *(delay_imports+%d)\\n\\tnop\\n\"", pos );
1026 else
1027 fprintf( outfile, "\"jmp *(delay_imports+%d)\\n\\tmovl %%esi,%%esi\\n\"", pos );
1028 #elif defined(__sparc__)
1029 if ( !UsePIC )
1031 fprintf( outfile, "\"sethi %%hi(delay_imports+%d), %%g1\\n\\t\"", pos );
1032 fprintf( outfile, "\"ld [%%g1+%%lo(delay_imports+%d)], %%g1\\n\\t\"", pos );
1033 fprintf( outfile, "\"jmp %%g1\\n\\tnop\\n\"" );
1035 else
1037 /* Hmpf. Stupid sparc assembler always interprets global variable
1038 names as GOT offsets, so we have to do it the long way ... */
1039 fprintf( outfile, "\"save %%sp, -96, %%sp\\n\"" );
1040 fprintf( outfile, "\"0:\\tcall 1f\\n\\tnop\\n\"" );
1041 fprintf( outfile, "\"1:\\tsethi %%hi(delay_imports+%d-0b), %%g1\\n\\t\"", pos );
1042 fprintf( outfile, "\"or %%g1, %%lo(delay_imports+%d-0b), %%g1\\n\\t\"", pos );
1043 fprintf( outfile, "\"ld [%%g1+%%o7], %%g1\\n\\t\"" );
1044 fprintf( outfile, "\"jmp %%g1\\n\\trestore\\n\"" );
1047 #elif defined(__PPC__)
1048 fprintf(outfile, "\t\"addi 1, 1, -0x4\\n\"\n");
1049 fprintf(outfile, "\t\"\\tstw 9, 0(1)\\n\"\n");
1050 fprintf(outfile, "\t\"\\taddi 1, 1, -0x4\\n\"\n");
1051 fprintf(outfile, "\t\"\\tstw 8, 0(1)\\n\"\n");
1052 fprintf(outfile, "\t\"\\taddi 1, 1, -0x4\\n\"\n");
1053 fprintf(outfile, "\t\"\\tstw 7, 0(1)\\n\"\n");
1055 fprintf(outfile, "\t\"\\tlis 9,delay_imports+%d@ha\\n\"\n", pos);
1056 fprintf(outfile, "\t\"\\tla 8,delay_imports+%d@l(9)\\n\"\n", pos);
1057 fprintf(outfile, "\t\"\\tlwz 7, 0(8)\\n\"\n");
1058 fprintf(outfile, "\t\"\\tmtctr 7\\n\"\n");
1060 fprintf(outfile, "\t\"\\tlwz 7, 0(1)\\n\"\n");
1061 fprintf(outfile, "\t\"\\taddi 1, 1, 0x4\\n\"\n");
1062 fprintf(outfile, "\t\"\\tlwz 8, 0(1)\\n\"\n");
1063 fprintf(outfile, "\t\"\\taddi 1, 1, 0x4\\n\"\n");
1064 fprintf(outfile, "\t\"\\tlwz 9, 0(1)\\n\"\n");
1065 fprintf(outfile, "\t\"\\taddi 1, 1, 0x4\\n\"\n");
1066 fprintf(outfile, "\t\"\\tbctr\\n\"");
1068 /*fprintf(outfile, "\t\"li r0,delay_imports\\n\\t\"\n" );
1069 fprintf(outfile, "\t\"lwz r0, %d(r0)\\n\\t\"\n", pos);
1070 fprintf(outfile, "\t\"mtctr r0\\n\\t\"\n");
1071 fprintf(outfile, "\t\"bctr\\n\"");*/
1072 #else
1073 #error You need to define delayed import thunks for your architecture!
1074 #endif
1075 fprintf( outfile, "\n" );
1078 fprintf( outfile, "\".section \\\".text\\\"\");\n" );
1079 fprintf( outfile, "#ifndef __GNUC__\n" );
1080 fprintf( outfile, "}\n" );
1081 fprintf( outfile, "#endif\n" );
1082 fprintf( outfile, "\n" );
1084 done:
1085 return nb_delayed;
1088 /* output the import and delayed import tables of a Win32 module
1089 * returns number of DLLs exported in 'immediate' mode
1091 int output_imports( FILE *outfile )
1093 output_delayed_imports( outfile );
1094 return output_immediate_imports( outfile );