msxml3: Use standard dlopen() instead of the libwine wrappers.
[wine/zf.git] / tools / winebuild / import.c
blob04ab433dd65af4e47590b3526a379226dcd27c00
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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 "wine/list.h"
39 #include "build.h"
41 /* standard C functions that are also exported from ntdll */
42 static const char *stdc_names[] =
44 "abs",
45 "atan",
46 "atoi",
47 "atol",
48 "bsearch",
49 "ceil",
50 "cos",
51 "fabs",
52 "floor",
53 "isalnum",
54 "isalpha",
55 "iscntrl",
56 "isdigit",
57 "isgraph",
58 "islower",
59 "isprint",
60 "ispunct",
61 "isspace",
62 "isupper",
63 "iswalpha",
64 "iswctype",
65 "iswdigit",
66 "iswlower",
67 "iswspace",
68 "iswxdigit",
69 "isxdigit",
70 "labs",
71 "log",
72 "mbstowcs",
73 "memchr",
74 "memcmp",
75 "memcpy",
76 "memmove",
77 "memset",
78 "pow",
79 "qsort",
80 "sin",
81 "sprintf",
82 "sqrt",
83 "sscanf",
84 "strcat",
85 "strchr",
86 "strcmp",
87 "strcpy",
88 "strcspn",
89 "strlen",
90 "strncat",
91 "strncmp",
92 "strncpy",
93 "strnlen",
94 "strpbrk",
95 "strrchr",
96 "strspn",
97 "strstr",
98 "strtol",
99 "strtoul",
100 "swprintf",
101 "tan",
102 "tolower",
103 "toupper",
104 "towlower",
105 "towupper",
106 "vsprintf",
107 "wcscat",
108 "wcschr",
109 "wcscmp",
110 "wcscpy",
111 "wcscspn",
112 "wcslen",
113 "wcsncat",
114 "wcsncmp",
115 "wcsncpy",
116 "wcspbrk",
117 "wcsrchr",
118 "wcsspn",
119 "wcsstr",
120 "wcstok",
121 "wcstol",
122 "wcstombs",
123 "wcstoul"
126 static struct strarray stdc_functions = { stdc_names, ARRAY_SIZE(stdc_names), ARRAY_SIZE(stdc_names) };
128 struct import_func
130 const char *name;
131 const char *export_name;
132 int ordinal;
133 int hint;
136 struct import
138 struct list entry; /* entry in global dll list */
139 char *dll_name; /* exported file name of the dll */
140 char *c_name; /* dll name as a C-compatible identifier */
141 char *full_name; /* full name of the input file */
142 dev_t dev; /* device/inode of the input file */
143 ino_t ino;
144 ORDDEF **exports; /* functions exported from this dll */
145 int nb_exports; /* number of exported functions */
146 struct import_func *imports; /* functions we want to import from this dll */
147 int nb_imports; /* number of imported functions */
148 int max_imports; /* size of imports array */
151 static struct strarray undef_symbols; /* list of undefined symbols */
152 static struct strarray extra_ld_symbols; /* list of extra symbols that ld should resolve */
153 static struct strarray delayed_imports; /* list of delayed import dlls */
154 static struct strarray ext_link_imports; /* list of external symbols to link to */
156 static struct list dll_imports = LIST_INIT( dll_imports );
157 static struct list dll_delayed = LIST_INIT( dll_delayed );
159 static struct strarray as_files;
161 static const char import_func_prefix[] = "__wine$func$";
162 static const char import_ord_prefix[] = "__wine$ord$";
164 static inline const char *ppc_reg( int reg )
166 static const char * const ppc_regs[32] = { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
167 "r8", "r9", "r10","r11","r12","r13","r14","r15",
168 "r16","r17","r18","r19","r20","r21","r22","r23",
169 "r24","r25","r26","r27","r28","r29","r30","r31" };
170 if (target_platform == PLATFORM_APPLE) return ppc_regs[reg];
171 return ppc_regs[reg] + 1; /* skip the 'r' */
174 /* compare function names; helper for resolve_imports */
175 static int name_cmp( const void *name, const void *entry )
177 return strcmp( *(const char* const *)name, *(const char* const *)entry );
180 /* compare function names; helper for resolve_imports */
181 static int func_cmp( const void *func1, const void *func2 )
183 const ORDDEF *odp1 = *(const ORDDEF * const *)func1;
184 const ORDDEF *odp2 = *(const ORDDEF * const *)func2;
185 return strcmp( odp1->name ? odp1->name : odp1->export_name,
186 odp2->name ? odp2->name : odp2->export_name );
189 /* remove a name from a name table */
190 static inline void remove_name( struct strarray *table, unsigned int idx )
192 assert( idx < table->count );
193 memmove( table->str + idx, table->str + idx + 1,
194 (table->count - idx - 1) * sizeof(*table->str) );
195 table->count--;
198 /* locate a name in a (sorted) list */
199 static inline const char *find_name( const char *name, const struct strarray *table )
201 char **res = NULL;
203 if (table->count) res = bsearch( &name, table->str, table->count, sizeof(*table->str), name_cmp );
204 return res ? *res : NULL;
207 /* sort a name table */
208 static inline void sort_names( struct strarray *table )
210 if (table->count) qsort( table->str, table->count, sizeof(*table->str), name_cmp );
213 /* locate an export in a (sorted) export list */
214 static inline ORDDEF *find_export( const char *name, ORDDEF **table, int size )
216 ORDDEF func, *odp, **res = NULL;
218 func.name = xstrdup(name);
219 func.ordinal = -1;
220 odp = &func;
221 if (table) res = bsearch( &odp, table, size, sizeof(*table), func_cmp );
222 free( func.name );
223 return res ? *res : NULL;
226 /* free an import structure */
227 static void free_imports( struct import *imp )
229 free( imp->exports );
230 free( imp->imports );
231 free( imp->dll_name );
232 free( imp->c_name );
233 free( imp->full_name );
234 free( imp );
237 /* check whether a given dll is imported in delayed mode */
238 static int is_delayed_import( const char *name )
240 unsigned int i;
242 for (i = 0; i < delayed_imports.count; i++)
244 if (!strcmp( delayed_imports.str[i], name )) return 1;
246 return 0;
249 /* find an imported dll from its name */
250 static struct import *find_import_dll( const char *name )
252 struct import *import;
254 LIST_FOR_EACH_ENTRY( import, &dll_imports, struct import, entry )
255 if (!strcasecmp( import->dll_name, name )) return import;
256 LIST_FOR_EACH_ENTRY( import, &dll_delayed, struct import, entry )
257 if (!strcasecmp( import->dll_name, name )) return import;
258 return NULL;
261 /* open the .so library for a given dll in a specified path */
262 static char *try_library_path( const char *path, const char *name )
264 char *buffer;
265 int fd;
267 buffer = strmake( "%s/lib%s.def", path, name );
269 /* check if the file exists */
270 if ((fd = open( buffer, O_RDONLY )) != -1)
272 close( fd );
273 return buffer;
275 free( buffer );
276 return NULL;
279 /* find the .def import library for a given dll */
280 static char *find_library( const char *name )
282 char *fullname;
283 unsigned int i;
285 for (i = 0; i < lib_path.count; i++)
287 if ((fullname = try_library_path( lib_path.str[i], name ))) return fullname;
289 fatal_error( "could not open .def file for %s\n", name );
290 return NULL;
293 /* read in the list of exported symbols of an import library */
294 static DLLSPEC *read_import_lib( struct import *imp )
296 FILE *f;
297 int i;
298 struct stat stat;
299 struct import *prev_imp;
300 DLLSPEC *spec = alloc_dll_spec();
302 f = open_input_file( NULL, imp->full_name );
303 fstat( fileno(f), &stat );
304 imp->dev = stat.st_dev;
305 imp->ino = stat.st_ino;
306 if (!parse_def_file( f, spec )) exit( 1 );
307 close_input_file( f );
309 /* check if we already imported that library from a different file */
310 if ((prev_imp = find_import_dll( spec->file_name )))
312 if (prev_imp->dev != imp->dev || prev_imp->ino != imp->ino)
313 fatal_error( "%s and %s have the same export name '%s'\n",
314 prev_imp->full_name, imp->full_name, spec->file_name );
315 free_dll_spec( spec );
316 return NULL; /* the same file was already loaded, ignore this one */
319 if (spec->nb_entry_points)
321 imp->exports = xmalloc( spec->nb_entry_points * sizeof(*imp->exports) );
322 for (i = 0; i < spec->nb_entry_points; i++)
323 imp->exports[imp->nb_exports++] = &spec->entry_points[i];
324 qsort( imp->exports, imp->nb_exports, sizeof(*imp->exports), func_cmp );
326 return spec;
329 /* build the dll exported name from the import lib name or path */
330 static char *get_dll_name( const char *name, const char *filename )
332 char *ret;
334 if (filename)
336 const char *basename = strrchr( filename, '/' );
337 if (!basename) basename = filename;
338 else basename++;
339 if (!strncmp( basename, "lib", 3 )) basename += 3;
340 ret = xmalloc( strlen(basename) + 5 );
341 strcpy( ret, basename );
342 if (strendswith( ret, ".def" )) ret[strlen(ret)-4] = 0;
344 else
346 ret = xmalloc( strlen(name) + 5 );
347 strcpy( ret, name );
349 if (!strchr( ret, '.' )) strcat( ret, ".dll" );
350 return ret;
353 /* add a dll to the list of imports */
354 void add_import_dll( const char *name, const char *filename )
356 DLLSPEC *spec;
357 char *dll_name = get_dll_name( name, filename );
358 struct import *imp = xmalloc( sizeof(*imp) );
360 memset( imp, 0, sizeof(*imp) );
362 if (filename) imp->full_name = xstrdup( filename );
363 else imp->full_name = find_library( name );
365 if (!(spec = read_import_lib( imp )))
367 free_imports( imp );
368 return;
371 imp->dll_name = spec->file_name ? spec->file_name : dll_name;
372 imp->c_name = make_c_identifier( imp->dll_name );
374 if (is_delayed_import( imp->dll_name ))
375 list_add_tail( &dll_delayed, &imp->entry );
376 else
377 list_add_tail( &dll_imports, &imp->entry );
380 /* add a library to the list of delayed imports */
381 void add_delayed_import( const char *name )
383 struct import *imp;
384 char *fullname = get_dll_name( name, NULL );
386 strarray_add( &delayed_imports, fullname, NULL );
387 if ((imp = find_import_dll( fullname )))
389 list_remove( &imp->entry );
390 list_add_tail( &dll_delayed, &imp->entry );
394 /* add a symbol to the list of extra symbols that ld must resolve */
395 void add_extra_ld_symbol( const char *name )
397 strarray_add( &extra_ld_symbols, name, NULL );
400 /* retrieve an imported dll, adding one if necessary */
401 struct import *add_static_import_dll( const char *name )
403 struct import *import;
404 char *dll_name = get_dll_name( name, NULL );
406 if ((import = find_import_dll( dll_name ))) return import;
408 import = xmalloc( sizeof(*import) );
409 memset( import, 0, sizeof(*import) );
411 import->dll_name = dll_name;
412 import->full_name = xstrdup( dll_name );
413 import->c_name = make_c_identifier( dll_name );
415 if (is_delayed_import( dll_name ))
416 list_add_tail( &dll_delayed, &import->entry );
417 else
418 list_add_tail( &dll_imports, &import->entry );
419 return import;
422 /* add a function to the list of imports from a given dll */
423 static void add_import_func( struct import *imp, const char *name, const char *export_name,
424 int ordinal, int hint )
426 if (imp->nb_imports == imp->max_imports)
428 imp->max_imports *= 2;
429 if (imp->max_imports < 32) imp->max_imports = 32;
430 imp->imports = xrealloc( imp->imports, imp->max_imports * sizeof(*imp->imports) );
432 imp->imports[imp->nb_imports].name = name;
433 imp->imports[imp->nb_imports].export_name = export_name;
434 imp->imports[imp->nb_imports].ordinal = ordinal;
435 imp->imports[imp->nb_imports].hint = hint;
436 imp->nb_imports++;
439 /* add an import for an undefined function of the form __wine$func$ */
440 static void add_undef_import( const char *name, int is_ordinal )
442 char *p, *dll_name = xstrdup( name );
443 int ordinal = 0;
444 struct import *import;
446 if (!(p = strchr( dll_name, '$' ))) return;
447 *p++ = 0;
448 while (*p >= '0' && *p <= '9') ordinal = 10 * ordinal + *p++ - '0';
449 if (*p != '$') return;
450 p++;
452 import = add_static_import_dll( dll_name );
453 if (is_ordinal)
454 add_import_func( import, NULL, xstrdup( p ), ordinal, 0 );
455 else
456 add_import_func( import, xstrdup( p ), NULL, ordinal, 0 );
459 /* check if the spec file exports any stubs */
460 static int has_stubs( const DLLSPEC *spec )
462 int i;
463 for (i = 0; i < spec->nb_entry_points; i++)
465 ORDDEF *odp = &spec->entry_points[i];
466 if (odp->type == TYPE_STUB) return 1;
468 return 0;
471 /* add the extra undefined symbols that will be contained in the generated spec file itself */
472 static void add_extra_undef_symbols( DLLSPEC *spec )
474 add_extra_ld_symbol( spec->init_func );
475 if (has_stubs( spec )) add_extra_ld_symbol( "__wine_spec_unimplemented_stub" );
476 if (delayed_imports.count) add_extra_ld_symbol( "__wine_spec_delay_load" );
479 /* check if a given imported dll is not needed, taking forwards into account */
480 static int check_unused( const struct import* imp, const DLLSPEC *spec )
482 int i;
483 const char *file_name = imp->dll_name;
484 size_t len = strlen( file_name );
485 const char *p = strchr( file_name, '.' );
486 if (p && !strcasecmp( p, ".dll" )) len = p - file_name;
488 for (i = spec->base; i <= spec->limit; i++)
490 ORDDEF *odp = spec->ordinals[i];
491 if (!odp || !(odp->flags & FLAG_FORWARD)) continue;
492 if (!strncasecmp( odp->link_name, file_name, len ) &&
493 odp->link_name[len] == '.')
494 return 0; /* found a forward, it is used */
496 return 1;
499 /* check if a given forward does exist in one of the imported dlls */
500 static void check_undefined_forwards( DLLSPEC *spec )
502 struct import *imp;
503 char *link_name, *api_name, *dll_name, *p;
504 int i;
506 for (i = 0; i < spec->nb_entry_points; i++)
508 ORDDEF *odp = &spec->entry_points[i];
510 if (!(odp->flags & FLAG_FORWARD)) continue;
512 link_name = xstrdup( odp->link_name );
513 p = strrchr( link_name, '.' );
514 *p = 0;
515 api_name = p + 1;
516 dll_name = get_dll_name( link_name, NULL );
518 if ((imp = find_import_dll( dll_name )))
520 if (!find_export( api_name, imp->exports, imp->nb_exports ))
521 warning( "%s:%d: forward '%s' not found in %s\n",
522 spec->src_name, odp->lineno, odp->link_name, imp->dll_name );
524 else warning( "%s:%d: forward '%s' not found in the imported dll list\n",
525 spec->src_name, odp->lineno, odp->link_name );
526 free( link_name );
527 free( dll_name );
531 /* flag the dll exports that link to an undefined symbol */
532 static void check_undefined_exports( DLLSPEC *spec )
534 int i;
536 for (i = 0; i < spec->nb_entry_points; i++)
538 ORDDEF *odp = &spec->entry_points[i];
539 if (odp->type == TYPE_STUB || odp->type == TYPE_ABS || odp->type == TYPE_VARIABLE) continue;
540 if (odp->flags & FLAG_FORWARD) continue;
541 if (find_name( odp->link_name, &undef_symbols ))
543 switch(odp->type)
545 case TYPE_PASCAL:
546 case TYPE_STDCALL:
547 case TYPE_CDECL:
548 case TYPE_VARARGS:
549 if (link_ext_symbols)
551 odp->flags |= FLAG_EXT_LINK;
552 strarray_add( &ext_link_imports, odp->link_name, NULL );
554 else error( "%s:%d: function '%s' not defined\n",
555 spec->src_name, odp->lineno, odp->link_name );
556 break;
557 default:
558 error( "%s:%d: external symbol '%s' is not a function\n",
559 spec->src_name, odp->lineno, odp->link_name );
560 break;
566 /* create a .o file that references all the undefined symbols we want to resolve */
567 static char *create_undef_symbols_file( DLLSPEC *spec )
569 char *as_file, *obj_file;
570 int i;
571 unsigned int j;
573 as_file = open_temp_output_file( ".s" );
574 output( "\t.data\n" );
576 for (i = 0; i < spec->nb_entry_points; i++)
578 ORDDEF *odp = &spec->entry_points[i];
579 if (odp->type == TYPE_STUB || odp->type == TYPE_ABS || odp->type == TYPE_VARIABLE) continue;
580 if (odp->flags & FLAG_FORWARD) continue;
581 output( "\t%s %s\n", get_asm_ptr_keyword(), asm_name( get_link_name( odp )));
583 for (j = 0; j < extra_ld_symbols.count; j++)
584 output( "\t%s %s\n", get_asm_ptr_keyword(), asm_name(extra_ld_symbols.str[j]) );
585 fclose( output_file );
587 obj_file = get_temp_file_name( output_file_name, ".o" );
588 assemble_file( as_file, obj_file );
589 return obj_file;
592 /* combine a list of object files with ld into a single object file */
593 /* returns the name of the combined file */
594 static const char *ldcombine_files( DLLSPEC *spec, char **argv )
596 char *ld_tmp_file, *undef_file;
597 struct strarray args = get_ld_command();
599 undef_file = create_undef_symbols_file( spec );
600 ld_tmp_file = get_temp_file_name( output_file_name, ".o" );
602 strarray_add( &args, "-r", "-o", ld_tmp_file, undef_file, NULL );
603 strarray_addv( &args, argv );
604 spawn( args );
605 return ld_tmp_file;
608 /* read in the list of undefined symbols */
609 void read_undef_symbols( DLLSPEC *spec, char **argv )
611 size_t prefix_len;
612 FILE *f;
613 const char *prog = get_nm_command();
614 char *cmd, buffer[1024], name_prefix[16];
615 int err;
616 const char *name;
618 if (!argv[0]) return;
620 add_extra_undef_symbols( spec );
622 strcpy( name_prefix, asm_name("") );
623 prefix_len = strlen( name_prefix );
625 name = ldcombine_files( spec, argv );
627 cmd = strmake( "%s -u %s", prog, name );
628 if (verbose)
629 fprintf( stderr, "%s\n", cmd );
630 if (!(f = popen( cmd, "r" )))
631 fatal_error( "Cannot execute '%s'\n", cmd );
633 while (fgets( buffer, sizeof(buffer), f ))
635 char *p = buffer + strlen(buffer) - 1;
636 if (p < buffer) continue;
637 if (*p == '\n') *p-- = 0;
638 p = buffer;
639 while (*p == ' ') p++;
640 if (p[0] == 'U' && p[1] == ' ' && p[2]) p += 2;
641 if (prefix_len && !strncmp( p, name_prefix, prefix_len )) p += prefix_len;
642 if (!strncmp( p, import_func_prefix, strlen(import_func_prefix) ))
643 add_undef_import( p + strlen( import_func_prefix ), 0 );
644 else if (!strncmp( p, import_ord_prefix, strlen(import_ord_prefix) ))
645 add_undef_import( p + strlen( import_ord_prefix ), 1 );
646 else if (!unix_lib || !find_name( p, &stdc_functions ))
647 strarray_add( &undef_symbols, xstrdup( p ), NULL );
649 if ((err = pclose( f ))) warning( "%s failed with status %d\n", cmd, err );
650 free( cmd );
653 void resolve_dll_imports( DLLSPEC *spec, struct list *list )
655 unsigned int j;
656 struct import *imp, *next;
657 ORDDEF *odp;
659 LIST_FOR_EACH_ENTRY_SAFE( imp, next, list, struct import, entry )
661 for (j = 0; j < undef_symbols.count; j++)
663 odp = find_export( undef_symbols.str[j], imp->exports, imp->nb_exports );
664 if (odp)
666 if (odp->flags & FLAG_PRIVATE) continue;
667 if (odp->type != TYPE_STDCALL && odp->type != TYPE_CDECL)
668 warning( "winebuild: Data export '%s' cannot be imported from %s\n",
669 odp->link_name, imp->dll_name );
670 else
672 add_import_func( imp, (odp->flags & FLAG_NONAME) ? NULL : odp->name,
673 odp->export_name, odp->ordinal, odp->hint );
674 remove_name( &undef_symbols, j-- );
678 if (!imp->nb_imports)
680 /* the dll is not used, get rid of it */
681 if (check_unused( imp, spec ))
682 warning( "winebuild: %s imported but no symbols used\n", imp->dll_name );
683 list_remove( &imp->entry );
684 free_imports( imp );
689 /* resolve the imports for a Win32 module */
690 void resolve_imports( DLLSPEC *spec )
692 check_undefined_forwards( spec );
693 resolve_dll_imports( spec, &dll_imports );
694 resolve_dll_imports( spec, &dll_delayed );
695 sort_names( &undef_symbols );
696 check_undefined_exports( spec );
699 /* check if symbol is still undefined */
700 int is_undefined( const char *name )
702 return find_name( name, &undef_symbols ) != NULL;
705 /* output the get_pc thunk if needed */
706 void output_get_pc_thunk(void)
708 assert( target_cpu == CPU_x86 );
709 output( "\n\t.text\n" );
710 output( "\t.align %d\n", get_alignment(4) );
711 output( "\t%s\n", func_declaration("__wine_spec_get_pc_thunk_eax") );
712 output( "%s:\n", asm_name("__wine_spec_get_pc_thunk_eax") );
713 output_cfi( ".cfi_startproc" );
714 output( "\tmovl (%%esp),%%eax\n" );
715 output( "\tret\n" );
716 output_cfi( ".cfi_endproc" );
717 output_function_size( "__wine_spec_get_pc_thunk_eax" );
720 /* output a single import thunk */
721 static void output_import_thunk( const char *name, const char *table, int pos )
723 output( "\n\t.align %d\n", get_alignment(4) );
724 output( "\t%s\n", func_declaration(name) );
725 output( "%s\n", asm_globl(name) );
726 output_cfi( ".cfi_startproc" );
728 switch(target_cpu)
730 case CPU_x86:
731 if (!UsePIC)
733 output( "\tjmp *(%s+%d)\n", table, pos );
735 else
737 output( "\tcall %s\n", asm_name("__wine_spec_get_pc_thunk_eax") );
738 output( "1:\tjmp *%s+%d-1b(%%eax)\n", table, pos );
739 needs_get_pc_thunk = 1;
741 break;
742 case CPU_x86_64:
743 output( "\tjmpq *%s+%d(%%rip)\n", table, pos );
744 break;
745 case CPU_ARM:
746 output( "\tldr IP,1f\n");
747 output( "\tldr PC,[PC,IP]\n" );
748 output( "1:\t.long %s+%u-(1b+4)\n", table, pos );
749 break;
750 case CPU_ARM64:
751 output( "\tadrp x9, %s\n", table );
752 output( "\tadd x9, x9, #:lo12:%s\n", table );
753 if (pos & 0xf000) output( "\tadd x9, x9, #%u\n", pos & 0xf000 );
754 if (pos & 0x0f00) output( "\tadd x9, x9, #%u\n", pos & 0x0f00 );
755 if (pos & 0x00f0) output( "\tadd x9, x9, #%u\n", pos & 0x00f0 );
756 if (pos & 0x000f) output( "\tadd x9, x9, #%u\n", pos & 0x000f );
757 output( "\tldur x9, [x9, #0]\n" );
758 output( "\tbr x9\n" );
759 break;
760 case CPU_POWERPC:
761 output( "\tmr %s, %s\n", ppc_reg(0), ppc_reg(31) );
762 if (target_platform == PLATFORM_APPLE)
764 output( "\tlis %s, ha16(%s+%d+32768)\n", ppc_reg(31), table, pos );
765 output( "\tla %s, lo16(%s+%d)(%s)\n", ppc_reg(31), table, pos, ppc_reg(31) );
767 else
769 output( "\tlis %s, (%s+%d+32768)@h\n", ppc_reg(31), table, pos );
770 output( "\tla %s, (%s+%d)@l(%s)\n", ppc_reg(31), table, pos, ppc_reg(31) );
772 output( "\tlwz %s, 0(%s)\n", ppc_reg(31), ppc_reg(31) );
773 output( "\tmtctr %s\n", ppc_reg(31) );
774 output( "\tmr %s, %s\n", ppc_reg(31), ppc_reg(0) );
775 output( "\tbctr\n" );
776 break;
778 output_cfi( ".cfi_endproc" );
779 output_function_size( name );
782 /* check if we need an import directory */
783 int has_imports(void)
785 return !list_empty( &dll_imports );
788 /* output the import table of a Win32 module */
789 static void output_immediate_imports(void)
791 int i, j;
792 struct import *import;
794 if (list_empty( &dll_imports )) return; /* no immediate imports */
796 /* main import header */
798 output( "\n/* import table */\n" );
799 output( "\n\t.data\n" );
800 output( "\t.align %d\n", get_alignment(4) );
801 output( ".L__wine_spec_imports:\n" );
803 /* list of dlls */
805 j = 0;
806 LIST_FOR_EACH_ENTRY( import, &dll_imports, struct import, entry )
808 output_rva( ".L__wine_spec_import_data_names + %d", j * get_ptr_size() ); /* OriginalFirstThunk */
809 output( "\t.long 0\n" ); /* TimeDateStamp */
810 output( "\t.long 0\n" ); /* ForwarderChain */
811 output_rva( ".L__wine_spec_import_name_%s", import->c_name ); /* Name */
812 output_rva( ".L__wine_spec_import_data_ptrs + %d", j * get_ptr_size() ); /* FirstThunk */
813 j += import->nb_imports + 1;
815 output( "\t.long 0\n" ); /* OriginalFirstThunk */
816 output( "\t.long 0\n" ); /* TimeDateStamp */
817 output( "\t.long 0\n" ); /* ForwarderChain */
818 output( "\t.long 0\n" ); /* Name */
819 output( "\t.long 0\n" ); /* FirstThunk */
821 output( "\n\t.align %d\n", get_alignment(get_ptr_size()) );
822 /* output the names twice, once for OriginalFirstThunk and once for FirstThunk */
823 for (i = 0; i < 2; i++)
825 output( ".L__wine_spec_import_data_%s:\n", i ? "ptrs" : "names" );
826 LIST_FOR_EACH_ENTRY( import, &dll_imports, struct import, entry )
828 for (j = 0; j < import->nb_imports; j++)
830 struct import_func *func = &import->imports[j];
831 if (i)
833 if (func->name) output( "__imp_%s:\n", asm_name( func->name ));
834 else if (func->export_name) output( "__imp_%s:\n", asm_name( func->export_name ));
836 if (func->name)
837 output( "\t%s .L__wine_spec_import_data_%s_%s-.L__wine_spec_rva_base\n",
838 get_asm_ptr_keyword(), import->c_name, func->name );
839 else
841 if (get_ptr_size() == 8)
842 output( "\t.quad 0x800000000000%04x\n", func->ordinal );
843 else
844 output( "\t.long 0x8000%04x\n", func->ordinal );
847 output( "\t%s 0\n", get_asm_ptr_keyword() );
850 output( ".L__wine_spec_imports_end:\n" );
852 LIST_FOR_EACH_ENTRY( import, &dll_imports, struct import, entry )
854 for (j = 0; j < import->nb_imports; j++)
856 struct import_func *func = &import->imports[j];
857 if (!func->name) continue;
858 output( "\t.align %d\n", get_alignment(2) );
859 output( ".L__wine_spec_import_data_%s_%s:\n", import->c_name, func->name );
860 output( "\t.short %d\n", func->hint );
861 output( "\t%s \"%s\"\n", get_asm_string_keyword(), func->name );
865 LIST_FOR_EACH_ENTRY( import, &dll_imports, struct import, entry )
867 output( ".L__wine_spec_import_name_%s:\n\t%s \"%s\"\n",
868 import->c_name, get_asm_string_keyword(), import->dll_name );
872 /* output the import thunks of a Win32 module */
873 static void output_immediate_import_thunks(void)
875 int j, pos;
876 struct import *import;
877 static const char import_thunks[] = "__wine_spec_import_thunks";
879 if (list_empty( &dll_imports )) return;
881 output( "\n/* immediate import thunks */\n\n" );
882 output( "\t.text\n" );
883 output( "\t.align %d\n", get_alignment(8) );
884 output( "%s:\n", asm_name(import_thunks));
886 pos = 0;
887 LIST_FOR_EACH_ENTRY( import, &dll_imports, struct import, entry )
889 for (j = 0; j < import->nb_imports; j++, pos += get_ptr_size())
891 struct import_func *func = &import->imports[j];
892 output_import_thunk( func->name ? func->name : func->export_name,
893 ".L__wine_spec_import_data_ptrs", pos );
895 pos += get_ptr_size();
897 output_function_size( import_thunks );
900 /* output the delayed import table of a Win32 module */
901 static void output_delayed_imports( const DLLSPEC *spec )
903 int j, mod;
904 struct import *import;
906 if (list_empty( &dll_delayed )) return;
908 output( "\n/* delayed imports */\n\n" );
909 output( "\t.data\n" );
910 output( "\t.align %d\n", get_alignment(get_ptr_size()) );
911 output( "%s\n", asm_globl("__wine_spec_delay_imports") );
913 /* list of dlls */
915 j = mod = 0;
916 LIST_FOR_EACH_ENTRY( import, &dll_delayed, struct import, entry )
918 output( "\t%s 0\n", get_asm_ptr_keyword() ); /* grAttrs */
919 output( "\t%s .L__wine_delay_name_%s\n", /* szName */
920 get_asm_ptr_keyword(), import->c_name );
921 output( "\t%s .L__wine_delay_modules+%d\n", /* phmod */
922 get_asm_ptr_keyword(), mod * get_ptr_size() );
923 output( "\t%s .L__wine_delay_IAT+%d\n", /* pIAT */
924 get_asm_ptr_keyword(), j * get_ptr_size() );
925 output( "\t%s .L__wine_delay_INT+%d\n", /* pINT */
926 get_asm_ptr_keyword(), j * get_ptr_size() );
927 output( "\t%s 0\n", get_asm_ptr_keyword() ); /* pBoundIAT */
928 output( "\t%s 0\n", get_asm_ptr_keyword() ); /* pUnloadIAT */
929 output( "\t%s 0\n", get_asm_ptr_keyword() ); /* dwTimeStamp */
930 j += import->nb_imports;
931 mod++;
933 output( "\t%s 0\n", get_asm_ptr_keyword() ); /* grAttrs */
934 output( "\t%s 0\n", get_asm_ptr_keyword() ); /* szName */
935 output( "\t%s 0\n", get_asm_ptr_keyword() ); /* phmod */
936 output( "\t%s 0\n", get_asm_ptr_keyword() ); /* pIAT */
937 output( "\t%s 0\n", get_asm_ptr_keyword() ); /* pINT */
938 output( "\t%s 0\n", get_asm_ptr_keyword() ); /* pBoundIAT */
939 output( "\t%s 0\n", get_asm_ptr_keyword() ); /* pUnloadIAT */
940 output( "\t%s 0\n", get_asm_ptr_keyword() ); /* dwTimeStamp */
942 output( "\n.L__wine_delay_IAT:\n" );
943 LIST_FOR_EACH_ENTRY( import, &dll_delayed, struct import, entry )
945 for (j = 0; j < import->nb_imports; j++)
947 struct import_func *func = &import->imports[j];
948 const char *name = func->name ? func->name : func->export_name;
949 output( "\t%s .L__wine_delay_imp_%s_%s\n",
950 get_asm_ptr_keyword(), import->c_name, name );
954 output( "\n.L__wine_delay_INT:\n" );
955 LIST_FOR_EACH_ENTRY( import, &dll_delayed, struct import, entry )
957 for (j = 0; j < import->nb_imports; j++)
959 struct import_func *func = &import->imports[j];
960 if (!func->name)
961 output( "\t%s %d\n", get_asm_ptr_keyword(), func->ordinal );
962 else
963 output( "\t%s .L__wine_delay_data_%s_%s\n",
964 get_asm_ptr_keyword(), import->c_name, func->name );
968 output( "\n.L__wine_delay_modules:\n" );
969 LIST_FOR_EACH_ENTRY( import, &dll_delayed, struct import, entry )
971 output( "\t%s 0\n", get_asm_ptr_keyword() );
974 LIST_FOR_EACH_ENTRY( import, &dll_delayed, struct import, entry )
976 output( ".L__wine_delay_name_%s:\n", import->c_name );
977 output( "\t%s \"%s\"\n", get_asm_string_keyword(), import->dll_name );
980 LIST_FOR_EACH_ENTRY( import, &dll_delayed, struct import, entry )
982 for (j = 0; j < import->nb_imports; j++)
984 struct import_func *func = &import->imports[j];
985 if (!func->name) continue;
986 output( ".L__wine_delay_data_%s_%s:\n", import->c_name, func->name );
987 output( "\t%s \"%s\"\n", get_asm_string_keyword(), func->name );
990 output_function_size( "__wine_spec_delay_imports" );
993 /* output the delayed import thunks of a Win32 module */
994 static void output_delayed_import_thunks( const DLLSPEC *spec )
996 int idx, j, pos, extra_stack_storage = 0;
997 struct import *import;
998 static const char delayed_import_loaders[] = "__wine_spec_delayed_import_loaders";
999 static const char delayed_import_thunks[] = "__wine_spec_delayed_import_thunks";
1001 if (list_empty( &dll_delayed )) return;
1003 output( "\n/* delayed import thunks */\n\n" );
1004 output( "\t.text\n" );
1005 output( "\t.align %d\n", get_alignment(8) );
1006 output( "%s:\n", asm_name(delayed_import_loaders));
1007 output( "\t%s\n", func_declaration("__wine_delay_load_asm") );
1008 output( "%s:\n", asm_name("__wine_delay_load_asm") );
1009 output_cfi( ".cfi_startproc" );
1010 switch(target_cpu)
1012 case CPU_x86:
1013 output( "\tpushl %%ecx\n" );
1014 output_cfi( ".cfi_adjust_cfa_offset 4" );
1015 output( "\tpushl %%edx\n" );
1016 output_cfi( ".cfi_adjust_cfa_offset 4" );
1017 output( "\tpushl %%eax\n" );
1018 output_cfi( ".cfi_adjust_cfa_offset 4" );
1019 output( "\tcall %s\n", asm_name("__wine_spec_delay_load") );
1020 output_cfi( ".cfi_adjust_cfa_offset -4" );
1021 output( "\tpopl %%edx\n" );
1022 output_cfi( ".cfi_adjust_cfa_offset -4" );
1023 output( "\tpopl %%ecx\n" );
1024 output_cfi( ".cfi_adjust_cfa_offset -4" );
1025 output( "\tjmp *%%eax\n" );
1026 break;
1027 case CPU_x86_64:
1028 output( "\tsubq $0x98,%%rsp\n" );
1029 output_cfi( ".cfi_adjust_cfa_offset 0x98" );
1030 output( "\tmovq %%rdx,0x88(%%rsp)\n" );
1031 output( "\tmovq %%rcx,0x80(%%rsp)\n" );
1032 output( "\tmovq %%r8,0x78(%%rsp)\n" );
1033 output( "\tmovq %%r9,0x70(%%rsp)\n" );
1034 output( "\tmovq %%r10,0x68(%%rsp)\n" );
1035 output( "\tmovq %%r11,0x60(%%rsp)\n" );
1036 output( "\tmovups %%xmm0,0x50(%%rsp)\n" );
1037 output( "\tmovups %%xmm1,0x40(%%rsp)\n" );
1038 output( "\tmovups %%xmm2,0x30(%%rsp)\n" );
1039 output( "\tmovups %%xmm3,0x20(%%rsp)\n" );
1040 output( "\tmovq %%rax,%%rcx\n" );
1041 output( "\tcall %s\n", asm_name("__wine_spec_delay_load") );
1042 output( "\tmovups 0x20(%%rsp),%%xmm3\n" );
1043 output( "\tmovups 0x30(%%rsp),%%xmm2\n" );
1044 output( "\tmovups 0x40(%%rsp),%%xmm1\n" );
1045 output( "\tmovups 0x50(%%rsp),%%xmm0\n" );
1046 output( "\tmovq 0x60(%%rsp),%%r11\n" );
1047 output( "\tmovq 0x68(%%rsp),%%r10\n" );
1048 output( "\tmovq 0x70(%%rsp),%%r9\n" );
1049 output( "\tmovq 0x78(%%rsp),%%r8\n" );
1050 output( "\tmovq 0x80(%%rsp),%%rcx\n" );
1051 output( "\tmovq 0x88(%%rsp),%%rdx\n" );
1052 output( "\taddq $0x98,%%rsp\n" );
1053 output_cfi( ".cfi_adjust_cfa_offset -0x98" );
1054 output( "\tjmp *%%rax\n" );
1055 break;
1056 case CPU_ARM:
1057 output( "\tpush {r0-r3,FP,LR}\n" );
1058 output( "\tmov r0,IP\n" );
1059 output( "\tldr IP,2f\n");
1060 output( "\tadd IP,PC\n");
1061 output( "\tblx IP\n");
1062 output( "1:\tmov IP,r0\n");
1063 output( "\tpop {r0-r3,FP,LR}\n" );
1064 output( "\tbx IP\n");
1065 output( "2:\t.long %s-1b\n", asm_name("__wine_spec_delay_load") );
1066 break;
1067 case CPU_ARM64:
1068 output( "\tstp x29, x30, [sp,#-16]!\n" );
1069 output( "\tmov x29, sp\n" );
1070 output( "\tadrp x9, %s\n", asm_name("__wine_spec_delay_load") );
1071 output( "\tadd x9, x9, #:lo12:%s\n", asm_name("__wine_spec_delay_load") );
1072 output( "\tblr x9\n" );
1073 output( "\tmov x9, x0\n" );
1074 output( "\tldp x29, x30, [sp],#16\n" );
1075 output( "\tldp x0, x1, [sp,#16]\n" );
1076 output( "\tldp x2, x3, [sp,#32]\n" );
1077 output( "\tldp x4, x5, [sp,#48]\n" );
1078 output( "\tldp x6, x7, [sp],#80\n" );
1079 output( "\tbr x9\n" ); /* or "ret x9" */
1080 break;
1081 case CPU_POWERPC:
1082 if (target_platform == PLATFORM_APPLE) extra_stack_storage = 56;
1084 /* Save all callee saved registers into a stackframe. */
1085 output( "\tstwu %s, -%d(%s)\n",ppc_reg(1), 48+extra_stack_storage, ppc_reg(1));
1086 output( "\tstw %s, %d(%s)\n", ppc_reg(3), 4+extra_stack_storage, ppc_reg(1));
1087 output( "\tstw %s, %d(%s)\n", ppc_reg(4), 8+extra_stack_storage, ppc_reg(1));
1088 output( "\tstw %s, %d(%s)\n", ppc_reg(5), 12+extra_stack_storage, ppc_reg(1));
1089 output( "\tstw %s, %d(%s)\n", ppc_reg(6), 16+extra_stack_storage, ppc_reg(1));
1090 output( "\tstw %s, %d(%s)\n", ppc_reg(7), 20+extra_stack_storage, ppc_reg(1));
1091 output( "\tstw %s, %d(%s)\n", ppc_reg(8), 24+extra_stack_storage, ppc_reg(1));
1092 output( "\tstw %s, %d(%s)\n", ppc_reg(9), 28+extra_stack_storage, ppc_reg(1));
1093 output( "\tstw %s, %d(%s)\n", ppc_reg(10),32+extra_stack_storage, ppc_reg(1));
1094 output( "\tstw %s, %d(%s)\n", ppc_reg(11),36+extra_stack_storage, ppc_reg(1));
1095 output( "\tstw %s, %d(%s)\n", ppc_reg(12),40+extra_stack_storage, ppc_reg(1));
1097 /* r0 -> r3 (arg1) */
1098 output( "\tmr %s, %s\n", ppc_reg(3), ppc_reg(0));
1100 /* save return address */
1101 output( "\tmflr %s\n", ppc_reg(0));
1102 output( "\tstw %s, %d(%s)\n", ppc_reg(0), 44+extra_stack_storage, ppc_reg(1));
1104 /* Call the __wine_delay_load function, arg1 is arg1. */
1105 output( "\tbl %s\n", asm_name("__wine_spec_delay_load") );
1107 /* Load return value from call into ctr register */
1108 output( "\tmtctr %s\n", ppc_reg(3));
1110 /* restore all saved registers and drop stackframe. */
1111 output( "\tlwz %s, %d(%s)\n", ppc_reg(3), 4+extra_stack_storage, ppc_reg(1));
1112 output( "\tlwz %s, %d(%s)\n", ppc_reg(4), 8+extra_stack_storage, ppc_reg(1));
1113 output( "\tlwz %s, %d(%s)\n", ppc_reg(5), 12+extra_stack_storage, ppc_reg(1));
1114 output( "\tlwz %s, %d(%s)\n", ppc_reg(6), 16+extra_stack_storage, ppc_reg(1));
1115 output( "\tlwz %s, %d(%s)\n", ppc_reg(7), 20+extra_stack_storage, ppc_reg(1));
1116 output( "\tlwz %s, %d(%s)\n", ppc_reg(8), 24+extra_stack_storage, ppc_reg(1));
1117 output( "\tlwz %s, %d(%s)\n", ppc_reg(9), 28+extra_stack_storage, ppc_reg(1));
1118 output( "\tlwz %s, %d(%s)\n", ppc_reg(10),32+extra_stack_storage, ppc_reg(1));
1119 output( "\tlwz %s, %d(%s)\n", ppc_reg(11),36+extra_stack_storage, ppc_reg(1));
1120 output( "\tlwz %s, %d(%s)\n", ppc_reg(12),40+extra_stack_storage, ppc_reg(1));
1122 /* Load return value from call into return register */
1123 output( "\tlwz %s, %d(%s)\n", ppc_reg(0), 44+extra_stack_storage, ppc_reg(1));
1124 output( "\tmtlr %s\n", ppc_reg(0));
1125 output( "\taddi %s, %s, %d\n", ppc_reg(1), ppc_reg(1), 48+extra_stack_storage);
1127 /* branch to ctr register. */
1128 output( "\tbctr\n");
1129 break;
1131 output_cfi( ".cfi_endproc" );
1132 output_function_size( "__wine_delay_load_asm" );
1133 output( "\n" );
1135 idx = 0;
1136 LIST_FOR_EACH_ENTRY( import, &dll_delayed, struct import, entry )
1138 for (j = 0; j < import->nb_imports; j++)
1140 struct import_func *func = &import->imports[j];
1141 const char *name = func->name ? func->name : func->export_name;
1143 output( ".L__wine_delay_imp_%s_%s:\n", import->c_name, name );
1144 output_cfi( ".cfi_startproc" );
1145 switch(target_cpu)
1147 case CPU_x86:
1148 output( "\tmovl $%d, %%eax\n", (idx << 16) | j );
1149 output( "\tjmp %s\n", asm_name("__wine_delay_load_asm") );
1150 break;
1151 case CPU_x86_64:
1152 output( "\tmovq $%d,%%rax\n", (idx << 16) | j );
1153 output( "\tjmp %s\n", asm_name("__wine_delay_load_asm") );
1154 break;
1155 case CPU_ARM:
1157 unsigned int mask, count = 0, val = (idx << 16) | j;
1159 for (mask = 0xff; mask; mask <<= 8)
1160 if (val & mask) output( "\t%s IP,#%u\n", count++ ? "add" : "mov", val & mask );
1161 if (!count) output( "\tmov IP,#0\n" );
1162 output( "\tb %s\n", asm_name("__wine_delay_load_asm") );
1163 break;
1165 case CPU_ARM64:
1166 output( "\tstp x6, x7, [sp,#-80]!\n" );
1167 output( "\tstp x4, x5, [sp,#48]\n" );
1168 output( "\tstp x2, x3, [sp,#32]\n" );
1169 output( "\tstp x0, x1, [sp,#16]\n" );
1170 output( "\tmov x0, #%d\n", idx );
1171 output( "\tmov x1, #16384\n" );
1172 output( "\tmul x1, x0, x1\n" );
1173 output( "\tmov x0, x1\n" );
1174 output( "\tmov x1, #4\n" );
1175 output( "\tmul x1, x0, x1\n" );
1176 output( "\tmov x0, x1\n" );
1177 output( "\tadd x0, x0, #%d\n", j );
1178 output( "\tadr x9, %s\n", asm_name("__wine_delay_load_asm") );
1179 output( "\tbr x9\n" );
1180 break;
1181 case CPU_POWERPC:
1182 switch(target_platform)
1184 case PLATFORM_APPLE:
1185 /* On Darwin we can use r0 and r2 */
1186 /* Upper part in r2 */
1187 output( "\tlis %s, %d\n", ppc_reg(2), idx);
1188 /* Lower part + r2 -> r0, Note we can't use r0 directly */
1189 output( "\taddi %s, %s, %d\n", ppc_reg(0), ppc_reg(2), j);
1190 output( "\tb %s\n", asm_name("__wine_delay_load_asm") );
1191 break;
1192 default:
1193 /* On linux we can't use r2 since r2 is not a scratch register (hold the TOC) */
1194 /* Save r13 on the stack */
1195 output( "\taddi %s, %s, -0x4\n", ppc_reg(1), ppc_reg(1));
1196 output( "\tstw %s, 0(%s)\n", ppc_reg(13), ppc_reg(1));
1197 /* Upper part in r13 */
1198 output( "\tlis %s, %d\n", ppc_reg(13), idx);
1199 /* Lower part + r13 -> r0, Note we can't use r0 directly */
1200 output( "\taddi %s, %s, %d\n", ppc_reg(0), ppc_reg(13), j);
1201 /* Restore r13 */
1202 output( "\tstw %s, 0(%s)\n", ppc_reg(13), ppc_reg(1));
1203 output( "\taddic %s, %s, 0x4\n", ppc_reg(1), ppc_reg(1));
1204 output( "\tb %s\n", asm_name("__wine_delay_load_asm") );
1205 break;
1207 break;
1209 output_cfi( ".cfi_endproc" );
1211 idx++;
1213 output_function_size( delayed_import_loaders );
1215 output( "\n\t.align %d\n", get_alignment(get_ptr_size()) );
1216 output( "%s:\n", asm_name(delayed_import_thunks));
1217 pos = 0;
1218 LIST_FOR_EACH_ENTRY( import, &dll_delayed, struct import, entry )
1220 for (j = 0; j < import->nb_imports; j++, pos += get_ptr_size())
1222 struct import_func *func = &import->imports[j];
1223 output_import_thunk( func->name ? func->name : func->export_name,
1224 ".L__wine_delay_IAT", pos );
1227 output_function_size( delayed_import_thunks );
1230 /* output import stubs for exported entry points that link to external symbols */
1231 static void output_external_link_imports( DLLSPEC *spec )
1233 unsigned int i, pos;
1235 if (!ext_link_imports.count) return; /* nothing to do */
1237 sort_names( &ext_link_imports );
1239 /* get rid of duplicate names */
1240 for (i = 1; i < ext_link_imports.count; i++)
1242 if (!strcmp( ext_link_imports.str[i-1], ext_link_imports.str[i] ))
1243 remove_name( &ext_link_imports, i-- );
1246 output( "\n/* external link thunks */\n\n" );
1247 output( "\t.data\n" );
1248 output( "\t.align %d\n", get_alignment(get_ptr_size()) );
1249 output( ".L__wine_spec_external_links:\n" );
1250 for (i = 0; i < ext_link_imports.count; i++)
1251 output( "\t%s %s\n", get_asm_ptr_keyword(), asm_name(ext_link_imports.str[i]) );
1253 output( "\n\t.text\n" );
1254 output( "\t.align %d\n", get_alignment(get_ptr_size()) );
1255 output( "%s:\n", asm_name("__wine_spec_external_link_thunks") );
1257 for (i = pos = 0; i < ext_link_imports.count; i++)
1259 char *buffer = strmake( "__wine_spec_ext_link_%s", ext_link_imports.str[i] );
1260 output_import_thunk( buffer, ".L__wine_spec_external_links", pos );
1261 free( buffer );
1262 pos += get_ptr_size();
1264 output_function_size( "__wine_spec_external_link_thunks" );
1267 /*******************************************************************
1268 * output_stubs
1270 * Output the functions for stub entry points
1272 void output_stubs( DLLSPEC *spec )
1274 const char *name, *exp_name;
1275 int i;
1277 if (!has_stubs( spec )) return;
1279 output( "\n/* stub functions */\n\n" );
1280 output( "\t.text\n" );
1282 for (i = 0; i < spec->nb_entry_points; i++)
1284 ORDDEF *odp = &spec->entry_points[i];
1285 if (odp->type != TYPE_STUB) continue;
1287 name = get_stub_name( odp, spec );
1288 exp_name = odp->name ? odp->name : odp->export_name;
1289 output( "\t.align %d\n", get_alignment(4) );
1290 output( "\t%s\n", func_declaration(name) );
1291 output( "%s:\n", asm_name(name) );
1292 output_cfi( ".cfi_startproc" );
1294 switch (target_cpu)
1296 case CPU_x86:
1297 /* flesh out the stub a bit to make safedisc happy */
1298 output(" \tnop\n" );
1299 output(" \tnop\n" );
1300 output(" \tnop\n" );
1301 output(" \tnop\n" );
1302 output(" \tnop\n" );
1303 output(" \tnop\n" );
1304 output(" \tnop\n" );
1305 output(" \tnop\n" );
1306 output(" \tnop\n" );
1308 output( "\tsubl $12,%%esp\n" );
1309 output_cfi( ".cfi_adjust_cfa_offset 12" );
1310 if (UsePIC)
1312 output( "\tcall %s\n", asm_name("__wine_spec_get_pc_thunk_eax") );
1313 output( "1:" );
1314 needs_get_pc_thunk = 1;
1315 if (exp_name)
1317 output( "\tleal .L%s_string-1b(%%eax),%%ecx\n", name );
1318 output( "\tmovl %%ecx,4(%%esp)\n" );
1320 else
1321 output( "\tmovl $%d,4(%%esp)\n", odp->ordinal );
1322 output( "\tleal .L__wine_spec_file_name-1b(%%eax),%%ecx\n" );
1323 output( "\tmovl %%ecx,(%%esp)\n" );
1325 else
1327 if (exp_name)
1328 output( "\tmovl $.L%s_string,4(%%esp)\n", name );
1329 else
1330 output( "\tmovl $%d,4(%%esp)\n", odp->ordinal );
1331 output( "\tmovl $.L__wine_spec_file_name,(%%esp)\n" );
1333 output( "\tcall %s\n", asm_name("__wine_spec_unimplemented_stub") );
1334 break;
1335 case CPU_x86_64:
1336 output( "\tsubq $0x28,%%rsp\n" );
1337 output_cfi( ".cfi_adjust_cfa_offset 8" );
1338 output( "\tleaq .L__wine_spec_file_name(%%rip),%%rcx\n" );
1339 if (exp_name)
1340 output( "leaq .L%s_string(%%rip),%%rdx\n", name );
1341 else
1342 output( "\tmovq $%d,%%rdx\n", odp->ordinal );
1343 output( "\tcall %s\n", asm_name("__wine_spec_unimplemented_stub") );
1344 break;
1345 case CPU_ARM:
1346 output( "\tldr r0,2f\n");
1347 output( "\tadd r0,PC\n");
1348 output( "\tldr r1,2f+4\n");
1349 output( "1:" );
1350 if (exp_name) output( "\tadd r1,PC\n");
1351 output( "\tbl %s\n", asm_name("__wine_spec_unimplemented_stub") );
1352 output( "2:\t.long .L__wine_spec_file_name-1b\n" );
1353 if (exp_name) output( "\t.long .L%s_string-2b\n", name );
1354 else output( "\t.long %u\n", odp->ordinal );
1355 break;
1356 case CPU_ARM64:
1357 output( "\tadrp x0, .L__wine_spec_file_name\n" );
1358 output( "\tadd x0, x0, #:lo12:.L__wine_spec_file_name\n" );
1359 if (exp_name)
1361 output( "\tadrp x1, .L%s_string\n", name );
1362 output( "\tadd x1, x1, #:lo12:.L%s_string\n", name );
1364 else
1365 output( "\tmov x1, %u\n", odp->ordinal );
1366 output( "\tadrp x2, %s\n", asm_name("__wine_spec_unimplemented_stub") );
1367 output( "\tadd x2, x2, #:lo12:%s\n", asm_name("__wine_spec_unimplemented_stub") );
1368 output( "\tblr x2\n" );
1369 break;
1370 default:
1371 assert(0);
1373 output_cfi( ".cfi_endproc" );
1374 output_function_size( name );
1377 output( "\t%s\n", get_asm_string_section() );
1378 output( ".L__wine_spec_file_name:\n" );
1379 output( "\t%s \"%s\"\n", get_asm_string_keyword(), spec->file_name );
1380 for (i = 0; i < spec->nb_entry_points; i++)
1382 ORDDEF *odp = &spec->entry_points[i];
1383 if (odp->type != TYPE_STUB) continue;
1384 exp_name = odp->name ? odp->name : odp->export_name;
1385 if (exp_name)
1387 name = get_stub_name( odp, spec );
1388 output( ".L%s_string:\n", name );
1389 output( "\t%s \"%s\"\n", get_asm_string_keyword(), exp_name );
1394 /* output the import and delayed import tables of a Win32 module */
1395 void output_imports( DLLSPEC *spec )
1397 if (target_platform == PLATFORM_WINDOWS) return;
1398 output_immediate_imports();
1399 output_delayed_imports( spec );
1400 output_immediate_import_thunks();
1401 output_delayed_import_thunks( spec );
1402 output_external_link_imports( spec );
1405 /* create a new asm temp file */
1406 static void new_output_as_file(void)
1408 char *name;
1410 if (output_file) fclose( output_file );
1411 name = open_temp_output_file( ".s" );
1412 strarray_add( &as_files, name, NULL );
1415 /* assemble all the asm files */
1416 static void assemble_files( const char *prefix )
1418 unsigned int i;
1420 if (output_file) fclose( output_file );
1421 output_file = NULL;
1423 for (i = 0; i < as_files.count; i++)
1425 char *obj = get_temp_file_name( prefix, ".o" );
1426 assemble_file( as_files.str[i], obj );
1427 as_files.str[i] = obj;
1431 /* build a library from the current asm files and any additional object files in argv */
1432 static void build_library( const char *output_name, char **argv, int create )
1434 struct strarray args = find_tool( "ar", NULL );
1435 struct strarray ranlib = find_tool( "ranlib", NULL );
1437 strarray_add( &args, create ? "rc" : "r", output_name, NULL );
1438 strarray_addall( &args, as_files );
1439 strarray_addv( &args, argv );
1440 if (create) unlink( output_name );
1441 spawn( args );
1443 strarray_add( &ranlib, output_name, NULL );
1444 spawn( ranlib );
1447 /* create a Windows-style import library */
1448 static void build_windows_import_lib( DLLSPEC *spec )
1450 struct strarray args;
1451 char *def_file;
1452 const char *as_flags, *m_flag;
1454 def_file = open_temp_output_file( ".def" );
1455 output_def_file( spec, 1 );
1456 fclose( output_file );
1458 args = find_tool( "dlltool", NULL );
1459 switch (target_cpu)
1461 case CPU_x86:
1462 m_flag = "i386";
1463 as_flags = "--as-flags=--32";
1464 break;
1465 case CPU_x86_64:
1466 m_flag = "i386:x86-64";
1467 as_flags = "--as-flags=--64";
1468 break;
1469 default:
1470 m_flag = NULL;
1471 break;
1473 strarray_add( &args, "-k", strendswith( output_file_name, ".delay.a" ) ? "-y" : "-l",
1474 output_file_name, "-d", def_file, NULL );
1475 if (m_flag)
1476 strarray_add( &args, "-m", m_flag, as_flags, NULL );
1477 spawn( args );
1480 /* create a Unix-style import library */
1481 static void build_unix_import_lib( DLLSPEC *spec )
1483 static const char valid_chars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789._@";
1484 int i, total;
1485 const char *name, *prefix;
1486 char *dll_name = xstrdup( spec->file_name );
1488 if (strendswith( dll_name, ".dll" )) dll_name[strlen(dll_name) - 4] = 0;
1489 if (strspn( dll_name, valid_chars ) < strlen( dll_name ))
1490 fatal_error( "%s contains invalid characters\n", spec->file_name );
1492 /* entry points */
1494 for (i = total = 0; i < spec->nb_entry_points; i++)
1496 const ORDDEF *odp = &spec->entry_points[i];
1498 if (odp->name) name = odp->name;
1499 else if (odp->export_name) name = odp->export_name;
1500 else continue;
1502 if (odp->flags & FLAG_PRIVATE) continue;
1503 total++;
1505 /* C++ mangled names cannot be imported */
1506 if (strpbrk( name, "?@" )) continue;
1508 switch(odp->type)
1510 case TYPE_VARARGS:
1511 case TYPE_CDECL:
1512 case TYPE_STDCALL:
1513 prefix = (!odp->name || (odp->flags & FLAG_ORDINAL)) ? import_ord_prefix : import_func_prefix;
1514 new_output_as_file();
1515 output( "\t.text\n" );
1516 output( "\n\t.align %d\n", get_alignment( get_ptr_size() ));
1517 output( "\t%s\n", func_declaration( name ) );
1518 output( "%s\n", asm_globl( name ) );
1519 output( "\t%s %s%s$%u$%s\n", get_asm_ptr_keyword(),
1520 asm_name( prefix ), dll_name, odp->ordinal, name );
1521 output_function_size( name );
1522 output_gnu_stack_note();
1523 break;
1525 default:
1526 break;
1529 if (!total) warning( "%s: Import library doesn't export anything\n", spec->file_name );
1531 if (!as_files.count) /* create a dummy file to avoid empty import libraries */
1533 new_output_as_file();
1534 output( "\t.text\n" );
1537 assemble_files( spec->file_name );
1538 free( dll_name );
1541 /* output an import library for a Win32 module and additional object files */
1542 void output_static_lib( DLLSPEC *spec, char **argv )
1544 if (target_platform == PLATFORM_WINDOWS)
1546 if (spec) build_windows_import_lib( spec );
1547 if (argv[0] || !spec) build_library( output_file_name, argv, !spec );
1549 else
1551 if (spec) build_unix_import_lib( spec );
1552 build_library( output_file_name, argv, 1 );