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 /* add the extra undefined symbols that will be contained in the generated spec file itself */
483 static void add_extra_undef_symbols( const DLLSPEC
*spec
)
485 const char *extras
[10];
486 int i
, count
= 0, nb_stubs
= 0;
487 int kernel_imports
= 0, ntdll_imports
= 0;
489 sort_names( &undef_symbols
);
491 for (i
= 0; i
< spec
->nb_entry_points
; i
++)
493 ORDDEF
*odp
= &spec
->entry_points
[i
];
494 if (odp
->type
== TYPE_STUB
) nb_stubs
++;
497 /* add symbols that will be contained in the spec file itself */
498 if (!(spec
->characteristics
& IMAGE_FILE_DLL
))
500 switch (spec
->subsystem
)
502 case IMAGE_SUBSYSTEM_WINDOWS_GUI
:
503 case IMAGE_SUBSYSTEM_WINDOWS_CUI
:
504 kernel_imports
+= add_extra_symbol( extras
, &count
, "GetCommandLineA", spec
);
505 kernel_imports
+= add_extra_symbol( extras
, &count
, "GetStartupInfoA", spec
);
506 kernel_imports
+= add_extra_symbol( extras
, &count
, "GetModuleHandleA", spec
);
507 kernel_imports
+= add_extra_symbol( extras
, &count
, "ExitProcess", spec
);
513 kernel_imports
+= add_extra_symbol( extras
, &count
, "LoadLibraryA", spec
);
514 kernel_imports
+= add_extra_symbol( extras
, &count
, "FreeLibrary", spec
);
515 kernel_imports
+= add_extra_symbol( extras
, &count
, "GetProcAddress", spec
);
516 kernel_imports
+= add_extra_symbol( extras
, &count
, "DelayLoadFailureHook", spec
);
519 ntdll_imports
+= add_extra_symbol( extras
, &count
, "RtlRaiseException", spec
);
521 /* make sure we import the dlls that contain these functions */
522 if (kernel_imports
) add_import_dll( "kernel32", NULL
);
523 if (ntdll_imports
) add_import_dll( "ntdll", NULL
);
527 for (i
= 0; i
< count
; i
++) add_name( &undef_symbols
, extras
[i
] );
528 sort_names( &undef_symbols
);
532 /* check if a given imported dll is not needed, taking forwards into account */
533 static int check_unused( const struct import
* imp
, const DLLSPEC
*spec
)
536 const char *file_name
= imp
->spec
->file_name
;
537 size_t len
= strlen( file_name
);
538 const char *p
= strchr( file_name
, '.' );
539 if (p
&& !strcasecmp( p
, ".dll" )) len
= p
- file_name
;
541 for (i
= spec
->base
; i
<= spec
->limit
; i
++)
543 ORDDEF
*odp
= spec
->ordinals
[i
];
544 if (!odp
|| !(odp
->flags
& FLAG_FORWARD
)) continue;
545 if (!strncasecmp( odp
->link_name
, file_name
, len
) &&
546 odp
->link_name
[len
] == '.')
547 return 0; /* found a forward, it is used */
552 /* combine a list of object files with ld into a single object file */
553 /* returns the name of the combined file */
554 static const char *ldcombine_files( char **argv
)
556 unsigned int i
, len
= 0;
560 if (output_file_name
&& output_file_name
[0])
562 ld_tmp_file
= xmalloc( strlen(output_file_name
) + 10 );
563 strcpy( ld_tmp_file
, output_file_name
);
564 strcat( ld_tmp_file
, ".XXXXXX.o" );
566 else ld_tmp_file
= xstrdup( "/tmp/winebuild.tmp.XXXXXX.o" );
568 if ((fd
= mkstemps( ld_tmp_file
, 2 ) == -1)) fatal_error( "could not generate a temp file\n" );
570 atexit( remove_ld_tmp_file
);
572 if (!ld_command
) ld_command
= xstrdup("ld");
573 for (i
= 0; i
< extra_ld_symbols
.count
; i
++) len
+= strlen(extra_ld_symbols
.names
[i
]) + 5;
574 for (i
= 0; argv
[i
]; i
++) len
+= strlen(argv
[i
]) + 1;
575 cmd
= p
= xmalloc( len
+ strlen(ld_tmp_file
) + 8 + strlen(ld_command
) );
576 p
+= sprintf( cmd
, "%s -r -o %s", ld_command
, ld_tmp_file
);
577 for (i
= 0; i
< extra_ld_symbols
.count
; i
++)
578 p
+= sprintf( p
, " -u %s", asm_name(extra_ld_symbols
.names
[i
]) );
579 for (i
= 0; argv
[i
]; i
++)
580 p
+= sprintf( p
, " %s", argv
[i
] );
582 if (err
) fatal_error( "%s -r failed with status %d\n", ld_command
, err
);
587 /* read in the list of undefined symbols */
588 void read_undef_symbols( DLLSPEC
*spec
, char **argv
)
592 char *cmd
, buffer
[1024], name_prefix
[16];
596 if (!argv
[0]) return;
598 if (spec
->init_func
) add_extra_ld_symbol( spec
->init_func
);
599 else if (spec
->characteristics
& IMAGE_FILE_DLL
) add_extra_ld_symbol( "DllMain" );
600 else if (spec
->subsystem
== IMAGE_SUBSYSTEM_NATIVE
) add_extra_ld_symbol( "DriverEntry ");
601 else add_extra_ld_symbol( "main" );
603 strcpy( name_prefix
, asm_name("") );
604 prefix_len
= strlen( name_prefix
);
606 name
= ldcombine_files( argv
);
608 if (!nm_command
) nm_command
= xstrdup("nm");
609 cmd
= xmalloc( strlen(nm_command
) + strlen(name
) + 5 );
610 sprintf( cmd
, "%s -u %s", nm_command
, name
);
611 if (!(f
= popen( cmd
, "r" )))
612 fatal_error( "Cannot execute '%s'\n", cmd
);
614 while (fgets( buffer
, sizeof(buffer
), f
))
616 char *p
= buffer
+ strlen(buffer
) - 1;
617 if (p
< buffer
) continue;
618 if (*p
== '\n') *p
-- = 0;
620 while (*p
== ' ') p
++;
621 if (p
[0] == 'U' && p
[1] == ' ' && p
[2]) p
+= 2;
622 if (prefix_len
&& !strncmp( p
, name_prefix
, prefix_len
)) p
+= prefix_len
;
623 add_name( &undef_symbols
, p
);
625 if ((err
= pclose( f
))) warning( "%s failed with status %d\n", cmd
, err
);
629 static void remove_ignored_symbols(void)
633 if (!ignore_symbols
.size
) init_ignored_symbols();
634 sort_names( &ignore_symbols
);
635 for (i
= 0; i
< undef_symbols
.count
; i
++)
637 if (find_name( undef_symbols
.names
[i
], &ignore_symbols
))
638 remove_name( &undef_symbols
, i
-- );
642 /* resolve the imports for a Win32 module */
643 int resolve_imports( DLLSPEC
*spec
)
645 unsigned int i
, j
, removed
;
647 add_extra_undef_symbols( spec
);
648 remove_ignored_symbols();
650 for (i
= 0; i
< nb_imports
; i
++)
652 struct import
*imp
= dll_imports
[i
];
654 for (j
= removed
= 0; j
< undef_symbols
.count
; j
++)
656 ORDDEF
*odp
= find_export( undef_symbols
.names
[j
], imp
->exports
, imp
->nb_exports
);
659 add_import_func( imp
, odp
);
660 remove_name( &undef_symbols
, j
-- );
664 if (!removed
&& check_unused( imp
, spec
))
666 /* the dll is not used, get rid of it */
667 warning( "%s imported but no symbols used\n", imp
->spec
->file_name
);
668 remove_import_dll( i
);
675 /* output a single import thunk */
676 static void output_import_thunk( FILE *outfile
, const char *name
, const char *table
, int pos
)
678 fprintf( outfile
, " \"\\t.align %d\\n\"\n", get_alignment(4) );
679 fprintf( outfile
, " \"\\t%s\\n\"\n", func_declaration(name
) );
680 fprintf( outfile
, " \"\\t.globl %s\\n\"\n", asm_name(name
) );
681 fprintf( outfile
, " \"%s:\\n\"\n", asm_name(name
) );
688 if (strstr( name
, "__wine_call_from_16" )) fprintf( outfile
, " \"\\t.byte 0x2e\\n\"\n" );
689 fprintf( outfile
, " \"\\tjmp *(%s+%d)\\n\"\n", asm_name(table
), pos
);
693 if (!strcmp( name
, "__wine_call_from_32_regs" ))
695 /* special case: need to preserve all registers */
696 fprintf( outfile
, " \"\\tpushl %%eax\\n\"\n" );
697 fprintf( outfile
, " \"\\tcall .L__wine_spec_%s\\n\"\n", name
);
698 fprintf( outfile
, " \".L__wine_spec_%s:\\n\"\n", name
);
699 fprintf( outfile
, " \"\\tpopl %%eax\\n\"\n" );
700 if (!strcmp( name
, "__wine_call_from_16_regs" ))
701 fprintf( outfile
, " \"\\t.byte 0x2e\\n\"\n" );
702 fprintf( outfile
, " \"\\tmovl %s+%d-.L__wine_spec_%s(%%eax),%%eax\\n\"\n",
703 asm_name(table
), pos
, name
);
704 fprintf( outfile
, " \"\\txchgl %%eax,(%%esp)\\n\"\n" );
705 fprintf( outfile
, " \"\\tret\\n\"\n" );
707 else if (!strcmp( name
, "__wine_call_from_16_regs" ))
709 /* special case: need to preserve all registers */
710 fprintf( outfile
, " \"\\tpushl %%eax\\n\"\n" );
711 fprintf( outfile
, " \"\\tpushl %%ecx\\n\"\n" );
712 fprintf( outfile
, " \"\\tcall .L__wine_spec_%s\\n\"\n", name
);
713 fprintf( outfile
, " \".L__wine_spec_%s:\\n\"\n", name
);
714 fprintf( outfile
, " \"\\tpopl %%eax\\n\"\n" );
715 fprintf( outfile
, " \"\\t.byte 0x2e\\n\"\n" );
716 fprintf( outfile
, " \"\\tmovl %s+%d-.L__wine_spec_%s(%%eax),%%eax\\n\"\n",
717 asm_name(table
), pos
, name
);
718 fprintf( outfile
, " \"\\tmovzwl %%sp, %%ecx\\n\"\n" );
719 fprintf( outfile
, " \"\\t.byte 0x36\\n\"\n" );
720 fprintf( outfile
, " \"\\txchgl %%eax,4(%%ecx)\\n\"\n" );
721 fprintf( outfile
, " \"\\tpopl %%ecx\\n\"\n" );
722 fprintf( outfile
, " \"\\tret\\n\"\n" );
726 fprintf( outfile
, " \"\\tcall .L__wine_spec_%s\\n\"\n", name
);
727 fprintf( outfile
, " \".L__wine_spec_%s:\\n\"\n", name
);
728 fprintf( outfile
, " \"\\tpopl %%eax\\n\"\n" );
729 if (strstr( name
, "__wine_call_from_16" ))
730 fprintf( outfile
, " \"\\t.byte 0x2e\\n\"\n" );
731 fprintf( outfile
, " \"\\tjmp *%s+%d-.L__wine_spec_%s(%%eax)\\n\"\n",
732 asm_name(table
), pos
, name
);
739 fprintf( outfile
, " \"\\tsethi %%hi(%s+%d), %%g1\\n\"\n", table
, pos
);
740 fprintf( outfile
, " \"\\tld [%%g1+%%lo(%s+%d)], %%g1\\n\"\n", table
, pos
);
741 fprintf( outfile
, " \"\\tjmp %%g1\\n\\tnop\\n\"\n" );
745 /* Hmpf. Stupid sparc assembler always interprets global variable
746 names as GOT offsets, so we have to do it the long way ... */
747 fprintf( outfile
, " \"\\tsave %%sp, -96, %%sp\\n\"\n" );
748 fprintf( outfile
, " \"0:\\tcall 1f\\n\\tnop\\n\"\n" );
749 fprintf( outfile
, " \"1:\\tsethi %%hi(%s+%d-0b), %%g1\\n\"\n", table
, pos
);
750 fprintf( outfile
, " \"\\tor %%g1, %%lo(%s+%d-0b), %%g1\\n\"\n", table
, pos
);
751 fprintf( outfile
, " \"\\tld [%%g1+%%o7], %%g1\\n\"\n" );
752 fprintf( outfile
, " \"\\tjmp %%g1\\n\\trestore\\n\"\n" );
756 fprintf( outfile
, " \"\\tlda $0,%s\\n\"\n", table
);
757 fprintf( outfile
, " \"\\tlda $0,%d($0)\\n\"\n", pos
);
758 fprintf( outfile
, " \"\\tjmp $31,($0)\\n\"\n" );
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(9), ppc_reg(1));
763 fprintf(outfile
, " \"\\taddi %s, %s, -0x4\\n\"\n", ppc_reg(1), ppc_reg(1));
764 fprintf(outfile
, " \"\\tstw %s, 0(%s)\\n\"\n", ppc_reg(8), ppc_reg(1));
765 fprintf(outfile
, " \"\\taddi %s, %s, -0x4\\n\"\n", ppc_reg(1), ppc_reg(1));
766 fprintf(outfile
, " \"\\tstw %s, 0(%s)\\n\"\n", ppc_reg(7), ppc_reg(1));
767 if (target_platform
== PLATFORM_APPLE
)
769 fprintf(outfile
, " \"\\tlis %s, ha16(%s+%d)\\n\"\n",
770 ppc_reg(9), asm_name(table
), pos
);
771 fprintf(outfile
, " \"\\tla %s, lo16(%s+%d)(%s)\\n\"\n",
772 ppc_reg(8), asm_name(table
), pos
, ppc_reg(9));
776 fprintf(outfile
, " \"\\tlis %s, (%s+%d)@hi\\n\"\n",
777 ppc_reg(9), asm_name(table
), pos
);
778 fprintf(outfile
, " \"\\tla %s, (%s+%d)@l(%s)\\n\"\n",
779 ppc_reg(8), asm_name(table
), pos
, ppc_reg(9));
781 fprintf(outfile
, " \"\\tlwz %s, 0(%s)\\n\"\n", ppc_reg(7), ppc_reg(8));
782 fprintf(outfile
, " \"\\tmtctr %s\\n\"\n", ppc_reg(7));
783 fprintf(outfile
, " \"\\tlwz %s, 0(%s)\\n\"\n", ppc_reg(7), ppc_reg(1));
784 fprintf(outfile
, " \"\\taddi %s, %s, 0x4\\n\"\n", ppc_reg(1), ppc_reg(1));
785 fprintf(outfile
, " \"\\tlwz %s, 0(%s)\\n\"\n", ppc_reg(8), ppc_reg(1));
786 fprintf(outfile
, " \"\\taddi %s, %s, 0x4\\n\"\n", ppc_reg(1), ppc_reg(1));
787 fprintf(outfile
, " \"\\tlwz %s, 0(%s)\\n\"\n", ppc_reg(9), ppc_reg(1));
788 fprintf(outfile
, " \"\\taddi %s, %s, 0x4\\n\"\n", ppc_reg(1), ppc_reg(1));
789 fprintf(outfile
, " \"\\tbctr\\n\"\n");
792 output_function_size( outfile
, name
);
795 /* output the import table of a Win32 module */
796 static int output_immediate_imports( FILE *outfile
)
798 int i
, j
, nb_imm
= nb_imports
- nb_delayed
;
800 if (!nb_imm
) return 0;
802 /* main import header */
804 fprintf( outfile
, "\nstatic struct {\n" );
805 fprintf( outfile
, " struct {\n" );
806 fprintf( outfile
, " void *OriginalFirstThunk;\n" );
807 fprintf( outfile
, " unsigned int TimeDateStamp;\n" );
808 fprintf( outfile
, " unsigned int ForwarderChain;\n" );
809 fprintf( outfile
, " const char *Name;\n" );
810 fprintf( outfile
, " void *FirstThunk;\n" );
811 fprintf( outfile
, " } imp[%d];\n", nb_imm
+1 );
812 fprintf( outfile
, " const char *data[%d];\n",
813 total_imports
- total_delayed
+ nb_imm
);
814 fprintf( outfile
, "} imports = {\n {\n" );
818 for (i
= j
= 0; i
< nb_imports
; i
++)
820 if (dll_imports
[i
]->delay
) continue;
821 fprintf( outfile
, " { 0, 0, 0, \"%s\", &imports.data[%d] },\n",
822 dll_imports
[i
]->spec
->file_name
, j
);
823 j
+= dll_imports
[i
]->nb_imports
+ 1;
826 fprintf( outfile
, " { 0, 0, 0, 0, 0 },\n" );
827 fprintf( outfile
, " },\n {\n" );
829 /* list of imported functions */
831 for (i
= 0; i
< nb_imports
; i
++)
833 if (dll_imports
[i
]->delay
) continue;
834 fprintf( outfile
, " /* %s */\n", dll_imports
[i
]->spec
->file_name
);
835 for (j
= 0; j
< dll_imports
[i
]->nb_imports
; j
++)
837 ORDDEF
*odp
= dll_imports
[i
]->imports
[j
];
838 if (!(odp
->flags
& FLAG_NONAME
))
840 unsigned short ord
= odp
->ordinal
;
841 fprintf( outfile
, " \"\\%03o\\%03o%s\",\n",
842 *(unsigned char *)&ord
, *((unsigned char *)&ord
+ 1), odp
->name
);
845 fprintf( outfile
, " (char *)%d,\n", odp
->ordinal
);
847 fprintf( outfile
, " 0,\n" );
849 fprintf( outfile
, " }\n};\n\n" );
854 /* output the import thunks of a Win32 module */
855 static void output_immediate_import_thunks( FILE *outfile
)
858 int nb_imm
= nb_imports
- nb_delayed
;
859 static const char import_thunks
[] = "__wine_spec_import_thunks";
863 pos
= (sizeof(void *) + 2*sizeof(unsigned int) + sizeof(const char *) + sizeof(void *)) *
864 (nb_imm
+ 1); /* offset of imports.data from start of imports */
865 fprintf( outfile
, "/* immediate import thunks */\n" );
866 fprintf( outfile
, "asm(\".text\\n\\t.align %d\\n\"\n", get_alignment(8) );
867 fprintf( outfile
, " \"%s:\\n\"\n", asm_name(import_thunks
));
869 for (i
= 0; i
< nb_imports
; i
++)
871 if (dll_imports
[i
]->delay
) continue;
872 for (j
= 0; j
< dll_imports
[i
]->nb_imports
; j
++, pos
+= sizeof(const char *))
874 ORDDEF
*odp
= dll_imports
[i
]->imports
[j
];
875 output_import_thunk( outfile
, odp
->name
? odp
->name
: odp
->export_name
,
880 output_function_size( outfile
, import_thunks
);
881 fprintf( outfile
, ");\n" );
884 /* output the delayed import table of a Win32 module */
885 static int output_delayed_imports( FILE *outfile
, const DLLSPEC
*spec
)
889 if (!nb_delayed
) return 0;
891 fprintf( outfile
, "static void *__wine_delay_imp_hmod[%d];\n", nb_delayed
);
892 for (i
= 0; i
< nb_imports
; i
++)
894 if (!dll_imports
[i
]->delay
) continue;
895 for (j
= 0; j
< dll_imports
[i
]->nb_imports
; j
++)
897 ORDDEF
*odp
= dll_imports
[i
]->imports
[j
];
898 const char *name
= odp
->name
? odp
->name
: odp
->export_name
;
899 fprintf( outfile
, "void __wine_delay_imp_%d_%s();\n", i
, name
);
902 fprintf( outfile
, "\n" );
903 fprintf( outfile
, "static struct {\n" );
904 fprintf( outfile
, " struct ImgDelayDescr {\n" );
905 fprintf( outfile
, " unsigned int grAttrs;\n" );
906 fprintf( outfile
, " const char *szName;\n" );
907 fprintf( outfile
, " void **phmod;\n" );
908 fprintf( outfile
, " void **pIAT;\n" );
909 fprintf( outfile
, " const char **pINT;\n" );
910 fprintf( outfile
, " void* pBoundIAT;\n" );
911 fprintf( outfile
, " void* pUnloadIAT;\n" );
912 fprintf( outfile
, " unsigned long dwTimeStamp;\n" );
913 fprintf( outfile
, " } imp[%d];\n", nb_delayed
);
914 fprintf( outfile
, " void *IAT[%d];\n", total_delayed
);
915 fprintf( outfile
, " const char *INT[%d];\n", total_delayed
);
916 fprintf( outfile
, "} delay_imports = {\n" );
917 fprintf( outfile
, " {\n" );
918 for (i
= j
= 0; i
< nb_imports
; i
++)
920 if (!dll_imports
[i
]->delay
) continue;
921 fprintf( outfile
, " { 0, \"%s\", &__wine_delay_imp_hmod[%d], &delay_imports.IAT[%d], &delay_imports.INT[%d], 0, 0, 0 },\n",
922 dll_imports
[i
]->spec
->file_name
, i
, j
, j
);
923 j
+= dll_imports
[i
]->nb_imports
;
925 fprintf( outfile
, " },\n {\n" );
926 for (i
= 0; i
< nb_imports
; i
++)
928 if (!dll_imports
[i
]->delay
) continue;
929 fprintf( outfile
, " /* %s */\n", dll_imports
[i
]->spec
->file_name
);
930 for (j
= 0; j
< dll_imports
[i
]->nb_imports
; j
++)
932 ORDDEF
*odp
= dll_imports
[i
]->imports
[j
];
933 const char *name
= odp
->name
? odp
->name
: odp
->export_name
;
934 fprintf( outfile
, " &__wine_delay_imp_%d_%s,\n", i
, name
);
937 fprintf( outfile
, " },\n {\n" );
938 for (i
= 0; i
< nb_imports
; i
++)
940 if (!dll_imports
[i
]->delay
) continue;
941 fprintf( outfile
, " /* %s */\n", dll_imports
[i
]->spec
->file_name
);
942 for (j
= 0; j
< dll_imports
[i
]->nb_imports
; j
++)
944 ORDDEF
*odp
= dll_imports
[i
]->imports
[j
];
946 fprintf( outfile
, " (char *)%d,\n", odp
->ordinal
);
948 fprintf( outfile
, " \"%s\",\n", odp
->name
);
951 fprintf( outfile
, " }\n};\n\n" );
953 fprintf( outfile
, "extern void * __stdcall LoadLibraryA(const char*);\n");
954 fprintf( outfile
, "extern void * __stdcall GetProcAddress(void *, const char*);\n");
955 fprintf( outfile
, "extern void * __stdcall DelayLoadFailureHook(const char *, const char*);\n");
956 fprintf( outfile
, "\n" );
958 fprintf( outfile
, "void *__stdcall __wine_delay_load( int idx_nr )\n" );
959 fprintf( outfile
, "{\n" );
960 fprintf( outfile
, " int idx = idx_nr >> 16, nr = idx_nr & 0xffff;\n" );
961 fprintf( outfile
, " struct ImgDelayDescr *imd = delay_imports.imp + idx;\n" );
962 fprintf( outfile
, " void **pIAT = imd->pIAT + nr;\n" );
963 fprintf( outfile
, " const char** pINT = imd->pINT + nr;\n" );
964 fprintf( outfile
, " void *fn;\n\n" );
966 fprintf( outfile
, " if (!*imd->phmod) *imd->phmod = LoadLibraryA(imd->szName);\n" );
967 fprintf( outfile
, " if (!*imd->phmod || !(fn = GetProcAddress(*imd->phmod, *pINT)))\n");
968 fprintf( outfile
, " fn = DelayLoadFailureHook(imd->szName, *pINT);\n" );
969 fprintf( outfile
, " /* patch IAT with final value */\n" );
970 fprintf( outfile
, " return *pIAT = fn;\n" );
971 fprintf( outfile
, "}\n" );
976 /* output the delayed import thunks of a Win32 module */
977 static void output_delayed_import_thunks( FILE *outfile
, const DLLSPEC
*spec
)
979 int i
, idx
, j
, pos
, extra_stack_storage
= 0;
980 static const char delayed_import_loaders
[] = "__wine_spec_delayed_import_loaders";
981 static const char delayed_import_thunks
[] = "__wine_spec_delayed_import_thunks";
983 if (!nb_delayed
) return;
985 fprintf( outfile
, "/* delayed import thunks */\n" );
986 fprintf( outfile
, "asm(\".text\\n\"\n" );
987 fprintf( outfile
, " \"\\t.align %d\\n\"\n", get_alignment(8) );
988 fprintf( outfile
, " \"%s:\\n\"\n", asm_name(delayed_import_loaders
));
989 fprintf( outfile
, " \"\\t%s\\n\"\n", func_declaration("__wine_delay_load_asm") );
990 fprintf( outfile
, " \"%s:\\n\"\n", asm_name("__wine_delay_load_asm") );
994 fprintf( outfile
, " \"\\tpushl %%ecx\\n\\tpushl %%edx\\n\\tpushl %%eax\\n\"\n" );
995 fprintf( outfile
, " \"\\tcall %s\\n\"\n", asm_name("__wine_delay_load") );
996 fprintf( outfile
, " \"\\tpopl %%edx\\n\\tpopl %%ecx\\n\\tjmp *%%eax\\n\"\n" );
999 fprintf( outfile
, " \"\\tsave %%sp, -96, %%sp\\n\"\n" );
1000 fprintf( outfile
, " \"\\tcall %s\\n\"\n", asm_name("__wine_delay_load") );
1001 fprintf( outfile
, " \"\\tmov %%g1, %%o0\\n\"\n" );
1002 fprintf( outfile
, " \"\\tjmp %%o0\\n\\trestore\\n\"\n" );
1005 fprintf( outfile
, " \"\\tjsr $26,%s\\n\"\n", asm_name("__wine_delay_load") );
1006 fprintf( outfile
, " \"\\tjmp $31,($0)\\n\"\n" );
1009 if (target_platform
== PLATFORM_APPLE
) extra_stack_storage
= 56;
1011 /* Save all callee saved registers into a stackframe. */
1012 fprintf( outfile
, " \"\\tstwu %s, -%d(%s)\\n\"\n",ppc_reg(1), 48+extra_stack_storage
, ppc_reg(1));
1013 fprintf( outfile
, " \"\\tstw %s, %d(%s)\\n\"\n", ppc_reg(3), 4+extra_stack_storage
, ppc_reg(1));
1014 fprintf( outfile
, " \"\\tstw %s, %d(%s)\\n\"\n", ppc_reg(4), 8+extra_stack_storage
, ppc_reg(1));
1015 fprintf( outfile
, " \"\\tstw %s, %d(%s)\\n\"\n", ppc_reg(5), 12+extra_stack_storage
, ppc_reg(1));
1016 fprintf( outfile
, " \"\\tstw %s, %d(%s)\\n\"\n", ppc_reg(6), 16+extra_stack_storage
, ppc_reg(1));
1017 fprintf( outfile
, " \"\\tstw %s, %d(%s)\\n\"\n", ppc_reg(7), 20+extra_stack_storage
, ppc_reg(1));
1018 fprintf( outfile
, " \"\\tstw %s, %d(%s)\\n\"\n", ppc_reg(8), 24+extra_stack_storage
, ppc_reg(1));
1019 fprintf( outfile
, " \"\\tstw %s, %d(%s)\\n\"\n", ppc_reg(9), 28+extra_stack_storage
, ppc_reg(1));
1020 fprintf( outfile
, " \"\\tstw %s, %d(%s)\\n\"\n", ppc_reg(10),32+extra_stack_storage
, ppc_reg(1));
1021 fprintf( outfile
, " \"\\tstw %s, %d(%s)\\n\"\n", ppc_reg(11),36+extra_stack_storage
, ppc_reg(1));
1022 fprintf( outfile
, " \"\\tstw %s, %d(%s)\\n\"\n", ppc_reg(12),40+extra_stack_storage
, ppc_reg(1));
1024 /* r0 -> r3 (arg1) */
1025 fprintf( outfile
, " \"\\tmr %s, %s\\n\"\n", ppc_reg(3), ppc_reg(0));
1027 /* save return address */
1028 fprintf( outfile
, " \"\\tmflr %s\\n\"\n", ppc_reg(0));
1029 fprintf( outfile
, " \"\\tstw %s, %d(%s)\\n\"\n", ppc_reg(0), 44+extra_stack_storage
, ppc_reg(1));
1031 /* Call the __wine_delay_load function, arg1 is arg1. */
1032 fprintf( outfile
, " \"\\tbl %s\\n\"\n", asm_name("__wine_delay_load") );
1034 /* Load return value from call into ctr register */
1035 fprintf( outfile
, " \"\\tmtctr %s\\n\"\n", ppc_reg(3));
1037 /* restore all saved registers and drop stackframe. */
1038 fprintf( outfile
, " \"\\tlwz %s, %d(%s)\\n\"\n", ppc_reg(3), 4+extra_stack_storage
, ppc_reg(1));
1039 fprintf( outfile
, " \"\\tlwz %s, %d(%s)\\n\"\n", ppc_reg(4), 8+extra_stack_storage
, ppc_reg(1));
1040 fprintf( outfile
, " \"\\tlwz %s, %d(%s)\\n\"\n", ppc_reg(5), 12+extra_stack_storage
, ppc_reg(1));
1041 fprintf( outfile
, " \"\\tlwz %s, %d(%s)\\n\"\n", ppc_reg(6), 16+extra_stack_storage
, ppc_reg(1));
1042 fprintf( outfile
, " \"\\tlwz %s, %d(%s)\\n\"\n", ppc_reg(7), 20+extra_stack_storage
, ppc_reg(1));
1043 fprintf( outfile
, " \"\\tlwz %s, %d(%s)\\n\"\n", ppc_reg(8), 24+extra_stack_storage
, ppc_reg(1));
1044 fprintf( outfile
, " \"\\tlwz %s, %d(%s)\\n\"\n", ppc_reg(9), 28+extra_stack_storage
, ppc_reg(1));
1045 fprintf( outfile
, " \"\\tlwz %s, %d(%s)\\n\"\n", ppc_reg(10),32+extra_stack_storage
, ppc_reg(1));
1046 fprintf( outfile
, " \"\\tlwz %s, %d(%s)\\n\"\n", ppc_reg(11),36+extra_stack_storage
, ppc_reg(1));
1047 fprintf( outfile
, " \"\\tlwz %s, %d(%s)\\n\"\n", ppc_reg(12),40+extra_stack_storage
, ppc_reg(1));
1049 /* Load return value from call into return register */
1050 fprintf( outfile
, " \"\\tlwz %s, %d(%s)\\n\"\n", ppc_reg(0), 44+extra_stack_storage
, ppc_reg(1));
1051 fprintf( outfile
, " \"\\tmtlr %s\\n\"\n", ppc_reg(0));
1052 fprintf( outfile
, " \"\\taddi %s, %s, %d\\n\"\n", ppc_reg(1), ppc_reg(1), 48+extra_stack_storage
);
1054 /* branch to ctr register. */
1055 fprintf( outfile
, " \"bctr\\n\"\n");
1058 output_function_size( outfile
, "__wine_delay_load_asm" );
1060 for (i
= idx
= 0; i
< nb_imports
; i
++)
1062 if (!dll_imports
[i
]->delay
) continue;
1063 for (j
= 0; j
< dll_imports
[i
]->nb_imports
; j
++)
1066 ORDDEF
*odp
= dll_imports
[i
]->imports
[j
];
1067 const char *name
= odp
->name
? odp
->name
: odp
->export_name
;
1069 sprintf( buffer
, "__wine_delay_imp_%d_%s", i
, name
);
1070 fprintf( outfile
, " \"\\t%s\\n\"\n", func_declaration(buffer
) );
1071 fprintf( outfile
, " \"%s:\\n\"\n", asm_name(buffer
) );
1075 fprintf( outfile
, " \"\\tmovl $%d, %%eax\\n\"\n", (idx
<< 16) | j
);
1076 fprintf( outfile
, " \"\\tjmp %s\\n\"\n", asm_name("__wine_delay_load_asm") );
1079 fprintf( outfile
, " \"\\tset %d, %%g1\\n\"\n", (idx
<< 16) | j
);
1080 fprintf( outfile
, " \"\\tb,a %s\\n\"\n", asm_name("__wine_delay_load_asm") );
1083 fprintf( outfile
, " \"\\tlda $0,%d($31)\\n\"\n", j
);
1084 fprintf( outfile
, " \"\\tldah $0,%d($0)\\n\"\n", idx
);
1085 fprintf( outfile
, " \"\\tjmp $31,%s\\n\"\n", asm_name("__wine_delay_load_asm") );
1088 switch(target_platform
)
1090 case PLATFORM_APPLE
:
1091 /* On Darwin we can use r0 and r2 */
1092 /* Upper part in r2 */
1093 fprintf( outfile
, " \"\\tlis %s, %d\\n\"\n", ppc_reg(2), idx
);
1094 /* Lower part + r2 -> r0, Note we can't use r0 directly */
1095 fprintf( outfile
, " \"\\taddi %s, %s, %d\\n\"\n", ppc_reg(0), ppc_reg(2), j
);
1096 fprintf( outfile
, " \"\\tb %s\\n\"\n", asm_name("__wine_delay_load_asm") );
1099 /* On linux we can't use r2 since r2 is not a scratch register (hold the TOC) */
1100 /* Save r13 on the stack */
1101 fprintf( outfile
, " \"\\taddi %s, %s, -0x4\\n\"\n", ppc_reg(1), ppc_reg(1));
1102 fprintf( outfile
, " \"\\tstw %s, 0(%s)\\n\"\n", ppc_reg(13), ppc_reg(1));
1103 /* Upper part in r13 */
1104 fprintf( outfile
, " \"\\tlis %s, %d\\n\"\n", ppc_reg(13), idx
);
1105 /* Lower part + r13 -> r0, Note we can't use r0 directly */
1106 fprintf( outfile
, " \"\\taddi %s, %s, %d\\n\"\n", ppc_reg(0), ppc_reg(13), j
);
1108 fprintf( outfile
, " \"\\tstw %s, 0(%s)\\n\"\n", ppc_reg(13), ppc_reg(1));
1109 fprintf( outfile
, " \"\\taddic %s, %s, 0x4\\n\"\n", ppc_reg(1), ppc_reg(1));
1110 fprintf( outfile
, " \"\\tb %s\\n\"\n", asm_name("__wine_delay_load_asm") );
1115 output_function_size( outfile
, name
);
1119 output_function_size( outfile
, delayed_import_loaders
);
1121 fprintf( outfile
, "\n \".align %d\\n\"\n", get_alignment(8) );
1122 fprintf( outfile
, " \"%s:\\n\"\n", asm_name(delayed_import_thunks
));
1123 pos
= nb_delayed
* 32;
1124 for (i
= 0; i
< nb_imports
; i
++)
1126 if (!dll_imports
[i
]->delay
) continue;
1127 for (j
= 0; j
< dll_imports
[i
]->nb_imports
; j
++, pos
+= 4)
1129 ORDDEF
*odp
= dll_imports
[i
]->imports
[j
];
1130 output_import_thunk( outfile
, odp
->name
? odp
->name
: odp
->export_name
,
1131 "delay_imports", pos
);
1134 output_function_size( outfile
, delayed_import_thunks
);
1135 fprintf( outfile
, ");\n" );
1138 /* output the import and delayed import tables of a Win32 module
1139 * returns number of DLLs exported in 'immediate' mode
1141 int output_imports( FILE *outfile
, DLLSPEC
*spec
, int *nb_delayed
)
1143 *nb_delayed
= output_delayed_imports( outfile
, spec
);
1144 return output_immediate_imports( outfile
);
1147 /* output the import and delayed import thunks of a Win32 module */
1148 void output_import_thunks( FILE *outfile
, DLLSPEC
*spec
)
1150 output_delayed_import_thunks( outfile
, spec
);
1151 output_immediate_import_thunks( outfile
);