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
23 #include "wine/port.h"
31 #ifdef HAVE_SYS_STAT_H
32 # include <sys/stat.h>
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 */
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 */
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
[] =
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
) );
173 /* make a name table empty */
174 inline static void empty_name_table( struct name_table
*table
)
178 for (i
= 0; i
< table
->count
; i
++) free( table
->names
[i
] );
182 /* locate a name in a (sorted) list */
183 inline static const char *find_name( const char *name
, const struct name_table
*table
)
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
;
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
);
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
)
236 for (i
= 0; i
< delayed_imports
.count
; i
++)
238 if (!strcmp( delayed_imports
.names
[i
], name
)) return 1;
243 /* check whether a given dll has already been imported */
244 static struct import
*is_already_imported( const char *name
)
248 for (i
= 0; i
< nb_imports
; i
++)
250 if (!strcmp( dll_imports
[i
]->spec
->file_name
, name
)) return dll_imports
[i
];
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
)
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)
274 /* find the .def import library for a given dll */
275 static char *find_library( const char *name
)
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
);
288 /* read in the list of exported symbols of an import library */
289 static int read_import_lib( struct import
*imp
)
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
);
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
))
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
) );
332 qsort( imp
->exports
, imp
->nb_exports
, sizeof(*imp
->exports
), func_cmp
);
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
)
343 const char *basename
= strrchr( filename
, '/' );
344 if (!basename
) basename
= filename
;
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;
353 ret
= xmalloc( strlen(name
) + 5 );
356 if (!strchr( ret
, '.' )) strcat( ret
, ".dll" );
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
);
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
;
384 if (nb_errors
) exit(1);
388 /* add a library to the list of delayed imports */
389 void add_delayed_import( const char *name
)
392 char *fullname
= get_dll_name( name
, NULL
);
394 add_name( &delayed_imports
, fullname
);
395 if ((imp
= is_already_imported( fullname
)) && !imp
->delay
)
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) );
410 if (imp
->delay
) nb_delayed
--;
414 /* initialize the list of ignored symbols */
415 static void init_ignored_symbols(void)
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
)
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
;
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
)
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
;
482 /* check if the spec file exports any stubs */
483 static int has_stubs( const DLLSPEC
*spec
)
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;
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];
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
);
515 /* make sure we import the dlls that contain these functions */
516 if (kernel_imports
) add_import_dll( "kernel32", NULL
);
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
)
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 */
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;
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" );
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
] );
575 if (err
) fatal_error( "%s -r failed with status %d\n", ld_command
, err
);
580 /* read in the list of undefined symbols */
581 void read_undef_symbols( DLLSPEC
*spec
, char **argv
)
585 char *cmd
, buffer
[1024], name_prefix
[16];
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;
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
);
625 static void remove_ignored_symbols(void)
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
);
655 add_import_func( imp
, odp
);
656 remove_name( &undef_symbols
, j
-- );
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
);
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
) );
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
);
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" );
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
);
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" );
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" );
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" );
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));
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");
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" );
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
);
841 fprintf( outfile
, " (char *)%d,\n", odp
->ordinal
);
843 fprintf( outfile
, " 0,\n" );
845 fprintf( outfile
, " }\n};\n\n" );
850 /* output the import thunks of a Win32 module */
851 static void output_immediate_import_thunks( FILE *outfile
)
854 int nb_imm
= nb_imports
- nb_delayed
;
855 static const char import_thunks
[] = "__wine_spec_import_thunks";
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
,
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
)
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
];
942 fprintf( outfile
, " (char *)%d,\n", odp
->ordinal
);
944 fprintf( outfile
, " \"%s\",\n", odp
->name
);
947 fprintf( outfile
, " }\n};\n\n" );
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") );
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" );
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" );
981 fprintf( outfile
, " \"\\tjsr $26,%s\\n\"\n", asm_name("__wine_spec_delay_load") );
982 fprintf( outfile
, " \"\\tjmp $31,($0)\\n\"\n" );
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");
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
++)
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
) );
1051 fprintf( outfile
, " \"\\tmovl $%d, %%eax\\n\"\n", (idx
<< 16) | j
);
1052 fprintf( outfile
, " \"\\tjmp %s\\n\"\n", asm_name("__wine_delay_load_asm") );
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") );
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") );
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") );
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
);
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") );
1091 output_function_size( outfile
, name
);
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
);