Moved the delay loading support code to the winecrt0 library.
[wine/testsucceed.git] / tools / winebuild / import.c
blobb482712114449e585a5fe9862e22b9f8ce5d046d
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 <assert.h>
26 #include <ctype.h>
27 #include <fcntl.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include <stdarg.h>
31 #ifdef HAVE_SYS_STAT_H
32 # include <sys/stat.h>
33 #endif
34 #ifdef HAVE_UNISTD_H
35 # include <unistd.h>
36 #endif
38 #include "windef.h"
39 #include "winbase.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 struct name_table
57 char **names;
58 unsigned int count, size;
61 static struct name_table undef_symbols; /* list of undefined symbols */
62 static struct name_table ignore_symbols; /* list of symbols to ignore */
63 static struct name_table extra_ld_symbols; /* list of extra symbols that ld should resolve */
64 static struct name_table delayed_imports; /* list of delayed import dlls */
66 static char *ld_tmp_file; /* ld temp file name */
68 static struct import **dll_imports = NULL;
69 static int nb_imports = 0; /* number of imported dlls (delayed or not) */
70 static int nb_delayed = 0; /* number of delayed dlls */
71 static int total_imports = 0; /* total number of imported functions */
72 static int total_delayed = 0; /* total number of imported functions in delayed DLLs */
74 /* list of symbols that are ignored by default */
75 static const char * const default_ignored_symbols[] =
77 "abs",
78 "acos",
79 "asin",
80 "atan",
81 "atan2",
82 "atof",
83 "atoi",
84 "atol",
85 "bsearch",
86 "ceil",
87 "cos",
88 "cosh",
89 "exp",
90 "fabs",
91 "floor",
92 "fmod",
93 "frexp",
94 "labs",
95 "log",
96 "log10",
97 "memchr",
98 "memcmp",
99 "memcpy",
100 "memmove",
101 "memset",
102 "modf",
103 "pow",
104 "qsort",
105 "sin",
106 "sinh",
107 "sqrt",
108 "strcat",
109 "strchr",
110 "strcmp",
111 "strcpy",
112 "strcspn",
113 "strlen",
114 "strncat",
115 "strncmp",
116 "strncpy",
117 "strpbrk",
118 "strrchr",
119 "strspn",
120 "strstr",
121 "tan",
122 "tanh"
126 static inline const char *ppc_reg( int reg )
128 static const char * const ppc_regs[32] = { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
129 "r8", "r9", "r10","r11","r12","r13","r14","r15",
130 "r16","r17","r18","r19","r20","r21","r22","r23",
131 "r24","r25","r26","r27","r28","r29","r30","r31" };
132 if (target_platform == PLATFORM_APPLE) return ppc_regs[reg];
133 return ppc_regs[reg] + 1; /* skip the 'r' */
136 /* compare function names; helper for resolve_imports */
137 static int name_cmp( const void *name, const void *entry )
139 return strcmp( *(const char* const *)name, *(const char* const *)entry );
142 /* compare function names; helper for resolve_imports */
143 static int func_cmp( const void *func1, const void *func2 )
145 const ORDDEF *odp1 = *(const ORDDEF * const *)func1;
146 const ORDDEF *odp2 = *(const ORDDEF * const *)func2;
147 return strcmp( odp1->name ? odp1->name : odp1->export_name,
148 odp2->name ? odp2->name : odp2->export_name );
151 /* add a name to a name table */
152 inline static void add_name( struct name_table *table, const char *name )
154 if (table->count == table->size)
156 table->size += (table->size / 2);
157 if (table->size < 32) table->size = 32;
158 table->names = xrealloc( table->names, table->size * sizeof(*table->names) );
160 table->names[table->count++] = xstrdup( name );
163 /* remove a name from a name table */
164 inline static void remove_name( struct name_table *table, unsigned int idx )
166 assert( idx < table->count );
167 free( table->names[idx] );
168 memmove( table->names + idx, table->names + idx + 1,
169 (table->count - idx - 1) * sizeof(*table->names) );
170 table->count--;
173 /* make a name table empty */
174 inline static void empty_name_table( struct name_table *table )
176 unsigned int i;
178 for (i = 0; i < table->count; i++) free( table->names[i] );
179 table->count = 0;
182 /* locate a name in a (sorted) list */
183 inline static const char *find_name( const char *name, const struct name_table *table )
185 char **res = NULL;
187 if (table->count) res = bsearch( &name, table->names, table->count, sizeof(*table->names), name_cmp );
188 return res ? *res : NULL;
191 /* sort a name table */
192 inline static void sort_names( struct name_table *table )
194 if (table->count) qsort( table->names, table->count, sizeof(*table->names), name_cmp );
197 /* locate an export in a (sorted) export list */
198 inline static ORDDEF *find_export( const char *name, ORDDEF **table, int size )
200 ORDDEF func, *odp, **res = NULL;
202 func.name = (char *)name;
203 func.ordinal = -1;
204 odp = &func;
205 if (table) res = bsearch( &odp, table, size, sizeof(*table), func_cmp );
206 return res ? *res : NULL;
209 inline static void output_function_size( FILE *outfile, const char *name )
211 const char *size = func_size( name );
212 if (size[0]) fprintf( outfile, " \"\\t%s\\n\"\n", size );
215 /* free an import structure */
216 static void free_imports( struct import *imp )
218 free( imp->exports );
219 free( imp->imports );
220 free_dll_spec( imp->spec );
221 free( imp->full_name );
222 free( imp );
225 /* remove the temp file at exit */
226 static void remove_ld_tmp_file(void)
228 if (ld_tmp_file) unlink( ld_tmp_file );
231 /* check whether a given dll is imported in delayed mode */
232 static int is_delayed_import( const char *name )
234 int i;
236 for (i = 0; i < delayed_imports.count; i++)
238 if (!strcmp( delayed_imports.names[i], name )) return 1;
240 return 0;
243 /* check whether a given dll has already been imported */
244 static struct import *is_already_imported( const char *name )
246 int i;
248 for (i = 0; i < nb_imports; i++)
250 if (!strcmp( dll_imports[i]->spec->file_name, name )) return dll_imports[i];
252 return NULL;
255 /* open the .so library for a given dll in a specified path */
256 static char *try_library_path( const char *path, const char *name )
258 char *buffer;
259 int fd;
261 buffer = xmalloc( strlen(path) + strlen(name) + 9 );
262 sprintf( buffer, "%s/lib%s.def", path, name );
264 /* check if the file exists */
265 if ((fd = open( buffer, O_RDONLY )) != -1)
267 close( fd );
268 return buffer;
270 free( buffer );
271 return NULL;
274 /* find the .def import library for a given dll */
275 static char *find_library( const char *name )
277 char *fullname;
278 int i;
280 for (i = 0; i < nb_lib_paths; i++)
282 if ((fullname = try_library_path( lib_path[i], name ))) return fullname;
284 fatal_error( "could not open .def file for %s\n", name );
285 return NULL;
288 /* read in the list of exported symbols of an import library */
289 static int read_import_lib( struct import *imp )
291 FILE *f;
292 int i, ret;
293 struct stat stat;
294 struct import *prev_imp;
295 DLLSPEC *spec = imp->spec;
297 f = open_input_file( NULL, imp->full_name );
298 fstat( fileno(f), &stat );
299 imp->dev = stat.st_dev;
300 imp->ino = stat.st_ino;
301 ret = parse_def_file( f, spec );
302 close_input_file( f );
303 if (!ret) return 0;
305 /* check if we already imported that library from a different file */
306 if ((prev_imp = is_already_imported( spec->file_name )))
308 if (prev_imp->dev != imp->dev || prev_imp->ino != imp->ino)
309 fatal_error( "%s and %s have the same export name '%s'\n",
310 prev_imp->full_name, imp->full_name, spec->file_name );
311 return 0; /* the same file was already loaded, ignore this one */
314 if (is_delayed_import( spec->file_name ))
316 imp->delay = 1;
317 nb_delayed++;
320 imp->exports = xmalloc( spec->nb_entry_points * sizeof(*imp->exports) );
322 for (i = 0; i < spec->nb_entry_points; i++)
324 ORDDEF *odp = &spec->entry_points[i];
326 if (odp->type != TYPE_STDCALL && odp->type != TYPE_CDECL) continue;
327 if (odp->flags & FLAG_PRIVATE) continue;
328 imp->exports[imp->nb_exports++] = odp;
330 imp->exports = xrealloc( imp->exports, imp->nb_exports * sizeof(*imp->exports) );
331 if (imp->nb_exports)
332 qsort( imp->exports, imp->nb_exports, sizeof(*imp->exports), func_cmp );
333 return 1;
336 /* build the dll exported name from the import lib name or path */
337 static char *get_dll_name( const char *name, const char *filename )
339 char *ret;
341 if (filename)
343 const char *basename = strrchr( filename, '/' );
344 if (!basename) basename = filename;
345 else basename++;
346 if (!strncmp( basename, "lib", 3 )) basename += 3;
347 ret = xmalloc( strlen(basename) + 5 );
348 strcpy( ret, basename );
349 if (strendswith( ret, ".def" )) ret[strlen(ret)-4] = 0;
351 else
353 ret = xmalloc( strlen(name) + 5 );
354 strcpy( ret, name );
356 if (!strchr( ret, '.' )) strcat( ret, ".dll" );
357 return ret;
360 /* add a dll to the list of imports */
361 void add_import_dll( const char *name, const char *filename )
363 struct import *imp = xmalloc( sizeof(*imp) );
365 imp->spec = alloc_dll_spec();
366 imp->spec->file_name = get_dll_name( name, filename );
367 imp->delay = 0;
368 imp->imports = NULL;
369 imp->nb_imports = 0;
370 imp->exports = NULL;
371 imp->nb_exports = 0;
373 if (filename) imp->full_name = xstrdup( filename );
374 else imp->full_name = find_library( name );
376 if (read_import_lib( imp ))
378 dll_imports = xrealloc( dll_imports, (nb_imports+1) * sizeof(*dll_imports) );
379 dll_imports[nb_imports++] = imp;
381 else
383 free_imports( imp );
384 if (nb_errors) exit(1);
388 /* add a library to the list of delayed imports */
389 void add_delayed_import( const char *name )
391 struct import *imp;
392 char *fullname = get_dll_name( name, NULL );
394 add_name( &delayed_imports, fullname );
395 if ((imp = is_already_imported( fullname )) && !imp->delay)
397 imp->delay = 1;
398 nb_delayed++;
400 free( fullname );
403 /* remove an imported dll, based on its index in the dll_imports array */
404 static void remove_import_dll( int index )
406 struct import *imp = dll_imports[index];
408 memmove( &dll_imports[index], &dll_imports[index+1], sizeof(imp) * (nb_imports - index - 1) );
409 nb_imports--;
410 if (imp->delay) nb_delayed--;
411 free_imports( imp );
414 /* initialize the list of ignored symbols */
415 static void init_ignored_symbols(void)
417 unsigned int i;
419 for (i = 0; i < sizeof(default_ignored_symbols)/sizeof(default_ignored_symbols[0]); i++)
420 add_name( &ignore_symbols, default_ignored_symbols[i] );
423 /* add a symbol to the ignored symbol list */
424 /* if the name starts with '-' the symbol is removed instead */
425 void add_ignore_symbol( const char *name )
427 unsigned int i;
429 if (!ignore_symbols.size) init_ignored_symbols(); /* first time around, fill list with defaults */
431 if (name[0] == '-') /* remove it */
433 if (!name[1]) empty_name_table( &ignore_symbols ); /* remove everything */
434 else for (i = 0; i < ignore_symbols.count; i++)
436 if (!strcmp( ignore_symbols.names[i], name+1 )) remove_name( &ignore_symbols, i-- );
439 else add_name( &ignore_symbols, name );
442 /* add a symbol to the list of extra symbols that ld must resolve */
443 void add_extra_ld_symbol( const char *name )
445 add_name( &extra_ld_symbols, name );
448 /* add a function to the list of imports from a given dll */
449 static void add_import_func( struct import *imp, ORDDEF *func )
451 imp->imports = xrealloc( imp->imports, (imp->nb_imports+1) * sizeof(*imp->imports) );
452 imp->imports[imp->nb_imports++] = func;
453 total_imports++;
454 if (imp->delay) total_delayed++;
457 /* add a symbol to the extra list, but only if needed */
458 static int add_extra_symbol( const char **extras, int *count, const char *name, const DLLSPEC *spec )
460 int i;
462 if (!find_name( name, &undef_symbols ))
464 /* check if the symbol is being exported by this dll */
465 for (i = 0; i < spec->nb_entry_points; i++)
467 ORDDEF *odp = &spec->entry_points[i];
468 if (odp->type == TYPE_STDCALL ||
469 odp->type == TYPE_CDECL ||
470 odp->type == TYPE_VARARGS ||
471 odp->type == TYPE_EXTERN)
473 if (odp->name && !strcmp( odp->name, name )) return 0;
476 extras[*count] = name;
477 (*count)++;
479 return 1;
482 /* check if the spec file exports any stubs */
483 static int has_stubs( const DLLSPEC *spec )
485 int i;
486 for (i = 0; i < spec->nb_entry_points; i++)
488 ORDDEF *odp = &spec->entry_points[i];
489 if (odp->type == TYPE_STUB) return 1;
491 return 0;
494 /* add the extra undefined symbols that will be contained in the generated spec file itself */
495 static void add_extra_undef_symbols( const DLLSPEC *spec )
497 const char *extras[10];
498 int i, count = 0;
499 int kernel_imports = 0;
501 sort_names( &undef_symbols );
503 /* add symbols that will be contained in the spec file itself */
504 if (!(spec->characteristics & IMAGE_FILE_DLL))
506 switch (spec->subsystem)
508 case IMAGE_SUBSYSTEM_WINDOWS_GUI:
509 case IMAGE_SUBSYSTEM_WINDOWS_CUI:
510 kernel_imports += add_extra_symbol( extras, &count, "ExitProcess", spec );
511 break;
515 /* make sure we import the dlls that contain these functions */
516 if (kernel_imports) add_import_dll( "kernel32", NULL );
518 if (count)
520 for (i = 0; i < count; i++) add_name( &undef_symbols, extras[i] );
521 sort_names( &undef_symbols );
525 /* check if a given imported dll is not needed, taking forwards into account */
526 static int check_unused( const struct import* imp, const DLLSPEC *spec )
528 int i;
529 const char *file_name = imp->spec->file_name;
530 size_t len = strlen( file_name );
531 const char *p = strchr( file_name, '.' );
532 if (p && !strcasecmp( p, ".dll" )) len = p - file_name;
534 for (i = spec->base; i <= spec->limit; i++)
536 ORDDEF *odp = spec->ordinals[i];
537 if (!odp || !(odp->flags & FLAG_FORWARD)) continue;
538 if (!strncasecmp( odp->link_name, file_name, len ) &&
539 odp->link_name[len] == '.')
540 return 0; /* found a forward, it is used */
542 return 1;
545 /* combine a list of object files with ld into a single object file */
546 /* returns the name of the combined file */
547 static const char *ldcombine_files( char **argv )
549 unsigned int i, len = 0;
550 char *cmd, *p;
551 int fd, err;
553 if (output_file_name && output_file_name[0])
555 ld_tmp_file = xmalloc( strlen(output_file_name) + 10 );
556 strcpy( ld_tmp_file, output_file_name );
557 strcat( ld_tmp_file, ".XXXXXX.o" );
559 else ld_tmp_file = xstrdup( "/tmp/winebuild.tmp.XXXXXX.o" );
561 if ((fd = mkstemps( ld_tmp_file, 2 ) == -1)) fatal_error( "could not generate a temp file\n" );
562 close( fd );
563 atexit( remove_ld_tmp_file );
565 if (!ld_command) ld_command = xstrdup("ld");
566 for (i = 0; i < extra_ld_symbols.count; i++) len += strlen(extra_ld_symbols.names[i]) + 5;
567 for (i = 0; argv[i]; i++) len += strlen(argv[i]) + 1;
568 cmd = p = xmalloc( len + strlen(ld_tmp_file) + 8 + strlen(ld_command) );
569 p += sprintf( cmd, "%s -r -o %s", ld_command, ld_tmp_file );
570 for (i = 0; i < extra_ld_symbols.count; i++)
571 p += sprintf( p, " -u %s", asm_name(extra_ld_symbols.names[i]) );
572 for (i = 0; argv[i]; i++)
573 p += sprintf( p, " %s", argv[i] );
574 err = system( cmd );
575 if (err) fatal_error( "%s -r failed with status %d\n", ld_command, err );
576 free( cmd );
577 return ld_tmp_file;
580 /* read in the list of undefined symbols */
581 void read_undef_symbols( DLLSPEC *spec, char **argv )
583 size_t prefix_len;
584 FILE *f;
585 char *cmd, buffer[1024], name_prefix[16];
586 int err;
587 const char *name;
589 if (!argv[0]) return;
591 if (spec->init_func) add_extra_ld_symbol( spec->init_func );
592 else if (spec->characteristics & IMAGE_FILE_DLL) add_extra_ld_symbol( "DllMain" );
593 else if (spec->subsystem == IMAGE_SUBSYSTEM_NATIVE) add_extra_ld_symbol( "DriverEntry ");
594 else add_extra_ld_symbol( "main" );
596 if (has_stubs( spec )) add_extra_ld_symbol( "__wine_spec_unimplemented_stub" );
597 if (nb_delayed) add_extra_ld_symbol( "__wine_spec_delay_load" );
599 strcpy( name_prefix, asm_name("") );
600 prefix_len = strlen( name_prefix );
602 name = ldcombine_files( argv );
604 if (!nm_command) nm_command = xstrdup("nm");
605 cmd = xmalloc( strlen(nm_command) + strlen(name) + 5 );
606 sprintf( cmd, "%s -u %s", nm_command, name );
607 if (!(f = popen( cmd, "r" )))
608 fatal_error( "Cannot execute '%s'\n", cmd );
610 while (fgets( buffer, sizeof(buffer), f ))
612 char *p = buffer + strlen(buffer) - 1;
613 if (p < buffer) continue;
614 if (*p == '\n') *p-- = 0;
615 p = buffer;
616 while (*p == ' ') p++;
617 if (p[0] == 'U' && p[1] == ' ' && p[2]) p += 2;
618 if (prefix_len && !strncmp( p, name_prefix, prefix_len )) p += prefix_len;
619 add_name( &undef_symbols, p );
621 if ((err = pclose( f ))) warning( "%s failed with status %d\n", cmd, err );
622 free( cmd );
625 static void remove_ignored_symbols(void)
627 unsigned int i;
629 if (!ignore_symbols.size) init_ignored_symbols();
630 sort_names( &ignore_symbols );
631 for (i = 0; i < undef_symbols.count; i++)
633 if (find_name( undef_symbols.names[i], &ignore_symbols ))
634 remove_name( &undef_symbols, i-- );
638 /* resolve the imports for a Win32 module */
639 int resolve_imports( DLLSPEC *spec )
641 unsigned int i, j, removed;
643 add_extra_undef_symbols( spec );
644 remove_ignored_symbols();
646 for (i = 0; i < nb_imports; i++)
648 struct import *imp = dll_imports[i];
650 for (j = removed = 0; j < undef_symbols.count; j++)
652 ORDDEF *odp = find_export( undef_symbols.names[j], imp->exports, imp->nb_exports );
653 if (odp)
655 add_import_func( imp, odp );
656 remove_name( &undef_symbols, j-- );
657 removed++;
660 if (!removed && check_unused( imp, spec ))
662 /* the dll is not used, get rid of it */
663 warning( "%s imported but no symbols used\n", imp->spec->file_name );
664 remove_import_dll( i );
665 i--;
668 return 1;
671 /* output a single import thunk */
672 static void output_import_thunk( FILE *outfile, const char *name, const char *table, int pos )
674 fprintf( outfile, " \"\\t.align %d\\n\"\n", get_alignment(4) );
675 fprintf( outfile, " \"\\t%s\\n\"\n", func_declaration(name) );
676 fprintf( outfile, " \"\\t.globl %s\\n\"\n", asm_name(name) );
677 fprintf( outfile, " \"%s:\\n\"\n", asm_name(name) );
679 switch(target_cpu)
681 case CPU_x86:
682 if (!UsePIC)
684 if (strstr( name, "__wine_call_from_16" )) fprintf( outfile, " \"\\t.byte 0x2e\\n\"\n" );
685 fprintf( outfile, " \"\\tjmp *(%s+%d)\\n\"\n", asm_name(table), pos );
687 else
689 if (!strcmp( name, "__wine_call_from_32_regs" ))
691 /* special case: need to preserve all registers */
692 fprintf( outfile, " \"\\tpushl %%eax\\n\"\n" );
693 fprintf( outfile, " \"\\tcall .L__wine_spec_%s\\n\"\n", name );
694 fprintf( outfile, " \".L__wine_spec_%s:\\n\"\n", name );
695 fprintf( outfile, " \"\\tpopl %%eax\\n\"\n" );
696 if (!strcmp( name, "__wine_call_from_16_regs" ))
697 fprintf( outfile, " \"\\t.byte 0x2e\\n\"\n" );
698 fprintf( outfile, " \"\\tmovl %s+%d-.L__wine_spec_%s(%%eax),%%eax\\n\"\n",
699 asm_name(table), pos, name );
700 fprintf( outfile, " \"\\txchgl %%eax,(%%esp)\\n\"\n" );
701 fprintf( outfile, " \"\\tret\\n\"\n" );
703 else if (!strcmp( name, "__wine_call_from_16_regs" ))
705 /* special case: need to preserve all registers */
706 fprintf( outfile, " \"\\tpushl %%eax\\n\"\n" );
707 fprintf( outfile, " \"\\tpushl %%ecx\\n\"\n" );
708 fprintf( outfile, " \"\\tcall .L__wine_spec_%s\\n\"\n", name );
709 fprintf( outfile, " \".L__wine_spec_%s:\\n\"\n", name );
710 fprintf( outfile, " \"\\tpopl %%eax\\n\"\n" );
711 fprintf( outfile, " \"\\t.byte 0x2e\\n\"\n" );
712 fprintf( outfile, " \"\\tmovl %s+%d-.L__wine_spec_%s(%%eax),%%eax\\n\"\n",
713 asm_name(table), pos, name );
714 fprintf( outfile, " \"\\tmovzwl %%sp, %%ecx\\n\"\n" );
715 fprintf( outfile, " \"\\t.byte 0x36\\n\"\n" );
716 fprintf( outfile, " \"\\txchgl %%eax,4(%%ecx)\\n\"\n" );
717 fprintf( outfile, " \"\\tpopl %%ecx\\n\"\n" );
718 fprintf( outfile, " \"\\tret\\n\"\n" );
720 else
722 fprintf( outfile, " \"\\tcall .L__wine_spec_%s\\n\"\n", name );
723 fprintf( outfile, " \".L__wine_spec_%s:\\n\"\n", name );
724 fprintf( outfile, " \"\\tpopl %%eax\\n\"\n" );
725 if (strstr( name, "__wine_call_from_16" ))
726 fprintf( outfile, " \"\\t.byte 0x2e\\n\"\n" );
727 fprintf( outfile, " \"\\tjmp *%s+%d-.L__wine_spec_%s(%%eax)\\n\"\n",
728 asm_name(table), pos, name );
731 break;
732 case CPU_SPARC:
733 if ( !UsePIC )
735 fprintf( outfile, " \"\\tsethi %%hi(%s+%d), %%g1\\n\"\n", table, pos );
736 fprintf( outfile, " \"\\tld [%%g1+%%lo(%s+%d)], %%g1\\n\"\n", table, pos );
737 fprintf( outfile, " \"\\tjmp %%g1\\n\\tnop\\n\"\n" );
739 else
741 /* Hmpf. Stupid sparc assembler always interprets global variable
742 names as GOT offsets, so we have to do it the long way ... */
743 fprintf( outfile, " \"\\tsave %%sp, -96, %%sp\\n\"\n" );
744 fprintf( outfile, " \"0:\\tcall 1f\\n\\tnop\\n\"\n" );
745 fprintf( outfile, " \"1:\\tsethi %%hi(%s+%d-0b), %%g1\\n\"\n", table, pos );
746 fprintf( outfile, " \"\\tor %%g1, %%lo(%s+%d-0b), %%g1\\n\"\n", table, pos );
747 fprintf( outfile, " \"\\tld [%%g1+%%o7], %%g1\\n\"\n" );
748 fprintf( outfile, " \"\\tjmp %%g1\\n\\trestore\\n\"\n" );
750 break;
751 case CPU_ALPHA:
752 fprintf( outfile, " \"\\tlda $0,%s\\n\"\n", table );
753 fprintf( outfile, " \"\\tlda $0,%d($0)\\n\"\n", pos);
754 fprintf( outfile, " \"\\tjmp $31,($0)\\n\"\n" );
755 break;
756 case CPU_POWERPC:
757 fprintf(outfile, " \"\\taddi %s, %s, -0x4\\n\"\n", ppc_reg(1), ppc_reg(1));
758 fprintf(outfile, " \"\\tstw %s, 0(%s)\\n\"\n", ppc_reg(9), ppc_reg(1));
759 fprintf(outfile, " \"\\taddi %s, %s, -0x4\\n\"\n", ppc_reg(1), ppc_reg(1));
760 fprintf(outfile, " \"\\tstw %s, 0(%s)\\n\"\n", ppc_reg(8), ppc_reg(1));
761 fprintf(outfile, " \"\\taddi %s, %s, -0x4\\n\"\n", ppc_reg(1), ppc_reg(1));
762 fprintf(outfile, " \"\\tstw %s, 0(%s)\\n\"\n", ppc_reg(7), ppc_reg(1));
763 if (target_platform == PLATFORM_APPLE)
765 fprintf(outfile, " \"\\tlis %s, ha16(%s+%d)\\n\"\n",
766 ppc_reg(9), asm_name(table), pos);
767 fprintf(outfile, " \"\\tla %s, lo16(%s+%d)(%s)\\n\"\n",
768 ppc_reg(8), asm_name(table), pos, ppc_reg(9));
770 else
772 fprintf(outfile, " \"\\tlis %s, (%s+%d)@hi\\n\"\n",
773 ppc_reg(9), asm_name(table), pos);
774 fprintf(outfile, " \"\\tla %s, (%s+%d)@l(%s)\\n\"\n",
775 ppc_reg(8), asm_name(table), pos, ppc_reg(9));
777 fprintf(outfile, " \"\\tlwz %s, 0(%s)\\n\"\n", ppc_reg(7), ppc_reg(8));
778 fprintf(outfile, " \"\\tmtctr %s\\n\"\n", ppc_reg(7));
779 fprintf(outfile, " \"\\tlwz %s, 0(%s)\\n\"\n", ppc_reg(7), ppc_reg(1));
780 fprintf(outfile, " \"\\taddi %s, %s, 0x4\\n\"\n", ppc_reg(1), ppc_reg(1));
781 fprintf(outfile, " \"\\tlwz %s, 0(%s)\\n\"\n", ppc_reg(8), ppc_reg(1));
782 fprintf(outfile, " \"\\taddi %s, %s, 0x4\\n\"\n", ppc_reg(1), ppc_reg(1));
783 fprintf(outfile, " \"\\tlwz %s, 0(%s)\\n\"\n", ppc_reg(9), ppc_reg(1));
784 fprintf(outfile, " \"\\taddi %s, %s, 0x4\\n\"\n", ppc_reg(1), ppc_reg(1));
785 fprintf(outfile, " \"\\tbctr\\n\"\n");
786 break;
788 output_function_size( outfile, name );
791 /* output the import table of a Win32 module */
792 static int output_immediate_imports( FILE *outfile )
794 int i, j, nb_imm = nb_imports - nb_delayed;
796 if (!nb_imm) return 0;
798 /* main import header */
800 fprintf( outfile, "\nstatic struct {\n" );
801 fprintf( outfile, " struct {\n" );
802 fprintf( outfile, " void *OriginalFirstThunk;\n" );
803 fprintf( outfile, " unsigned int TimeDateStamp;\n" );
804 fprintf( outfile, " unsigned int ForwarderChain;\n" );
805 fprintf( outfile, " const char *Name;\n" );
806 fprintf( outfile, " void *FirstThunk;\n" );
807 fprintf( outfile, " } imp[%d];\n", nb_imm+1 );
808 fprintf( outfile, " const char *data[%d];\n",
809 total_imports - total_delayed + nb_imm );
810 fprintf( outfile, "} imports = {\n {\n" );
812 /* list of dlls */
814 for (i = j = 0; i < nb_imports; i++)
816 if (dll_imports[i]->delay) continue;
817 fprintf( outfile, " { 0, 0, 0, \"%s\", &imports.data[%d] },\n",
818 dll_imports[i]->spec->file_name, j );
819 j += dll_imports[i]->nb_imports + 1;
822 fprintf( outfile, " { 0, 0, 0, 0, 0 },\n" );
823 fprintf( outfile, " },\n {\n" );
825 /* list of imported functions */
827 for (i = 0; i < nb_imports; i++)
829 if (dll_imports[i]->delay) continue;
830 fprintf( outfile, " /* %s */\n", dll_imports[i]->spec->file_name );
831 for (j = 0; j < dll_imports[i]->nb_imports; j++)
833 ORDDEF *odp = dll_imports[i]->imports[j];
834 if (!(odp->flags & FLAG_NONAME))
836 unsigned short ord = odp->ordinal;
837 fprintf( outfile, " \"\\%03o\\%03o%s\",\n",
838 *(unsigned char *)&ord, *((unsigned char *)&ord + 1), odp->name );
840 else
841 fprintf( outfile, " (char *)%d,\n", odp->ordinal );
843 fprintf( outfile, " 0,\n" );
845 fprintf( outfile, " }\n};\n\n" );
847 return nb_imm;
850 /* output the import thunks of a Win32 module */
851 static void output_immediate_import_thunks( FILE *outfile )
853 int i, j, pos;
854 int nb_imm = nb_imports - nb_delayed;
855 static const char import_thunks[] = "__wine_spec_import_thunks";
857 if (!nb_imm) return;
859 pos = (sizeof(void *) + 2*sizeof(unsigned int) + sizeof(const char *) + sizeof(void *)) *
860 (nb_imm + 1); /* offset of imports.data from start of imports */
861 fprintf( outfile, "/* immediate import thunks */\n" );
862 fprintf( outfile, "asm(\".text\\n\\t.align %d\\n\"\n", get_alignment(8) );
863 fprintf( outfile, " \"%s:\\n\"\n", asm_name(import_thunks));
865 for (i = 0; i < nb_imports; i++)
867 if (dll_imports[i]->delay) continue;
868 for (j = 0; j < dll_imports[i]->nb_imports; j++, pos += sizeof(const char *))
870 ORDDEF *odp = dll_imports[i]->imports[j];
871 output_import_thunk( outfile, odp->name ? odp->name : odp->export_name,
872 "imports", pos );
874 pos += 4;
876 output_function_size( outfile, import_thunks );
877 fprintf( outfile, ");\n" );
880 /* output the delayed import table of a Win32 module */
881 static int output_delayed_imports( FILE *outfile, const DLLSPEC *spec )
883 int i, j;
885 if (!nb_delayed) return 0;
887 fprintf( outfile, "static void *__wine_delay_imp_hmod[%d];\n", nb_delayed );
888 for (i = 0; i < nb_imports; i++)
890 if (!dll_imports[i]->delay) continue;
891 for (j = 0; j < dll_imports[i]->nb_imports; j++)
893 ORDDEF *odp = dll_imports[i]->imports[j];
894 const char *name = odp->name ? odp->name : odp->export_name;
895 fprintf( outfile, "void __wine_delay_imp_%d_%s();\n", i, name );
898 fprintf( outfile, "\n" );
899 fprintf( outfile, "struct {\n" );
900 fprintf( outfile, " struct ImgDelayDescr {\n" );
901 fprintf( outfile, " unsigned int grAttrs;\n" );
902 fprintf( outfile, " const char *szName;\n" );
903 fprintf( outfile, " void **phmod;\n" );
904 fprintf( outfile, " void **pIAT;\n" );
905 fprintf( outfile, " const char **pINT;\n" );
906 fprintf( outfile, " void* pBoundIAT;\n" );
907 fprintf( outfile, " void* pUnloadIAT;\n" );
908 fprintf( outfile, " unsigned long dwTimeStamp;\n" );
909 fprintf( outfile, " } imp[%d];\n", nb_delayed + 1 );
910 fprintf( outfile, " void *IAT[%d];\n", total_delayed );
911 fprintf( outfile, " const char *INT[%d];\n", total_delayed );
912 fprintf( outfile, "} __wine_spec_delay_imports = {\n" );
913 fprintf( outfile, " {\n" );
914 for (i = j = 0; i < nb_imports; i++)
916 if (!dll_imports[i]->delay) continue;
917 fprintf( outfile, " { 0, \"%s\", &__wine_delay_imp_hmod[%d], &__wine_spec_delay_imports.IAT[%d], &__wine_spec_delay_imports.INT[%d], 0, 0, 0 },\n",
918 dll_imports[i]->spec->file_name, i, j, j );
919 j += dll_imports[i]->nb_imports;
921 fprintf( outfile, " },\n {\n" );
922 for (i = 0; i < nb_imports; i++)
924 if (!dll_imports[i]->delay) continue;
925 fprintf( outfile, " /* %s */\n", dll_imports[i]->spec->file_name );
926 for (j = 0; j < dll_imports[i]->nb_imports; j++)
928 ORDDEF *odp = dll_imports[i]->imports[j];
929 const char *name = odp->name ? odp->name : odp->export_name;
930 fprintf( outfile, " &__wine_delay_imp_%d_%s,\n", i, name );
933 fprintf( outfile, " },\n {\n" );
934 for (i = 0; i < nb_imports; i++)
936 if (!dll_imports[i]->delay) continue;
937 fprintf( outfile, " /* %s */\n", dll_imports[i]->spec->file_name );
938 for (j = 0; j < dll_imports[i]->nb_imports; j++)
940 ORDDEF *odp = dll_imports[i]->imports[j];
941 if (!odp->name)
942 fprintf( outfile, " (char *)%d,\n", odp->ordinal );
943 else
944 fprintf( outfile, " \"%s\",\n", odp->name );
947 fprintf( outfile, " }\n};\n\n" );
949 return nb_delayed;
952 /* output the delayed import thunks of a Win32 module */
953 static void output_delayed_import_thunks( FILE *outfile, const DLLSPEC *spec )
955 int i, idx, j, pos, extra_stack_storage = 0;
956 static const char delayed_import_loaders[] = "__wine_spec_delayed_import_loaders";
957 static const char delayed_import_thunks[] = "__wine_spec_delayed_import_thunks";
959 if (!nb_delayed) return;
961 fprintf( outfile, "/* delayed import thunks */\n" );
962 fprintf( outfile, "asm(\".text\\n\"\n" );
963 fprintf( outfile, " \"\\t.align %d\\n\"\n", get_alignment(8) );
964 fprintf( outfile, " \"%s:\\n\"\n", asm_name(delayed_import_loaders));
965 fprintf( outfile, " \"\\t%s\\n\"\n", func_declaration("__wine_delay_load_asm") );
966 fprintf( outfile, " \"%s:\\n\"\n", asm_name("__wine_delay_load_asm") );
967 switch(target_cpu)
969 case CPU_x86:
970 fprintf( outfile, " \"\\tpushl %%ecx\\n\\tpushl %%edx\\n\\tpushl %%eax\\n\"\n" );
971 fprintf( outfile, " \"\\tcall %s\\n\"\n", asm_name("__wine_spec_delay_load") );
972 fprintf( outfile, " \"\\tpopl %%edx\\n\\tpopl %%ecx\\n\\tjmp *%%eax\\n\"\n" );
973 break;
974 case CPU_SPARC:
975 fprintf( outfile, " \"\\tsave %%sp, -96, %%sp\\n\"\n" );
976 fprintf( outfile, " \"\\tcall %s\\n\"\n", asm_name("__wine_spec_delay_load") );
977 fprintf( outfile, " \"\\tmov %%g1, %%o0\\n\"\n" );
978 fprintf( outfile, " \"\\tjmp %%o0\\n\\trestore\\n\"\n" );
979 break;
980 case CPU_ALPHA:
981 fprintf( outfile, " \"\\tjsr $26,%s\\n\"\n", asm_name("__wine_spec_delay_load") );
982 fprintf( outfile, " \"\\tjmp $31,($0)\\n\"\n" );
983 break;
984 case CPU_POWERPC:
985 if (target_platform == PLATFORM_APPLE) extra_stack_storage = 56;
987 /* Save all callee saved registers into a stackframe. */
988 fprintf( outfile, " \"\\tstwu %s, -%d(%s)\\n\"\n",ppc_reg(1), 48+extra_stack_storage, ppc_reg(1));
989 fprintf( outfile, " \"\\tstw %s, %d(%s)\\n\"\n", ppc_reg(3), 4+extra_stack_storage, ppc_reg(1));
990 fprintf( outfile, " \"\\tstw %s, %d(%s)\\n\"\n", ppc_reg(4), 8+extra_stack_storage, ppc_reg(1));
991 fprintf( outfile, " \"\\tstw %s, %d(%s)\\n\"\n", ppc_reg(5), 12+extra_stack_storage, ppc_reg(1));
992 fprintf( outfile, " \"\\tstw %s, %d(%s)\\n\"\n", ppc_reg(6), 16+extra_stack_storage, ppc_reg(1));
993 fprintf( outfile, " \"\\tstw %s, %d(%s)\\n\"\n", ppc_reg(7), 20+extra_stack_storage, ppc_reg(1));
994 fprintf( outfile, " \"\\tstw %s, %d(%s)\\n\"\n", ppc_reg(8), 24+extra_stack_storage, ppc_reg(1));
995 fprintf( outfile, " \"\\tstw %s, %d(%s)\\n\"\n", ppc_reg(9), 28+extra_stack_storage, ppc_reg(1));
996 fprintf( outfile, " \"\\tstw %s, %d(%s)\\n\"\n", ppc_reg(10),32+extra_stack_storage, ppc_reg(1));
997 fprintf( outfile, " \"\\tstw %s, %d(%s)\\n\"\n", ppc_reg(11),36+extra_stack_storage, ppc_reg(1));
998 fprintf( outfile, " \"\\tstw %s, %d(%s)\\n\"\n", ppc_reg(12),40+extra_stack_storage, ppc_reg(1));
1000 /* r0 -> r3 (arg1) */
1001 fprintf( outfile, " \"\\tmr %s, %s\\n\"\n", ppc_reg(3), ppc_reg(0));
1003 /* save return address */
1004 fprintf( outfile, " \"\\tmflr %s\\n\"\n", ppc_reg(0));
1005 fprintf( outfile, " \"\\tstw %s, %d(%s)\\n\"\n", ppc_reg(0), 44+extra_stack_storage, ppc_reg(1));
1007 /* Call the __wine_delay_load function, arg1 is arg1. */
1008 fprintf( outfile, " \"\\tbl %s\\n\"\n", asm_name("__wine_spec_delay_load") );
1010 /* Load return value from call into ctr register */
1011 fprintf( outfile, " \"\\tmtctr %s\\n\"\n", ppc_reg(3));
1013 /* restore all saved registers and drop stackframe. */
1014 fprintf( outfile, " \"\\tlwz %s, %d(%s)\\n\"\n", ppc_reg(3), 4+extra_stack_storage, ppc_reg(1));
1015 fprintf( outfile, " \"\\tlwz %s, %d(%s)\\n\"\n", ppc_reg(4), 8+extra_stack_storage, ppc_reg(1));
1016 fprintf( outfile, " \"\\tlwz %s, %d(%s)\\n\"\n", ppc_reg(5), 12+extra_stack_storage, ppc_reg(1));
1017 fprintf( outfile, " \"\\tlwz %s, %d(%s)\\n\"\n", ppc_reg(6), 16+extra_stack_storage, ppc_reg(1));
1018 fprintf( outfile, " \"\\tlwz %s, %d(%s)\\n\"\n", ppc_reg(7), 20+extra_stack_storage, ppc_reg(1));
1019 fprintf( outfile, " \"\\tlwz %s, %d(%s)\\n\"\n", ppc_reg(8), 24+extra_stack_storage, ppc_reg(1));
1020 fprintf( outfile, " \"\\tlwz %s, %d(%s)\\n\"\n", ppc_reg(9), 28+extra_stack_storage, ppc_reg(1));
1021 fprintf( outfile, " \"\\tlwz %s, %d(%s)\\n\"\n", ppc_reg(10),32+extra_stack_storage, ppc_reg(1));
1022 fprintf( outfile, " \"\\tlwz %s, %d(%s)\\n\"\n", ppc_reg(11),36+extra_stack_storage, ppc_reg(1));
1023 fprintf( outfile, " \"\\tlwz %s, %d(%s)\\n\"\n", ppc_reg(12),40+extra_stack_storage, ppc_reg(1));
1025 /* Load return value from call into return register */
1026 fprintf( outfile, " \"\\tlwz %s, %d(%s)\\n\"\n", ppc_reg(0), 44+extra_stack_storage, ppc_reg(1));
1027 fprintf( outfile, " \"\\tmtlr %s\\n\"\n", ppc_reg(0));
1028 fprintf( outfile, " \"\\taddi %s, %s, %d\\n\"\n", ppc_reg(1), ppc_reg(1), 48+extra_stack_storage);
1030 /* branch to ctr register. */
1031 fprintf( outfile, " \"bctr\\n\"\n");
1032 break;
1034 output_function_size( outfile, "__wine_delay_load_asm" );
1036 for (i = idx = 0; i < nb_imports; i++)
1038 if (!dll_imports[i]->delay) continue;
1039 for (j = 0; j < dll_imports[i]->nb_imports; j++)
1041 char buffer[128];
1042 ORDDEF *odp = dll_imports[i]->imports[j];
1043 const char *name = odp->name ? odp->name : odp->export_name;
1045 sprintf( buffer, "__wine_delay_imp_%d_%s", i, name );
1046 fprintf( outfile, " \"\\t%s\\n\"\n", func_declaration(buffer) );
1047 fprintf( outfile, " \"%s:\\n\"\n", asm_name(buffer) );
1048 switch(target_cpu)
1050 case CPU_x86:
1051 fprintf( outfile, " \"\\tmovl $%d, %%eax\\n\"\n", (idx << 16) | j );
1052 fprintf( outfile, " \"\\tjmp %s\\n\"\n", asm_name("__wine_delay_load_asm") );
1053 break;
1054 case CPU_SPARC:
1055 fprintf( outfile, " \"\\tset %d, %%g1\\n\"\n", (idx << 16) | j );
1056 fprintf( outfile, " \"\\tb,a %s\\n\"\n", asm_name("__wine_delay_load_asm") );
1057 break;
1058 case CPU_ALPHA:
1059 fprintf( outfile, " \"\\tlda $0,%d($31)\\n\"\n", j);
1060 fprintf( outfile, " \"\\tldah $0,%d($0)\\n\"\n", idx);
1061 fprintf( outfile, " \"\\tjmp $31,%s\\n\"\n", asm_name("__wine_delay_load_asm") );
1062 break;
1063 case CPU_POWERPC:
1064 switch(target_platform)
1066 case PLATFORM_APPLE:
1067 /* On Darwin we can use r0 and r2 */
1068 /* Upper part in r2 */
1069 fprintf( outfile, " \"\\tlis %s, %d\\n\"\n", ppc_reg(2), idx);
1070 /* Lower part + r2 -> r0, Note we can't use r0 directly */
1071 fprintf( outfile, " \"\\taddi %s, %s, %d\\n\"\n", ppc_reg(0), ppc_reg(2), j);
1072 fprintf( outfile, " \"\\tb %s\\n\"\n", asm_name("__wine_delay_load_asm") );
1073 break;
1074 default:
1075 /* On linux we can't use r2 since r2 is not a scratch register (hold the TOC) */
1076 /* Save r13 on the stack */
1077 fprintf( outfile, " \"\\taddi %s, %s, -0x4\\n\"\n", ppc_reg(1), ppc_reg(1));
1078 fprintf( outfile, " \"\\tstw %s, 0(%s)\\n\"\n", ppc_reg(13), ppc_reg(1));
1079 /* Upper part in r13 */
1080 fprintf( outfile, " \"\\tlis %s, %d\\n\"\n", ppc_reg(13), idx);
1081 /* Lower part + r13 -> r0, Note we can't use r0 directly */
1082 fprintf( outfile, " \"\\taddi %s, %s, %d\\n\"\n", ppc_reg(0), ppc_reg(13), j);
1083 /* Restore r13 */
1084 fprintf( outfile, " \"\\tstw %s, 0(%s)\\n\"\n", ppc_reg(13), ppc_reg(1));
1085 fprintf( outfile, " \"\\taddic %s, %s, 0x4\\n\"\n", ppc_reg(1), ppc_reg(1));
1086 fprintf( outfile, " \"\\tb %s\\n\"\n", asm_name("__wine_delay_load_asm") );
1087 break;
1089 break;
1091 output_function_size( outfile, name );
1093 idx++;
1095 output_function_size( outfile, delayed_import_loaders );
1097 fprintf( outfile, "\n \".align %d\\n\"\n", get_alignment(8) );
1098 fprintf( outfile, " \"%s:\\n\"\n", asm_name(delayed_import_thunks));
1099 pos = (nb_delayed + 1) * 32;
1100 for (i = 0; i < nb_imports; i++)
1102 if (!dll_imports[i]->delay) continue;
1103 for (j = 0; j < dll_imports[i]->nb_imports; j++, pos += 4)
1105 ORDDEF *odp = dll_imports[i]->imports[j];
1106 output_import_thunk( outfile, odp->name ? odp->name : odp->export_name,
1107 "__wine_spec_delay_imports", pos );
1110 output_function_size( outfile, delayed_import_thunks );
1111 fprintf( outfile, ");\n" );
1114 /* output the import and delayed import tables of a Win32 module
1115 * returns number of DLLs exported in 'immediate' mode
1117 int output_imports( FILE *outfile, DLLSPEC *spec, int *nb_delayed )
1119 *nb_delayed = output_delayed_imports( outfile, spec );
1120 return output_immediate_imports( outfile );
1123 /* output the import and delayed import thunks of a Win32 module */
1124 void output_import_thunks( FILE *outfile, DLLSPEC *spec )
1126 output_delayed_import_thunks( outfile, spec );
1127 output_immediate_import_thunks( outfile );