Added a --target option to allow cross-compilation.
[wine/multimedia.git] / tools / winebuild / import.c
blob47885b87961d79b321ca67ec0047a5de733b5388
1 /*
2 * DLL imports support
4 * Copyright 2000, 2004 Alexandre Julliard
5 * Copyright 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 #include <stdarg.h>
30 #ifdef HAVE_SYS_STAT_H
31 # include <sys/stat.h>
32 #endif
33 #ifdef HAVE_UNISTD_H
34 # include <unistd.h>
35 #endif
37 #include "windef.h"
38 #include "winbase.h"
39 #include "wine/exception.h"
40 #include "build.h"
42 struct import
44 DLLSPEC *spec; /* description of the imported dll */
45 char *full_name; /* full name of the input file */
46 dev_t dev; /* device/inode of the input file */
47 ino_t ino;
48 int delay; /* delay or not dll loading ? */
49 ORDDEF **exports; /* functions exported from this dll */
50 int nb_exports; /* number of exported functions */
51 ORDDEF **imports; /* functions we want to import from this dll */
52 int nb_imports; /* number of imported functions */
55 static char **undef_symbols; /* list of undefined symbols */
56 static int nb_undef_symbols = -1;
57 static int undef_size;
59 static char **ignore_symbols; /* list of symbols to ignore */
60 static int nb_ignore_symbols;
61 static int ignore_size;
63 static char *ld_tmp_file; /* ld temp file name */
65 static struct import **dll_imports = NULL;
66 static int nb_imports = 0; /* number of imported dlls (delayed or not) */
67 static int nb_delayed = 0; /* number of delayed dlls */
68 static int total_imports = 0; /* total number of imported functions */
69 static int total_delayed = 0; /* total number of imported functions in delayed DLLs */
70 static char **delayed_imports; /* names of delayed import dlls */
71 static int nb_delayed_imports; /* size of the delayed_imports array */
73 /* list of symbols that are ignored by default */
74 static const char * const default_ignored_symbols[] =
76 "abs",
77 "acos",
78 "asin",
79 "atan",
80 "atan2",
81 "atof",
82 "atoi",
83 "atol",
84 "bsearch",
85 "ceil",
86 "cos",
87 "cosh",
88 "exp",
89 "fabs",
90 "floor",
91 "fmod",
92 "frexp",
93 "labs",
94 "log",
95 "log10",
96 "memchr",
97 "memcmp",
98 "memcpy",
99 "memmove",
100 "memset",
101 "modf",
102 "pow",
103 "qsort",
104 "sin",
105 "sinh",
106 "sqrt",
107 "strcat",
108 "strchr",
109 "strcmp",
110 "strcpy",
111 "strcspn",
112 "strlen",
113 "strncat",
114 "strncmp",
115 "strncpy",
116 "strpbrk",
117 "strrchr",
118 "strspn",
119 "strstr",
120 "tan",
121 "tanh"
125 static inline const char *ppc_reg( int reg )
127 static const char * const ppc_regs[32] = { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
128 "r8", "r9", "r10","r11","r12","r13","r14","r15",
129 "r16","r17","r18","r19","r20","r21","r22","r23",
130 "r24","r25","r26","r27","r28","r29","r30","r31" };
131 if (target_platform == PLATFORM_APPLE) return ppc_regs[reg];
132 return ppc_regs[reg] + 1; /* skip the 'r' */
135 /* compare function names; helper for resolve_imports */
136 static int name_cmp( const void *name, const void *entry )
138 return strcmp( *(const char* const *)name, *(const char* const *)entry );
141 /* compare function names; helper for resolve_imports */
142 static int func_cmp( const void *func1, const void *func2 )
144 const ORDDEF *odp1 = *(const ORDDEF * const *)func1;
145 const ORDDEF *odp2 = *(const ORDDEF * const *)func2;
146 return strcmp( odp1->name ? odp1->name : odp1->export_name,
147 odp2->name ? odp2->name : odp2->export_name );
150 /* locate a symbol in a (sorted) list */
151 inline static const char *find_symbol( const char *name, char **table, int size )
153 char **res = NULL;
155 if (table) {
156 res = bsearch( &name, table, size, sizeof(*table), name_cmp );
159 return res ? *res : NULL;
162 /* locate an export in a (sorted) export list */
163 inline static ORDDEF *find_export( const char *name, ORDDEF **table, int size )
165 ORDDEF func, *odp, **res = NULL;
167 func.name = (char *)name;
168 func.ordinal = -1;
169 odp = &func;
170 if (table) res = bsearch( &odp, table, size, sizeof(*table), func_cmp );
171 return res ? *res : NULL;
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 inline static void output_function_size( FILE *outfile, const char *name )
183 const char *size = func_size( name );
184 if (size[0]) fprintf( outfile, " \"\\t%s\\n\"\n", size );
187 /* free an import structure */
188 static void free_imports( struct import *imp )
190 free( imp->exports );
191 free( imp->imports );
192 free_dll_spec( imp->spec );
193 free( imp->full_name );
194 free( imp );
197 /* remove the temp file at exit */
198 static void remove_ld_tmp_file(void)
200 if (ld_tmp_file) unlink( ld_tmp_file );
203 /* check whether a given dll is imported in delayed mode */
204 static int is_delayed_import( const char *name )
206 int i;
208 for (i = 0; i < nb_delayed_imports; i++)
210 if (!strcmp( delayed_imports[i], name )) return 1;
212 return 0;
215 /* check whether a given dll has already been imported */
216 static struct import *is_already_imported( const char *name )
218 int i;
220 for (i = 0; i < nb_imports; i++)
222 if (!strcmp( dll_imports[i]->spec->file_name, name )) return dll_imports[i];
224 return NULL;
227 /* open the .so library for a given dll in a specified path */
228 static char *try_library_path( const char *path, const char *name )
230 char *buffer;
231 int fd;
233 buffer = xmalloc( strlen(path) + strlen(name) + 9 );
234 sprintf( buffer, "%s/lib%s.def", path, name );
236 /* check if the file exists */
237 if ((fd = open( buffer, O_RDONLY )) != -1)
239 close( fd );
240 return buffer;
242 free( buffer );
243 return NULL;
246 /* find the .def import library for a given dll */
247 static char *find_library( const char *name )
249 char *fullname;
250 int i;
252 for (i = 0; i < nb_lib_paths; i++)
254 if ((fullname = try_library_path( lib_path[i], name ))) return fullname;
256 fatal_error( "could not open .def file for %s\n", name );
257 return NULL;
260 /* read in the list of exported symbols of an import library */
261 static int read_import_lib( struct import *imp )
263 FILE *f;
264 int i, ret;
265 struct stat stat;
266 struct import *prev_imp;
267 DLLSPEC *spec = imp->spec;
269 f = open_input_file( NULL, imp->full_name );
270 fstat( fileno(f), &stat );
271 imp->dev = stat.st_dev;
272 imp->ino = stat.st_ino;
273 ret = parse_def_file( f, spec );
274 close_input_file( f );
275 if (!ret) return 0;
277 /* check if we already imported that library from a different file */
278 if ((prev_imp = is_already_imported( spec->file_name )))
280 if (prev_imp->dev != imp->dev || prev_imp->ino != imp->ino)
281 fatal_error( "%s and %s have the same export name '%s'\n",
282 prev_imp->full_name, imp->full_name, spec->file_name );
283 return 0; /* the same file was already loaded, ignore this one */
286 if (is_delayed_import( spec->file_name ))
288 imp->delay = 1;
289 nb_delayed++;
292 imp->exports = xmalloc( spec->nb_entry_points * sizeof(*imp->exports) );
294 for (i = 0; i < spec->nb_entry_points; i++)
296 ORDDEF *odp = &spec->entry_points[i];
298 if (odp->type != TYPE_STDCALL && odp->type != TYPE_CDECL) continue;
299 if (odp->flags & FLAG_PRIVATE) continue;
300 imp->exports[imp->nb_exports++] = odp;
302 imp->exports = xrealloc( imp->exports, imp->nb_exports * sizeof(*imp->exports) );
303 if (imp->nb_exports)
304 qsort( imp->exports, imp->nb_exports, sizeof(*imp->exports), func_cmp );
305 return 1;
308 /* build the dll exported name from the import lib name or path */
309 static char *get_dll_name( const char *name, const char *filename )
311 char *ret;
313 if (filename)
315 const char *basename = strrchr( filename, '/' );
316 if (!basename) basename = filename;
317 else basename++;
318 if (!strncmp( basename, "lib", 3 )) basename += 3;
319 ret = xmalloc( strlen(basename) + 5 );
320 strcpy( ret, basename );
321 if (strendswith( ret, ".def" )) ret[strlen(ret)-4] = 0;
323 else
325 ret = xmalloc( strlen(name) + 5 );
326 strcpy( ret, name );
328 if (!strchr( ret, '.' )) strcat( ret, ".dll" );
329 return ret;
332 /* add a dll to the list of imports */
333 void add_import_dll( const char *name, const char *filename )
335 struct import *imp = xmalloc( sizeof(*imp) );
337 imp->spec = alloc_dll_spec();
338 imp->spec->file_name = get_dll_name( name, filename );
339 imp->delay = 0;
340 imp->imports = NULL;
341 imp->nb_imports = 0;
342 imp->exports = NULL;
343 imp->nb_exports = 0;
345 if (filename) imp->full_name = xstrdup( filename );
346 else imp->full_name = find_library( name );
348 if (read_import_lib( imp ))
350 dll_imports = xrealloc( dll_imports, (nb_imports+1) * sizeof(*dll_imports) );
351 dll_imports[nb_imports++] = imp;
353 else
355 free_imports( imp );
356 if (nb_errors) exit(1);
360 /* add a library to the list of delayed imports */
361 void add_delayed_import( const char *name )
363 struct import *imp;
364 char *fullname = get_dll_name( name, NULL );
366 delayed_imports = xrealloc( delayed_imports, (nb_delayed_imports+1) * sizeof(*delayed_imports) );
367 delayed_imports[nb_delayed_imports++] = fullname;
368 if ((imp = is_already_imported( fullname )) && !imp->delay)
370 imp->delay = 1;
371 nb_delayed++;
375 /* remove an imported dll, based on its index in the dll_imports array */
376 static void remove_import_dll( int index )
378 struct import *imp = dll_imports[index];
380 memmove( &dll_imports[index], &dll_imports[index+1], sizeof(imp) * (nb_imports - index - 1) );
381 nb_imports--;
382 if (imp->delay) nb_delayed--;
383 free_imports( imp );
386 /* initialize the list of ignored symbols */
387 static void init_ignored_symbols(void)
389 int i;
391 nb_ignore_symbols = sizeof(default_ignored_symbols)/sizeof(default_ignored_symbols[0]);
392 ignore_size = nb_ignore_symbols + 32;
393 ignore_symbols = xmalloc( ignore_size * sizeof(*ignore_symbols) );
394 for (i = 0; i < nb_ignore_symbols; i++)
395 ignore_symbols[i] = xstrdup( default_ignored_symbols[i] );
398 /* add a symbol to the ignored symbol list */
399 /* if the name starts with '-' the symbol is removed instead */
400 void add_ignore_symbol( const char *name )
402 int i;
404 if (!ignore_symbols) init_ignored_symbols(); /* first time around, fill list with defaults */
406 if (name[0] == '-') /* remove it */
408 if (!name[1]) /* remove everything */
410 for (i = 0; i < nb_ignore_symbols; i++) free( ignore_symbols[i] );
411 nb_ignore_symbols = 0;
413 else
415 for (i = 0; i < nb_ignore_symbols; i++)
417 if (!strcmp( ignore_symbols[i], name+1 ))
419 free( ignore_symbols[i] );
420 memmove( &ignore_symbols[i], &ignore_symbols[i+1], nb_ignore_symbols - i - 1 );
421 nb_ignore_symbols--;
426 else
428 if (nb_ignore_symbols == ignore_size)
430 ignore_size += 32;
431 ignore_symbols = xrealloc( ignore_symbols, ignore_size * sizeof(*ignore_symbols) );
433 ignore_symbols[nb_ignore_symbols++] = xstrdup( name );
437 /* add a function to the list of imports from a given dll */
438 static void add_import_func( struct import *imp, ORDDEF *func )
440 imp->imports = xrealloc( imp->imports, (imp->nb_imports+1) * sizeof(*imp->imports) );
441 imp->imports[imp->nb_imports++] = func;
442 total_imports++;
443 if (imp->delay) total_delayed++;
446 /* add a symbol to the undef list */
447 inline static void add_undef_symbol( const char *name )
449 if (nb_undef_symbols == undef_size)
451 undef_size += 128;
452 undef_symbols = xrealloc( undef_symbols, undef_size * sizeof(*undef_symbols) );
454 undef_symbols[nb_undef_symbols++] = xstrdup( name );
457 /* remove all the holes in the undefined symbol list; return the number of removed symbols */
458 static int remove_symbol_holes(void)
460 int i, off;
461 for (i = off = 0; i < nb_undef_symbols; i++)
463 if (!undef_symbols[i]) off++;
464 else undef_symbols[i - off] = undef_symbols[i];
466 nb_undef_symbols -= off;
467 return off;
470 /* add a symbol to the extra list, but only if needed */
471 static int add_extra_symbol( const char **extras, int *count, const char *name, const DLLSPEC *spec )
473 int i;
475 if (!find_symbol( name, undef_symbols, nb_undef_symbols ))
477 /* check if the symbol is being exported by this dll */
478 for (i = 0; i < spec->nb_entry_points; i++)
480 ORDDEF *odp = &spec->entry_points[i];
481 if (odp->type == TYPE_STDCALL ||
482 odp->type == TYPE_CDECL ||
483 odp->type == TYPE_VARARGS ||
484 odp->type == TYPE_EXTERN)
486 if (odp->name && !strcmp( odp->name, name )) return 0;
489 extras[*count] = name;
490 (*count)++;
492 return 1;
495 /* add the extra undefined symbols that will be contained in the generated spec file itself */
496 static void add_extra_undef_symbols( const DLLSPEC *spec )
498 const char *extras[10];
499 int i, count = 0, nb_stubs = 0;
500 int kernel_imports = 0, ntdll_imports = 0;
502 sort_symbols( undef_symbols, nb_undef_symbols );
504 for (i = 0; i < spec->nb_entry_points; i++)
506 ORDDEF *odp = &spec->entry_points[i];
507 if (odp->type == TYPE_STUB) nb_stubs++;
510 /* add symbols that will be contained in the spec file itself */
511 if (!(spec->characteristics & IMAGE_FILE_DLL))
513 switch (spec->subsystem)
515 case IMAGE_SUBSYSTEM_WINDOWS_GUI:
516 case IMAGE_SUBSYSTEM_WINDOWS_CUI:
517 kernel_imports += add_extra_symbol( extras, &count, "GetCommandLineA", spec );
518 kernel_imports += add_extra_symbol( extras, &count, "GetStartupInfoA", spec );
519 kernel_imports += add_extra_symbol( extras, &count, "GetModuleHandleA", spec );
520 kernel_imports += add_extra_symbol( extras, &count, "ExitProcess", spec );
521 break;
524 if (nb_delayed)
526 kernel_imports += add_extra_symbol( extras, &count, "LoadLibraryA", spec );
527 kernel_imports += add_extra_symbol( extras, &count, "FreeLibrary", spec );
528 kernel_imports += add_extra_symbol( extras, &count, "GetProcAddress", spec );
529 kernel_imports += add_extra_symbol( extras, &count, "RaiseException", spec );
531 if (nb_stubs)
532 ntdll_imports += add_extra_symbol( extras, &count, "RtlRaiseException", spec );
534 /* make sure we import the dlls that contain these functions */
535 if (kernel_imports) add_import_dll( "kernel32", NULL );
536 if (ntdll_imports) add_import_dll( "ntdll", NULL );
538 if (count)
540 for (i = 0; i < count; i++) add_undef_symbol( extras[i] );
541 sort_symbols( undef_symbols, nb_undef_symbols );
545 /* check if a given imported dll is not needed, taking forwards into account */
546 static int check_unused( const struct import* imp, const DLLSPEC *spec )
548 int i;
549 const char *file_name = imp->spec->file_name;
550 size_t len = strlen( file_name );
551 const char *p = strchr( file_name, '.' );
552 if (p && !strcasecmp( p, ".dll" )) len = p - file_name;
554 for (i = spec->base; i <= spec->limit; i++)
556 ORDDEF *odp = spec->ordinals[i];
557 if (!odp || !(odp->flags & FLAG_FORWARD)) continue;
558 if (!strncasecmp( odp->link_name, file_name, len ) &&
559 odp->link_name[len] == '.')
560 return 0; /* found a forward, it is used */
562 return 1;
565 /* combine a list of object files with ld into a single object file */
566 /* returns the name of the combined file */
567 static const char *ldcombine_files( char **argv )
569 int i, len = 0;
570 char *cmd;
571 int fd, err;
573 if (output_file_name && output_file_name[0])
575 ld_tmp_file = xmalloc( strlen(output_file_name) + 10 );
576 strcpy( ld_tmp_file, output_file_name );
577 strcat( ld_tmp_file, ".XXXXXX.o" );
579 else ld_tmp_file = xstrdup( "/tmp/winebuild.tmp.XXXXXX.o" );
581 if ((fd = mkstemps( ld_tmp_file, 2 ) == -1)) fatal_error( "could not generate a temp file\n" );
582 close( fd );
583 atexit( remove_ld_tmp_file );
585 if (!ld_command) ld_command = xstrdup("ld");
586 for (i = 0; argv[i]; i++) len += strlen(argv[i]) + 1;
587 cmd = xmalloc( len + strlen(ld_tmp_file) + 8 + strlen(ld_command) );
588 sprintf( cmd, "%s -r -o %s", ld_command, ld_tmp_file );
589 for (i = 0; argv[i]; i++) sprintf( cmd + strlen(cmd), " %s", argv[i] );
590 err = system( cmd );
591 if (err) fatal_error( "%s -r failed with status %d\n", ld_command, err );
592 free( cmd );
593 return ld_tmp_file;
596 /* read in the list of undefined symbols */
597 void read_undef_symbols( char **argv )
599 size_t prefix_len;
600 FILE *f;
601 char *cmd, buffer[1024], name_prefix[16];
602 int err;
603 const char *name;
605 if (!argv[0]) return;
607 strcpy( name_prefix, asm_name("") );
608 prefix_len = strlen( name_prefix );
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 if (!nm_command) nm_command = xstrdup("nm");
617 cmd = xmalloc( strlen(nm_command) + strlen(name) + 5 );
618 sprintf( cmd, "%s -u %s", nm_command, name );
619 if (!(f = popen( cmd, "r" )))
620 fatal_error( "Cannot execute '%s'\n", cmd );
622 while (fgets( buffer, sizeof(buffer), f ))
624 char *p = buffer + strlen(buffer) - 1;
625 if (p < buffer) continue;
626 if (*p == '\n') *p-- = 0;
627 p = buffer;
628 while (*p == ' ') p++;
629 if (p[0] == 'U' && p[1] == ' ' && p[2]) p += 2;
630 if (prefix_len && !strncmp( p, name_prefix, prefix_len )) p += prefix_len;
631 add_undef_symbol( p );
633 if ((err = pclose( f ))) warning( "%s failed with status %d\n", cmd, err );
634 free( cmd );
637 static void remove_ignored_symbols(void)
639 int i;
641 if (!ignore_symbols) init_ignored_symbols();
642 sort_symbols( ignore_symbols, nb_ignore_symbols );
643 for (i = 0; i < nb_undef_symbols; i++)
645 if (find_symbol( undef_symbols[i], ignore_symbols, nb_ignore_symbols ))
647 free( undef_symbols[i] );
648 undef_symbols[i] = NULL;
651 remove_symbol_holes();
654 /* resolve the imports for a Win32 module */
655 int resolve_imports( DLLSPEC *spec )
657 int i, j;
659 if (nb_undef_symbols == -1) return 0; /* no symbol file specified */
661 add_extra_undef_symbols( spec );
662 remove_ignored_symbols();
664 for (i = 0; i < nb_imports; i++)
666 struct import *imp = dll_imports[i];
668 for (j = 0; j < nb_undef_symbols; j++)
670 ORDDEF *odp = find_export( undef_symbols[j], imp->exports, imp->nb_exports );
671 if (odp)
673 add_import_func( imp, odp );
674 free( undef_symbols[j] );
675 undef_symbols[j] = NULL;
678 /* remove all the holes in the undef symbols list */
679 if (!remove_symbol_holes() && check_unused( imp, spec ))
681 /* the dll is not used, get rid of it */
682 warning( "%s imported but no symbols used\n", imp->spec->file_name );
683 remove_import_dll( i );
684 i--;
687 return 1;
690 /* output a single import thunk */
691 static void output_import_thunk( FILE *outfile, const char *name, const char *table, int pos )
693 fprintf( outfile, " \"\\t.align %d\\n\"\n", get_alignment(4) );
694 fprintf( outfile, " \"\\t%s\\n\"\n", func_declaration(name) );
695 fprintf( outfile, " \"\\t.globl %s\\n\"\n", asm_name(name) );
696 fprintf( outfile, " \"%s:\\n\"\n", asm_name(name) );
698 switch(target_cpu)
700 case CPU_x86:
701 if (!UsePIC)
703 if (strstr( name, "__wine_call_from_16" )) fprintf( outfile, " \"\\t.byte 0x2e\\n\"\n" );
704 fprintf( outfile, " \"\\tjmp *(imports+%d)\\n\"\n", pos );
706 else
708 if (!strcmp( name, "__wine_call_from_32_regs" ) ||
709 !strcmp( name, "__wine_call_from_16_regs" ))
711 /* special case: need to preserve all registers */
712 fprintf( outfile, " \"\\tpushl %%eax\\n\"\n" );
713 fprintf( outfile, " \"\\tcall .L__wine_spec_%s\\n\"\n", name );
714 fprintf( outfile, " \".L__wine_spec_%s:\\n\"\n", name );
715 fprintf( outfile, " \"\\tpopl %%eax\\n\"\n" );
716 if (!strcmp( name, "__wine_call_from_16_regs" ))
717 fprintf( outfile, " \"\\t.byte 0x2e\\n\"\n" );
718 fprintf( outfile, " \"\\tmovl %s+%d-.L__wine_spec_%s(%%eax),%%eax\\n\"\n",
719 asm_name(table), pos, name );
720 fprintf( outfile, " \"\\txchgl %%eax,(%%esp)\\n\"\n" );
721 fprintf( outfile, " \"\\tret\\n\"\n" );
723 else
725 fprintf( outfile, " \"\\tcall .L__wine_spec_%s\\n\"\n", name );
726 fprintf( outfile, " \".L__wine_spec_%s:\\n\"\n", name );
727 fprintf( outfile, " \"\\tpopl %%eax\\n\"\n" );
728 if (strstr( name, "__wine_call_from_16" ))
729 fprintf( outfile, " \"\\t.byte 0x2e\\n\"\n" );
730 fprintf( outfile, " \"\\tjmp *%s+%d-.L__wine_spec_%s(%%eax)\\n\"\n",
731 asm_name(table), pos, name );
734 break;
735 case CPU_SPARC:
736 if ( !UsePIC )
738 fprintf( outfile, " \"\\tsethi %%hi(%s+%d), %%g1\\n\"\n", table, pos );
739 fprintf( outfile, " \"\\tld [%%g1+%%lo(%s+%d)], %%g1\\n\"\n", table, pos );
740 fprintf( outfile, " \"\\tjmp %%g1\\n\\tnop\\n\"\n" );
742 else
744 /* Hmpf. Stupid sparc assembler always interprets global variable
745 names as GOT offsets, so we have to do it the long way ... */
746 fprintf( outfile, " \"\\tsave %%sp, -96, %%sp\\n\"\n" );
747 fprintf( outfile, " \"0:\\tcall 1f\\n\\tnop\\n\"\n" );
748 fprintf( outfile, " \"1:\\tsethi %%hi(%s+%d-0b), %%g1\\n\"\n", table, pos );
749 fprintf( outfile, " \"\\tor %%g1, %%lo(%s+%d-0b), %%g1\\n\"\n", table, pos );
750 fprintf( outfile, " \"\\tld [%%g1+%%o7], %%g1\\n\"\n" );
751 fprintf( outfile, " \"\\tjmp %%g1\\n\\trestore\\n\"\n" );
753 break;
754 case CPU_ALPHA:
755 fprintf( outfile, " \"\\tlda $0,%s\\n\"\n", table );
756 fprintf( outfile, " \"\\tlda $0,%d($0)\\n\"\n", pos);
757 fprintf( outfile, " \"\\tjmp $31,($0)\\n\"\n" );
758 break;
759 case CPU_POWERPC:
760 fprintf(outfile, " \"\\taddi %s, %s, -0x4\\n\"\n", ppc_reg(1), ppc_reg(1));
761 fprintf(outfile, " \"\\tstw %s, 0(%s)\\n\"\n", ppc_reg(9), ppc_reg(1));
762 fprintf(outfile, " \"\\taddi %s, %s, -0x4\\n\"\n", ppc_reg(1), ppc_reg(1));
763 fprintf(outfile, " \"\\tstw %s, 0(%s)\\n\"\n", ppc_reg(8), ppc_reg(1));
764 fprintf(outfile, " \"\\taddi %s, %s, -0x4\\n\"\n", ppc_reg(1), ppc_reg(1));
765 fprintf(outfile, " \"\\tstw %s, 0(%s)\\n\"\n", ppc_reg(7), ppc_reg(1));
766 if (target_platform == PLATFORM_APPLE)
768 fprintf(outfile, " \"\\tlis %s, ha16(%s+%d)\\n\"\n",
769 ppc_reg(9), asm_name(table), pos);
770 fprintf(outfile, " \"\\tla %s, lo16(%s+%d)(%s)\\n\"\n",
771 ppc_reg(8), asm_name(table), pos, ppc_reg(9));
773 else
775 fprintf(outfile, " \"\\tlis %s, (%s+%d)@hi\\n\"\n",
776 ppc_reg(9), asm_name(table), pos);
777 fprintf(outfile, " \"\\tla %s, (%s+%d)@l(%s)\\n\"\n",
778 ppc_reg(8), asm_name(table), pos, ppc_reg(9));
780 fprintf(outfile, " \"\\tlwz %s, 0(%s)\\n\"\n", ppc_reg(7), ppc_reg(8));
781 fprintf(outfile, " \"\\tmtctr %s\\n\"\n", ppc_reg(7));
782 fprintf(outfile, " \"\\tlwz %s, 0(%s)\\n\"\n", ppc_reg(7), ppc_reg(1));
783 fprintf(outfile, " \"\\taddi %s, %s, 0x4\\n\"\n", ppc_reg(1), ppc_reg(1));
784 fprintf(outfile, " \"\\tlwz %s, 0(%s)\\n\"\n", ppc_reg(8), ppc_reg(1));
785 fprintf(outfile, " \"\\taddi %s, %s, 0x4\\n\"\n", ppc_reg(1), ppc_reg(1));
786 fprintf(outfile, " \"\\tlwz %s, 0(%s)\\n\"\n", ppc_reg(9), ppc_reg(1));
787 fprintf(outfile, " \"\\taddi %s, %s, 0x4\\n\"\n", ppc_reg(1), ppc_reg(1));
788 fprintf(outfile, " \"\\tbctr\\n\"\n");
789 break;
791 output_function_size( outfile, name );
794 /* output the import table of a Win32 module */
795 static int output_immediate_imports( FILE *outfile )
797 int i, j, nb_imm = nb_imports - nb_delayed;
799 if (!nb_imm) return 0;
801 /* main import header */
803 fprintf( outfile, "\nstatic struct {\n" );
804 fprintf( outfile, " struct {\n" );
805 fprintf( outfile, " void *OriginalFirstThunk;\n" );
806 fprintf( outfile, " unsigned int TimeDateStamp;\n" );
807 fprintf( outfile, " unsigned int ForwarderChain;\n" );
808 fprintf( outfile, " const char *Name;\n" );
809 fprintf( outfile, " void *FirstThunk;\n" );
810 fprintf( outfile, " } imp[%d];\n", nb_imm+1 );
811 fprintf( outfile, " const char *data[%d];\n",
812 total_imports - total_delayed + nb_imm );
813 fprintf( outfile, "} imports = {\n {\n" );
815 /* list of dlls */
817 for (i = j = 0; i < nb_imports; i++)
819 if (dll_imports[i]->delay) continue;
820 fprintf( outfile, " { 0, 0, 0, \"%s\", &imports.data[%d] },\n",
821 dll_imports[i]->spec->file_name, j );
822 j += dll_imports[i]->nb_imports + 1;
825 fprintf( outfile, " { 0, 0, 0, 0, 0 },\n" );
826 fprintf( outfile, " },\n {\n" );
828 /* list of imported functions */
830 for (i = 0; i < nb_imports; i++)
832 if (dll_imports[i]->delay) continue;
833 fprintf( outfile, " /* %s */\n", dll_imports[i]->spec->file_name );
834 for (j = 0; j < dll_imports[i]->nb_imports; j++)
836 ORDDEF *odp = dll_imports[i]->imports[j];
837 if (!(odp->flags & FLAG_NONAME))
839 unsigned short ord = odp->ordinal;
840 fprintf( outfile, " \"\\%03o\\%03o%s\",\n",
841 *(unsigned char *)&ord, *((unsigned char *)&ord + 1), odp->name );
843 else
844 fprintf( outfile, " (char *)%d,\n", odp->ordinal );
846 fprintf( outfile, " 0,\n" );
848 fprintf( outfile, " }\n};\n\n" );
850 return nb_imm;
853 /* output the import thunks of a Win32 module */
854 static void output_immediate_import_thunks( FILE *outfile )
856 int i, j, pos;
857 int nb_imm = nb_imports - nb_delayed;
858 static const char import_thunks[] = "__wine_spec_import_thunks";
860 if (!nb_imm) return;
862 pos = (sizeof(void *) + 2*sizeof(unsigned int) + sizeof(const char *) + sizeof(void *)) *
863 (nb_imm + 1); /* offset of imports.data from start of imports */
864 fprintf( outfile, "/* immediate import thunks */\n" );
865 fprintf( outfile, "asm(\".text\\n\\t.align %d\\n\"\n", get_alignment(8) );
866 fprintf( outfile, " \"%s:\\n\"\n", asm_name(import_thunks));
868 for (i = 0; i < nb_imports; i++)
870 if (dll_imports[i]->delay) continue;
871 for (j = 0; j < dll_imports[i]->nb_imports; j++, pos += sizeof(const char *))
873 ORDDEF *odp = dll_imports[i]->imports[j];
874 output_import_thunk( outfile, odp->name ? odp->name : odp->export_name,
875 "imports", pos );
877 pos += 4;
879 output_function_size( outfile, import_thunks );
880 fprintf( outfile, ");\n" );
883 /* output the delayed import table of a Win32 module */
884 static int output_delayed_imports( FILE *outfile, const DLLSPEC *spec )
886 int i, j;
888 if (!nb_delayed) return 0;
890 fprintf( outfile, "static void *__wine_delay_imp_hmod[%d];\n", nb_delayed );
891 for (i = 0; i < nb_imports; i++)
893 if (!dll_imports[i]->delay) continue;
894 for (j = 0; j < dll_imports[i]->nb_imports; j++)
896 ORDDEF *odp = dll_imports[i]->imports[j];
897 const char *name = odp->name ? odp->name : odp->export_name;
898 fprintf( outfile, "void __wine_delay_imp_%d_%s();\n", i, name );
901 fprintf( outfile, "\n" );
902 fprintf( outfile, "static struct {\n" );
903 fprintf( outfile, " struct ImgDelayDescr {\n" );
904 fprintf( outfile, " unsigned int grAttrs;\n" );
905 fprintf( outfile, " const char *szName;\n" );
906 fprintf( outfile, " void **phmod;\n" );
907 fprintf( outfile, " void **pIAT;\n" );
908 fprintf( outfile, " const char **pINT;\n" );
909 fprintf( outfile, " void* pBoundIAT;\n" );
910 fprintf( outfile, " void* pUnloadIAT;\n" );
911 fprintf( outfile, " unsigned long dwTimeStamp;\n" );
912 fprintf( outfile, " } imp[%d];\n", nb_delayed );
913 fprintf( outfile, " void *IAT[%d];\n", total_delayed );
914 fprintf( outfile, " const char *INT[%d];\n", total_delayed );
915 fprintf( outfile, "} delay_imports = {\n" );
916 fprintf( outfile, " {\n" );
917 for (i = j = 0; i < nb_imports; i++)
919 if (!dll_imports[i]->delay) continue;
920 fprintf( outfile, " { 0, \"%s\", &__wine_delay_imp_hmod[%d], &delay_imports.IAT[%d], &delay_imports.INT[%d], 0, 0, 0 },\n",
921 dll_imports[i]->spec->file_name, i, j, j );
922 j += dll_imports[i]->nb_imports;
924 fprintf( outfile, " },\n {\n" );
925 for (i = 0; i < nb_imports; i++)
927 if (!dll_imports[i]->delay) continue;
928 fprintf( outfile, " /* %s */\n", dll_imports[i]->spec->file_name );
929 for (j = 0; j < dll_imports[i]->nb_imports; j++)
931 ORDDEF *odp = dll_imports[i]->imports[j];
932 const char *name = odp->name ? odp->name : odp->export_name;
933 fprintf( outfile, " &__wine_delay_imp_%d_%s,\n", i, name );
936 fprintf( outfile, " },\n {\n" );
937 for (i = 0; i < nb_imports; i++)
939 if (!dll_imports[i]->delay) continue;
940 fprintf( outfile, " /* %s */\n", dll_imports[i]->spec->file_name );
941 for (j = 0; j < dll_imports[i]->nb_imports; j++)
943 ORDDEF *odp = dll_imports[i]->imports[j];
944 if (!odp->name)
945 fprintf( outfile, " (char *)%d,\n", odp->ordinal );
946 else
947 fprintf( outfile, " \"%s\",\n", odp->name );
950 fprintf( outfile, " }\n};\n\n" );
952 fprintf( outfile, "extern void __stdcall RaiseException(unsigned int, unsigned int, unsigned int, const void *args[]);\n" );
953 fprintf( outfile, "extern void * __stdcall LoadLibraryA(const char*);\n");
954 fprintf( outfile, "extern void * __stdcall GetProcAddress(void *, const char*);\n");
955 fprintf( outfile, "\n" );
957 fprintf( outfile, "void *__stdcall __wine_delay_load( int idx_nr )\n" );
958 fprintf( outfile, "{\n" );
959 fprintf( outfile, " int idx = idx_nr >> 16, nr = idx_nr & 0xffff;\n" );
960 fprintf( outfile, " struct ImgDelayDescr *imd = delay_imports.imp + idx;\n" );
961 fprintf( outfile, " void **pIAT = imd->pIAT + nr;\n" );
962 fprintf( outfile, " const char** pINT = imd->pINT + nr;\n" );
963 fprintf( outfile, " void *fn;\n\n" );
965 fprintf( outfile, " if (!*imd->phmod) *imd->phmod = LoadLibraryA(imd->szName);\n" );
966 fprintf( outfile, " if (*imd->phmod && (fn = GetProcAddress(*imd->phmod, *pINT)))\n");
967 fprintf( outfile, " /* patch IAT with final value */\n" );
968 fprintf( outfile, " return *pIAT = fn;\n" );
969 fprintf( outfile, " else {\n");
970 fprintf( outfile, " const void *args[2];\n" );
971 fprintf( outfile, " args[0] = imd->szName;\n" );
972 fprintf( outfile, " args[1] = *pINT;\n" );
973 fprintf( outfile, " RaiseException( 0x%08x, %d, 2, args );\n",
974 EXCEPTION_WINE_STUB, EH_NONCONTINUABLE );
975 fprintf( outfile, " return 0;\n" );
976 fprintf( outfile, " }\n}\n" );
978 return nb_delayed;
981 /* output the delayed import thunks of a Win32 module */
982 static void output_delayed_import_thunks( FILE *outfile, const DLLSPEC *spec )
984 int i, idx, j, pos, extra_stack_storage = 0;
985 static const char delayed_import_loaders[] = "__wine_spec_delayed_import_loaders";
986 static const char delayed_import_thunks[] = "__wine_spec_delayed_import_thunks";
988 if (!nb_delayed) return;
990 fprintf( outfile, "/* delayed import thunks */\n" );
991 fprintf( outfile, "asm(\".text\\n\"\n" );
992 fprintf( outfile, " \"\\t.align %d\\n\"\n", get_alignment(8) );
993 fprintf( outfile, " \"%s:\\n\"\n", asm_name(delayed_import_loaders));
994 fprintf( outfile, " \"\\t%s\\n\"\n", func_declaration("__wine_delay_load_asm") );
995 fprintf( outfile, " \"%s:\\n\"\n", asm_name("__wine_delay_load_asm") );
996 switch(target_cpu)
998 case CPU_x86:
999 fprintf( outfile, " \"\\tpushl %%ecx\\n\\tpushl %%edx\\n\\tpushl %%eax\\n\"\n" );
1000 fprintf( outfile, " \"\\tcall %s\\n\"\n", asm_name("__wine_delay_load") );
1001 fprintf( outfile, " \"\\tpopl %%edx\\n\\tpopl %%ecx\\n\\tjmp *%%eax\\n\"\n" );
1002 break;
1003 case CPU_SPARC:
1004 fprintf( outfile, " \"\\tsave %%sp, -96, %%sp\\n\"\n" );
1005 fprintf( outfile, " \"\\tcall %s\\n\"\n", asm_name("__wine_delay_load") );
1006 fprintf( outfile, " \"\\tmov %%g1, %%o0\\n\"\n" );
1007 fprintf( outfile, " \"\\tjmp %%o0\\n\\trestore\\n\"\n" );
1008 break;
1009 case CPU_ALPHA:
1010 fprintf( outfile, " \"\\tjsr $26,%s\\n\"\n", asm_name("__wine_delay_load") );
1011 fprintf( outfile, " \"\\tjmp $31,($0)\\n\"\n" );
1012 break;
1013 case CPU_POWERPC:
1014 if (target_platform == PLATFORM_APPLE) extra_stack_storage = 56;
1016 /* Save all callee saved registers into a stackframe. */
1017 fprintf( outfile, " \"\\tstwu %s, -%d(%s)\\n\"\n",ppc_reg(1), 48+extra_stack_storage, ppc_reg(1));
1018 fprintf( outfile, " \"\\tstw %s, %d(%s)\\n\"\n", ppc_reg(3), 4+extra_stack_storage, ppc_reg(1));
1019 fprintf( outfile, " \"\\tstw %s, %d(%s)\\n\"\n", ppc_reg(4), 8+extra_stack_storage, ppc_reg(1));
1020 fprintf( outfile, " \"\\tstw %s, %d(%s)\\n\"\n", ppc_reg(5), 12+extra_stack_storage, ppc_reg(1));
1021 fprintf( outfile, " \"\\tstw %s, %d(%s)\\n\"\n", ppc_reg(6), 16+extra_stack_storage, ppc_reg(1));
1022 fprintf( outfile, " \"\\tstw %s, %d(%s)\\n\"\n", ppc_reg(7), 20+extra_stack_storage, ppc_reg(1));
1023 fprintf( outfile, " \"\\tstw %s, %d(%s)\\n\"\n", ppc_reg(8), 24+extra_stack_storage, ppc_reg(1));
1024 fprintf( outfile, " \"\\tstw %s, %d(%s)\\n\"\n", ppc_reg(9), 28+extra_stack_storage, ppc_reg(1));
1025 fprintf( outfile, " \"\\tstw %s, %d(%s)\\n\"\n", ppc_reg(10),32+extra_stack_storage, ppc_reg(1));
1026 fprintf( outfile, " \"\\tstw %s, %d(%s)\\n\"\n", ppc_reg(11),36+extra_stack_storage, ppc_reg(1));
1027 fprintf( outfile, " \"\\tstw %s, %d(%s)\\n\"\n", ppc_reg(12),40+extra_stack_storage, ppc_reg(1));
1029 /* r0 -> r3 (arg1) */
1030 fprintf( outfile, " \"\\tmr %s, %s\\n\"\n", ppc_reg(3), ppc_reg(0));
1032 /* save return address */
1033 fprintf( outfile, " \"\\tmflr %s\\n\"\n", ppc_reg(0));
1034 fprintf( outfile, " \"\\tstw %s, %d(%s)\\n\"\n", ppc_reg(0), 44+extra_stack_storage, ppc_reg(1));
1036 /* Call the __wine_delay_load function, arg1 is arg1. */
1037 fprintf( outfile, " \"\\tbl %s\\n\"\n", asm_name("__wine_delay_load") );
1039 /* Load return value from call into ctr register */
1040 fprintf( outfile, " \"\\tmtctr %s\\n\"\n", ppc_reg(3));
1042 /* restore all saved registers and drop stackframe. */
1043 fprintf( outfile, " \"\\tlwz %s, %d(%s)\\n\"\n", ppc_reg(3), 4+extra_stack_storage, ppc_reg(1));
1044 fprintf( outfile, " \"\\tlwz %s, %d(%s)\\n\"\n", ppc_reg(4), 8+extra_stack_storage, ppc_reg(1));
1045 fprintf( outfile, " \"\\tlwz %s, %d(%s)\\n\"\n", ppc_reg(5), 12+extra_stack_storage, ppc_reg(1));
1046 fprintf( outfile, " \"\\tlwz %s, %d(%s)\\n\"\n", ppc_reg(6), 16+extra_stack_storage, ppc_reg(1));
1047 fprintf( outfile, " \"\\tlwz %s, %d(%s)\\n\"\n", ppc_reg(7), 20+extra_stack_storage, ppc_reg(1));
1048 fprintf( outfile, " \"\\tlwz %s, %d(%s)\\n\"\n", ppc_reg(8), 24+extra_stack_storage, ppc_reg(1));
1049 fprintf( outfile, " \"\\tlwz %s, %d(%s)\\n\"\n", ppc_reg(9), 28+extra_stack_storage, ppc_reg(1));
1050 fprintf( outfile, " \"\\tlwz %s, %d(%s)\\n\"\n", ppc_reg(10),32+extra_stack_storage, ppc_reg(1));
1051 fprintf( outfile, " \"\\tlwz %s, %d(%s)\\n\"\n", ppc_reg(11),36+extra_stack_storage, ppc_reg(1));
1052 fprintf( outfile, " \"\\tlwz %s, %d(%s)\\n\"\n", ppc_reg(12),40+extra_stack_storage, ppc_reg(1));
1054 /* Load return value from call into return register */
1055 fprintf( outfile, " \"\\tlwz %s, %d(%s)\\n\"\n", ppc_reg(0), 44+extra_stack_storage, ppc_reg(1));
1056 fprintf( outfile, " \"\\tmtlr %s\\n\"\n", ppc_reg(0));
1057 fprintf( outfile, " \"\\taddi %s, %s, %d\\n\"\n", ppc_reg(1), ppc_reg(1), 48+extra_stack_storage);
1059 /* branch to ctr register. */
1060 fprintf( outfile, " \"bctr\\n\"\n");
1061 break;
1063 output_function_size( outfile, "__wine_delay_load_asm" );
1065 for (i = idx = 0; i < nb_imports; i++)
1067 if (!dll_imports[i]->delay) continue;
1068 for (j = 0; j < dll_imports[i]->nb_imports; j++)
1070 char buffer[128];
1071 ORDDEF *odp = dll_imports[i]->imports[j];
1072 const char *name = odp->name ? odp->name : odp->export_name;
1074 sprintf( buffer, "__wine_delay_imp_%d_%s", i, name );
1075 fprintf( outfile, " \"\\t%s\\n\"\n", func_declaration(buffer) );
1076 fprintf( outfile, " \"%s:\\n\"\n", asm_name(buffer) );
1077 switch(target_cpu)
1079 case CPU_x86:
1080 fprintf( outfile, " \"\\tmovl $%d, %%eax\\n\"\n", (idx << 16) | j );
1081 fprintf( outfile, " \"\\tjmp %s\\n\"\n", asm_name("__wine_delay_load_asm") );
1082 break;
1083 case CPU_SPARC:
1084 fprintf( outfile, " \"\\tset %d, %%g1\\n\"\n", (idx << 16) | j );
1085 fprintf( outfile, " \"\\tb,a %s\\n\"\n", asm_name("__wine_delay_load_asm") );
1086 break;
1087 case CPU_ALPHA:
1088 fprintf( outfile, " \"\\tlda $0,%d($31)\\n\"\n", j);
1089 fprintf( outfile, " \"\\tldah $0,%d($0)\\n\"\n", idx);
1090 fprintf( outfile, " \"\\tjmp $31,%s\\n\"\n", asm_name("__wine_delay_load_asm") );
1091 break;
1092 case CPU_POWERPC:
1093 switch(target_platform)
1095 case PLATFORM_APPLE:
1096 /* On Darwin we can use r0 and r2 */
1097 /* Upper part in r2 */
1098 fprintf( outfile, " \"\\tlis %s, %d\\n\"\n", ppc_reg(2), idx);
1099 /* Lower part + r2 -> r0, Note we can't use r0 directly */
1100 fprintf( outfile, " \"\\taddi %s, %s, %d\\n\"\n", ppc_reg(0), ppc_reg(2), j);
1101 fprintf( outfile, " \"\\tb %s\\n\"\n", asm_name("__wine_delay_load_asm") );
1102 break;
1103 default:
1104 /* On linux we can't use r2 since r2 is not a scratch register (hold the TOC) */
1105 /* Save r13 on the stack */
1106 fprintf( outfile, " \"\\taddi %s, %s, -0x4\\n\"\n", ppc_reg(1), ppc_reg(1));
1107 fprintf( outfile, " \"\\tstw %s, 0(%s)\\n\"\n", ppc_reg(13), ppc_reg(1));
1108 /* Upper part in r13 */
1109 fprintf( outfile, " \"\\tlis %s, %d\\n\"\n", ppc_reg(13), idx);
1110 /* Lower part + r13 -> r0, Note we can't use r0 directly */
1111 fprintf( outfile, " \"\\taddi %s, %s, %d\\n\"\n", ppc_reg(0), ppc_reg(13), j);
1112 /* Restore r13 */
1113 fprintf( outfile, " \"\\tstw %s, 0(%s)\\n\"\n", ppc_reg(13), ppc_reg(1));
1114 fprintf( outfile, " \"\\taddic %s, %s, 0x4\\n\"\n", ppc_reg(1), ppc_reg(1));
1115 fprintf( outfile, " \"\\tb %s\\n\"\n", asm_name("__wine_delay_load_asm") );
1116 break;
1118 break;
1120 output_function_size( outfile, name );
1122 idx++;
1124 output_function_size( outfile, delayed_import_loaders );
1126 fprintf( outfile, "\n \".align %d\\n\"\n", get_alignment(8) );
1127 fprintf( outfile, " \"%s:\\n\"\n", asm_name(delayed_import_thunks));
1128 pos = nb_delayed * 32;
1129 for (i = 0; i < nb_imports; i++)
1131 if (!dll_imports[i]->delay) continue;
1132 for (j = 0; j < dll_imports[i]->nb_imports; j++, pos += 4)
1134 ORDDEF *odp = dll_imports[i]->imports[j];
1135 output_import_thunk( outfile, odp->name ? odp->name : odp->export_name,
1136 "delay_imports", pos );
1139 output_function_size( outfile, delayed_import_thunks );
1140 fprintf( outfile, ");\n" );
1143 /* output the import and delayed import tables of a Win32 module
1144 * returns number of DLLs exported in 'immediate' mode
1146 int output_imports( FILE *outfile, DLLSPEC *spec, int *nb_delayed )
1148 *nb_delayed = output_delayed_imports( outfile, spec );
1149 return output_immediate_imports( outfile );
1152 /* output the import and delayed import thunks of a Win32 module */
1153 void output_import_thunks( FILE *outfile, DLLSPEC *spec )
1155 output_delayed_import_thunks( outfile, spec );
1156 output_immediate_import_thunks( outfile );