iphlpapi: Rewrite GetAdaptersAddresses() to first alloc and then copy the info.
[wine.git] / tools / winebuild / import.c
blobef12b5fa4b0dce77350f5815624d8fe0a11aff7f
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 = func.export_name = xstrdup(name);
219 odp = &func;
220 if (table) res = bsearch( &odp, table, size, sizeof(*table), func_cmp );
221 free( func.name );
222 return res ? *res : NULL;
225 /* free an import structure */
226 static void free_imports( struct import *imp )
228 free( imp->exports );
229 free( imp->imports );
230 free( imp->dll_name );
231 free( imp->c_name );
232 free( imp->full_name );
233 free( imp );
236 /* check whether a given dll is imported in delayed mode */
237 static int is_delayed_import( const char *name )
239 unsigned int i;
241 for (i = 0; i < delayed_imports.count; i++)
243 if (!strcmp( delayed_imports.str[i], name )) return 1;
245 return 0;
248 /* find an imported dll from its name */
249 static struct import *find_import_dll( const char *name )
251 struct import *import;
253 LIST_FOR_EACH_ENTRY( import, &dll_imports, struct import, entry )
254 if (!strcasecmp( import->dll_name, name )) return import;
255 LIST_FOR_EACH_ENTRY( import, &dll_delayed, struct import, entry )
256 if (!strcasecmp( import->dll_name, name )) return import;
257 return NULL;
260 /* open the .so library for a given dll in a specified path */
261 static char *try_library_path( const char *path, const char *name )
263 char *buffer;
264 int fd;
266 buffer = strmake( "%s/lib%s.def", path, name );
268 /* check if the file exists */
269 if ((fd = open( buffer, O_RDONLY )) != -1)
271 close( fd );
272 return buffer;
274 free( buffer );
275 return NULL;
278 /* find the .def import library for a given dll */
279 static char *find_library( const char *name )
281 char *fullname;
282 unsigned int i;
284 for (i = 0; i < lib_path.count; i++)
286 if ((fullname = try_library_path( lib_path.str[i], name ))) return fullname;
288 fatal_error( "could not open .def file for %s\n", name );
289 return NULL;
292 /* read in the list of exported symbols of an import library */
293 static DLLSPEC *read_import_lib( struct import *imp )
295 FILE *f;
296 int i;
297 struct stat stat;
298 struct import *prev_imp;
299 DLLSPEC *spec = alloc_dll_spec();
301 f = open_input_file( NULL, imp->full_name );
302 fstat( fileno(f), &stat );
303 imp->dev = stat.st_dev;
304 imp->ino = stat.st_ino;
305 if (!parse_def_file( f, spec )) exit( 1 );
306 close_input_file( f );
308 /* check if we already imported that library from a different file */
309 if ((prev_imp = find_import_dll( spec->file_name )))
311 if (prev_imp->dev != imp->dev || prev_imp->ino != imp->ino)
312 fatal_error( "%s and %s have the same export name '%s'\n",
313 prev_imp->full_name, imp->full_name, spec->file_name );
314 free_dll_spec( spec );
315 return NULL; /* the same file was already loaded, ignore this one */
318 if (spec->nb_entry_points)
320 imp->exports = xmalloc( spec->nb_entry_points * sizeof(*imp->exports) );
321 for (i = 0; i < spec->nb_entry_points; i++)
322 imp->exports[imp->nb_exports++] = &spec->entry_points[i];
323 qsort( imp->exports, imp->nb_exports, sizeof(*imp->exports), func_cmp );
325 return spec;
328 /* build the dll exported name from the import lib name or path */
329 static char *get_dll_name( const char *name, const char *filename )
331 char *ret;
333 if (filename)
335 const char *basename = strrchr( filename, '/' );
336 if (!basename) basename = filename;
337 else basename++;
338 if (!strncmp( basename, "lib", 3 )) basename += 3;
339 ret = xmalloc( strlen(basename) + 5 );
340 strcpy( ret, basename );
341 if (strendswith( ret, ".def" )) ret[strlen(ret)-4] = 0;
343 else
345 ret = xmalloc( strlen(name) + 5 );
346 strcpy( ret, name );
348 if (!strchr( ret, '.' )) strcat( ret, ".dll" );
349 return ret;
352 /* add a dll to the list of imports */
353 void add_import_dll( const char *name, const char *filename )
355 DLLSPEC *spec;
356 char *dll_name = get_dll_name( name, filename );
357 struct import *imp = xmalloc( sizeof(*imp) );
359 memset( imp, 0, sizeof(*imp) );
361 if (filename) imp->full_name = xstrdup( filename );
362 else imp->full_name = find_library( name );
364 if (!(spec = read_import_lib( imp )))
366 free_imports( imp );
367 return;
370 imp->dll_name = spec->file_name ? spec->file_name : dll_name;
371 imp->c_name = make_c_identifier( imp->dll_name );
373 if (is_delayed_import( imp->dll_name ))
374 list_add_tail( &dll_delayed, &imp->entry );
375 else
376 list_add_tail( &dll_imports, &imp->entry );
379 /* add a library to the list of delayed imports */
380 void add_delayed_import( const char *name )
382 struct import *imp;
383 char *fullname = get_dll_name( name, NULL );
385 strarray_add( &delayed_imports, fullname, NULL );
386 if ((imp = find_import_dll( fullname )))
388 list_remove( &imp->entry );
389 list_add_tail( &dll_delayed, &imp->entry );
393 /* add a symbol to the list of extra symbols that ld must resolve */
394 void add_extra_ld_symbol( const char *name )
396 strarray_add( &extra_ld_symbols, name, NULL );
399 /* retrieve an imported dll, adding one if necessary */
400 struct import *add_static_import_dll( const char *name )
402 struct import *import;
403 char *dll_name = get_dll_name( name, NULL );
405 if ((import = find_import_dll( dll_name ))) return import;
407 import = xmalloc( sizeof(*import) );
408 memset( import, 0, sizeof(*import) );
410 import->dll_name = dll_name;
411 import->full_name = xstrdup( dll_name );
412 import->c_name = make_c_identifier( dll_name );
414 if (is_delayed_import( dll_name ))
415 list_add_tail( &dll_delayed, &import->entry );
416 else
417 list_add_tail( &dll_imports, &import->entry );
418 return import;
421 /* add a function to the list of imports from a given dll */
422 static void add_import_func( struct import *imp, const char *name, const char *export_name,
423 int ordinal, int hint )
425 if (imp->nb_imports == imp->max_imports)
427 imp->max_imports *= 2;
428 if (imp->max_imports < 32) imp->max_imports = 32;
429 imp->imports = xrealloc( imp->imports, imp->max_imports * sizeof(*imp->imports) );
431 imp->imports[imp->nb_imports].name = name;
432 imp->imports[imp->nb_imports].export_name = export_name;
433 imp->imports[imp->nb_imports].ordinal = ordinal;
434 imp->imports[imp->nb_imports].hint = hint;
435 imp->nb_imports++;
438 /* add an import for an undefined function of the form __wine$func$ */
439 static void add_undef_import( const char *name, int is_ordinal )
441 char *p, *dll_name = xstrdup( name );
442 int ordinal = 0;
443 struct import *import;
445 if (!(p = strchr( dll_name, '$' ))) return;
446 *p++ = 0;
447 while (*p >= '0' && *p <= '9') ordinal = 10 * ordinal + *p++ - '0';
448 if (*p != '$') return;
449 p++;
451 import = add_static_import_dll( dll_name );
452 if (is_ordinal)
453 add_import_func( import, NULL, xstrdup( p ), ordinal, 0 );
454 else
455 add_import_func( import, xstrdup( p ), NULL, ordinal, 0 );
458 /* check if the spec file exports any stubs */
459 static int has_stubs( const DLLSPEC *spec )
461 int i;
463 if (unix_lib) return 0;
465 for (i = 0; i < spec->nb_entry_points; i++)
467 ORDDEF *odp = &spec->entry_points[i];
468 if (odp->type == TYPE_STUB) return 1;
470 return 0;
473 /* add the extra undefined symbols that will be contained in the generated spec file itself */
474 static void add_extra_undef_symbols( DLLSPEC *spec )
476 add_extra_ld_symbol( spec->init_func );
477 if (spec->type == SPEC_WIN16) add_extra_ld_symbol( "DllMain" );
478 if (has_stubs( spec )) add_extra_ld_symbol( "__wine_spec_unimplemented_stub" );
479 if (delayed_imports.count) add_extra_ld_symbol( "__wine_spec_delay_load" );
482 /* check if a given imported dll is not needed, taking forwards into account */
483 static int check_unused( const struct import* imp, const DLLSPEC *spec )
485 int i;
486 const char *file_name = imp->dll_name;
487 size_t len = strlen( file_name );
488 const char *p = strchr( file_name, '.' );
489 if (p && !strcasecmp( p, ".dll" )) len = p - file_name;
491 for (i = spec->base; i <= spec->limit; i++)
493 ORDDEF *odp = spec->ordinals[i];
494 if (!odp || !(odp->flags & FLAG_FORWARD)) continue;
495 if (!strncasecmp( odp->link_name, file_name, len ) &&
496 odp->link_name[len] == '.')
497 return 0; /* found a forward, it is used */
499 return 1;
502 /* check if a given forward does exist in one of the imported dlls */
503 static void check_undefined_forwards( DLLSPEC *spec )
505 struct import *imp;
506 char *link_name, *api_name, *dll_name, *p;
507 int i;
509 if (unix_lib) return;
511 for (i = 0; i < spec->nb_entry_points; i++)
513 ORDDEF *odp = &spec->entry_points[i];
515 if (!(odp->flags & FLAG_FORWARD)) continue;
517 link_name = xstrdup( odp->link_name );
518 p = strrchr( link_name, '.' );
519 *p = 0;
520 api_name = p + 1;
521 dll_name = get_dll_name( link_name, NULL );
523 if ((imp = find_import_dll( dll_name )))
525 if (!find_export( api_name, imp->exports, imp->nb_exports ))
526 warning( "%s:%d: forward '%s' not found in %s\n",
527 spec->src_name, odp->lineno, odp->link_name, imp->dll_name );
529 else warning( "%s:%d: forward '%s' not found in the imported dll list\n",
530 spec->src_name, odp->lineno, odp->link_name );
531 free( link_name );
532 free( dll_name );
536 /* flag the dll exports that link to an undefined symbol */
537 static void check_undefined_exports( DLLSPEC *spec )
539 int i;
541 if (unix_lib) return;
543 for (i = 0; i < spec->nb_entry_points; i++)
545 ORDDEF *odp = &spec->entry_points[i];
546 if (odp->type == TYPE_STUB || odp->type == TYPE_ABS || odp->type == TYPE_VARIABLE) continue;
547 if (odp->flags & FLAG_FORWARD) continue;
548 if (odp->flags & FLAG_SYSCALL) continue;
549 if (find_name( odp->link_name, &undef_symbols ))
551 switch(odp->type)
553 case TYPE_PASCAL:
554 case TYPE_STDCALL:
555 case TYPE_CDECL:
556 case TYPE_VARARGS:
557 if (link_ext_symbols)
559 odp->flags |= FLAG_EXT_LINK;
560 strarray_add( &ext_link_imports, odp->link_name, NULL );
562 else error( "%s:%d: function '%s' not defined\n",
563 spec->src_name, odp->lineno, odp->link_name );
564 break;
565 default:
566 if (!strcmp( odp->link_name, "__wine_syscall_dispatcher" )) break;
567 error( "%s:%d: external symbol '%s' is not a function\n",
568 spec->src_name, odp->lineno, odp->link_name );
569 break;
575 /* create a .o file that references all the undefined symbols we want to resolve */
576 static char *create_undef_symbols_file( DLLSPEC *spec )
578 char *as_file, *obj_file;
579 int i;
580 unsigned int j;
582 if (unix_lib) return NULL;
584 as_file = open_temp_output_file( ".s" );
585 output( "\t.data\n" );
587 for (i = 0; i < spec->nb_entry_points; i++)
589 ORDDEF *odp = &spec->entry_points[i];
590 if (odp->type == TYPE_STUB || odp->type == TYPE_ABS || odp->type == TYPE_VARIABLE) continue;
591 if (odp->flags & FLAG_FORWARD) continue;
592 if (odp->flags & FLAG_SYSCALL) continue;
593 output( "\t%s %s\n", get_asm_ptr_keyword(), asm_name( get_link_name( odp )));
595 for (j = 0; j < extra_ld_symbols.count; j++)
596 output( "\t%s %s\n", get_asm_ptr_keyword(), asm_name(extra_ld_symbols.str[j]) );
597 fclose( output_file );
599 obj_file = get_temp_file_name( output_file_name, ".o" );
600 assemble_file( as_file, obj_file );
601 return obj_file;
604 /* combine a list of object files with ld into a single object file */
605 /* returns the name of the combined file */
606 static const char *ldcombine_files( DLLSPEC *spec, char **argv )
608 char *ld_tmp_file, *undef_file;
609 struct strarray args = get_ld_command();
611 undef_file = create_undef_symbols_file( spec );
612 ld_tmp_file = get_temp_file_name( output_file_name, ".o" );
614 strarray_add( &args, "-r", "-o", ld_tmp_file, undef_file, NULL );
615 strarray_addv( &args, argv );
616 spawn( args );
617 return ld_tmp_file;
620 /* read in the list of undefined symbols */
621 void read_undef_symbols( DLLSPEC *spec, char **argv )
623 size_t prefix_len;
624 FILE *f;
625 const char *prog = get_nm_command();
626 char *cmd, buffer[1024], name_prefix[16];
627 int err;
628 const char *name;
630 if (!argv[0]) return;
632 add_extra_undef_symbols( spec );
634 strcpy( name_prefix, asm_name("") );
635 prefix_len = strlen( name_prefix );
637 name = ldcombine_files( spec, argv );
639 cmd = strmake( "%s -u %s", prog, name );
640 if (verbose)
641 fprintf( stderr, "%s\n", cmd );
642 if (!(f = popen( cmd, "r" )))
643 fatal_error( "Cannot execute '%s'\n", cmd );
645 while (fgets( buffer, sizeof(buffer), f ))
647 char *p = buffer + strlen(buffer) - 1;
648 if (p < buffer) continue;
649 if (*p == '\n') *p-- = 0;
650 p = buffer;
651 while (*p == ' ') p++;
652 if (p[0] == 'U' && p[1] == ' ' && p[2]) p += 2;
653 if (prefix_len && !strncmp( p, name_prefix, prefix_len )) p += prefix_len;
654 if (!strncmp( p, import_func_prefix, strlen(import_func_prefix) ))
655 add_undef_import( p + strlen( import_func_prefix ), 0 );
656 else if (!strncmp( p, import_ord_prefix, strlen(import_ord_prefix) ))
657 add_undef_import( p + strlen( import_ord_prefix ), 1 );
658 else if (use_msvcrt || !find_name( p, &stdc_functions ))
659 strarray_add( &undef_symbols, xstrdup( p ), NULL );
661 if ((err = pclose( f ))) warning( "%s failed with status %d\n", cmd, err );
662 free( cmd );
665 void resolve_dll_imports( DLLSPEC *spec, struct list *list )
667 unsigned int j;
668 struct import *imp, *next;
669 ORDDEF *odp;
671 LIST_FOR_EACH_ENTRY_SAFE( imp, next, list, struct import, entry )
673 for (j = 0; j < undef_symbols.count; j++)
675 odp = find_export( undef_symbols.str[j], imp->exports, imp->nb_exports );
676 if (odp)
678 if (odp->flags & FLAG_PRIVATE) continue;
679 if (odp->type != TYPE_STDCALL && odp->type != TYPE_CDECL)
680 warning( "winebuild: Data export '%s' cannot be imported from %s\n",
681 odp->link_name, imp->dll_name );
682 else
684 add_import_func( imp, (odp->flags & FLAG_NONAME) ? NULL : odp->name,
685 odp->export_name, odp->ordinal, odp->hint );
686 remove_name( &undef_symbols, j-- );
690 if (!imp->nb_imports)
692 /* the dll is not used, get rid of it */
693 if (check_unused( imp, spec ))
694 warning( "winebuild: %s imported but no symbols used\n", imp->dll_name );
695 list_remove( &imp->entry );
696 free_imports( imp );
701 /* resolve the imports for a Win32 module */
702 void resolve_imports( DLLSPEC *spec )
704 check_undefined_forwards( spec );
705 resolve_dll_imports( spec, &dll_imports );
706 resolve_dll_imports( spec, &dll_delayed );
707 sort_names( &undef_symbols );
708 check_undefined_exports( spec );
711 /* check if symbol is still undefined */
712 int is_undefined( const char *name )
714 return find_name( name, &undef_symbols ) != NULL;
717 /* output the get_pc thunk if needed */
718 void output_get_pc_thunk(void)
720 assert( target_cpu == CPU_x86 );
721 output( "\n\t.text\n" );
722 output( "\t.align %d\n", get_alignment(4) );
723 output( "\t%s\n", func_declaration("__wine_spec_get_pc_thunk_eax") );
724 output( "%s:\n", asm_name("__wine_spec_get_pc_thunk_eax") );
725 output_cfi( ".cfi_startproc" );
726 output( "\tmovl (%%esp),%%eax\n" );
727 output( "\tret\n" );
728 output_cfi( ".cfi_endproc" );
729 output_function_size( "__wine_spec_get_pc_thunk_eax" );
732 /* output a single import thunk */
733 static void output_import_thunk( const char *name, const char *table, int pos )
735 output( "\n\t.align %d\n", get_alignment(4) );
736 output( "\t%s\n", func_declaration(name) );
737 output( "%s\n", asm_globl(name) );
738 output_cfi( ".cfi_startproc" );
740 switch(target_cpu)
742 case CPU_x86:
743 if (!UsePIC)
745 output( "\tjmp *(%s+%d)\n", table, pos );
747 else
749 output( "\tcall %s\n", asm_name("__wine_spec_get_pc_thunk_eax") );
750 output( "1:\tjmp *%s+%d-1b(%%eax)\n", table, pos );
751 needs_get_pc_thunk = 1;
753 break;
754 case CPU_x86_64:
755 output( "\tjmpq *%s+%d(%%rip)\n", table, pos );
756 break;
757 case CPU_ARM:
758 if (UsePIC)
760 output( "\tldr ip, 2f\n");
761 output( "1:\tadd ip, pc\n" );
762 output( "\tldr pc, [ip]\n");
763 output( "2:\t.long %s+%u-1b-%u\n", table, pos, thumb_mode ? 4 : 8 );
765 else
767 output( "\tldr ip, 1f\n");
768 output( "\tldr pc, [ip]\n");
769 output( "1:\t.long %s+%u\n", table, pos );
771 break;
772 case CPU_ARM64:
773 output( "\tadrp x16, %s\n", arm64_page( table ) );
774 output( "\tadd x16, x16, #%s\n", arm64_pageoff( table ) );
775 if (pos & ~0x7fff) output( "\tadd x16, x16, #%u\n", pos & ~0x7fff );
776 output( "\tldr x16, [x16, #%u]\n", pos & 0x7fff );
777 output( "\tbr x16\n" );
778 break;
779 case CPU_POWERPC:
780 output( "\tmr %s, %s\n", ppc_reg(0), ppc_reg(31) );
781 if (target_platform == PLATFORM_APPLE)
783 output( "\tlis %s, ha16(%s+%d+32768)\n", ppc_reg(31), table, pos );
784 output( "\tla %s, lo16(%s+%d)(%s)\n", ppc_reg(31), table, pos, ppc_reg(31) );
786 else
788 output( "\tlis %s, (%s+%d+32768)@h\n", ppc_reg(31), table, pos );
789 output( "\tla %s, (%s+%d)@l(%s)\n", ppc_reg(31), table, pos, ppc_reg(31) );
791 output( "\tlwz %s, 0(%s)\n", ppc_reg(31), ppc_reg(31) );
792 output( "\tmtctr %s\n", ppc_reg(31) );
793 output( "\tmr %s, %s\n", ppc_reg(31), ppc_reg(0) );
794 output( "\tbctr\n" );
795 break;
797 output_cfi( ".cfi_endproc" );
798 output_function_size( name );
801 /* check if we need an import directory */
802 int has_imports(void)
804 return !list_empty( &dll_imports );
807 /* output the import table of a Win32 module */
808 static void output_immediate_imports(void)
810 int i, j;
811 struct import *import;
813 if (list_empty( &dll_imports )) return; /* no immediate imports */
815 /* main import header */
817 output( "\n/* import table */\n" );
818 output( "\n\t.data\n" );
819 output( "\t.align %d\n", get_alignment(4) );
820 output( ".L__wine_spec_imports:\n" );
822 /* list of dlls */
824 j = 0;
825 LIST_FOR_EACH_ENTRY( import, &dll_imports, struct import, entry )
827 output_rva( ".L__wine_spec_import_data_names + %d", j * get_ptr_size() ); /* OriginalFirstThunk */
828 output( "\t.long 0\n" ); /* TimeDateStamp */
829 output( "\t.long 0\n" ); /* ForwarderChain */
830 output_rva( ".L__wine_spec_import_name_%s", import->c_name ); /* Name */
831 output_rva( ".L__wine_spec_import_data_ptrs + %d", j * get_ptr_size() ); /* FirstThunk */
832 j += import->nb_imports + 1;
834 output( "\t.long 0\n" ); /* OriginalFirstThunk */
835 output( "\t.long 0\n" ); /* TimeDateStamp */
836 output( "\t.long 0\n" ); /* ForwarderChain */
837 output( "\t.long 0\n" ); /* Name */
838 output( "\t.long 0\n" ); /* FirstThunk */
840 output( "\n\t.align %d\n", get_alignment(get_ptr_size()) );
841 /* output the names twice, once for OriginalFirstThunk and once for FirstThunk */
842 for (i = 0; i < 2; i++)
844 output( ".L__wine_spec_import_data_%s:\n", i ? "ptrs" : "names" );
845 LIST_FOR_EACH_ENTRY( import, &dll_imports, struct import, entry )
847 for (j = 0; j < import->nb_imports; j++)
849 struct import_func *func = &import->imports[j];
850 if (i)
852 if (func->name) output( "__imp_%s:\n", asm_name( func->name ));
853 else if (func->export_name) output( "__imp_%s:\n", asm_name( func->export_name ));
855 if (func->name)
856 output( "\t%s .L__wine_spec_import_data_%s_%s-.L__wine_spec_rva_base\n",
857 get_asm_ptr_keyword(), import->c_name, func->name );
858 else
860 if (get_ptr_size() == 8)
861 output( "\t.quad 0x800000000000%04x\n", func->ordinal );
862 else
863 output( "\t.long 0x8000%04x\n", func->ordinal );
866 output( "\t%s 0\n", get_asm_ptr_keyword() );
869 output( ".L__wine_spec_imports_end:\n" );
871 LIST_FOR_EACH_ENTRY( import, &dll_imports, struct import, entry )
873 for (j = 0; j < import->nb_imports; j++)
875 struct import_func *func = &import->imports[j];
876 if (!func->name) continue;
877 output( "\t.align %d\n", get_alignment(2) );
878 output( ".L__wine_spec_import_data_%s_%s:\n", import->c_name, func->name );
879 output( "\t.short %d\n", func->hint );
880 output( "\t%s \"%s\"\n", get_asm_string_keyword(), func->name );
884 LIST_FOR_EACH_ENTRY( import, &dll_imports, struct import, entry )
886 output( ".L__wine_spec_import_name_%s:\n\t%s \"%s\"\n",
887 import->c_name, get_asm_string_keyword(), import->dll_name );
891 /* output the import thunks of a Win32 module */
892 static void output_immediate_import_thunks(void)
894 int j, pos;
895 struct import *import;
896 static const char import_thunks[] = "__wine_spec_import_thunks";
898 if (list_empty( &dll_imports )) return;
900 output( "\n/* immediate import thunks */\n\n" );
901 output( "\t.text\n" );
902 output( "\t.align %d\n", get_alignment(8) );
903 output( "%s:\n", asm_name(import_thunks));
905 pos = 0;
906 LIST_FOR_EACH_ENTRY( import, &dll_imports, struct import, entry )
908 for (j = 0; j < import->nb_imports; j++, pos += get_ptr_size())
910 struct import_func *func = &import->imports[j];
911 output_import_thunk( func->name ? func->name : func->export_name,
912 ".L__wine_spec_import_data_ptrs", pos );
914 pos += get_ptr_size();
916 output_function_size( import_thunks );
919 /* output the delayed import table of a Win32 module */
920 static void output_delayed_imports( const DLLSPEC *spec )
922 int j, mod;
923 struct import *import;
925 if (list_empty( &dll_delayed )) return;
927 output( "\n/* delayed imports */\n\n" );
928 output( "\t.data\n" );
929 output( "\t.align %d\n", get_alignment(get_ptr_size()) );
930 output( "%s\n", asm_globl("__wine_spec_delay_imports") );
932 /* list of dlls */
934 j = mod = 0;
935 LIST_FOR_EACH_ENTRY( import, &dll_delayed, struct import, entry )
937 output( "\t%s 0\n", get_asm_ptr_keyword() ); /* grAttrs */
938 output( "\t%s .L__wine_delay_name_%s\n", /* szName */
939 get_asm_ptr_keyword(), import->c_name );
940 output( "\t%s .L__wine_delay_modules+%d\n", /* phmod */
941 get_asm_ptr_keyword(), mod * get_ptr_size() );
942 output( "\t%s .L__wine_delay_IAT+%d\n", /* pIAT */
943 get_asm_ptr_keyword(), j * get_ptr_size() );
944 output( "\t%s .L__wine_delay_INT+%d\n", /* pINT */
945 get_asm_ptr_keyword(), j * get_ptr_size() );
946 output( "\t%s 0\n", get_asm_ptr_keyword() ); /* pBoundIAT */
947 output( "\t%s 0\n", get_asm_ptr_keyword() ); /* pUnloadIAT */
948 output( "\t%s 0\n", get_asm_ptr_keyword() ); /* dwTimeStamp */
949 j += import->nb_imports;
950 mod++;
952 output( "\t%s 0\n", get_asm_ptr_keyword() ); /* grAttrs */
953 output( "\t%s 0\n", get_asm_ptr_keyword() ); /* szName */
954 output( "\t%s 0\n", get_asm_ptr_keyword() ); /* phmod */
955 output( "\t%s 0\n", get_asm_ptr_keyword() ); /* pIAT */
956 output( "\t%s 0\n", get_asm_ptr_keyword() ); /* pINT */
957 output( "\t%s 0\n", get_asm_ptr_keyword() ); /* pBoundIAT */
958 output( "\t%s 0\n", get_asm_ptr_keyword() ); /* pUnloadIAT */
959 output( "\t%s 0\n", get_asm_ptr_keyword() ); /* dwTimeStamp */
961 output( "\n.L__wine_delay_IAT:\n" );
962 LIST_FOR_EACH_ENTRY( import, &dll_delayed, struct import, entry )
964 for (j = 0; j < import->nb_imports; j++)
966 struct import_func *func = &import->imports[j];
967 const char *name = func->name ? func->name : func->export_name;
968 output( "__imp_%s:\n", asm_name( name ));
969 output( "\t%s __wine_delay_imp_%s_%s\n",
970 get_asm_ptr_keyword(), import->c_name, name );
974 output( "\n.L__wine_delay_INT:\n" );
975 LIST_FOR_EACH_ENTRY( import, &dll_delayed, struct import, entry )
977 for (j = 0; j < import->nb_imports; j++)
979 struct import_func *func = &import->imports[j];
980 if (!func->name)
981 output( "\t%s %d\n", get_asm_ptr_keyword(), func->ordinal );
982 else
983 output( "\t%s .L__wine_delay_data_%s_%s\n",
984 get_asm_ptr_keyword(), import->c_name, func->name );
988 output( "\n.L__wine_delay_modules:\n" );
989 LIST_FOR_EACH_ENTRY( import, &dll_delayed, struct import, entry )
991 output( "\t%s 0\n", get_asm_ptr_keyword() );
994 LIST_FOR_EACH_ENTRY( import, &dll_delayed, struct import, entry )
996 output( ".L__wine_delay_name_%s:\n", import->c_name );
997 output( "\t%s \"%s\"\n", get_asm_string_keyword(), import->dll_name );
1000 LIST_FOR_EACH_ENTRY( import, &dll_delayed, struct import, entry )
1002 for (j = 0; j < import->nb_imports; j++)
1004 struct import_func *func = &import->imports[j];
1005 if (!func->name) continue;
1006 output( ".L__wine_delay_data_%s_%s:\n", import->c_name, func->name );
1007 output( "\t%s \"%s\"\n", get_asm_string_keyword(), func->name );
1010 output_function_size( "__wine_spec_delay_imports" );
1013 /* output the delayed import thunks of a Win32 module */
1014 static void output_delayed_import_thunks( const DLLSPEC *spec )
1016 int idx, j, pos, extra_stack_storage = 0;
1017 struct import *import;
1018 static const char delayed_import_loaders[] = "__wine_spec_delayed_import_loaders";
1019 static const char delayed_import_thunks[] = "__wine_spec_delayed_import_thunks";
1021 if (list_empty( &dll_delayed )) return;
1023 output( "\n/* delayed import thunks */\n\n" );
1024 output( "\t.text\n" );
1025 output( "\t.align %d\n", get_alignment(8) );
1026 output( "%s:\n", asm_name(delayed_import_loaders));
1027 output( "\t%s\n", func_declaration("__wine_delay_load_asm") );
1028 output( "%s:\n", asm_name("__wine_delay_load_asm") );
1029 output_cfi( ".cfi_startproc" );
1030 switch(target_cpu)
1032 case CPU_x86:
1033 output( "\tpushl %%ecx\n" );
1034 output_cfi( ".cfi_adjust_cfa_offset 4" );
1035 output( "\tpushl %%edx\n" );
1036 output_cfi( ".cfi_adjust_cfa_offset 4" );
1037 output( "\tpushl %%eax\n" );
1038 output_cfi( ".cfi_adjust_cfa_offset 4" );
1039 output( "\tcall %s\n", asm_name("__wine_spec_delay_load") );
1040 output_cfi( ".cfi_adjust_cfa_offset -4" );
1041 output( "\tpopl %%edx\n" );
1042 output_cfi( ".cfi_adjust_cfa_offset -4" );
1043 output( "\tpopl %%ecx\n" );
1044 output_cfi( ".cfi_adjust_cfa_offset -4" );
1045 output( "\tjmp *%%eax\n" );
1046 break;
1047 case CPU_x86_64:
1048 output( "\tsubq $0x98,%%rsp\n" );
1049 output_cfi( ".cfi_adjust_cfa_offset 0x98" );
1050 output( "\tmovq %%rdx,0x88(%%rsp)\n" );
1051 output( "\tmovq %%rcx,0x80(%%rsp)\n" );
1052 output( "\tmovq %%r8,0x78(%%rsp)\n" );
1053 output( "\tmovq %%r9,0x70(%%rsp)\n" );
1054 output( "\tmovq %%r10,0x68(%%rsp)\n" );
1055 output( "\tmovq %%r11,0x60(%%rsp)\n" );
1056 output( "\tmovups %%xmm0,0x50(%%rsp)\n" );
1057 output( "\tmovups %%xmm1,0x40(%%rsp)\n" );
1058 output( "\tmovups %%xmm2,0x30(%%rsp)\n" );
1059 output( "\tmovups %%xmm3,0x20(%%rsp)\n" );
1060 output( "\tmovq %%rax,%%rcx\n" );
1061 output( "\tcall %s\n", asm_name("__wine_spec_delay_load") );
1062 output( "\tmovups 0x20(%%rsp),%%xmm3\n" );
1063 output( "\tmovups 0x30(%%rsp),%%xmm2\n" );
1064 output( "\tmovups 0x40(%%rsp),%%xmm1\n" );
1065 output( "\tmovups 0x50(%%rsp),%%xmm0\n" );
1066 output( "\tmovq 0x60(%%rsp),%%r11\n" );
1067 output( "\tmovq 0x68(%%rsp),%%r10\n" );
1068 output( "\tmovq 0x70(%%rsp),%%r9\n" );
1069 output( "\tmovq 0x78(%%rsp),%%r8\n" );
1070 output( "\tmovq 0x80(%%rsp),%%rcx\n" );
1071 output( "\tmovq 0x88(%%rsp),%%rdx\n" );
1072 output( "\taddq $0x98,%%rsp\n" );
1073 output_cfi( ".cfi_adjust_cfa_offset -0x98" );
1074 output( "\tjmp *%%rax\n" );
1075 break;
1076 case CPU_ARM:
1077 output( "\tpush {r0-r3,FP,LR}\n" );
1078 output( "\tmov r0,IP\n" );
1079 output( "\tbl %s\n", asm_name("__wine_spec_delay_load") );
1080 output( "\tmov IP,r0\n");
1081 output( "\tpop {r0-r3,FP,LR}\n" );
1082 output( "\tbx IP\n");
1083 break;
1084 case CPU_ARM64:
1085 output( "\tstp x29, x30, [sp,#-80]!\n" );
1086 output( "\tmov x29, sp\n" );
1087 output( "\tstp x0, x1, [sp,#16]\n" );
1088 output( "\tstp x2, x3, [sp,#32]\n" );
1089 output( "\tstp x4, x5, [sp,#48]\n" );
1090 output( "\tstp x6, x7, [sp,#64]\n" );
1091 output( "\tmov x0, x16\n" );
1092 output( "\tbl %s\n", asm_name("__wine_spec_delay_load") );
1093 output( "\tmov x16, x0\n" );
1094 output( "\tldp x0, x1, [sp,#16]\n" );
1095 output( "\tldp x2, x3, [sp,#32]\n" );
1096 output( "\tldp x4, x5, [sp,#48]\n" );
1097 output( "\tldp x6, x7, [sp,#64]\n" );
1098 output( "\tldp x29, x30, [sp],#80\n" );
1099 output( "\tbr x16\n" );
1100 break;
1101 case CPU_POWERPC:
1102 if (target_platform == PLATFORM_APPLE) extra_stack_storage = 56;
1104 /* Save all callee saved registers into a stackframe. */
1105 output( "\tstwu %s, -%d(%s)\n",ppc_reg(1), 48+extra_stack_storage, ppc_reg(1));
1106 output( "\tstw %s, %d(%s)\n", ppc_reg(3), 4+extra_stack_storage, ppc_reg(1));
1107 output( "\tstw %s, %d(%s)\n", ppc_reg(4), 8+extra_stack_storage, ppc_reg(1));
1108 output( "\tstw %s, %d(%s)\n", ppc_reg(5), 12+extra_stack_storage, ppc_reg(1));
1109 output( "\tstw %s, %d(%s)\n", ppc_reg(6), 16+extra_stack_storage, ppc_reg(1));
1110 output( "\tstw %s, %d(%s)\n", ppc_reg(7), 20+extra_stack_storage, ppc_reg(1));
1111 output( "\tstw %s, %d(%s)\n", ppc_reg(8), 24+extra_stack_storage, ppc_reg(1));
1112 output( "\tstw %s, %d(%s)\n", ppc_reg(9), 28+extra_stack_storage, ppc_reg(1));
1113 output( "\tstw %s, %d(%s)\n", ppc_reg(10),32+extra_stack_storage, ppc_reg(1));
1114 output( "\tstw %s, %d(%s)\n", ppc_reg(11),36+extra_stack_storage, ppc_reg(1));
1115 output( "\tstw %s, %d(%s)\n", ppc_reg(12),40+extra_stack_storage, ppc_reg(1));
1117 /* r0 -> r3 (arg1) */
1118 output( "\tmr %s, %s\n", ppc_reg(3), ppc_reg(0));
1120 /* save return address */
1121 output( "\tmflr %s\n", ppc_reg(0));
1122 output( "\tstw %s, %d(%s)\n", ppc_reg(0), 44+extra_stack_storage, ppc_reg(1));
1124 /* Call the __wine_delay_load function, arg1 is arg1. */
1125 output( "\tbl %s\n", asm_name("__wine_spec_delay_load") );
1127 /* Load return value from call into ctr register */
1128 output( "\tmtctr %s\n", ppc_reg(3));
1130 /* restore all saved registers and drop stackframe. */
1131 output( "\tlwz %s, %d(%s)\n", ppc_reg(3), 4+extra_stack_storage, ppc_reg(1));
1132 output( "\tlwz %s, %d(%s)\n", ppc_reg(4), 8+extra_stack_storage, ppc_reg(1));
1133 output( "\tlwz %s, %d(%s)\n", ppc_reg(5), 12+extra_stack_storage, ppc_reg(1));
1134 output( "\tlwz %s, %d(%s)\n", ppc_reg(6), 16+extra_stack_storage, ppc_reg(1));
1135 output( "\tlwz %s, %d(%s)\n", ppc_reg(7), 20+extra_stack_storage, ppc_reg(1));
1136 output( "\tlwz %s, %d(%s)\n", ppc_reg(8), 24+extra_stack_storage, ppc_reg(1));
1137 output( "\tlwz %s, %d(%s)\n", ppc_reg(9), 28+extra_stack_storage, ppc_reg(1));
1138 output( "\tlwz %s, %d(%s)\n", ppc_reg(10),32+extra_stack_storage, ppc_reg(1));
1139 output( "\tlwz %s, %d(%s)\n", ppc_reg(11),36+extra_stack_storage, ppc_reg(1));
1140 output( "\tlwz %s, %d(%s)\n", ppc_reg(12),40+extra_stack_storage, ppc_reg(1));
1142 /* Load return value from call into return register */
1143 output( "\tlwz %s, %d(%s)\n", ppc_reg(0), 44+extra_stack_storage, ppc_reg(1));
1144 output( "\tmtlr %s\n", ppc_reg(0));
1145 output( "\taddi %s, %s, %d\n", ppc_reg(1), ppc_reg(1), 48+extra_stack_storage);
1147 /* branch to ctr register. */
1148 output( "\tbctr\n");
1149 break;
1151 output_cfi( ".cfi_endproc" );
1152 output_function_size( "__wine_delay_load_asm" );
1153 output( "\n" );
1155 idx = 0;
1156 LIST_FOR_EACH_ENTRY( import, &dll_delayed, struct import, entry )
1158 for (j = 0; j < import->nb_imports; j++)
1160 struct import_func *func = &import->imports[j];
1161 const char *name = func->name ? func->name : func->export_name;
1163 if (thumb_mode) output( "\t.thumb_func\n" );
1164 output( "__wine_delay_imp_%s_%s:\n", import->c_name, name );
1165 output_cfi( ".cfi_startproc" );
1166 switch(target_cpu)
1168 case CPU_x86:
1169 case CPU_x86_64:
1170 output( "\tmovl $%d,%%eax\n", (idx << 16) | j );
1171 output( "\tjmp %s\n", asm_name("__wine_delay_load_asm") );
1172 break;
1173 case CPU_ARM:
1174 output( "\tmov ip, #%u\n", j );
1175 if (idx) output( "\tmovt ip, #%u\n", idx );
1176 output( "\tb %s\n", asm_name("__wine_delay_load_asm") );
1177 break;
1178 case CPU_ARM64:
1179 if (idx)
1181 output( "\tmov x16, #0x%x\n", idx << 16 );
1182 if (j) output( "\tmovk x16, #0x%x\n", j );
1184 else output( "\tmov x16, #0x%x\n", j );
1185 output( "\tb %s\n", asm_name("__wine_delay_load_asm") );
1186 break;
1187 case CPU_POWERPC:
1188 switch(target_platform)
1190 case PLATFORM_APPLE:
1191 /* On Darwin we can use r0 and r2 */
1192 /* Upper part in r2 */
1193 output( "\tlis %s, %d\n", ppc_reg(2), idx);
1194 /* Lower part + r2 -> r0, Note we can't use r0 directly */
1195 output( "\taddi %s, %s, %d\n", ppc_reg(0), ppc_reg(2), j);
1196 output( "\tb %s\n", asm_name("__wine_delay_load_asm") );
1197 break;
1198 default:
1199 /* On linux we can't use r2 since r2 is not a scratch register (hold the TOC) */
1200 /* Save r13 on the stack */
1201 output( "\taddi %s, %s, -0x4\n", ppc_reg(1), ppc_reg(1));
1202 output( "\tstw %s, 0(%s)\n", ppc_reg(13), ppc_reg(1));
1203 /* Upper part in r13 */
1204 output( "\tlis %s, %d\n", ppc_reg(13), idx);
1205 /* Lower part + r13 -> r0, Note we can't use r0 directly */
1206 output( "\taddi %s, %s, %d\n", ppc_reg(0), ppc_reg(13), j);
1207 /* Restore r13 */
1208 output( "\tstw %s, 0(%s)\n", ppc_reg(13), ppc_reg(1));
1209 output( "\taddic %s, %s, 0x4\n", ppc_reg(1), ppc_reg(1));
1210 output( "\tb %s\n", asm_name("__wine_delay_load_asm") );
1211 break;
1213 break;
1215 output_cfi( ".cfi_endproc" );
1217 idx++;
1219 output_function_size( delayed_import_loaders );
1221 output( "\n\t.align %d\n", get_alignment(get_ptr_size()) );
1222 output( "%s:\n", asm_name(delayed_import_thunks));
1223 pos = 0;
1224 LIST_FOR_EACH_ENTRY( import, &dll_delayed, struct import, entry )
1226 for (j = 0; j < import->nb_imports; j++, pos += get_ptr_size())
1228 struct import_func *func = &import->imports[j];
1229 output_import_thunk( func->name ? func->name : func->export_name,
1230 ".L__wine_delay_IAT", pos );
1233 output_function_size( delayed_import_thunks );
1236 /* output import stubs for exported entry points that link to external symbols */
1237 static void output_external_link_imports( DLLSPEC *spec )
1239 unsigned int i, pos;
1241 if (!ext_link_imports.count) return; /* nothing to do */
1243 sort_names( &ext_link_imports );
1245 /* get rid of duplicate names */
1246 for (i = 1; i < ext_link_imports.count; i++)
1248 if (!strcmp( ext_link_imports.str[i-1], ext_link_imports.str[i] ))
1249 remove_name( &ext_link_imports, i-- );
1252 output( "\n/* external link thunks */\n\n" );
1253 output( "\t.data\n" );
1254 output( "\t.align %d\n", get_alignment(get_ptr_size()) );
1255 output( ".L__wine_spec_external_links:\n" );
1256 for (i = 0; i < ext_link_imports.count; i++)
1257 output( "\t%s %s\n", get_asm_ptr_keyword(), asm_name(ext_link_imports.str[i]) );
1259 output( "\n\t.text\n" );
1260 output( "\t.align %d\n", get_alignment(get_ptr_size()) );
1261 output( "%s:\n", asm_name("__wine_spec_external_link_thunks") );
1263 for (i = pos = 0; i < ext_link_imports.count; i++)
1265 char *buffer = strmake( "__wine_spec_ext_link_%s", ext_link_imports.str[i] );
1266 output_import_thunk( buffer, ".L__wine_spec_external_links", pos );
1267 free( buffer );
1268 pos += get_ptr_size();
1270 output_function_size( "__wine_spec_external_link_thunks" );
1273 /*******************************************************************
1274 * output_stubs
1276 * Output the functions for stub entry points
1278 void output_stubs( DLLSPEC *spec )
1280 const char *name, *exp_name;
1281 int i;
1283 if (!has_stubs( spec )) return;
1285 output( "\n/* stub functions */\n\n" );
1286 output( "\t.text\n" );
1288 for (i = 0; i < spec->nb_entry_points; i++)
1290 ORDDEF *odp = &spec->entry_points[i];
1291 if (odp->type != TYPE_STUB) continue;
1293 name = get_stub_name( odp, spec );
1294 exp_name = odp->name ? odp->name : odp->export_name;
1295 output( "\t.align %d\n", get_alignment(4) );
1296 output( "\t%s\n", func_declaration(name) );
1297 output( "%s:\n", asm_name(name) );
1298 output_cfi( ".cfi_startproc" );
1300 switch (target_cpu)
1302 case CPU_x86:
1303 /* flesh out the stub a bit to make safedisc happy */
1304 output(" \tnop\n" );
1305 output(" \tnop\n" );
1306 output(" \tnop\n" );
1307 output(" \tnop\n" );
1308 output(" \tnop\n" );
1309 output(" \tnop\n" );
1310 output(" \tnop\n" );
1311 output(" \tnop\n" );
1312 output(" \tnop\n" );
1314 output( "\tsubl $12,%%esp\n" );
1315 output_cfi( ".cfi_adjust_cfa_offset 12" );
1316 if (UsePIC)
1318 output( "\tcall %s\n", asm_name("__wine_spec_get_pc_thunk_eax") );
1319 output( "1:" );
1320 needs_get_pc_thunk = 1;
1321 if (exp_name)
1323 output( "\tleal .L%s_string-1b(%%eax),%%ecx\n", name );
1324 output( "\tmovl %%ecx,4(%%esp)\n" );
1326 else
1327 output( "\tmovl $%d,4(%%esp)\n", odp->ordinal );
1328 output( "\tleal .L__wine_spec_file_name-1b(%%eax),%%ecx\n" );
1329 output( "\tmovl %%ecx,(%%esp)\n" );
1331 else
1333 if (exp_name)
1334 output( "\tmovl $.L%s_string,4(%%esp)\n", name );
1335 else
1336 output( "\tmovl $%d,4(%%esp)\n", odp->ordinal );
1337 output( "\tmovl $.L__wine_spec_file_name,(%%esp)\n" );
1339 output( "\tcall %s\n", asm_name("__wine_spec_unimplemented_stub") );
1340 break;
1341 case CPU_x86_64:
1342 output( "\tsubq $0x28,%%rsp\n" );
1343 output_cfi( ".cfi_adjust_cfa_offset 8" );
1344 output( "\tleaq .L__wine_spec_file_name(%%rip),%%rcx\n" );
1345 if (exp_name)
1346 output( "leaq .L%s_string(%%rip),%%rdx\n", name );
1347 else
1348 output( "\tmovq $%d,%%rdx\n", odp->ordinal );
1349 output( "\tcall %s\n", asm_name("__wine_spec_unimplemented_stub") );
1350 break;
1351 case CPU_ARM:
1352 if (UsePIC)
1354 output( "\tldr r0,3f\n");
1355 output( "1:\tadd r0,PC\n");
1356 output( "\tldr r1,3f+4\n");
1357 if (exp_name) output( "2:\tadd r1,PC\n");
1358 output( "\tbl %s\n", asm_name("__wine_spec_unimplemented_stub") );
1359 output( "3:\t.long .L__wine_spec_file_name-1b-%u\n", thumb_mode ? 4 : 8 );
1360 if (exp_name) output( "\t.long .L%s_string-2b-%u\n", name, thumb_mode ? 4 : 8 );
1361 else output( "\t.long %u\n", odp->ordinal );
1363 else
1365 output( "\tmovw r0,:lower16:.L__wine_spec_file_name\n");
1366 output( "\tmovt r0,:upper16:.L__wine_spec_file_name\n");
1367 if (exp_name)
1369 output( "\tmovw r1,:lower16:.L%s_string\n", name );
1370 output( "\tmovt r1,:upper16:.L%s_string\n", name );
1372 else output( "\tmov r1,#%u\n", odp->ordinal );
1373 output( "\tbl %s\n", asm_name("__wine_spec_unimplemented_stub") );
1375 break;
1376 case CPU_ARM64:
1377 output( "\tadrp x0, %s\n", arm64_page(".L__wine_spec_file_name") );
1378 output( "\tadd x0, x0, #%s\n", arm64_pageoff(".L__wine_spec_file_name") );
1379 if (exp_name)
1381 char *sym = strmake( ".L%s_string", name );
1382 output( "\tadrp x1, %s\n", arm64_page( sym ) );
1383 output( "\tadd x1, x1, #%s\n", arm64_pageoff( sym ) );
1384 free( sym );
1386 else
1387 output( "\tmov x1, %u\n", odp->ordinal );
1388 output( "\tbl %s\n", asm_name("__wine_spec_unimplemented_stub") );
1389 break;
1390 default:
1391 assert(0);
1393 output_cfi( ".cfi_endproc" );
1394 output_function_size( name );
1397 output( "\t%s\n", get_asm_string_section() );
1398 output( ".L__wine_spec_file_name:\n" );
1399 output( "\t%s \"%s\"\n", get_asm_string_keyword(), spec->file_name );
1400 for (i = 0; i < spec->nb_entry_points; i++)
1402 ORDDEF *odp = &spec->entry_points[i];
1403 if (odp->type != TYPE_STUB) continue;
1404 exp_name = odp->name ? odp->name : odp->export_name;
1405 if (exp_name)
1407 name = get_stub_name( odp, spec );
1408 output( ".L%s_string:\n", name );
1409 output( "\t%s \"%s\"\n", get_asm_string_keyword(), exp_name );
1414 static int cmp_link_name( const void *e1, const void *e2 )
1416 const ORDDEF *odp1 = *(const ORDDEF * const *)e1;
1417 const ORDDEF *odp2 = *(const ORDDEF * const *)e2;
1419 return strcmp( odp1->link_name, odp2->link_name );
1423 /* output dispatcher for system calls */
1424 static void output_syscall_dispatcher(void)
1426 const unsigned int invalid_param = 0xc000000d; /* STATUS_INVALID_PARAMETER */
1427 unsigned int i;
1429 output( "\t.align %d\n", get_alignment(4) );
1430 output( "\t%s\n", func_declaration("__wine_syscall_dispatcher") );
1431 output( "%s\n", asm_globl("__wine_syscall_dispatcher") );
1432 output_cfi( ".cfi_startproc" );
1433 switch (target_cpu)
1435 case CPU_x86:
1436 output( "\tmovl %%fs:0x1f8,%%ecx\n" ); /* x86_thread_data()->syscall_frame */
1437 output( "\tmovl $0,0x00(%%ecx)\n" ); /* frame->restore_flags */
1438 output( "\tpopl 0x08(%%ecx)\n" ); /* frame->eip */
1439 output( "\tpushfl\n" );
1440 output( "\tpopl 0x04(%%ecx)\n" ); /* frame->eflags */
1441 output( "%s\n", asm_globl("__wine_syscall_dispatcher_prolog_end") );
1442 output( "\tmovl %%esp,0x0c(%%ecx)\n" ); /* frame->esp */
1443 output( "\tmovw %%cs,0x10(%%ecx)\n" );
1444 output( "\tmovw %%ss,0x12(%%ecx)\n" );
1445 output( "\tmovw %%ds,0x14(%%ecx)\n" );
1446 output( "\tmovw %%es,0x16(%%ecx)\n" );
1447 output( "\tmovw %%fs,0x18(%%ecx)\n" );
1448 output( "\tmovw %%gs,0x1a(%%ecx)\n" );
1449 output( "\tmovl %%eax,0x1c(%%ecx)\n" );
1450 output( "\tmovl %%ebx,0x20(%%ecx)\n" );
1451 output( "\tmovl %%edi,0x2c(%%ecx)\n" );
1452 output( "\tmovl %%esi,0x30(%%ecx)\n" );
1453 output( "\tmovl %%ebp,0x34(%%ecx)\n" );
1454 output( "\tleal 0x34(%%ecx),%%ebp\n" );
1455 output( "\tleal 4(%%esp),%%esi\n" ); /* first argument */
1456 output( "\tmovl %%eax,%%edx\n" );
1457 output( "\tshrl $8,%%edx\n" );
1458 output( "\tandl $0x30,%%edx\n" ); /* syscall table number */
1459 if (UsePIC)
1461 output( "\tcall %s\n", asm_name("__wine_spec_get_pc_thunk_eax") );
1462 output( "1:\tleal %s-1b(%%eax,%%edx),%%ebx\n", asm_name("KeServiceDescriptorTable") );
1463 needs_get_pc_thunk = 1;
1465 else output( "\tleal %s(%%edx),%%ebx\n", asm_name("KeServiceDescriptorTable") );
1466 output( "\ttestl $3,0x38(%%ecx)\n" ); /* SYSCALL_HAVE_XSAVE | SYSCALL_HAVE_XSAVEC */
1467 output( "\tjz 2f\n" );
1468 output( "\tmovl $7,%%eax\n" );
1469 output( "\txorl %%edx,%%edx\n" );
1470 for (i = 0; i < 6; i++) output( "\tmovl %%edx,0x%x(%%ecx)\n", 0x240 + i * 4 );
1471 output( "\ttestl $2,0x38(%%ecx)\n" ); /* SYSCALL_HAVE_XSAVEC */
1472 output( "\tjz 1f\n" );
1473 for (i = 6; i < 16; i++) output( "\tmovl %%edx,0x%x(%%ecx)\n", 0x240 + i * 4 );
1474 output( "\txsavec 0x40(%%ecx)\n" );
1475 output( "\tjmp 4f\n" );
1476 output( "1:\txsave 0x40(%%ecx)\n" );
1477 output( "\tjmp 4f\n" );
1478 output( "2:\ttestl $4,0x38(%%ecx)\n" ); /* SYSCALL_HAVE_FXSAVE */
1479 output( "\tjz 3f\n" );
1480 output( "\tfxsave 0x40(%%ecx)\n" );
1481 output( "\tjmp 4f\n" );
1482 output( "3:\tfnsave 0x40(%%ecx)\n" );
1483 output( "\tfwait\n" );
1484 output( "4:\tmovl %%ecx,%%esp\n" );
1485 output( "\tmovl 0x1c(%%esp),%%edx\n" ); /* frame->eax */
1486 output( "\tandl $0xfff,%%edx\n" ); /* syscall number */
1487 output( "\tcmpl 8(%%ebx),%%edx\n" ); /* table->ServiceLimit */
1488 output( "\tjae 6f\n" );
1489 output( "\tmovl 12(%%ebx),%%eax\n" ); /* table->ArgumentTable */
1490 output( "\tmovzbl (%%eax,%%edx,1),%%ecx\n" );
1491 output( "\tmovl (%%ebx),%%eax\n" ); /* table->ServiceTable */
1492 output( "\tsubl %%ecx,%%esp\n" );
1493 output( "\tshrl $2,%%ecx\n" );
1494 output( "\tandl $~15,%%esp\n" );
1495 output( "\tmovl %%esp,%%edi\n" );
1496 output( "\tcld\n" );
1497 output( "\trep; movsl\n" );
1498 output( "\tcall *(%%eax,%%edx,4)\n" );
1499 output( "\tleal -0x34(%%ebp),%%esp\n" );
1500 output( "5:\tmovl (%%esp),%%ecx\n" ); /* frame->restore_flags */
1501 output( "\ttestl $0x68,%%ecx\n" ); /* CONTEXT_FLOATING_POINT | CONTEXT_EXTENDED_REGISTERS | CONTEXT_XSAVE */
1502 output( "\tjz 3f\n" );
1503 output( "\ttestl $3,0x38(%%esp)\n" ); /* SYSCALL_HAVE_XSAVE | SYSCALL_HAVE_XSAVEC */
1504 output( "\tjz 1f\n" );
1505 output( "\tmovl %%eax,%%esi\n" );
1506 output( "\tmovl $7,%%eax\n" );
1507 output( "\txorl %%edx,%%edx\n" );
1508 output( "\txrstor 0x40(%%esp)\n" );
1509 output( "\tmovl %%esi,%%eax\n" );
1510 output( "\tjmp 3f\n" );
1511 output( "1:\ttestl $4,0x38(%%esp)\n" ); /* SYSCALL_HAVE_FXSAVE */
1512 output( "\tjz 2f\n" );
1513 output( "\tfxrstor 0x40(%%esp)\n" );
1514 output( "\tjmp 3f\n" );
1515 output( "2:\tfrstor 0x40(%%esp)\n" );
1516 output( "\tfwait\n" );
1517 output( "3:\tmovl 0x2c(%%esp),%%edi\n" );
1518 output( "\tmovl 0x30(%%esp),%%esi\n" );
1519 output( "\tmovl 0x34(%%esp),%%ebp\n" );
1520 output( "\ttestl $0x7,%%ecx\n" ); /* CONTEXT_CONTROL | CONTEXT_SEGMENTS | CONTEXT_INTEGER */
1521 output( "\tjnz 1f\n" );
1522 output( "\tmovl 0x20(%%esp),%%ebx\n" );
1523 output( "\tmovl 0x08(%%esp),%%ecx\n" ); /* frame->eip */
1524 output( "\tmovl 0x0c(%%esp),%%esp\n" ); /* frame->esp */
1525 output( "\tjmpl *%%ecx\n" );
1526 output( "1:\ttestl $0x2,%%ecx\n" ); /* CONTEXT_INTEGER */
1527 output( "\tjz 1f\n" );
1528 output( "\tmovl 0x1c(%%esp),%%eax\n" );
1529 output( "\tmovl 0x24(%%esp),%%ecx\n" );
1530 output( "\tmovl 0x28(%%esp),%%edx\n" );
1531 output( "1:\tmovl 0x0c(%%esp),%%ebx\n" ); /* frame->esp */
1532 output( "\tmovw 0x12(%%esp),%%ss\n" );
1533 output( "\txchgl %%ebx,%%esp\n" );
1534 output( "\tpushl 0x04(%%ebx)\n" ); /* frame->eflags */
1535 output( "\tpushl 0x10(%%ebx)\n" ); /* frame->cs */
1536 output( "\tpushl 0x08(%%ebx)\n" ); /* frame->eip */
1537 output( "\tpushl 0x14(%%ebx)\n" ); /* frame->ds */
1538 output( "\tmovw 0x16(%%ebx),%%es\n" );
1539 output( "\tmovw 0x18(%%ebx),%%fs\n" );
1540 output( "\tmovw 0x1a(%%ebx),%%gs\n" );
1541 output( "\tmovl 0x20(%%ebx),%%ebx\n" );
1542 output( "\tpopl %%ds\n" );
1543 output( "\tiret\n" );
1544 output( "6:\tmovl $0x%x,%%eax\n", invalid_param );
1545 output( "\tjmp 5b\n" );
1546 output( "%s\n", asm_globl("__wine_syscall_dispatcher_return") );
1547 output( "\tmovl 8(%%esp),%%eax\n" );
1548 output( "\tmovl 4(%%esp),%%esp\n" );
1549 output( "\tjmp 5b\n" );
1550 break;
1551 case CPU_x86_64:
1552 output( "\tmovq %%gs:0x30,%%rcx\n" );
1553 output( "\tmovq 0x328(%%rcx),%%rcx\n" ); /* amd64_thread_data()->syscall_frame */
1554 output( "\tpopq 0x70(%%rcx)\n" ); /* frame->rip */
1555 output( "\tpushfq\n" );
1556 output( "\tpopq 0x80(%%rcx)\n" );
1557 output( "\tmovl $0,0x94(%%rcx)\n" ); /* frame->restore_flags */
1558 output( "%s\n", asm_globl("__wine_syscall_dispatcher_prolog_end") );
1559 output( "\tmovq %%rax,0x00(%%rcx)\n" );
1560 output( "\tmovq %%rbx,0x08(%%rcx)\n" );
1561 output( "\tmovq %%rdx,0x18(%%rcx)\n" );
1562 output( "\tmovq %%rsi,0x20(%%rcx)\n" );
1563 output( "\tmovq %%rdi,0x28(%%rcx)\n" );
1564 output( "\tmovq %%r12,0x50(%%rcx)\n" );
1565 output( "\tmovq %%r13,0x58(%%rcx)\n" );
1566 output( "\tmovq %%r14,0x60(%%rcx)\n" );
1567 output( "\tmovq %%r15,0x68(%%rcx)\n" );
1568 output( "\tmovw %%cs,0x78(%%rcx)\n" );
1569 output( "\tmovw %%ds,0x7a(%%rcx)\n" );
1570 output( "\tmovw %%es,0x7c(%%rcx)\n" );
1571 output( "\tmovw %%fs,0x7e(%%rcx)\n" );
1572 output( "\tmovq %%rsp,0x88(%%rcx)\n" );
1573 output( "\tmovw %%ss,0x90(%%rcx)\n" );
1574 output( "\tmovw %%gs,0x92(%%rcx)\n" );
1575 output( "\tmovq %%rbp,0x98(%%rcx)\n" );
1576 /* Legends of Runeterra hooks the first system call return instruction, and
1577 * depends on us returning to it. Adjust the return address accordingly. */
1578 output( "\tsubq $0xb,0x70(%%rcx)\n" );
1579 output( "\tmovl %s(%%rip),%%r14d\n", asm_name("__wine_syscall_flags") );
1580 output( "\ttestl $3,%%r14d\n" ); /* SYSCALL_HAVE_XSAVE | SYSCALL_HAVE_XSAVEC */
1581 output( "\tjz 2f\n" );
1582 output( "\tmovl $7,%%eax\n" );
1583 output( "\txorl %%edx,%%edx\n" );
1584 output( "\tmovq %%rdx,0x2c0(%%rcx)\n" );
1585 output( "\tmovq %%rdx,0x2c8(%%rcx)\n" );
1586 output( "\tmovq %%rdx,0x2d0(%%rcx)\n" );
1587 output( "\ttestl $2,%%r14d\n" ); /* SYSCALL_HAVE_XSAVEC */
1588 output( "\tjz 1f\n" );
1589 output( "\tmovq %%rdx,0x2d8(%%rcx)\n" );
1590 output( "\tmovq %%rdx,0x2e0(%%rcx)\n" );
1591 output( "\tmovq %%rdx,0x2e8(%%rcx)\n" );
1592 output( "\tmovq %%rdx,0x2f0(%%rcx)\n" );
1593 output( "\tmovq %%rdx,0x2f8(%%rcx)\n" );
1594 output( "\txsavec64 0xc0(%%rcx)\n" );
1595 output( "\tjmp 3f\n" );
1596 output( "1:\txsave64 0xc0(%%rcx)\n" );
1597 output( "\tjmp 3f\n" );
1598 output( "2:\tfxsave64 0xc0(%%rcx)\n" );
1599 output( "3:\tleaq 0x98(%%rcx),%%rbp\n" );
1600 if (target_platform == PLATFORM_LINUX)
1602 output( "\ttestl $12,%%r14d\n" ); /* SYSCALL_HAVE_PTHREAD_TEB | SYSCALL_HAVE_WRFSGSBASE */
1603 output( "\tjz 2f\n" );
1604 output( "\tmovq %%gs:0x330,%%rsi\n" ); /* amd64_thread_data()->pthread_teb */
1605 output( "\ttestl $8,%%r14d\n" ); /* SYSCALL_HAVE_WRFSGSBASE */
1606 output( "\tjz 1f\n" );
1607 output( "\twrfsbase %%rsi\n" );
1608 output( "\tjmp 2f\n" );
1609 output( "1:\tmov $0x1002,%%edi\n" ); /* ARCH_SET_FS */
1610 output( "\tmov $158,%%eax\n" ); /* SYS_arch_prctl */
1611 output( "\tsyscall\n" );
1612 output( "\tleaq -0x98(%%rbp),%%rcx\n" );
1613 output( "2:\n" );
1615 output( "\tleaq 0x28(%%rsp),%%rsi\n" ); /* first argument */
1616 output( "\tmovq %%rcx,%%rsp\n" );
1617 output( "\tmovq 0x00(%%rcx),%%rax\n" );
1618 output( "\tmovq 0x18(%%rcx),%%rdx\n" );
1619 output( "\tmovl %%eax,%%ebx\n" );
1620 output( "\tshrl $8,%%ebx\n" );
1621 output( "\tandl $0x30,%%ebx\n" ); /* syscall table number */
1622 output( "\tleaq %s(%%rip),%%rcx\n", asm_name("KeServiceDescriptorTable") );
1623 output( "\tleaq (%%rcx,%%rbx,2),%%rbx\n" );
1624 output( "\tandl $0xfff,%%eax\n" ); /* syscall number */
1625 output( "\tcmpq 16(%%rbx),%%rax\n" ); /* table->ServiceLimit */
1626 output( "\tjae 5f\n" );
1627 output( "\tmovq 24(%%rbx),%%rcx\n" ); /* table->ArgumentTable */
1628 output( "\tmovzbl (%%rcx,%%rax),%%ecx\n" );
1629 output( "\tsubq $0x20,%%rcx\n" );
1630 output( "\tjbe 1f\n" );
1631 output( "\tsubq %%rcx,%%rsp\n" );
1632 output( "\tshrq $3,%%rcx\n" );
1633 output( "\tandq $~15,%%rsp\n\t" );
1634 output( "\tmovq %%rsp,%%rdi\n" );
1635 output( "\tcld\n" );
1636 output( "\trep; movsq\n" );
1637 output( "1:\tmovq %%r10,%%rcx\n" );
1638 output( "\tsubq $0x20,%%rsp\n" );
1639 output( "\tmovq (%%rbx),%%r10\n" ); /* table->ServiceTable */
1640 output( "\tcallq *(%%r10,%%rax,8)\n" );
1641 output( "\tleaq -0x98(%%rbp),%%rcx\n" );
1642 output( "2:\tmovl 0x94(%%rcx),%%edx\n" ); /* frame->restore_flags */
1643 if (target_platform == PLATFORM_LINUX)
1645 output( "\ttestl $12,%%r14d\n" ); /* SYSCALL_HAVE_PTHREAD_TEB | SYSCALL_HAVE_WRFSGSBASE */
1646 output( "\tjz 1f\n" );
1647 output( "\tmovw 0x7e(%%rcx),%%fs\n" );
1648 output( "1:\n" );
1650 output( "\ttestl $0x48,%%edx\n" ); /* CONTEXT_FLOATING_POINT | CONTEXT_XSTATE */
1651 output( "\tjz 4f\n" );
1652 output( "\ttestl $3,%%r14d\n" ); /* SYSCALL_HAVE_XSAVE | SYSCALL_HAVE_XSAVEC */
1653 output( "\tjz 3f\n" );
1654 output( "\tmovq %%rax,%%r11\n" );
1655 output( "\tmovl $7,%%eax\n" );
1656 output( "\txorl %%edx,%%edx\n" );
1657 output( "\txrstor64 0xc0(%%rcx)\n" );
1658 output( "\tmovq %%r11,%%rax\n" );
1659 output( "\tmovl 0x94(%%rcx),%%edx\n" );
1660 output( "\tjmp 4f\n" );
1661 output( "3:\tfxrstor64 0xc0(%%rcx)\n" );
1662 output( "4:\tmovq 0x98(%%rcx),%%rbp\n" );
1663 output( "\tmovq 0x68(%%rcx),%%r15\n" );
1664 output( "\tmovq 0x60(%%rcx),%%r14\n" );
1665 output( "\tmovq 0x58(%%rcx),%%r13\n" );
1666 output( "\tmovq 0x50(%%rcx),%%r12\n" );
1667 output( "\tmovq 0x28(%%rcx),%%rdi\n" );
1668 output( "\tmovq 0x20(%%rcx),%%rsi\n" );
1669 output( "\tmovq 0x08(%%rcx),%%rbx\n" );
1670 output( "\ttestl $0x3,%%edx\n" ); /* CONTEXT_CONTROL | CONTEXT_INTEGER */
1671 output( "\tjnz 1f\n" );
1672 output( "\tmovq 0x88(%%rcx),%%rsp\n" );
1673 output( "\tjmpq *0x70(%%rcx)\n" ); /* frame->rip */
1674 output( "1:\tleaq 0x70(%%rcx),%%rsp\n" );
1675 output( "\ttestl $0x2,%%edx\n" ); /* CONTEXT_INTEGER */
1676 output( "\tjz 1f\n" );
1677 output( "\tmovq 0x00(%%rcx),%%rax\n" );
1678 output( "\tmovq 0x18(%%rcx),%%rdx\n" );
1679 output( "\tmovq 0x30(%%rcx),%%r8\n" );
1680 output( "\tmovq 0x38(%%rcx),%%r9\n" );
1681 output( "\tmovq 0x40(%%rcx),%%r10\n" );
1682 output( "\tmovq 0x48(%%rcx),%%r11\n" );
1683 output( "\tmovq 0x10(%%rcx),%%rcx\n" );
1684 output( "1:\tiretq\n" );
1685 output( "5:\tmovl $0x%x,%%edx\n", invalid_param );
1686 output( "\tmovq %%rsp,%%rcx\n" );
1687 output( "%s\n", asm_globl("__wine_syscall_dispatcher_return") );
1688 output( "\tmovl %s(%%rip),%%r14d\n", asm_name("__wine_syscall_flags") );
1689 output( "\tmovq %%rdx,%%rax\n" );
1690 output( "\tjmp 2b\n" );
1691 break;
1692 case CPU_ARM:
1693 output( "\tmrc p15, 0, r1, c13, c0, 2\n" ); /* NtCurrentTeb() */
1694 output( "\tldr r1, [r1, #0x1d8]\n" ); /* arm_thread_data()->syscall_frame */
1695 output( "\tadd r0, r1, #0x10\n" );
1696 output( "\tstm r0, {r4-r12,lr}\n" );
1697 output( "\tstr sp, [r1, #0x38]\n" );
1698 output( "\tstr r3, [r1, #0x3c]\n" );
1699 output( "\tmrs r0, CPSR\n" );
1700 output( "\tbfi r0, lr, #5, #1\n" ); /* set thumb bit */
1701 output( "\tstr r0, [r1, #0x40]\n" );
1702 output( "\tmov r0, #0\n" );
1703 output( "\tstr r0, [r1, #0x44]\n" ); /* frame->restore_flags */
1704 if (strcmp( float_abi_option, "soft" ))
1706 output( "\tvmrs r0, fpscr\n" );
1707 output( "\tstr r0, [r1, #0x48]\n" );
1708 output( "\tadd r0, r1, #0x50\n" );
1709 output( "\tvstm r0, {d0-d15}\n" );
1711 output( "\tmov r6, sp\n" );
1712 output( "\tmov sp, r1\n" );
1713 output( "\tmov r8, r1\n" );
1714 output( "\tldr r5, 6f\n");
1715 if (UsePIC) output( "1:\tadd r5, pc\n");
1716 output( "\tubfx r4, ip, #12, #2\n" ); /* syscall table number */
1717 output( "\tbfc ip, #12, #20\n" ); /* syscall number */
1718 output( "\tadd r4, r5, r4, lsl #4\n" );
1719 output( "\tldr r5, [r4, #8]\n" ); /* table->ServiceLimit */
1720 output( "\tcmp ip, r5\n" );
1721 output( "\tbcs 5f\n" );
1722 output( "\tldr r5, [r4, #12]\n" ); /* table->ArgumentTable */
1723 output( "\tldrb r5, [r5, ip]\n" );
1724 output( "\tcmp r5, #16\n" );
1725 output( "\tit le\n" );
1726 output( "\tmovle r5, #16\n" );
1727 output( "\tsub r0, sp, r5\n" );
1728 output( "\tand r0, #~7\n" );
1729 output( "\tmov sp, r0\n" );
1730 output( "2:\tsubs r5, r5, #4\n" );
1731 output( "\tldr r0, [r6, r5]\n" );
1732 output( "\tstr r0, [sp, r5]\n" );
1733 output( "\tbgt 2b\n" );
1734 output( "\tpop {r0-r3}\n" ); /* first 4 args are in registers */
1735 output( "\tldr r5, [r4]\n"); /* table->ServiceTable */
1736 output( "\tldr ip, [r5, ip, lsl #2]\n");
1737 output( "\tblx ip\n");
1738 output( "4:\tldr ip, [r8, #0x44]\n" ); /* frame->restore_flags */
1739 if (strcmp( float_abi_option, "soft" ))
1741 output( "\ttst ip, #4\n" ); /* CONTEXT_FLOATING_POINT */
1742 output( "\tbeq 3f\n" );
1743 output( "\tldr r4, [r8, #0x48]\n" );
1744 output( "\tvmsr fpscr, r4\n" );
1745 output( "\tadd r4, r8, #0x50\n" );
1746 output( "\tvldm r4, {d0-d15}\n" );
1747 output( "3:\n" );
1749 output( "\ttst ip, #2\n" ); /* CONTEXT_INTEGER */
1750 output( "\tit ne\n" );
1751 output( "\tldmne r8, {r0-r3}\n" );
1752 output( "\tldr lr, [r8, #0x3c]\n" );
1753 output( "\tldr sp, [r8, #0x38]\n" );
1754 output( "\tadd r8, r8, #0x10\n" );
1755 output( "\tldm r8, {r4-r12,pc}\n" );
1756 output( "5:\tmovw r0, #0x%x\n", invalid_param & 0xffff );
1757 output( "\tmovt r0, #0x%x\n", invalid_param >> 16 );
1758 output( "\tb 4b\n" );
1759 output( "%s\n", asm_globl("__wine_syscall_dispatcher_return") );
1760 output( "\tmov r8, r0\n" );
1761 output( "\tmov r0, r1\n" );
1762 output( "\tb 4b\n" );
1763 if (UsePIC)
1764 output( "6:\t.long %s-1b-%u\n", asm_name("KeServiceDescriptorTable"), thumb_mode ? 4 : 8 );
1765 else
1766 output( "6:\t.long %s\n", asm_name("KeServiceDescriptorTable") );
1767 break;
1768 case CPU_ARM64:
1769 /* FIXME: use x18 directly instead */
1770 output( "\tstp x0, x1, [sp, #-96]!\n" );
1771 output( "\tstp x2, x3, [sp, #16]\n" );
1772 output( "\tstp x4, x5, [sp, #32]\n" );
1773 output( "\tstp x6, x7, [sp, #48]\n" );
1774 output( "\tstp x8, x9, [sp, #64]\n" );
1775 output( "\tstr x30, [sp, #80]\n" );
1776 output( "\tbl %s\n", asm_name("NtCurrentTeb") );
1777 output( "\tmov x18, x0\n" );
1778 output( "\tldp x2, x3, [sp, #16]\n" );
1779 output( "\tldp x4, x5, [sp, #32]\n" );
1780 output( "\tldp x6, x7, [sp, #48]\n" );
1781 output( "\tldp x8, x9, [sp, #64]\n" );
1782 output( "\tldr x30, [sp, #80]\n" );
1783 output( "\tldp x0, x1, [sp], #96\n" );
1785 output( "\tldr x10, [x18, #0x2f8]\n" ); /* arm64_thread_data()->syscall_frame */
1786 output( "\tstp x18, x19, [x10, #0x90]\n" );
1787 output( "\tstp x20, x21, [x10, #0xa0]\n" );
1788 output( "\tstp x22, x23, [x10, #0xb0]\n" );
1789 output( "\tstp x24, x25, [x10, #0xc0]\n" );
1790 output( "\tstp x26, x27, [x10, #0xd0]\n" );
1791 output( "\tstp x28, x29, [x10, #0xe0]\n" );
1792 output( "\tmov x19, sp\n" );
1793 output( "\tstp x9, x19, [x10, #0xf0]\n" );
1794 output( "\tmrs x9, NZCV\n" );
1795 output( "\tstp x30, x9, [x10, #0x100]\n" );
1796 output( "\tstr xzr, [x10, #0x110]\n" ); /* frame->restore_flags */
1797 output( "\tmrs x9, FPCR\n" );
1798 output( "\tstr w9, [x10, #0x118]\n" );
1799 output( "\tmrs x9, FPSR\n" );
1800 output( "\tstr w9, [x10, #0x11c]\n" );
1801 output( "\tstp q0, q1, [x10, #0x120]\n" );
1802 output( "\tstp q2, q3, [x10, #0x140]\n" );
1803 output( "\tstp q4, q5, [x10, #0x160]\n" );
1804 output( "\tstp q6, q7, [x10, #0x180]\n" );
1805 output( "\tstp q8, q9, [x10, #0x1a0]\n" );
1806 output( "\tstp q10, q11, [x10, #0x1c0]\n" );
1807 output( "\tstp q12, q13, [x10, #0x1e0]\n" );
1808 output( "\tstp q14, q15, [x10, #0x200]\n" );
1809 output( "\tstp q16, q17, [x10, #0x220]\n" );
1810 output( "\tstp q18, q19, [x10, #0x240]\n" );
1811 output( "\tstp q20, q21, [x10, #0x260]\n" );
1812 output( "\tstp q22, q23, [x10, #0x280]\n" );
1813 output( "\tstp q24, q25, [x10, #0x2a0]\n" );
1814 output( "\tstp q26, q27, [x10, #0x2c0]\n" );
1815 output( "\tstp q28, q29, [x10, #0x2e0]\n" );
1816 output( "\tstp q30, q31, [x10, #0x300]\n" );
1817 output( "\tmov sp, x10\n" );
1818 output( "\tand x20, x8, #0xfff\n" ); /* syscall number */
1819 output( "\tubfx x21, x8, #12, #2\n" ); /* syscall table number */
1820 output( "\tadrp x16, %s\n", arm64_page(asm_name("KeServiceDescriptorTable")) );
1821 output( "\tadd x16, x16, #%s\n", arm64_pageoff(asm_name("KeServiceDescriptorTable")) );
1822 output( "\tadd x21, x16, x21, lsl #5\n" );
1823 output( "\tldr x16, [x21, #16]\n" ); /* table->ServiceLimit */
1824 output( "\tcmp x20, x16\n" );
1825 output( "\tbcs 4f\n" );
1826 output( "\tmov x22, sp\n" );
1827 output( "\tldr x16, [x21, #24]\n" ); /* table->ArgumentTable */
1828 output( "\tldrb w9, [x16, x20]\n" );
1829 output( "\tsubs x9, x9, #64\n" );
1830 output( "\tbls 2f\n" );
1831 output( "\tsub sp, sp, x9\n" );
1832 output( "\ttbz x9, #3, 1f\n" );
1833 output( "\tsub sp, sp, #8\n" );
1834 output( "1:\tsub x9, x9, #8\n" );
1835 output( "\tldr x10, [x19, x9]\n" );
1836 output( "\tstr x10, [sp, x9]\n" );
1837 output( "\tcbnz x9, 1b\n" );
1838 output( "2:\tldr x16, [x21]\n" ); /* table->ServiceTable */
1839 output( "\tldr x16, [x16, x20, lsl 3]\n" );
1840 output( "\tblr x16\n" );
1841 output( "\tmov sp, x22\n" );
1842 output( "3:\tldp x18, x19, [sp, #0x90]\n" );
1843 output( "\tldp x20, x21, [sp, #0xa0]\n" );
1844 output( "\tldp x22, x23, [sp, #0xb0]\n" );
1845 output( "\tldp x24, x25, [sp, #0xc0]\n" );
1846 output( "\tldp x26, x27, [sp, #0xd0]\n" );
1847 output( "\tldp x28, x29, [sp, #0xe0]\n" );
1848 output( "\tldr x16, [sp, #0x110]\n" ); /* frame->restore_flags */
1849 output( "\ttbz x16, #2, 1f\n" ); /* CONTEXT_FLOATING_POINT */
1850 output( "\tldp q0, q1, [sp, #0x120]\n" );
1851 output( "\tldp q2, q3, [sp, #0x140]\n" );
1852 output( "\tldp q4, q5, [sp, #0x160]\n" );
1853 output( "\tldp q6, q7, [sp, #0x180]\n" );
1854 output( "\tldp q8, q9, [sp, #0x1a0]\n" );
1855 output( "\tldp q10, q11, [sp, #0x1c0]\n" );
1856 output( "\tldp q12, q13, [sp, #0x1e0]\n" );
1857 output( "\tldp q14, q15, [sp, #0x200]\n" );
1858 output( "\tldp q16, q17, [sp, #0x220]\n" );
1859 output( "\tldp q18, q19, [sp, #0x240]\n" );
1860 output( "\tldp q20, q21, [sp, #0x260]\n" );
1861 output( "\tldp q22, q23, [sp, #0x280]\n" );
1862 output( "\tldp q24, q25, [sp, #0x2a0]\n" );
1863 output( "\tldp q26, q27, [sp, #0x2c0]\n" );
1864 output( "\tldp q28, q29, [sp, #0x2e0]\n" );
1865 output( "\tldp q30, q31, [sp, #0x300]\n" );
1866 output( "\tldr w9, [sp, #0x118]\n" );
1867 output( "\tmsr FPCR, x9\n" );
1868 output( "\tldr w9, [sp, #0x11c]\n" );
1869 output( "\tmsr FPSR, x9\n" );
1870 output( "1:\ttbz x16, #1, 1f\n" ); /* CONTEXT_INTEGER */
1871 output( "\tldp x0, x1, [sp, #0x00]\n" );
1872 output( "\tldp x2, x3, [sp, #0x10]\n" );
1873 output( "\tldp x4, x5, [sp, #0x20]\n" );
1874 output( "\tldp x6, x7, [sp, #0x30]\n" );
1875 output( "\tldp x8, x9, [sp, #0x40]\n" );
1876 output( "\tldp x10, x11, [sp, #0x50]\n" );
1877 output( "\tldp x12, x13, [sp, #0x60]\n" );
1878 output( "\tldp x14, x15, [sp, #0x70]\n" );
1879 output( "1:\tldp x16, x17, [sp, #0x100]\n" );
1880 output( "\tmsr NZCV, x17\n" );
1881 output( "\tldp x30, x17, [sp, #0xf0]\n" );
1882 output( "\tmov sp, x17\n" );
1883 output( "\tret x16\n" );
1884 output( "4:\tmov x0, #0x%x\n", invalid_param & 0xffff0000 );
1885 output( "\tmovk x0, #0x%x\n", invalid_param & 0x0000ffff );
1886 output( "\tb 3b\n" );
1887 output( "%s\n", asm_globl("__wine_syscall_dispatcher_return") );
1888 output( "\tmov sp, x0\n" );
1889 output( "\tmov x0, x1\n" );
1890 output( "\tb 3b\n" );
1891 break;
1892 default:
1893 assert(0);
1895 output_cfi( ".cfi_endproc" );
1896 output_function_size( "__wine_syscall_dispatcher" );
1900 /* output the functions for system calls */
1901 void output_syscalls( DLLSPEC *spec )
1903 int i, count;
1904 ORDDEF **syscalls = NULL;
1906 for (i = count = 0; i < spec->nb_entry_points; i++)
1908 ORDDEF *odp = &spec->entry_points[i];
1909 if (!(odp->flags & FLAG_SYSCALL)) continue;
1910 if (!syscalls) syscalls = xmalloc( (spec->nb_entry_points - i) * sizeof(*syscalls) );
1911 syscalls[count++] = odp;
1913 if (!count) return;
1914 count = sort_func_list( syscalls, count, cmp_link_name );
1916 output( "\n/* system calls */\n\n" );
1917 output( "\t.text\n" );
1919 if (unix_lib)
1921 output_syscall_dispatcher();
1923 output( "\t.data\n" );
1924 output( "\t.align %d\n", get_alignment( get_ptr_size() ) );
1925 output( "%s\n", asm_globl("KeServiceDescriptorTable") );
1926 output( "\t%s .Lsyscall_table, 0, %u, .Lsyscall_args\n", get_asm_ptr_keyword(), count );
1927 output( "\t%s 0, 0, 0, 0\n", get_asm_ptr_keyword() );
1928 output( "\t%s 0, 0, 0, 0\n", get_asm_ptr_keyword() );
1929 output( "\t%s 0, 0, 0, 0\n", get_asm_ptr_keyword() );
1930 output( ".Lsyscall_table:\n" );
1931 for (i = 0; i < count; i++)
1932 output( "\t%s %s\n", get_asm_ptr_keyword(), asm_name( get_link_name( syscalls[i] )));
1933 output( ".Lsyscall_args:\n" );
1934 for (i = 0; i < count; i++)
1935 output( "\t.byte %u\n", get_args_size( syscalls[i] ));
1936 output( "\t.align %d\n", get_alignment(4) );
1937 output( "%s\n", asm_globl("__wine_syscall_flags") );
1938 output( "\t.long 0\n" );
1939 return;
1942 for (i = 0; i < count; i++)
1944 ORDDEF *odp = syscalls[i];
1945 const char *name = get_link_name(odp);
1946 output( "\t.align %d\n", get_alignment(16) );
1947 output( "\t%s\n", func_declaration(name) );
1948 output( "%s\n", asm_globl(name) );
1949 output_cfi( ".cfi_startproc" );
1950 switch (target_cpu)
1952 case CPU_x86:
1953 if (UsePIC)
1955 output( "\tcall %s\n", asm_name("__wine_spec_get_pc_thunk_eax") );
1956 output( "1:\tmovl %s-1b(%%eax),%%edx\n", asm_name("__wine_syscall_dispatcher") );
1957 output( "\tmovl $%u,%%eax\n", i );
1958 needs_get_pc_thunk = 1;
1960 else
1962 output( "\tmovl $%u,%%eax\n", i );
1963 output( "\tmovl $%s,%%edx\n", asm_name("__wine_syscall") );
1965 output( "\tcall *%%edx\n" );
1966 output( "\tret $%u\n", odp->type == TYPE_STDCALL ? get_args_size( odp ) : 0 );
1967 break;
1968 case CPU_x86_64:
1969 /* Chromium depends on syscall thunks having the same form as on
1970 * Windows. For 64-bit systems the only viable form we can emulate is
1971 * having an int $0x2e fallback. Since actually using an interrupt is
1972 * expensive, and since for some reason Chromium doesn't actually
1973 * validate that instruction, we can just put a jmp there instead. */
1974 output( "\t.byte 0x4c,0x8b,0xd1\n" ); /* movq %rcx,%r10 */
1975 output( "\t.byte 0xb8\n" ); /* movl $i,%eax */
1976 output( "\t.long %u\n", i );
1977 output( "\t.byte 0xf6,0x04,0x25,0x08,0x03,0xfe,0x7f,0x01\n" ); /* testb $1,0x7ffe0308 */
1978 output( "\t.byte 0x75,0x03\n" ); /* jne 1f */
1979 output( "\t.byte 0x0f,0x05\n" ); /* syscall */
1980 output( "\t.byte 0xc3\n" ); /* ret */
1981 output( "\tjmp 1f\n" );
1982 output( "\t.byte 0xc3\n" ); /* ret */
1983 if (is_pe())
1985 output( "1:\t.byte 0xff,0x14,0x25\n" ); /* 1: callq *(0x7ffe1000) */
1986 output( "\t.long 0x7ffe1000\n" );
1988 else
1990 output( "\tnop\n" );
1991 output( "1:\tcallq *%s(%%rip)\n", asm_name("__wine_syscall_dispatcher") );
1993 output( "\tret\n" );
1994 break;
1995 case CPU_ARM:
1996 output( "\tpush {r0-r3}\n" );
1997 output( "\tmovw ip, #%u\n", i );
1998 output( "\tmov r3, lr\n" );
1999 output( "\tbl %s\n", asm_name("__wine_syscall") );
2000 output( "\tadd sp, #16\n" );
2001 output( "\tbx lr\n" );
2002 break;
2003 case CPU_ARM64:
2004 output( "\tmov x8, #%u\n", i );
2005 output( "\tmov x9, x30\n" );
2006 output( "\tbl %s\n", asm_name("__wine_syscall" ));
2007 output( "\tret\n" );
2008 break;
2009 default:
2010 assert(0);
2012 output_cfi( ".cfi_endproc" );
2013 output_function_size( name );
2016 switch (target_cpu)
2018 case CPU_x86:
2019 if (UsePIC) break;
2020 output( "\t.align %d\n", get_alignment(16) );
2021 output( "\t%s\n", func_declaration("__wine_syscall") );
2022 output( "%s:\n", asm_name("__wine_syscall") );
2023 output( "\tjmp *(%s)\n", asm_name("__wine_syscall_dispatcher") );
2024 output_function_size( "__wine_syscall" );
2025 break;
2026 case CPU_ARM:
2027 output( "\t.align %d\n", get_alignment(16) );
2028 output( "\t%s\n", func_declaration("__wine_syscall") );
2029 output( "%s:\n", asm_name("__wine_syscall") );
2030 if (UsePIC)
2032 output( "\tldr r0, 2f\n");
2033 output( "1:\tadd r0, pc\n" );
2035 else
2037 output( "\tmovw r0, :lower16:%s\n", asm_name("__wine_syscall_dispatcher") );
2038 output( "\tmovt r0, :upper16:%s\n", asm_name("__wine_syscall_dispatcher") );
2040 output( "\tldr r0, [r0]\n");
2041 output( "\tbx r0\n");
2042 if (UsePIC) output( "2:\t.long %s-1b-%u\n", asm_name("__wine_syscall_dispatcher"), thumb_mode ? 4 : 8 );
2043 output_function_size( "__wine_syscall" );
2044 break;
2045 case CPU_ARM64:
2046 output( "\t.align %d\n", get_alignment(16) );
2047 output( "\t%s\n", func_declaration("__wine_syscall") );
2048 output( "%s:\n", asm_name("__wine_syscall") );
2049 output( "\tadrp x16, %s\n", arm64_page( asm_name("__wine_syscall_dispatcher") ) );
2050 output( "\tldr x16, [x16, #%s]\n", arm64_pageoff( asm_name("__wine_syscall_dispatcher") ) );
2051 output( "\tbr x16\n");
2052 output_function_size( "__wine_syscall" );
2053 default:
2054 break;
2056 output( "\t.data\n" );
2057 output( "\t.align %d\n", get_alignment( get_ptr_size() ) );
2058 output( "%s\n", asm_globl("__wine_syscall_dispatcher") );
2059 output( "\t%s 0\n", get_asm_ptr_keyword() );
2063 /* output the import and delayed import tables of a Win32 module */
2064 void output_imports( DLLSPEC *spec )
2066 if (is_pe()) return;
2067 output_immediate_imports();
2068 output_delayed_imports( spec );
2069 output_immediate_import_thunks();
2070 output_delayed_import_thunks( spec );
2071 output_external_link_imports( spec );
2074 /* create a new asm temp file */
2075 static void new_output_as_file(void)
2077 char *name;
2079 if (output_file) fclose( output_file );
2080 name = open_temp_output_file( ".s" );
2081 strarray_add( &as_files, name, NULL );
2084 /* assemble all the asm files */
2085 static void assemble_files( const char *prefix )
2087 unsigned int i;
2089 if (output_file) fclose( output_file );
2090 output_file = NULL;
2092 for (i = 0; i < as_files.count; i++)
2094 char *obj = get_temp_file_name( prefix, ".o" );
2095 assemble_file( as_files.str[i], obj );
2096 as_files.str[i] = obj;
2100 /* build a library from the current asm files and any additional object files in argv */
2101 static void build_library( const char *output_name, char **argv, int create )
2103 struct strarray args;
2105 if (!create || target_platform != PLATFORM_WINDOWS)
2107 args = find_tool( "ar", NULL );
2108 strarray_add( &args, create ? "rc" : "r", output_name, NULL );
2110 else
2112 args = find_link_tool();
2113 strarray_add( &args, "/lib", strmake( "-out:%s", output_name ), NULL );
2115 strarray_addall( &args, as_files );
2116 strarray_addv( &args, argv );
2117 if (create) unlink( output_name );
2118 spawn( args );
2120 if (target_platform != PLATFORM_WINDOWS)
2122 struct strarray ranlib = find_tool( "ranlib", NULL );
2123 strarray_add( &ranlib, output_name, NULL );
2124 spawn( ranlib );
2128 /* create a Windows-style import library */
2129 static void build_windows_import_lib( const char *lib_name, DLLSPEC *spec )
2131 struct strarray args;
2132 char *def_file;
2133 const char *as_flags, *m_flag;
2135 def_file = open_temp_output_file( ".def" );
2136 output_def_file( spec, 1 );
2137 fclose( output_file );
2139 args = find_tool( "dlltool", NULL );
2140 switch (target_cpu)
2142 case CPU_x86:
2143 m_flag = "i386";
2144 as_flags = "--as-flags=--32";
2145 break;
2146 case CPU_x86_64:
2147 m_flag = "i386:x86-64";
2148 as_flags = "--as-flags=--64";
2149 break;
2150 case CPU_ARM:
2151 m_flag = "arm";
2152 as_flags = NULL;
2153 break;
2154 case CPU_ARM64:
2155 m_flag = "arm64";
2156 as_flags = NULL;
2157 break;
2158 default:
2159 m_flag = NULL;
2160 break;
2163 strarray_add( &args, "-k", strendswith( lib_name, ".delay.a" ) ? "-y" : "-l",
2164 lib_name, "-d", def_file, NULL );
2165 if (m_flag)
2166 strarray_add( &args, "-m", m_flag, as_flags, NULL );
2167 spawn( args );
2170 /* create a Unix-style import library */
2171 static void build_unix_import_lib( DLLSPEC *spec )
2173 static const char valid_chars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789._@";
2174 int i, total;
2175 const char *name, *prefix;
2176 char *dll_name = xstrdup( spec->file_name );
2178 if (strendswith( dll_name, ".dll" )) dll_name[strlen(dll_name) - 4] = 0;
2179 if (strspn( dll_name, valid_chars ) < strlen( dll_name ))
2180 fatal_error( "%s contains invalid characters\n", spec->file_name );
2182 /* entry points */
2184 for (i = total = 0; i < spec->nb_entry_points; i++)
2186 const ORDDEF *odp = &spec->entry_points[i];
2188 if (odp->name) name = odp->name;
2189 else if (odp->export_name) name = odp->export_name;
2190 else continue;
2192 if (odp->flags & FLAG_PRIVATE) continue;
2193 total++;
2195 /* C++ mangled names cannot be imported */
2196 if (strpbrk( name, "?@" )) continue;
2198 switch(odp->type)
2200 case TYPE_VARARGS:
2201 case TYPE_CDECL:
2202 case TYPE_STDCALL:
2203 prefix = (!odp->name || (odp->flags & FLAG_ORDINAL)) ? import_ord_prefix : import_func_prefix;
2204 new_output_as_file();
2205 output( "\t.text\n" );
2206 output( "\n\t.align %d\n", get_alignment( get_ptr_size() ));
2207 output( "\t%s\n", func_declaration( name ) );
2208 output( "%s\n", asm_globl( name ) );
2209 output( "\t%s %s%s$%u$%s\n", get_asm_ptr_keyword(),
2210 asm_name( prefix ), dll_name, odp->ordinal, name );
2211 output_function_size( name );
2212 output_gnu_stack_note();
2213 break;
2215 default:
2216 break;
2219 if (!total) warning( "%s: Import library doesn't export anything\n", spec->file_name );
2221 if (!as_files.count) /* create a dummy file to avoid empty import libraries */
2223 new_output_as_file();
2224 output( "\t.text\n" );
2227 assemble_files( spec->file_name );
2228 free( dll_name );
2231 /* output an import library for a Win32 module and additional object files */
2232 void output_static_lib( DLLSPEC *spec, char **argv )
2234 if (is_pe())
2236 if (spec) build_windows_import_lib( output_file_name, spec );
2237 if (argv[0] || !spec) build_library( output_file_name, argv, !spec );
2239 else
2241 if (spec) build_unix_import_lib( spec );
2242 build_library( output_file_name, argv, 1 );