Support for Mac OS X powerpc register names (based on a patch by
[wine/multimedia.git] / tools / winebuild / import.c
blobb7c81962a0e53c5094b76c7cc8778ac46e8c293c
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 "sqrt",
104 "strcat",
105 "strchr",
106 "strcmp",
107 "strcpy",
108 "strcspn",
109 "strlen",
110 "strncat",
111 "strncmp",
112 "strncpy",
113 "strpbrk",
114 "strrchr",
115 "strspn",
116 "strstr",
117 "tan",
118 "tanh"
121 #ifdef __powerpc__
122 # ifdef __APPLE__
123 # define ppc_high(mem) "ha16(" mem ")"
124 # define ppc_low(mem) "lo16(" mem ")"
125 static const char * const ppc_reg[32] = { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
126 "r8", "r9", "r10","r11","r12","r13","r14","r15",
127 "r16","r17","r18","r19","r20","r21","r22","r23",
128 "r24","r25","r26","r27","r28","r29","r30","r31" };
129 # else /* __APPLE__ */
130 # define ppc_high(mem) "(" mem ")@hi"
131 # define ppc_low(mem) "(" mem ")@l"
132 static const char * const ppc_reg[32] = { "0", "1", "2", "3", "4", "5", "6", "7",
133 "8", "9", "10","11","12","13","14","15",
134 "16","17","18","19","20","21","22","23",
135 "24","25","26","27","28","29","30","31" };
136 # endif /* __APPLE__ */
137 #endif /* __powerpc__ */
139 /* compare function names; helper for resolve_imports */
140 static int name_cmp( const void *name, const void *entry )
142 return strcmp( *(char **)name, *(char **)entry );
145 /* compare function names; helper for resolve_imports */
146 static int func_cmp( const void *func1, const void *func2 )
148 return strcmp( ((struct func *)func1)->name, ((struct func *)func2)->name );
151 /* locate a symbol in a (sorted) list */
152 inline static const char *find_symbol( const char *name, char **table, int size )
154 char **res = NULL;
156 if (table) {
157 res = bsearch( &name, table, size, sizeof(*table), name_cmp );
160 return res ? *res : NULL;
163 /* locate an export in a (sorted) export list */
164 inline static struct func *find_export( const char *name, struct func *table, int size )
166 struct func func, *res = NULL;
168 func.name = (char *)name;
169 func.ordinal = -1;
170 if (table) res = bsearch( &func, table, size, sizeof(*table), func_cmp );
171 return res;
174 /* sort a symbol table */
175 inline static void sort_symbols( char **table, int size )
177 if (table )
178 qsort( table, size, sizeof(*table), name_cmp );
181 /* free an import structure */
182 static void free_imports( struct import *imp )
184 int i;
186 for (i = 0; i < imp->nb_exports; i++) free( imp->exports[i].name );
187 for (i = 0; i < imp->nb_imports; i++) free( imp->imports[i].name );
188 free( imp->exports );
189 free( imp->imports );
190 free( imp->dll );
191 free( imp );
194 /* remove the temp file at exit */
195 static void remove_ld_tmp_file(void)
197 if (ld_tmp_file) unlink( ld_tmp_file );
200 /* check whether a given dll has already been imported */
201 static int is_already_imported( const char *name )
203 int i;
205 for (i = 0; i < nb_imports; i++)
207 if (!strcmp( dll_imports[i]->dll, name )) return 1;
209 return 0;
212 /* open the .so library for a given dll in a specified path */
213 static char *try_library_path( const char *path, const char *name )
215 char *buffer;
216 int fd;
218 buffer = xmalloc( strlen(path) + strlen(name) + 9 );
219 sprintf( buffer, "%s/lib%s.def", path, name );
221 /* check if the file exists */
222 if ((fd = open( buffer, O_RDONLY )) != -1)
224 close( fd );
225 return buffer;
227 free( buffer );
228 return NULL;
231 /* open the .so library for a given dll */
232 static char *open_library( const char *name )
234 char *fullname;
235 int i;
237 for (i = 0; i < nb_lib_paths; i++)
239 if ((fullname = try_library_path( lib_path[i], name ))) return fullname;
241 if (!(fullname = try_library_path( ".", name )))
242 fatal_error( "could not open .def file for %s\n", name );
243 return fullname;
246 /* skip whitespace until the next token */
247 static char *skip_whitespace( char *p )
249 while (*p && isspace(*p)) p++;
250 if (!*p || *p == ';') p = NULL;
251 return p;
254 /* skip to the start of the next token, null terminating the current one */
255 static char *next_token( char *p )
257 while (*p && !isspace(*p)) p++;
258 if (*p) *p++ = 0;
259 return skip_whitespace( p );
262 /* remove the @nn suffix from stdcall names */
263 static char *remove_stdcall_decoration( char *buffer )
265 char *p = buffer + strlen(buffer) - 1;
266 while (p > buffer && isdigit(*p)) p--;
267 if (p > buffer && *p == '@') *p = 0;
268 return buffer;
271 /* read in the list of exported symbols of an import library */
272 static int read_import_lib( const char *name, struct import *imp )
274 FILE *f;
275 char buffer[1024];
276 char *fullname;
277 int size;
279 imp->exports = NULL;
280 imp->nb_exports = size = 0;
282 fullname = open_library( name );
283 f = open_input_file( NULL, fullname );
284 free( fullname );
286 while (fgets( buffer, sizeof(buffer), f ))
288 char *name, *flags;
289 int ordinal = 0, ord_only = 0;
291 char *p = buffer + strlen(buffer) - 1;
292 if (p < buffer) goto next;
293 if (*p == '\n') *p-- = 0;
295 p = buffer;
296 if (!(p = skip_whitespace(p))) goto next;
297 name = p;
298 p = next_token( name );
300 if (!strcmp( name, "LIBRARY" ))
302 if (!p)
304 error( "Expected name after LIBRARY\n" );
305 goto next;
307 name = p;
308 p = next_token( name );
309 if (p)
311 error( "Garbage after LIBRARY statement\n" );
312 goto next;
314 if (is_already_imported( name ))
316 close_input_file( f );
317 return 0; /* ignore this dll */
319 free( imp->dll );
320 imp->dll = xstrdup( name );
321 goto next;
323 if (!strcmp( name, "EXPORTS" )) goto next;
325 /* check for ordinal */
326 if (!p)
328 error( "Expected ordinal after function name\n" );
329 goto next;
331 if (*p != '@' || !isdigit(p[1]))
333 error( "Expected ordinal after function name '%s'\n", name );
334 goto next;
336 ordinal = strtol( p+1, &p, 10 );
337 if (ordinal >= MAX_ORDINALS)
339 error( "Invalid ordinal number %d\n", ordinal );
340 goto next;
343 /* check for optional flags */
344 while (p && (p = skip_whitespace(p)))
346 flags = p;
347 p = next_token( flags );
348 if (!strcmp( flags, "NONAME" ))
350 ord_only = 1;
351 if (!ordinal)
353 error( "Invalid ordinal number %d\n", ordinal );
354 goto next;
357 else if (!strcmp( flags, "CONSTANT" ) || !strcmp( flags, "DATA" ))
359 /* we don't support importing non-function entry points */
360 goto next;
362 else if (!strcmp( flags, "PRIVATE" ))
364 /* function must not be imported */
365 goto next;
367 else
369 error( "Garbage after ordinal declaration\n" );
370 goto next;
374 if (imp->nb_exports == size)
376 size += 128;
377 imp->exports = xrealloc( imp->exports, size * sizeof(*imp->exports) );
379 if ((p = strchr( name, '=' ))) *p = 0;
380 remove_stdcall_decoration( name );
381 imp->exports[imp->nb_exports].name = xstrdup( name );
382 imp->exports[imp->nb_exports].ordinal = ordinal;
383 imp->exports[imp->nb_exports].ord_only = ord_only;
384 imp->nb_exports++;
385 next:
386 current_line++;
388 close_input_file( f );
389 if (imp->nb_exports)
390 qsort( imp->exports, imp->nb_exports, sizeof(*imp->exports), func_cmp );
391 return !nb_errors;
394 /* add a dll to the list of imports */
395 void add_import_dll( const char *name, int delay )
397 struct import *imp;
398 char *fullname;
400 fullname = xmalloc( strlen(name) + 5 );
401 strcpy( fullname, name );
402 if (!strchr( fullname, '.' )) strcat( fullname, ".dll" );
404 /* check if we already imported it */
405 if (is_already_imported( fullname ))
407 free( fullname );
408 return;
411 imp = xmalloc( sizeof(*imp) );
412 imp->dll = fullname;
413 imp->delay = delay;
414 imp->imports = NULL;
415 imp->nb_imports = 0;
417 if (delay) nb_delayed++;
419 if (read_import_lib( name, imp ))
421 dll_imports = xrealloc( dll_imports, (nb_imports+1) * sizeof(*dll_imports) );
422 dll_imports[nb_imports++] = imp;
424 else
426 free_imports( imp );
427 if (nb_errors) exit(1);
431 /* remove an imported dll, based on its index in the dll_imports array */
432 static void remove_import_dll( int index )
434 struct import *imp = dll_imports[index];
436 memmove( &dll_imports[index], &dll_imports[index+1], sizeof(imp) * (nb_imports - index - 1) );
437 nb_imports--;
438 if (imp->delay) nb_delayed--;
439 free_imports( imp );
442 /* initialize the list of ignored symbols */
443 static void init_ignored_symbols(void)
445 int i;
447 nb_ignore_symbols = sizeof(default_ignored_symbols)/sizeof(default_ignored_symbols[0]);
448 ignore_size = nb_ignore_symbols + 32;
449 ignore_symbols = xmalloc( ignore_size * sizeof(*ignore_symbols) );
450 for (i = 0; i < nb_ignore_symbols; i++)
451 ignore_symbols[i] = xstrdup( default_ignored_symbols[i] );
454 /* add a symbol to the ignored symbol list */
455 /* if the name starts with '-' the symbol is removed instead */
456 void add_ignore_symbol( const char *name )
458 int i;
460 if (!ignore_symbols) init_ignored_symbols(); /* first time around, fill list with defaults */
462 if (name[0] == '-') /* remove it */
464 if (!name[1]) /* remove everything */
466 for (i = 0; i < nb_ignore_symbols; i++) free( ignore_symbols[i] );
467 nb_ignore_symbols = 0;
469 else
471 for (i = 0; i < nb_ignore_symbols; i++)
473 if (!strcmp( ignore_symbols[i], name+1 ))
475 free( ignore_symbols[i] );
476 memmove( &ignore_symbols[i], &ignore_symbols[i+1], nb_ignore_symbols - i - 1 );
477 nb_ignore_symbols--;
482 else
484 if (nb_ignore_symbols == ignore_size)
486 ignore_size += 32;
487 ignore_symbols = xrealloc( ignore_symbols, ignore_size * sizeof(*ignore_symbols) );
489 ignore_symbols[nb_ignore_symbols++] = xstrdup( name );
493 /* add a function to the list of imports from a given dll */
494 static void add_import_func( struct import *imp, const struct func *func )
496 imp->imports = xrealloc( imp->imports, (imp->nb_imports+1) * sizeof(*imp->imports) );
497 imp->imports[imp->nb_imports].name = xstrdup( func->name );
498 imp->imports[imp->nb_imports].ordinal = func->ordinal;
499 imp->imports[imp->nb_imports].ord_only = func->ord_only;
500 imp->nb_imports++;
501 total_imports++;
502 if (imp->delay) total_delayed++;
505 /* add a symbol to the undef list */
506 inline static void add_undef_symbol( const char *name )
508 if (nb_undef_symbols == undef_size)
510 undef_size += 128;
511 undef_symbols = xrealloc( undef_symbols, undef_size * sizeof(*undef_symbols) );
513 undef_symbols[nb_undef_symbols++] = xstrdup( name );
516 /* remove all the holes in the undefined symbol list; return the number of removed symbols */
517 static int remove_symbol_holes(void)
519 int i, off;
520 for (i = off = 0; i < nb_undef_symbols; i++)
522 if (!undef_symbols[i]) off++;
523 else undef_symbols[i - off] = undef_symbols[i];
525 nb_undef_symbols -= off;
526 return off;
529 /* add a symbol to the extra list, but only if needed */
530 static int add_extra_symbol( const char **extras, int *count, const char *name )
532 int i;
534 if (!find_symbol( name, undef_symbols, nb_undef_symbols ))
536 /* check if the symbol is being exported by this dll */
537 for (i = 0; i < nb_entry_points; i++)
539 ORDDEF *odp = EntryPoints[i];
540 if (odp->type == TYPE_STDCALL ||
541 odp->type == TYPE_CDECL ||
542 odp->type == TYPE_VARARGS ||
543 odp->type == TYPE_EXTERN)
545 if (odp->name && !strcmp( odp->name, name )) return 0;
548 extras[*count] = name;
549 (*count)++;
551 return 1;
554 /* add the extra undefined symbols that will be contained in the generated spec file itself */
555 static void add_extra_undef_symbols(void)
557 const char *extras[10];
558 int i, count = 0, nb_stubs = 0, nb_regs = 0;
559 int kernel_imports = 0, ntdll_imports = 0;
561 sort_symbols( undef_symbols, nb_undef_symbols );
563 for (i = 0; i < nb_entry_points; i++)
565 ORDDEF *odp = EntryPoints[i];
566 if (odp->type == TYPE_STUB) nb_stubs++;
567 if (odp->flags & FLAG_REGISTER) nb_regs++;
570 /* add symbols that will be contained in the spec file itself */
571 switch (SpecMode)
573 case SPEC_MODE_DLL:
574 break;
575 case SPEC_MODE_GUIEXE:
576 kernel_imports += add_extra_symbol( extras, &count, "GetCommandLineA" );
577 kernel_imports += add_extra_symbol( extras, &count, "GetStartupInfoA" );
578 kernel_imports += add_extra_symbol( extras, &count, "GetModuleHandleA" );
579 /* fall through */
580 case SPEC_MODE_CUIEXE:
581 kernel_imports += add_extra_symbol( extras, &count, "ExitProcess" );
582 break;
583 case SPEC_MODE_GUIEXE_UNICODE:
584 kernel_imports += add_extra_symbol( extras, &count, "GetCommandLineA" );
585 kernel_imports += add_extra_symbol( extras, &count, "GetStartupInfoA" );
586 kernel_imports += add_extra_symbol( extras, &count, "GetModuleHandleA" );
587 /* fall through */
588 case SPEC_MODE_CUIEXE_UNICODE:
589 kernel_imports += add_extra_symbol( extras, &count, "ExitProcess" );
590 break;
592 if (nb_delayed)
594 kernel_imports += add_extra_symbol( extras, &count, "LoadLibraryA" );
595 kernel_imports += add_extra_symbol( extras, &count, "GetProcAddress" );
597 if (nb_regs)
598 ntdll_imports += add_extra_symbol( extras, &count, "__wine_call_from_32_regs" );
599 if (nb_delayed || nb_stubs)
600 ntdll_imports += add_extra_symbol( extras, &count, "RtlRaiseException" );
602 /* make sure we import the dlls that contain these functions */
603 if (kernel_imports) add_import_dll( "kernel32", 0 );
604 if (ntdll_imports) add_import_dll( "ntdll", 0 );
606 if (count)
608 for (i = 0; i < count; i++) add_undef_symbol( extras[i] );
609 sort_symbols( undef_symbols, nb_undef_symbols );
613 /* check if a given imported dll is not needed, taking forwards into account */
614 static int check_unused( const struct import* imp )
616 int i;
617 size_t len = strlen(imp->dll);
618 const char *p = strchr( imp->dll, '.' );
619 if (p && !strcasecmp( p, ".dll" )) len = p - imp->dll;
621 for (i = Base; i <= Limit; i++)
623 ORDDEF *odp = Ordinals[i];
624 if (!odp || !(odp->flags & FLAG_FORWARD)) continue;
625 if (!strncasecmp( odp->link_name, imp->dll, len ) &&
626 odp->link_name[len] == '.')
627 return 0; /* found a forward, it is used */
629 return 1;
632 /* combine a list of object files with ld into a single object file */
633 /* returns the name of the combined file */
634 static const char *ldcombine_files( char **argv )
636 int i, len = 0;
637 char *cmd;
638 int fd, err;
640 if (output_file_name && output_file_name[0])
642 ld_tmp_file = xmalloc( strlen(output_file_name) + 10 );
643 strcpy( ld_tmp_file, output_file_name );
644 strcat( ld_tmp_file, ".XXXXXX.o" );
646 else ld_tmp_file = xstrdup( "/tmp/winebuild.tmp.XXXXXX.o" );
648 if ((fd = mkstemps( ld_tmp_file, 2 ) == -1)) fatal_error( "could not generate a temp file\n" );
649 close( fd );
650 atexit( remove_ld_tmp_file );
652 for (i = 0; argv[i]; i++) len += strlen(argv[i]) + 1;
653 cmd = xmalloc( len + strlen(ld_tmp_file) + 10 );
654 sprintf( cmd, "ld -r -o %s", ld_tmp_file );
655 for (i = 0; argv[i]; i++) sprintf( cmd + strlen(cmd), " %s", argv[i] );
656 err = system( cmd );
657 if (err) fatal_error( "ld -r failed with status %d\n", err );
658 free( cmd );
659 return ld_tmp_file;
662 /* read in the list of undefined symbols */
663 void read_undef_symbols( char **argv )
665 FILE *f;
666 char buffer[1024];
667 int err;
668 const char *name;
670 if (!argv[0]) return;
672 undef_size = nb_undef_symbols = 0;
674 /* if we have multiple object files, link them together */
675 if (argv[1]) name = ldcombine_files( argv );
676 else name = argv[0];
678 sprintf( buffer, "nm -u %s", name );
679 if (!(f = popen( buffer, "r" )))
680 fatal_error( "Cannot execute '%s'\n", buffer );
682 while (fgets( buffer, sizeof(buffer), f ))
684 char *p = buffer + strlen(buffer) - 1;
685 if (p < buffer) continue;
686 if (*p == '\n') *p-- = 0;
687 p = buffer;
688 while (*p == ' ') p++;
689 if (p[0] == 'U' && p[1] == ' ' && p[2]) p += 2;
690 add_undef_symbol( p );
692 if ((err = pclose( f ))) warning( "nm -u %s error %d\n", name, err );
695 static void remove_ignored_symbols(void)
697 int i;
699 if (!ignore_symbols) init_ignored_symbols();
700 sort_symbols( ignore_symbols, nb_ignore_symbols );
701 for (i = 0; i < nb_undef_symbols; i++)
703 if (find_symbol( undef_symbols[i], ignore_symbols, nb_ignore_symbols ))
705 free( undef_symbols[i] );
706 undef_symbols[i] = NULL;
709 remove_symbol_holes();
712 /* resolve the imports for a Win32 module */
713 int resolve_imports( void )
715 int i, j;
717 if (nb_undef_symbols == -1) return 0; /* no symbol file specified */
719 add_extra_undef_symbols();
720 remove_ignored_symbols();
722 for (i = 0; i < nb_imports; i++)
724 struct import *imp = dll_imports[i];
726 for (j = 0; j < nb_undef_symbols; j++)
728 struct func *func = find_export( undef_symbols[j], imp->exports, imp->nb_exports );
729 if (func)
731 add_import_func( imp, func );
732 free( undef_symbols[j] );
733 undef_symbols[j] = NULL;
736 /* remove all the holes in the undef symbols list */
737 if (!remove_symbol_holes() && check_unused( imp ))
739 /* the dll is not used, get rid of it */
740 warning( "%s imported but no symbols used\n", imp->dll );
741 remove_import_dll( i );
742 i--;
745 return 1;
748 /* output the import table of a Win32 module */
749 static int output_immediate_imports( FILE *outfile )
751 int i, j, pos;
752 int nb_imm = nb_imports - nb_delayed;
754 if (!nb_imm) goto done;
756 /* main import header */
758 fprintf( outfile, "\nstatic struct {\n" );
759 fprintf( outfile, " struct {\n" );
760 fprintf( outfile, " void *OriginalFirstThunk;\n" );
761 fprintf( outfile, " unsigned int TimeDateStamp;\n" );
762 fprintf( outfile, " unsigned int ForwarderChain;\n" );
763 fprintf( outfile, " const char *Name;\n" );
764 fprintf( outfile, " void *FirstThunk;\n" );
765 fprintf( outfile, " } imp[%d];\n", nb_imm+1 );
766 fprintf( outfile, " const char *data[%d];\n",
767 total_imports - total_delayed + nb_imm );
768 fprintf( outfile, "} imports = {\n {\n" );
770 /* list of dlls */
772 for (i = j = 0; i < nb_imports; i++)
774 if (dll_imports[i]->delay) continue;
775 fprintf( outfile, " { 0, 0, 0, \"%s\", &imports.data[%d] },\n",
776 dll_imports[i]->dll, j );
777 j += dll_imports[i]->nb_imports + 1;
780 fprintf( outfile, " { 0, 0, 0, 0, 0 },\n" );
781 fprintf( outfile, " },\n {\n" );
783 /* list of imported functions */
785 for (i = 0; i < nb_imports; i++)
787 if (dll_imports[i]->delay) continue;
788 fprintf( outfile, " /* %s */\n", dll_imports[i]->dll );
789 for (j = 0; j < dll_imports[i]->nb_imports; j++)
791 struct func *import = &dll_imports[i]->imports[j];
792 if (!import->ord_only)
794 unsigned short ord = import->ordinal;
795 fprintf( outfile, " \"\\%03o\\%03o%s\",\n",
796 *(unsigned char *)&ord, *((unsigned char *)&ord + 1), import->name );
798 else
799 fprintf( outfile, " (char *)%d,\n", import->ordinal );
801 fprintf( outfile, " 0,\n" );
803 fprintf( outfile, " }\n};\n\n" );
805 /* thunks for imported functions */
807 fprintf( outfile, "#ifndef __GNUC__\nstatic void __asm__dummy_import(void) {\n#endif\n\n" );
808 pos = 20 * (nb_imm + 1); /* offset of imports.data from start of imports */
809 fprintf( outfile, "asm(\".data\\n\\t.align %d\\n\"\n", get_alignment(8) );
810 for (i = 0; i < nb_imports; i++)
812 if (dll_imports[i]->delay) continue;
813 for (j = 0; j < dll_imports[i]->nb_imports; j++, pos += 4)
815 struct func *import = &dll_imports[i]->imports[j];
816 fprintf( outfile, " \"\\t" __ASM_FUNC("%s") "\\n\"\n", import->name );
817 fprintf( outfile, " \"\\t.globl " __ASM_NAME("%s") "\\n\"\n", import->name );
818 fprintf( outfile, " \"" __ASM_NAME("%s") ":\\n\\t", import->name);
820 #if defined(__i386__)
821 if (strstr( import->name, "__wine_call_from_16" ))
822 fprintf( outfile, ".byte 0x2e\\n\\tjmp *(imports+%d)\\n\\tnop\\n", pos );
823 else
824 fprintf( outfile, "jmp *(imports+%d)\\n\\tmovl %%esi,%%esi\\n", pos );
825 #elif defined(__sparc__)
826 if ( !UsePIC )
828 fprintf( outfile, "sethi %%hi(imports+%d), %%g1\\n\\t", pos );
829 fprintf( outfile, "ld [%%g1+%%lo(imports+%d)], %%g1\\n\\t", pos );
830 fprintf( outfile, "jmp %%g1\\n\\tnop\\n" );
832 else
834 /* Hmpf. Stupid sparc assembler always interprets global variable
835 names as GOT offsets, so we have to do it the long way ... */
836 fprintf( outfile, "save %%sp, -96, %%sp\\n" );
837 fprintf( outfile, "0:\\tcall 1f\\n\\tnop\\n" );
838 fprintf( outfile, "1:\\tsethi %%hi(imports+%d-0b), %%g1\\n\\t", pos );
839 fprintf( outfile, "or %%g1, %%lo(imports+%d-0b), %%g1\\n\\t", pos );
840 fprintf( outfile, "ld [%%g1+%%o7], %%g1\\n\\t" );
841 fprintf( outfile, "jmp %%g1\\n\\trestore\\n" );
844 #elif defined(__powerpc__)
845 fprintf(outfile, "\taddi %s, %s, -0x4\\n\"\n", ppc_reg[1], ppc_reg[1]);
846 fprintf(outfile, "\t\"\\tstw %s, 0(%s)\\n\"\n", ppc_reg[9], ppc_reg[1]);
847 fprintf(outfile, "\t\"\\taddi %s, %s, -0x4\\n\"\n", ppc_reg[1], ppc_reg[1]);
848 fprintf(outfile, "\t\"\\tstw %s, 0(%s)\\n\"\n", ppc_reg[8], ppc_reg[1]);
849 fprintf(outfile, "\t\"\\taddi %s, %s, -0x4\\n\"\n", ppc_reg[1], ppc_reg[1]);
850 fprintf(outfile, "\t\"\\tstw %s, 0(%s)\\n\"\n", ppc_reg[7], ppc_reg[1]);
852 fprintf(outfile, "\t\"\\tlis %s, " ppc_high(__ASM_NAME("imports") "+ %d") "\\n\"\n", ppc_reg[9], pos);
853 fprintf(outfile, "\t\"\\tla %s, " ppc_low (__ASM_NAME("imports") "+ %d") "(%s)\\n\"\n", ppc_reg[8], pos, ppc_reg[9]);
854 fprintf(outfile, "\t\"\\tlwz %s, 0(%s)\\n\"\n", ppc_reg[7], ppc_reg[8]);
855 fprintf(outfile, "\t\"\\tmctr %s\\n\"\n", ppc_reg[7]);
857 fprintf(outfile, "\t\"\\tlwz %s, 0(%s)\\n\"\n", ppc_reg[7], ppc_reg[1]);
858 fprintf(outfile, "\t\"\\taddi %s, %s, 0x4\\n\"\n", ppc_reg[1], ppc_reg[1]);
859 fprintf(outfile, "\t\"\\tlwz %s, 0(%s)\\n\"\n", ppc_reg[8], ppc_reg[1]);
860 fprintf(outfile, "\t\"\\taddi %s, %s, 0x4\\n\"\n", ppc_reg[1], ppc_reg[1]);
861 fprintf(outfile, "\t\"\\tlwz %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\"\\tbctr\\n");
864 #else
865 #error You need to define import thunks for your architecture!
866 #endif
867 fprintf( outfile, "\"\n" );
869 pos += 4;
871 fprintf( outfile, "\".section\\t\\\".text\\\"\");\n#ifndef __GNUC__\n}\n#endif\n\n" );
873 done:
874 return nb_imm;
877 /* output the delayed import table of a Win32 module */
878 static int output_delayed_imports( FILE *outfile )
880 int i, idx, j, pos;
882 if (!nb_delayed) goto done;
884 for (i = 0; i < nb_imports; i++)
886 if (!dll_imports[i]->delay) continue;
887 fprintf( outfile, "static void *__wine_delay_imp_%d_hmod;\n", i);
888 for (j = 0; j < dll_imports[i]->nb_imports; j++)
890 fprintf( outfile, "void __wine_delay_imp_%d_%s();\n",
891 i, dll_imports[i]->imports[j].name );
894 fprintf( outfile, "\n" );
895 fprintf( outfile, "static struct {\n" );
896 fprintf( outfile, " struct ImgDelayDescr {\n" );
897 fprintf( outfile, " unsigned int grAttrs;\n" );
898 fprintf( outfile, " const char *szName;\n" );
899 fprintf( outfile, " void **phmod;\n" );
900 fprintf( outfile, " void **pIAT;\n" );
901 fprintf( outfile, " const char **pINT;\n" );
902 fprintf( outfile, " void* pBoundIAT;\n" );
903 fprintf( outfile, " void* pUnloadIAT;\n" );
904 fprintf( outfile, " unsigned long dwTimeStamp;\n" );
905 fprintf( outfile, " } imp[%d];\n", nb_delayed );
906 fprintf( outfile, " void *IAT[%d];\n", total_delayed );
907 fprintf( outfile, " const char *INT[%d];\n", total_delayed );
908 fprintf( outfile, "} delay_imports = {\n" );
909 fprintf( outfile, " {\n" );
910 for (i = j = 0; i < nb_imports; i++)
912 if (!dll_imports[i]->delay) continue;
913 fprintf( outfile, " { 0, \"%s\", &__wine_delay_imp_%d_hmod, &delay_imports.IAT[%d], &delay_imports.INT[%d], 0, 0, 0 },\n",
914 dll_imports[i]->dll, i, j, j );
915 j += dll_imports[i]->nb_imports;
917 fprintf( outfile, " },\n {\n" );
918 for (i = 0; i < nb_imports; i++)
920 if (!dll_imports[i]->delay) continue;
921 fprintf( outfile, " /* %s */\n", dll_imports[i]->dll );
922 for (j = 0; j < dll_imports[i]->nb_imports; j++)
924 fprintf( outfile, " &__wine_delay_imp_%d_%s,\n", i, dll_imports[i]->imports[j].name);
927 fprintf( outfile, " },\n {\n" );
928 for (i = 0; i < nb_imports; i++)
930 if (!dll_imports[i]->delay) continue;
931 fprintf( outfile, " /* %s */\n", dll_imports[i]->dll );
932 for (j = 0; j < dll_imports[i]->nb_imports; j++)
934 struct func *import = &dll_imports[i]->imports[j];
935 if (import->ord_only)
936 fprintf( outfile, " (char *)%d,\n", import->ordinal );
937 else
938 fprintf( outfile, " \"%s\",\n", import->name );
941 fprintf( outfile, " }\n};\n\n" );
943 /* check if there's some stub defined. if so, exception struct
944 * is already defined, so don't emit it twice
946 for (i = 0; i < nb_entry_points; i++) if (EntryPoints[i]->type == TYPE_STUB) break;
948 if (i == nb_entry_points) {
949 fprintf( outfile, "struct exc_record {\n" );
950 fprintf( outfile, " unsigned int code, flags;\n" );
951 fprintf( outfile, " void *rec, *addr;\n" );
952 fprintf( outfile, " unsigned int params;\n" );
953 fprintf( outfile, " const void *info[15];\n" );
954 fprintf( outfile, "};\n\n" );
955 fprintf( outfile, "extern void __stdcall RtlRaiseException( struct exc_record * );\n" );
958 fprintf( outfile, "extern void * __stdcall LoadLibraryA(const char*);\n");
959 fprintf( outfile, "extern void * __stdcall GetProcAddress(void *, const char*);\n");
960 fprintf( outfile, "\n" );
962 fprintf( outfile, "void *__stdcall __wine_delay_load( int idx_nr )\n" );
963 fprintf( outfile, "{\n" );
964 fprintf( outfile, " int idx = idx_nr >> 16, nr = idx_nr & 0xffff;\n" );
965 fprintf( outfile, " struct ImgDelayDescr *imd = delay_imports.imp + idx;\n" );
966 fprintf( outfile, " void **pIAT = imd->pIAT + nr;\n" );
967 fprintf( outfile, " const char** pINT = imd->pINT + nr;\n" );
968 fprintf( outfile, " void *fn;\n\n" );
970 fprintf( outfile, " if (!*imd->phmod) *imd->phmod = LoadLibraryA(imd->szName);\n" );
971 fprintf( outfile, " if (*imd->phmod && (fn = GetProcAddress(*imd->phmod, *pINT)))\n");
972 fprintf( outfile, " /* patch IAT with final value */\n" );
973 fprintf( outfile, " return *pIAT = fn;\n" );
974 fprintf( outfile, " else {\n");
975 fprintf( outfile, " struct exc_record rec;\n" );
976 fprintf( outfile, " rec.code = 0x80000100;\n" );
977 fprintf( outfile, " rec.flags = 1;\n" );
978 fprintf( outfile, " rec.rec = 0;\n" );
979 fprintf( outfile, " rec.params = 2;\n" );
980 fprintf( outfile, " rec.info[0] = imd->szName;\n" );
981 fprintf( outfile, " rec.info[1] = *pINT + 2;\n" );
982 fprintf( outfile, "#ifdef __GNUC__\n" );
983 fprintf( outfile, " rec.addr = __builtin_return_address(1);\n" );
984 fprintf( outfile, "#else\n" );
985 fprintf( outfile, " rec.addr = 0;\n" );
986 fprintf( outfile, "#endif\n" );
987 fprintf( outfile, " for (;;) RtlRaiseException( &rec );\n" );
988 fprintf( outfile, " return 0; /* shouldn't go here */\n" );
989 fprintf( outfile, " }\n}\n\n" );
991 fprintf( outfile, "#ifndef __GNUC__\n" );
992 fprintf( outfile, "static void __asm__dummy_delay_import(void) {\n" );
993 fprintf( outfile, "#endif\n" );
995 fprintf( outfile, "asm(\".align %d\\n\"\n", get_alignment(8) );
996 fprintf( outfile, " \"\\t" __ASM_FUNC("__wine_delay_load_asm") "\\n\"\n" );
997 fprintf( outfile, " \"" __ASM_NAME("__wine_delay_load_asm") ":\\n\"\n" );
998 #if defined(__i386__)
999 fprintf( outfile, " \"\\tpushl %%ecx\\n\\tpushl %%edx\\n\\tpushl %%eax\\n\"\n" );
1000 fprintf( outfile, " \"\\tcall __wine_delay_load\\n\"\n" );
1001 fprintf( outfile, " \"\\tpopl %%edx\\n\\tpopl %%ecx\\n\\tjmp *%%eax\\n\"\n" );
1002 #elif defined(__sparc__)
1003 fprintf( outfile, " \"\\tsave %%sp, -96, %%sp\\n\"\n" );
1004 fprintf( outfile, " \"\\tcall __wine_delay_load\\n\"\n" );
1005 fprintf( outfile, " \"\\tmov %%g1, %%o0\\n\"\n" );
1006 fprintf( outfile, " \"\\tjmp %%o0\\n\\trestore\\n\"\n" );
1007 #elif defined(__powerpc__)
1008 /* Save all callee saved registers into a stackframe. */
1009 fprintf( outfile, " \"\\tstwu %s, -48, %s\\n\"\n", ppc_reg[1], ppc_reg[1]);
1010 fprintf( outfile, " \"\\tstw %s, 4, %s\\n\"\n", ppc_reg[3], ppc_reg[1]);
1011 fprintf( outfile, " \"\\tstw %s, 8, %s\\n\"\n", ppc_reg[4], ppc_reg[1]);
1012 fprintf( outfile, " \"\\tstw %s, 12, %s\\n\"\n", ppc_reg[5], ppc_reg[1]);
1013 fprintf( outfile, " \"\\tstw %s, 16, %s\\n\"\n", ppc_reg[6], ppc_reg[1]);
1014 fprintf( outfile, " \"\\tstw %s, 20, %s\\n\"\n", ppc_reg[7], ppc_reg[1]);
1015 fprintf( outfile, " \"\\tstw %s, 24, %s\\n\"\n", ppc_reg[8], ppc_reg[1]);
1016 fprintf( outfile, " \"\\tstw %s, 28, %s\\n\"\n", ppc_reg[9], ppc_reg[1]);
1017 fprintf( outfile, " \"\\tstw %s, 32, %s\\n\"\n", ppc_reg[10], ppc_reg[1]);
1018 fprintf( outfile, " \"\\tstw %s, 36, %s\\n\"\n", ppc_reg[11], ppc_reg[1]);
1019 fprintf( outfile, " \"\\tstw %s, 40, %s\\n\"\n", ppc_reg[12], ppc_reg[1]);
1021 /* r0 -> r3 (arg1) */
1022 fprintf( outfile, " \"\\tmr %s, %s\\n\"\n", ppc_reg[3], ppc_reg[0]);
1024 /* save return address */
1025 fprintf( outfile, " \"\\tmflr %s\\n\"\n", ppc_reg[0]);
1026 fprintf( outfile, " \"\\tstw %s, 44, %s\\n\"\n", ppc_reg[0], ppc_reg[1]);
1028 /* Call the __wine_delay_load function, arg1 is arg1. */
1029 fprintf( outfile, " \"\\tbl " __ASM_NAME("__wine_delay_load") "\\n\"\n");
1031 /* Load return value from call into ctr register */
1032 fprintf( outfile, " \"\\tmtctr %s\\n\"\n", ppc_reg[3]);
1034 /* restore all saved registers and drop stackframe. */
1035 fprintf( outfile, " \"\\tlwz %s, 4, %s\\n\"\n", ppc_reg[3], ppc_reg[1]);
1036 fprintf( outfile, " \"\\tlwz %s, 8, %s\\n\"\n", ppc_reg[4], ppc_reg[1]);
1037 fprintf( outfile, " \"\\tlwz %s, 12, %s\\n\"\n", ppc_reg[5], ppc_reg[1]);
1038 fprintf( outfile, " \"\\tlwz %s, 16, %s\\n\"\n", ppc_reg[6], ppc_reg[1]);
1039 fprintf( outfile, " \"\\tlwz %s, 20, %s\\n\"\n", ppc_reg[7], ppc_reg[1]);
1040 fprintf( outfile, " \"\\tlwz %s, 24, %s\\n\"\n", ppc_reg[8], ppc_reg[1]);
1041 fprintf( outfile, " \"\\tlwz %s, 28, %s\\n\"\n", ppc_reg[9], ppc_reg[1]);
1042 fprintf( outfile, " \"\\tlwz %s, 32, %s\\n\"\n", ppc_reg[10], ppc_reg[1]);
1043 fprintf( outfile, " \"\\tlwz %s, 36, %s\\n\"\n", ppc_reg[11], ppc_reg[1]);
1044 fprintf( outfile, " \"\\tlwz %s, 40, %s\\n\"\n", ppc_reg[12], ppc_reg[1]);
1046 /* Load return value from call into return register */
1047 fprintf( outfile, " \"\\tlwz %s, 44, %s\\n\"\n", ppc_reg[0], ppc_reg[1]);
1048 fprintf( outfile, " \"\\tmtlr %s\\n\"\n", ppc_reg[0]);
1049 fprintf( outfile, " \"\\taddi %s, %s, 48\\n\"\n", ppc_reg[1], ppc_reg[1]);
1051 /* branch to ctr register. */
1052 fprintf( outfile, "\"bctr\\n\"\n");
1053 #else
1054 #error You need to defined delayed import thunks for your architecture!
1055 #endif
1057 for (i = idx = 0; i < nb_imports; i++)
1059 if (!dll_imports[i]->delay) continue;
1060 for (j = 0; j < dll_imports[i]->nb_imports; j++)
1062 char buffer[128];
1063 sprintf( buffer, "__wine_delay_imp_%d_%s", i, dll_imports[i]->imports[j].name );
1064 fprintf( outfile, " \"\\t" __ASM_FUNC("%s") "\\n\"\n", buffer );
1065 fprintf( outfile, " \"" __ASM_NAME("%s") ":\\n\"\n", buffer );
1066 #if defined(__i386__)
1067 fprintf( outfile, " \"\\tmovl $%d, %%eax\\n\"\n", (idx << 16) | j );
1068 fprintf( outfile, " \"\\tjmp __wine_delay_load_asm\\n\"\n" );
1069 #elif defined(__sparc__)
1070 fprintf( outfile, " \"\\tset %d, %%g1\\n\"\n", (idx << 16) | j );
1071 fprintf( outfile, " \"\\tb,a __wine_delay_load_asm\\n\"\n" );
1072 #elif defined(__powerpc__)
1073 /* g0 is a function scratch register or so I understand. */
1074 /* First load the upper half-word, and then the lower part */
1075 fprintf( outfile, " \"\\lis %s, %d\\n\"\n", ppc_reg[0], idx);
1076 fprintf( outfile, " \"\\taddi %s, %s, %d\\n\"\n", ppc_reg[0], ppc_reg[0], j);
1077 fprintf( outfile, " \"\\tb " __ASM_NAME("__wine_delay_load_asm") "\\n\"\n");
1078 #else
1079 #error You need to defined delayed import thunks for your architecture!
1080 #endif
1082 idx++;
1085 fprintf( outfile, "\n \".data\\n\\t.align %d\\n\"\n", get_alignment(8) );
1086 pos = nb_delayed * 32;
1087 for (i = 0; i < nb_imports; i++)
1089 if (!dll_imports[i]->delay) continue;
1090 for (j = 0; j < dll_imports[i]->nb_imports; j++, pos += 4)
1092 struct func *import = &dll_imports[i]->imports[j];
1093 fprintf( outfile, " \"\\t" __ASM_FUNC("%s") "\\n\"\n", import->name );
1094 fprintf( outfile, " \"\\t.globl " __ASM_NAME("%s") "\\n\"\n", import->name );
1095 fprintf( outfile, " \"" __ASM_NAME("%s") ":\\n\\t\"", import->name);
1096 #if defined(__i386__)
1097 if (strstr( import->name, "__wine_call_from_16" ))
1098 fprintf( outfile, "\".byte 0x2e\\n\\tjmp *(delay_imports+%d)\\n\\tnop\\n\"", pos );
1099 else
1100 fprintf( outfile, "\"jmp *(delay_imports+%d)\\n\\tmovl %%esi,%%esi\\n\"", pos );
1101 #elif defined(__sparc__)
1102 if ( !UsePIC )
1104 fprintf( outfile, "\"sethi %%hi(delay_imports+%d), %%g1\\n\\t\"", pos );
1105 fprintf( outfile, "\"ld [%%g1+%%lo(delay_imports+%d)], %%g1\\n\\t\"", pos );
1106 fprintf( outfile, "\"jmp %%g1\\n\\tnop\\n\"" );
1108 else
1110 /* Hmpf. Stupid sparc assembler always interprets global variable
1111 names as GOT offsets, so we have to do it the long way ... */
1112 fprintf( outfile, "\"save %%sp, -96, %%sp\\n\"" );
1113 fprintf( outfile, "\"0:\\tcall 1f\\n\\tnop\\n\"" );
1114 fprintf( outfile, "\"1:\\tsethi %%hi(delay_imports+%d-0b), %%g1\\n\\t\"", pos );
1115 fprintf( outfile, "\"or %%g1, %%lo(delay_imports+%d-0b), %%g1\\n\\t\"", pos );
1116 fprintf( outfile, "\"ld [%%g1+%%o7], %%g1\\n\\t\"" );
1117 fprintf( outfile, "\"jmp %%g1\\n\\trestore\\n\"" );
1120 #elif defined(__powerpc__)
1121 fprintf( outfile, "\t addi %s, %s, -0x4\\n\"\n", ppc_reg[1], ppc_reg[1]);
1122 fprintf( outfile, "\t\"\\tstw %s, 0(%s)\\n\"\n", ppc_reg[9], ppc_reg[1]);
1123 fprintf( outfile, "\t\"\\taddi %s, %s, -0x4\\n\"\n", ppc_reg[1], ppc_reg[1]);
1124 fprintf( outfile, "\t\"\\tstw %s, 0(%s)\\n\"\n", ppc_reg[8], ppc_reg[1]);
1125 fprintf( outfile, "\t\"\\taddi %s, %s, -0x4\\n\"\n", ppc_reg[1], ppc_reg[1]);
1126 fprintf( outfile, "\t\"\\tstw %s, 0(%s)\\n\"\n", ppc_reg[7], ppc_reg[1]);
1127 fprintf( outfile, "\t\"\\tlis %s " ppc_high(__ASM_NAME("imports") "+ %d") "\\n\"\n", ppc_reg[9], pos);
1128 fprintf( outfile, "\t\"\\tla %s " ppc_low (__ASM_NAME("imports") "+ %d") "(%s)\\n\"\n", ppc_reg[8], pos, ppc_reg[9]);
1129 fprintf( outfile, "\t\"\\tlwz %s, 0(%s)\\n\"\n", ppc_reg[7], ppc_reg[8]);
1130 fprintf( outfile, "\t\"\\tmtctr %s\\n\"\n", ppc_reg[7]);
1132 fprintf( outfile, "\t\"\\tlwz %s, 0(%s)\\n\"\n", ppc_reg[7], ppc_reg[1]);
1133 fprintf( outfile, "\t\"\\taddi %s, %s, 0x4\\n\"\n", ppc_reg[1], ppc_reg[1]);
1134 fprintf( outfile, "\t\"\\tlwz %s, 0(%s)\\n\"\n", ppc_reg[8], ppc_reg[1]);
1135 fprintf( outfile, "\t\"\\taddi %s, %s, 0x4\\n\"\n", ppc_reg[1], ppc_reg[1]);
1136 fprintf( outfile, "\t\"\\tlwz %s, 0(%s)\\n\"\n", ppc_reg[9], ppc_reg[1]);
1137 fprintf( outfile, "\t\"\\taddi %s, %s, 0x4\\n\"\n", ppc_reg[1], ppc_reg[1]);
1138 fprintf( outfile, "\t\"\\tbctr\\n");
1139 #else
1140 #error You need to define delayed import thunks for your architecture!
1141 #endif
1142 fprintf( outfile, "\n" );
1145 fprintf( outfile, "\".section \\\".text\\\"\");\n" );
1146 fprintf( outfile, "#ifndef __GNUC__\n" );
1147 fprintf( outfile, "}\n" );
1148 fprintf( outfile, "#endif\n" );
1149 fprintf( outfile, "\n" );
1151 done:
1152 return nb_delayed;
1155 /* output the import and delayed import tables of a Win32 module
1156 * returns number of DLLs exported in 'immediate' mode
1158 int output_imports( FILE *outfile )
1160 output_delayed_imports( outfile );
1161 return output_immediate_imports( outfile );