Moved more of the spec initialization code to the winecrt0 library,
[wine.git] / tools / winebuild / import.c
blob989e5bb0fffa3a45c120282b365a7fd9eb5cc050
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 /* check if the spec file exports any stubs */
458 static int has_stubs( const DLLSPEC *spec )
460 int i;
461 for (i = 0; i < spec->nb_entry_points; i++)
463 ORDDEF *odp = &spec->entry_points[i];
464 if (odp->type == TYPE_STUB) return 1;
466 return 0;
469 /* get the default entry point for a given spec file */
470 static const char *get_default_entry_point( const DLLSPEC *spec )
472 if (spec->characteristics & IMAGE_FILE_DLL) return "__wine_spec_dll_entry";
473 if (spec->subsystem == IMAGE_SUBSYSTEM_NATIVE) return "DriverEntry";
474 return "__wine_spec_exe_entry";
477 /* add the extra undefined symbols that will be contained in the generated spec file itself */
478 static void add_extra_undef_symbols( DLLSPEC *spec )
480 if (!spec->init_func) spec->init_func = xstrdup( get_default_entry_point(spec) );
481 add_extra_ld_symbol( spec->init_func );
482 if (has_stubs( spec )) add_extra_ld_symbol( "__wine_spec_unimplemented_stub" );
483 if (nb_delayed) add_extra_ld_symbol( "__wine_spec_delay_load" );
486 /* check if a given imported dll is not needed, taking forwards into account */
487 static int check_unused( const struct import* imp, const DLLSPEC *spec )
489 int i;
490 const char *file_name = imp->spec->file_name;
491 size_t len = strlen( file_name );
492 const char *p = strchr( file_name, '.' );
493 if (p && !strcasecmp( p, ".dll" )) len = p - file_name;
495 for (i = spec->base; i <= spec->limit; i++)
497 ORDDEF *odp = spec->ordinals[i];
498 if (!odp || !(odp->flags & FLAG_FORWARD)) continue;
499 if (!strncasecmp( odp->link_name, file_name, len ) &&
500 odp->link_name[len] == '.')
501 return 0; /* found a forward, it is used */
503 return 1;
506 /* combine a list of object files with ld into a single object file */
507 /* returns the name of the combined file */
508 static const char *ldcombine_files( char **argv )
510 unsigned int i, len = 0;
511 char *cmd, *p;
512 int fd, err;
514 if (output_file_name && output_file_name[0])
516 ld_tmp_file = xmalloc( strlen(output_file_name) + 10 );
517 strcpy( ld_tmp_file, output_file_name );
518 strcat( ld_tmp_file, ".XXXXXX.o" );
520 else ld_tmp_file = xstrdup( "/tmp/winebuild.tmp.XXXXXX.o" );
522 if ((fd = mkstemps( ld_tmp_file, 2 ) == -1)) fatal_error( "could not generate a temp file\n" );
523 close( fd );
524 atexit( remove_ld_tmp_file );
526 if (!ld_command) ld_command = xstrdup("ld");
527 for (i = 0; i < extra_ld_symbols.count; i++) len += strlen(extra_ld_symbols.names[i]) + 5;
528 for (i = 0; argv[i]; i++) len += strlen(argv[i]) + 1;
529 cmd = p = xmalloc( len + strlen(ld_tmp_file) + 8 + strlen(ld_command) );
530 p += sprintf( cmd, "%s -r -o %s", ld_command, ld_tmp_file );
531 for (i = 0; i < extra_ld_symbols.count; i++)
532 p += sprintf( p, " -u %s", asm_name(extra_ld_symbols.names[i]) );
533 for (i = 0; argv[i]; i++)
534 p += sprintf( p, " %s", argv[i] );
535 err = system( cmd );
536 if (err) fatal_error( "%s -r failed with status %d\n", ld_command, err );
537 free( cmd );
538 return ld_tmp_file;
541 /* read in the list of undefined symbols */
542 void read_undef_symbols( DLLSPEC *spec, char **argv )
544 size_t prefix_len;
545 FILE *f;
546 char *cmd, buffer[1024], name_prefix[16];
547 int err;
548 const char *name;
550 if (!argv[0]) return;
552 add_extra_undef_symbols( spec );
554 strcpy( name_prefix, asm_name("") );
555 prefix_len = strlen( name_prefix );
557 name = ldcombine_files( argv );
559 if (!nm_command) nm_command = xstrdup("nm");
560 cmd = xmalloc( strlen(nm_command) + strlen(name) + 5 );
561 sprintf( cmd, "%s -u %s", nm_command, name );
562 if (!(f = popen( cmd, "r" )))
563 fatal_error( "Cannot execute '%s'\n", cmd );
565 while (fgets( buffer, sizeof(buffer), f ))
567 char *p = buffer + strlen(buffer) - 1;
568 if (p < buffer) continue;
569 if (*p == '\n') *p-- = 0;
570 p = buffer;
571 while (*p == ' ') p++;
572 if (p[0] == 'U' && p[1] == ' ' && p[2]) p += 2;
573 if (prefix_len && !strncmp( p, name_prefix, prefix_len )) p += prefix_len;
574 add_name( &undef_symbols, p );
576 if ((err = pclose( f ))) warning( "%s failed with status %d\n", cmd, err );
577 free( cmd );
580 static void remove_ignored_symbols(void)
582 unsigned int i;
584 if (!ignore_symbols.size) init_ignored_symbols();
585 sort_names( &ignore_symbols );
586 for (i = 0; i < undef_symbols.count; i++)
588 if (find_name( undef_symbols.names[i], &ignore_symbols ))
589 remove_name( &undef_symbols, i-- );
593 /* resolve the imports for a Win32 module */
594 int resolve_imports( DLLSPEC *spec )
596 unsigned int i, j, removed;
598 remove_ignored_symbols();
600 for (i = 0; i < nb_imports; i++)
602 struct import *imp = dll_imports[i];
604 for (j = removed = 0; j < undef_symbols.count; j++)
606 ORDDEF *odp = find_export( undef_symbols.names[j], imp->exports, imp->nb_exports );
607 if (odp)
609 add_import_func( imp, odp );
610 remove_name( &undef_symbols, j-- );
611 removed++;
614 if (!removed && check_unused( imp, spec ))
616 /* the dll is not used, get rid of it */
617 warning( "%s imported but no symbols used\n", imp->spec->file_name );
618 remove_import_dll( i );
619 i--;
622 return 1;
625 /* output a single import thunk */
626 static void output_import_thunk( FILE *outfile, const char *name, const char *table, int pos )
628 fprintf( outfile, " \"\\t.align %d\\n\"\n", get_alignment(4) );
629 fprintf( outfile, " \"\\t%s\\n\"\n", func_declaration(name) );
630 fprintf( outfile, " \"\\t.globl %s\\n\"\n", asm_name(name) );
631 fprintf( outfile, " \"%s:\\n\"\n", asm_name(name) );
633 switch(target_cpu)
635 case CPU_x86:
636 if (!UsePIC)
638 if (strstr( name, "__wine_call_from_16" )) fprintf( outfile, " \"\\t.byte 0x2e\\n\"\n" );
639 fprintf( outfile, " \"\\tjmp *(%s+%d)\\n\"\n", asm_name(table), pos );
641 else
643 if (!strcmp( name, "__wine_call_from_32_regs" ))
645 /* special case: need to preserve all registers */
646 fprintf( outfile, " \"\\tpushl %%eax\\n\"\n" );
647 fprintf( outfile, " \"\\tcall .L__wine_spec_%s\\n\"\n", name );
648 fprintf( outfile, " \".L__wine_spec_%s:\\n\"\n", name );
649 fprintf( outfile, " \"\\tpopl %%eax\\n\"\n" );
650 if (!strcmp( name, "__wine_call_from_16_regs" ))
651 fprintf( outfile, " \"\\t.byte 0x2e\\n\"\n" );
652 fprintf( outfile, " \"\\tmovl %s+%d-.L__wine_spec_%s(%%eax),%%eax\\n\"\n",
653 asm_name(table), pos, name );
654 fprintf( outfile, " \"\\txchgl %%eax,(%%esp)\\n\"\n" );
655 fprintf( outfile, " \"\\tret\\n\"\n" );
657 else if (!strcmp( name, "__wine_call_from_16_regs" ))
659 /* special case: need to preserve all registers */
660 fprintf( outfile, " \"\\tpushl %%eax\\n\"\n" );
661 fprintf( outfile, " \"\\tpushl %%ecx\\n\"\n" );
662 fprintf( outfile, " \"\\tcall .L__wine_spec_%s\\n\"\n", name );
663 fprintf( outfile, " \".L__wine_spec_%s:\\n\"\n", name );
664 fprintf( outfile, " \"\\tpopl %%eax\\n\"\n" );
665 fprintf( outfile, " \"\\t.byte 0x2e\\n\"\n" );
666 fprintf( outfile, " \"\\tmovl %s+%d-.L__wine_spec_%s(%%eax),%%eax\\n\"\n",
667 asm_name(table), pos, name );
668 fprintf( outfile, " \"\\tmovzwl %%sp, %%ecx\\n\"\n" );
669 fprintf( outfile, " \"\\t.byte 0x36\\n\"\n" );
670 fprintf( outfile, " \"\\txchgl %%eax,4(%%ecx)\\n\"\n" );
671 fprintf( outfile, " \"\\tpopl %%ecx\\n\"\n" );
672 fprintf( outfile, " \"\\tret\\n\"\n" );
674 else
676 fprintf( outfile, " \"\\tcall .L__wine_spec_%s\\n\"\n", name );
677 fprintf( outfile, " \".L__wine_spec_%s:\\n\"\n", name );
678 fprintf( outfile, " \"\\tpopl %%eax\\n\"\n" );
679 if (strstr( name, "__wine_call_from_16" ))
680 fprintf( outfile, " \"\\t.byte 0x2e\\n\"\n" );
681 fprintf( outfile, " \"\\tjmp *%s+%d-.L__wine_spec_%s(%%eax)\\n\"\n",
682 asm_name(table), pos, name );
685 break;
686 case CPU_SPARC:
687 if ( !UsePIC )
689 fprintf( outfile, " \"\\tsethi %%hi(%s+%d), %%g1\\n\"\n", table, pos );
690 fprintf( outfile, " \"\\tld [%%g1+%%lo(%s+%d)], %%g1\\n\"\n", table, pos );
691 fprintf( outfile, " \"\\tjmp %%g1\\n\\tnop\\n\"\n" );
693 else
695 /* Hmpf. Stupid sparc assembler always interprets global variable
696 names as GOT offsets, so we have to do it the long way ... */
697 fprintf( outfile, " \"\\tsave %%sp, -96, %%sp\\n\"\n" );
698 fprintf( outfile, " \"0:\\tcall 1f\\n\\tnop\\n\"\n" );
699 fprintf( outfile, " \"1:\\tsethi %%hi(%s+%d-0b), %%g1\\n\"\n", table, pos );
700 fprintf( outfile, " \"\\tor %%g1, %%lo(%s+%d-0b), %%g1\\n\"\n", table, pos );
701 fprintf( outfile, " \"\\tld [%%g1+%%o7], %%g1\\n\"\n" );
702 fprintf( outfile, " \"\\tjmp %%g1\\n\\trestore\\n\"\n" );
704 break;
705 case CPU_ALPHA:
706 fprintf( outfile, " \"\\tlda $0,%s\\n\"\n", table );
707 fprintf( outfile, " \"\\tlda $0,%d($0)\\n\"\n", pos);
708 fprintf( outfile, " \"\\tjmp $31,($0)\\n\"\n" );
709 break;
710 case CPU_POWERPC:
711 fprintf(outfile, " \"\\taddi %s, %s, -0x4\\n\"\n", ppc_reg(1), ppc_reg(1));
712 fprintf(outfile, " \"\\tstw %s, 0(%s)\\n\"\n", ppc_reg(9), ppc_reg(1));
713 fprintf(outfile, " \"\\taddi %s, %s, -0x4\\n\"\n", ppc_reg(1), ppc_reg(1));
714 fprintf(outfile, " \"\\tstw %s, 0(%s)\\n\"\n", ppc_reg(8), ppc_reg(1));
715 fprintf(outfile, " \"\\taddi %s, %s, -0x4\\n\"\n", ppc_reg(1), ppc_reg(1));
716 fprintf(outfile, " \"\\tstw %s, 0(%s)\\n\"\n", ppc_reg(7), ppc_reg(1));
717 if (target_platform == PLATFORM_APPLE)
719 fprintf(outfile, " \"\\tlis %s, ha16(%s+%d)\\n\"\n",
720 ppc_reg(9), asm_name(table), pos);
721 fprintf(outfile, " \"\\tla %s, lo16(%s+%d)(%s)\\n\"\n",
722 ppc_reg(8), asm_name(table), pos, ppc_reg(9));
724 else
726 fprintf(outfile, " \"\\tlis %s, (%s+%d)@hi\\n\"\n",
727 ppc_reg(9), asm_name(table), pos);
728 fprintf(outfile, " \"\\tla %s, (%s+%d)@l(%s)\\n\"\n",
729 ppc_reg(8), asm_name(table), pos, ppc_reg(9));
731 fprintf(outfile, " \"\\tlwz %s, 0(%s)\\n\"\n", ppc_reg(7), ppc_reg(8));
732 fprintf(outfile, " \"\\tmtctr %s\\n\"\n", ppc_reg(7));
733 fprintf(outfile, " \"\\tlwz %s, 0(%s)\\n\"\n", ppc_reg(7), ppc_reg(1));
734 fprintf(outfile, " \"\\taddi %s, %s, 0x4\\n\"\n", ppc_reg(1), ppc_reg(1));
735 fprintf(outfile, " \"\\tlwz %s, 0(%s)\\n\"\n", ppc_reg(8), ppc_reg(1));
736 fprintf(outfile, " \"\\taddi %s, %s, 0x4\\n\"\n", ppc_reg(1), ppc_reg(1));
737 fprintf(outfile, " \"\\tlwz %s, 0(%s)\\n\"\n", ppc_reg(9), ppc_reg(1));
738 fprintf(outfile, " \"\\taddi %s, %s, 0x4\\n\"\n", ppc_reg(1), ppc_reg(1));
739 fprintf(outfile, " \"\\tbctr\\n\"\n");
740 break;
742 output_function_size( outfile, name );
745 /* output the import table of a Win32 module */
746 static int output_immediate_imports( FILE *outfile )
748 int i, j, nb_imm = nb_imports - nb_delayed;
750 if (!nb_imm) return 0;
752 /* main import header */
754 fprintf( outfile, "\nstatic struct {\n" );
755 fprintf( outfile, " struct {\n" );
756 fprintf( outfile, " void *OriginalFirstThunk;\n" );
757 fprintf( outfile, " unsigned int TimeDateStamp;\n" );
758 fprintf( outfile, " unsigned int ForwarderChain;\n" );
759 fprintf( outfile, " const char *Name;\n" );
760 fprintf( outfile, " void *FirstThunk;\n" );
761 fprintf( outfile, " } imp[%d];\n", nb_imm+1 );
762 fprintf( outfile, " const char *data[%d];\n",
763 total_imports - total_delayed + nb_imm );
764 fprintf( outfile, "} imports = {\n {\n" );
766 /* list of dlls */
768 for (i = j = 0; i < nb_imports; i++)
770 if (dll_imports[i]->delay) continue;
771 fprintf( outfile, " { 0, 0, 0, \"%s\", &imports.data[%d] },\n",
772 dll_imports[i]->spec->file_name, j );
773 j += dll_imports[i]->nb_imports + 1;
776 fprintf( outfile, " { 0, 0, 0, 0, 0 },\n" );
777 fprintf( outfile, " },\n {\n" );
779 /* list of imported functions */
781 for (i = 0; i < nb_imports; i++)
783 if (dll_imports[i]->delay) continue;
784 fprintf( outfile, " /* %s */\n", dll_imports[i]->spec->file_name );
785 for (j = 0; j < dll_imports[i]->nb_imports; j++)
787 ORDDEF *odp = dll_imports[i]->imports[j];
788 if (!(odp->flags & FLAG_NONAME))
790 unsigned short ord = odp->ordinal;
791 fprintf( outfile, " \"\\%03o\\%03o%s\",\n",
792 *(unsigned char *)&ord, *((unsigned char *)&ord + 1), odp->name );
794 else
795 fprintf( outfile, " (char *)%d,\n", odp->ordinal );
797 fprintf( outfile, " 0,\n" );
799 fprintf( outfile, " }\n};\n\n" );
801 return nb_imm;
804 /* output the import thunks of a Win32 module */
805 static void output_immediate_import_thunks( FILE *outfile )
807 int i, j, pos;
808 int nb_imm = nb_imports - nb_delayed;
809 static const char import_thunks[] = "__wine_spec_import_thunks";
811 if (!nb_imm) return;
813 pos = (sizeof(void *) + 2*sizeof(unsigned int) + sizeof(const char *) + sizeof(void *)) *
814 (nb_imm + 1); /* offset of imports.data from start of imports */
815 fprintf( outfile, "/* immediate import thunks */\n" );
816 fprintf( outfile, "asm(\".text\\n\\t.align %d\\n\"\n", get_alignment(8) );
817 fprintf( outfile, " \"%s:\\n\"\n", asm_name(import_thunks));
819 for (i = 0; i < nb_imports; i++)
821 if (dll_imports[i]->delay) continue;
822 for (j = 0; j < dll_imports[i]->nb_imports; j++, pos += sizeof(const char *))
824 ORDDEF *odp = dll_imports[i]->imports[j];
825 output_import_thunk( outfile, odp->name ? odp->name : odp->export_name,
826 "imports", pos );
828 pos += 4;
830 output_function_size( outfile, import_thunks );
831 fprintf( outfile, ");\n" );
834 /* output the delayed import table of a Win32 module */
835 static int output_delayed_imports( FILE *outfile, const DLLSPEC *spec )
837 int i, j;
839 if (!nb_delayed) return 0;
841 fprintf( outfile, "static void *__wine_delay_imp_hmod[%d];\n", nb_delayed );
842 for (i = 0; i < nb_imports; i++)
844 if (!dll_imports[i]->delay) continue;
845 for (j = 0; j < dll_imports[i]->nb_imports; j++)
847 ORDDEF *odp = dll_imports[i]->imports[j];
848 const char *name = odp->name ? odp->name : odp->export_name;
849 fprintf( outfile, "void __wine_delay_imp_%d_%s();\n", i, name );
852 fprintf( outfile, "\n" );
853 fprintf( outfile, "struct {\n" );
854 fprintf( outfile, " struct ImgDelayDescr {\n" );
855 fprintf( outfile, " unsigned int grAttrs;\n" );
856 fprintf( outfile, " const char *szName;\n" );
857 fprintf( outfile, " void **phmod;\n" );
858 fprintf( outfile, " void **pIAT;\n" );
859 fprintf( outfile, " const char **pINT;\n" );
860 fprintf( outfile, " void* pBoundIAT;\n" );
861 fprintf( outfile, " void* pUnloadIAT;\n" );
862 fprintf( outfile, " unsigned long dwTimeStamp;\n" );
863 fprintf( outfile, " } imp[%d];\n", nb_delayed + 1 );
864 fprintf( outfile, " void *IAT[%d];\n", total_delayed );
865 fprintf( outfile, " const char *INT[%d];\n", total_delayed );
866 fprintf( outfile, "} __wine_spec_delay_imports = {\n" );
867 fprintf( outfile, " {\n" );
868 for (i = j = 0; i < nb_imports; i++)
870 if (!dll_imports[i]->delay) continue;
871 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",
872 dll_imports[i]->spec->file_name, i, j, j );
873 j += dll_imports[i]->nb_imports;
875 fprintf( outfile, " },\n {\n" );
876 for (i = 0; i < nb_imports; i++)
878 if (!dll_imports[i]->delay) continue;
879 fprintf( outfile, " /* %s */\n", dll_imports[i]->spec->file_name );
880 for (j = 0; j < dll_imports[i]->nb_imports; j++)
882 ORDDEF *odp = dll_imports[i]->imports[j];
883 const char *name = odp->name ? odp->name : odp->export_name;
884 fprintf( outfile, " &__wine_delay_imp_%d_%s,\n", i, name );
887 fprintf( outfile, " },\n {\n" );
888 for (i = 0; i < nb_imports; i++)
890 if (!dll_imports[i]->delay) continue;
891 fprintf( outfile, " /* %s */\n", dll_imports[i]->spec->file_name );
892 for (j = 0; j < dll_imports[i]->nb_imports; j++)
894 ORDDEF *odp = dll_imports[i]->imports[j];
895 if (!odp->name)
896 fprintf( outfile, " (char *)%d,\n", odp->ordinal );
897 else
898 fprintf( outfile, " \"%s\",\n", odp->name );
901 fprintf( outfile, " }\n};\n\n" );
903 return nb_delayed;
906 /* output the delayed import thunks of a Win32 module */
907 static void output_delayed_import_thunks( FILE *outfile, const DLLSPEC *spec )
909 int i, idx, j, pos, extra_stack_storage = 0;
910 static const char delayed_import_loaders[] = "__wine_spec_delayed_import_loaders";
911 static const char delayed_import_thunks[] = "__wine_spec_delayed_import_thunks";
913 if (!nb_delayed) return;
915 fprintf( outfile, "/* delayed import thunks */\n" );
916 fprintf( outfile, "asm(\".text\\n\"\n" );
917 fprintf( outfile, " \"\\t.align %d\\n\"\n", get_alignment(8) );
918 fprintf( outfile, " \"%s:\\n\"\n", asm_name(delayed_import_loaders));
919 fprintf( outfile, " \"\\t%s\\n\"\n", func_declaration("__wine_delay_load_asm") );
920 fprintf( outfile, " \"%s:\\n\"\n", asm_name("__wine_delay_load_asm") );
921 switch(target_cpu)
923 case CPU_x86:
924 fprintf( outfile, " \"\\tpushl %%ecx\\n\\tpushl %%edx\\n\\tpushl %%eax\\n\"\n" );
925 fprintf( outfile, " \"\\tcall %s\\n\"\n", asm_name("__wine_spec_delay_load") );
926 fprintf( outfile, " \"\\tpopl %%edx\\n\\tpopl %%ecx\\n\\tjmp *%%eax\\n\"\n" );
927 break;
928 case CPU_SPARC:
929 fprintf( outfile, " \"\\tsave %%sp, -96, %%sp\\n\"\n" );
930 fprintf( outfile, " \"\\tcall %s\\n\"\n", asm_name("__wine_spec_delay_load") );
931 fprintf( outfile, " \"\\tmov %%g1, %%o0\\n\"\n" );
932 fprintf( outfile, " \"\\tjmp %%o0\\n\\trestore\\n\"\n" );
933 break;
934 case CPU_ALPHA:
935 fprintf( outfile, " \"\\tjsr $26,%s\\n\"\n", asm_name("__wine_spec_delay_load") );
936 fprintf( outfile, " \"\\tjmp $31,($0)\\n\"\n" );
937 break;
938 case CPU_POWERPC:
939 if (target_platform == PLATFORM_APPLE) extra_stack_storage = 56;
941 /* Save all callee saved registers into a stackframe. */
942 fprintf( outfile, " \"\\tstwu %s, -%d(%s)\\n\"\n",ppc_reg(1), 48+extra_stack_storage, ppc_reg(1));
943 fprintf( outfile, " \"\\tstw %s, %d(%s)\\n\"\n", ppc_reg(3), 4+extra_stack_storage, ppc_reg(1));
944 fprintf( outfile, " \"\\tstw %s, %d(%s)\\n\"\n", ppc_reg(4), 8+extra_stack_storage, ppc_reg(1));
945 fprintf( outfile, " \"\\tstw %s, %d(%s)\\n\"\n", ppc_reg(5), 12+extra_stack_storage, ppc_reg(1));
946 fprintf( outfile, " \"\\tstw %s, %d(%s)\\n\"\n", ppc_reg(6), 16+extra_stack_storage, ppc_reg(1));
947 fprintf( outfile, " \"\\tstw %s, %d(%s)\\n\"\n", ppc_reg(7), 20+extra_stack_storage, ppc_reg(1));
948 fprintf( outfile, " \"\\tstw %s, %d(%s)\\n\"\n", ppc_reg(8), 24+extra_stack_storage, ppc_reg(1));
949 fprintf( outfile, " \"\\tstw %s, %d(%s)\\n\"\n", ppc_reg(9), 28+extra_stack_storage, ppc_reg(1));
950 fprintf( outfile, " \"\\tstw %s, %d(%s)\\n\"\n", ppc_reg(10),32+extra_stack_storage, ppc_reg(1));
951 fprintf( outfile, " \"\\tstw %s, %d(%s)\\n\"\n", ppc_reg(11),36+extra_stack_storage, ppc_reg(1));
952 fprintf( outfile, " \"\\tstw %s, %d(%s)\\n\"\n", ppc_reg(12),40+extra_stack_storage, ppc_reg(1));
954 /* r0 -> r3 (arg1) */
955 fprintf( outfile, " \"\\tmr %s, %s\\n\"\n", ppc_reg(3), ppc_reg(0));
957 /* save return address */
958 fprintf( outfile, " \"\\tmflr %s\\n\"\n", ppc_reg(0));
959 fprintf( outfile, " \"\\tstw %s, %d(%s)\\n\"\n", ppc_reg(0), 44+extra_stack_storage, ppc_reg(1));
961 /* Call the __wine_delay_load function, arg1 is arg1. */
962 fprintf( outfile, " \"\\tbl %s\\n\"\n", asm_name("__wine_spec_delay_load") );
964 /* Load return value from call into ctr register */
965 fprintf( outfile, " \"\\tmtctr %s\\n\"\n", ppc_reg(3));
967 /* restore all saved registers and drop stackframe. */
968 fprintf( outfile, " \"\\tlwz %s, %d(%s)\\n\"\n", ppc_reg(3), 4+extra_stack_storage, ppc_reg(1));
969 fprintf( outfile, " \"\\tlwz %s, %d(%s)\\n\"\n", ppc_reg(4), 8+extra_stack_storage, ppc_reg(1));
970 fprintf( outfile, " \"\\tlwz %s, %d(%s)\\n\"\n", ppc_reg(5), 12+extra_stack_storage, ppc_reg(1));
971 fprintf( outfile, " \"\\tlwz %s, %d(%s)\\n\"\n", ppc_reg(6), 16+extra_stack_storage, ppc_reg(1));
972 fprintf( outfile, " \"\\tlwz %s, %d(%s)\\n\"\n", ppc_reg(7), 20+extra_stack_storage, ppc_reg(1));
973 fprintf( outfile, " \"\\tlwz %s, %d(%s)\\n\"\n", ppc_reg(8), 24+extra_stack_storage, ppc_reg(1));
974 fprintf( outfile, " \"\\tlwz %s, %d(%s)\\n\"\n", ppc_reg(9), 28+extra_stack_storage, ppc_reg(1));
975 fprintf( outfile, " \"\\tlwz %s, %d(%s)\\n\"\n", ppc_reg(10),32+extra_stack_storage, ppc_reg(1));
976 fprintf( outfile, " \"\\tlwz %s, %d(%s)\\n\"\n", ppc_reg(11),36+extra_stack_storage, ppc_reg(1));
977 fprintf( outfile, " \"\\tlwz %s, %d(%s)\\n\"\n", ppc_reg(12),40+extra_stack_storage, ppc_reg(1));
979 /* Load return value from call into return register */
980 fprintf( outfile, " \"\\tlwz %s, %d(%s)\\n\"\n", ppc_reg(0), 44+extra_stack_storage, ppc_reg(1));
981 fprintf( outfile, " \"\\tmtlr %s\\n\"\n", ppc_reg(0));
982 fprintf( outfile, " \"\\taddi %s, %s, %d\\n\"\n", ppc_reg(1), ppc_reg(1), 48+extra_stack_storage);
984 /* branch to ctr register. */
985 fprintf( outfile, " \"bctr\\n\"\n");
986 break;
988 output_function_size( outfile, "__wine_delay_load_asm" );
990 for (i = idx = 0; i < nb_imports; i++)
992 if (!dll_imports[i]->delay) continue;
993 for (j = 0; j < dll_imports[i]->nb_imports; j++)
995 char buffer[128];
996 ORDDEF *odp = dll_imports[i]->imports[j];
997 const char *name = odp->name ? odp->name : odp->export_name;
999 sprintf( buffer, "__wine_delay_imp_%d_%s", i, name );
1000 fprintf( outfile, " \"\\t%s\\n\"\n", func_declaration(buffer) );
1001 fprintf( outfile, " \"%s:\\n\"\n", asm_name(buffer) );
1002 switch(target_cpu)
1004 case CPU_x86:
1005 fprintf( outfile, " \"\\tmovl $%d, %%eax\\n\"\n", (idx << 16) | j );
1006 fprintf( outfile, " \"\\tjmp %s\\n\"\n", asm_name("__wine_delay_load_asm") );
1007 break;
1008 case CPU_SPARC:
1009 fprintf( outfile, " \"\\tset %d, %%g1\\n\"\n", (idx << 16) | j );
1010 fprintf( outfile, " \"\\tb,a %s\\n\"\n", asm_name("__wine_delay_load_asm") );
1011 break;
1012 case CPU_ALPHA:
1013 fprintf( outfile, " \"\\tlda $0,%d($31)\\n\"\n", j);
1014 fprintf( outfile, " \"\\tldah $0,%d($0)\\n\"\n", idx);
1015 fprintf( outfile, " \"\\tjmp $31,%s\\n\"\n", asm_name("__wine_delay_load_asm") );
1016 break;
1017 case CPU_POWERPC:
1018 switch(target_platform)
1020 case PLATFORM_APPLE:
1021 /* On Darwin we can use r0 and r2 */
1022 /* Upper part in r2 */
1023 fprintf( outfile, " \"\\tlis %s, %d\\n\"\n", ppc_reg(2), idx);
1024 /* Lower part + r2 -> r0, Note we can't use r0 directly */
1025 fprintf( outfile, " \"\\taddi %s, %s, %d\\n\"\n", ppc_reg(0), ppc_reg(2), j);
1026 fprintf( outfile, " \"\\tb %s\\n\"\n", asm_name("__wine_delay_load_asm") );
1027 break;
1028 default:
1029 /* On linux we can't use r2 since r2 is not a scratch register (hold the TOC) */
1030 /* Save r13 on the stack */
1031 fprintf( outfile, " \"\\taddi %s, %s, -0x4\\n\"\n", ppc_reg(1), ppc_reg(1));
1032 fprintf( outfile, " \"\\tstw %s, 0(%s)\\n\"\n", ppc_reg(13), ppc_reg(1));
1033 /* Upper part in r13 */
1034 fprintf( outfile, " \"\\tlis %s, %d\\n\"\n", ppc_reg(13), idx);
1035 /* Lower part + r13 -> r0, Note we can't use r0 directly */
1036 fprintf( outfile, " \"\\taddi %s, %s, %d\\n\"\n", ppc_reg(0), ppc_reg(13), j);
1037 /* Restore r13 */
1038 fprintf( outfile, " \"\\tstw %s, 0(%s)\\n\"\n", ppc_reg(13), ppc_reg(1));
1039 fprintf( outfile, " \"\\taddic %s, %s, 0x4\\n\"\n", ppc_reg(1), ppc_reg(1));
1040 fprintf( outfile, " \"\\tb %s\\n\"\n", asm_name("__wine_delay_load_asm") );
1041 break;
1043 break;
1045 output_function_size( outfile, name );
1047 idx++;
1049 output_function_size( outfile, delayed_import_loaders );
1051 fprintf( outfile, "\n \".align %d\\n\"\n", get_alignment(8) );
1052 fprintf( outfile, " \"%s:\\n\"\n", asm_name(delayed_import_thunks));
1053 pos = (nb_delayed + 1) * 32;
1054 for (i = 0; i < nb_imports; i++)
1056 if (!dll_imports[i]->delay) continue;
1057 for (j = 0; j < dll_imports[i]->nb_imports; j++, pos += 4)
1059 ORDDEF *odp = dll_imports[i]->imports[j];
1060 output_import_thunk( outfile, odp->name ? odp->name : odp->export_name,
1061 "__wine_spec_delay_imports", pos );
1064 output_function_size( outfile, delayed_import_thunks );
1065 fprintf( outfile, ");\n" );
1068 /* output the import and delayed import tables of a Win32 module
1069 * returns number of DLLs exported in 'immediate' mode
1071 int output_imports( FILE *outfile, DLLSPEC *spec, int *nb_delayed )
1073 *nb_delayed = output_delayed_imports( outfile, spec );
1074 return output_immediate_imports( outfile );
1077 /* output the import and delayed import thunks of a Win32 module */
1078 void output_import_thunks( FILE *outfile, DLLSPEC *spec )
1080 output_delayed_import_thunks( outfile, spec );
1081 output_immediate_import_thunks( outfile );