winex11.drv: Map coordinates before calling send_mouse_input.
[wine/zf.git] / tools / winebuild / import.c
blobb745f16db4281535ad5b14feaafb1315539c8fc2
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( int count, const char *variant )
1426 const unsigned int invalid_param = 0xc000000d; /* STATUS_INVALID_PARAMETER */
1427 const char *symbol = strmake( "__wine_syscall_dispatcher%s", variant );
1428 unsigned int i;
1430 output( "\t.align %d\n", get_alignment(4) );
1431 output( "\t%s\n", func_declaration(symbol) );
1432 output( "%s\n", asm_globl(symbol) );
1433 output_cfi( ".cfi_startproc" );
1434 switch (target_cpu)
1436 case CPU_x86:
1437 output( "\tpushl %%ebp\n" );
1438 output_cfi( ".cfi_adjust_cfa_offset 4\n" );
1439 output_cfi( ".cfi_rel_offset %%ebp,0\n" );
1440 output( "\tmovl %%esp,%%ebp\n" );
1441 output_cfi( ".cfi_def_cfa_register %%ebp\n" );
1442 output( "\tleal -0x2c(%%esp),%%esp\n" );
1443 output( "\tmovl %%ebx,-0x14(%%ebp)\n" );
1444 output_cfi( ".cfi_rel_offset %%ebx,-0x14\n" );
1445 output( "\tmovl %%edi,-0x08(%%ebp)\n" );
1446 output_cfi( ".cfi_rel_offset %%edi,-0x08\n" );
1447 output( "\tmovl %%esi,-0x04(%%ebp)\n" );
1448 output_cfi( ".cfi_rel_offset %%esi,-0x04\n" );
1449 output( "\tpushfl\n" );
1450 output( "\tmovw %%gs,-0x1a(%%ebp)\n" );
1451 output( "\tmovw %%fs,-0x1c(%%ebp)\n" );
1452 output( "\tmovw %%es,-0x1e(%%ebp)\n" );
1453 output( "\tmovw %%ds,-0x20(%%ebp)\n" );
1454 output( "\tmovw %%ss,-0x22(%%ebp)\n" );
1455 output( "\tmovw %%cs,-0x24(%%ebp)\n" );
1456 output( "\tleal 8(%%ebp),%%ecx\n" );
1457 output( "\tmovl %%ecx,-0x28(%%ebp)\n" ); /* frame->esp */
1458 output( "\tmovl 4(%%ebp),%%ecx\n" );
1459 output( "\tmovl %%ecx,-0x2c(%%ebp)\n" ); /* frame->eip */
1460 output( "\tsubl $0x2c0,%%esp\n") ;
1461 output( "\tandl $~63,%%esp\n" );
1462 if (!*variant)
1464 output( "\tfnsave (%%esp)\n" );
1465 output( "\tfwait\n" );
1467 else if(!strcmp( variant, "_fxsave" ))
1469 output( "\tfxsave (%%esp)\n" );
1471 else if(!strcmp( variant, "_xsave" ))
1473 output( "\tmovl %%eax,%%ecx\n ");
1474 output( "\tmovl $7,%%eax\n" );
1475 output( "\txorl %%edx,%%edx\n" );
1476 for (i = 0; i < 6; i++)
1477 output( "\tmovl %%edx,0x%x(%%esp)\n", 0x200 + i * 4 );
1478 output( "\txsave (%%esp)\n" );
1479 output( "\tmovl %%ecx,%%eax\n ");
1481 else /* _xsavec */
1483 output( "\tmovl %%eax,%%ecx\n ");
1484 output( "\tmovl $7,%%eax\n" );
1485 output( "\txorl %%edx,%%edx\n" );
1486 for (i = 0; i < 16; i++)
1487 output( "\tmovl %%edx,0x%x(%%esp)\n", 0x200 + i * 4 );
1488 output( "\txsavec (%%esp)\n" );
1489 output( "\tmovl %%ecx,%%eax\n ");
1491 output( "\tleal -0x30(%%ebp),%%ecx\n" );
1492 output( "\tmovl %%ecx,%%fs:0x1f8\n" ); /* x86_thread_data()->syscall_frame */
1493 output( "\tcmpl $%u,%%eax\n", count );
1494 output( "\tjae 4f\n" );
1495 if (UsePIC)
1497 output( "\tmovl %%eax,%%edx\n" );
1498 output( "\tcall %s\n", asm_name("__wine_spec_get_pc_thunk_eax") );
1499 output( "1:\tmovzbl .Lsyscall_args-1b(%%eax,%%edx,1),%%ecx\n" );
1500 needs_get_pc_thunk = 1;
1502 else output( "\tmovzbl .Lsyscall_args(%%eax),%%ecx\n" );
1503 output( "\tsubl %%ecx,%%esp\n" );
1504 output( "\tshrl $2,%%ecx\n" );
1505 output( "\tleal 12(%%ebp),%%esi\n" );
1506 output( "\tandl $~15,%%esp\n" );
1507 output( "\tmovl %%esp,%%edi\n" );
1508 output( "\tcld\n" );
1509 output( "\trep; movsl\n" );
1510 if (UsePIC)
1511 output( "\tcall *.Lsyscall_table-1b(%%eax,%%edx,4)\n" );
1512 else
1513 output( "\tcall *.Lsyscall_table(,%%eax,4)\n" );
1514 output( "2:\tmovl $0,%%fs:0x1f8\n" );
1515 output( "\tleal -0x2f0(%%ebp),%%ebx\n") ;
1516 output( "\tandl $~63,%%ebx\n" );
1517 if (!*variant)
1519 output( "\tfrstor (%%ebx)\n" );
1520 output( "\tfwait\n" );
1522 else if(!strcmp( variant, "_fxsave" ))
1524 output( "\tfxrstor (%%ebx)\n" );
1526 else
1528 output( "\tmovl %%eax,%%ecx\n" );
1529 output( "\tmovl $7,%%eax\n" );
1530 output( "\txorl %%edx,%%edx\n" );
1531 output( "\txrstor (%%ebx)\n" );
1532 output( "\tmovl %%ecx,%%eax\n" );
1534 output( "\tleal -0x30(%%ebp),%%ebx\n" );
1535 output_cfi( ".cfi_def_cfa_register %%ebx" );
1536 output_cfi( ".cfi_adjust_cfa_offset 0x30\n" );
1537 output( "\tmovl %%eax,0x18(%%ebx)\n" );
1538 output( "\tmovw 0x16(%%ebx),%%gs\n" );
1539 output( "\tmovw 0x14(%%ebx),%%fs\n" );
1540 output( "\tmovw 0x12(%%ebx),%%es\n" );
1541 output( "\tmovl 0x28(%%ebx),%%edi\n" );
1542 output_cfi( ".cfi_same_value %%edi" );
1543 output( "\tmovl 0x2c(%%ebx),%%esi\n" );
1544 output_cfi( ".cfi_same_value %%esi" );
1545 output( "\tmovl (%%ebp),%%ebp\n" );
1546 output_cfi( ".cfi_same_value %%ebp" );
1547 output( "\tmovw %%ss,%%cx\n" );
1548 output( "\tcmpw 0x0e(%%ebx),%%cx\n" );
1549 output( "\tjne 3f\n" );
1550 /* As soon as we have switched stacks the context structure could
1551 * be invalid (when signal handlers are executed for example). Copy
1552 * values on the target stack before changing ESP. */
1553 output( "\tmovl 0x08(%%ebx),%%ecx\n" );
1554 output( "\tleal -3*4(%%ecx),%%ecx\n" );
1555 output( "\tmovl (%%ebx),%%edx\n" );
1556 output( "\tmovl %%edx,2*4(%%ecx)\n" );
1557 output( "\tmovl 0x0c(%%ebx),%%edx\n" );
1558 output( "\tmovl %%edx,1*4(%%ecx)\n" );
1559 output( "\tmovl 0x04(%%ebx),%%edx\n" );
1560 output( "\tmovl %%edx,0*4(%%ecx)\n" );
1561 output( "\tpushl 0x10(%%ebx)\n" );
1562 output( "\tmovl 0x1c(%%ebx),%%ebx\n" );
1563 output_cfi( ".cfi_same_value %%ebx" );
1564 output( "\tpopl %%ds\n" );
1565 output( "\tmovl %%ecx,%%esp\n" );
1566 output( "\tiret\n" );
1567 /* Restore the context when the stack segment changes. We can't use
1568 * the same code as above because we do not know if the stack segment
1569 * is 16 or 32 bit, and 'movl' will throw an exception when we try to
1570 * access memory above the limit. */
1571 output( "\t3:\tmovl 0x18(%%ebx),%%ecx\n" );
1572 output( "\tmovw 0x0e(%%ebx),%%ss\n" );
1573 output( "\tmovl 0x08(%%ebx),%%esp\n" );
1574 output( "\tpushl 0x00(%%ebx)\n" );
1575 output( "\tpushl 0x0c(%%ebx)\n" );
1576 output( "\tpushl 0x04(%%ebx)\n" );
1577 output( "\tpushl 0x10(%%ebx)\n" );
1578 output( "\tmovl 0x1c(%%ebx),%%ebx\n" );
1579 output( "\tpopl %%ds\n" );
1580 output( "\tiret\n" );
1581 output( "4:\tmovl $0x%x,%%eax\n", invalid_param );
1582 output( "\tjmp 2b\n" );
1583 break;
1584 case CPU_x86_64:
1585 output( "\tpushq %%rbp\n" );
1586 output_cfi( ".cfi_adjust_cfa_offset 8" );
1587 output_cfi( ".cfi_rel_offset %%rbp,0" );
1588 output( "\tmovq %%rsp,%%rbp\n" );
1589 output_cfi( ".cfi_def_cfa_register %%rbp" );
1590 output( "\tleaq -0x10(%%rbp),%%rsp\n" );
1591 output( "\tpushfq\n" );
1592 output( "\tsubq $0x3c0,%%rsp\n" );
1593 output( "\tandq $~63,%%rsp\n" );
1594 output( "\tmovq %%rbx,-0x90(%%rbp)\n" );
1595 output_cfi( ".cfi_rel_offset %%rbx,-144" );
1596 output( "\tmovq %%rsi,-0x78(%%rbp)\n" );
1597 output_cfi( ".cfi_rel_offset %%rsi,-120" );
1598 output( "\tmovq %%rdi,-0x70(%%rbp)\n" );
1599 output_cfi( ".cfi_rel_offset %%rdi,-112" );
1600 output( "\tmovq %%r12,-0x48(%%rbp)\n" );
1601 output_cfi( ".cfi_rel_offset %%r12,-72" );
1602 output( "\tmovq %%r13,-0x40(%%rbp)\n" );
1603 output( "\tmovq %%r14,-0x38(%%rbp)\n" );
1604 output( "\tmovq %%r15,-0x30(%%rbp)\n" );
1605 /* Legends of Runeterra hooks the first system call return instruction, and
1606 * depends on us returning to it. Adjust the return address accordingly. */
1607 output( "\tsubq $0xb,0x8(%%rbp)\n" );
1608 output( "\tmovq 0x8(%%rbp),%%rbx\n" );
1609 output( "\tmovq %%rbx,-0x28(%%rbp)\n" );
1610 output( "\tleaq 0x10(%%rbp),%%rbx\n" );
1611 output( "\tmovq %%rbx,-0x10(%%rbp)\n" );
1612 output( "\tmovw %%cs,-0x20(%%rbp)\n" );
1613 output( "\tmovw %%ds,-0x1e(%%rbp)\n" );
1614 output( "\tmovw %%es,-0x1c(%%rbp)\n" );
1615 output( "\tmovw %%fs,-0x1a(%%rbp)\n" );
1616 output( "\tmovw %%ss,-0x8(%%rbp)\n" );
1617 output( "\tmovw %%gs,-0x6(%%rbp)\n" );
1618 output( "\tmovq %%rsp,%%r12\n" );
1619 output( "\tmovq %%rax,%%r11\n" );
1620 if (!*variant)
1622 output( "\tfxsave64 (%%r12)\n" );
1624 else
1626 output( "\tmovl $7,%%eax\n" );
1627 output( "\tmovq %%rdx,%%rsi\n" );
1628 output( "\txorq %%rdx,%%rdx\n" );
1629 output( "\tmovq %%rdx,0x200(%%r12)\n" );
1630 output( "\tmovq %%rdx,0x208(%%r12)\n" );
1631 output( "\tmovq %%rdx,0x210(%%r12)\n" );
1632 if (!strcmp( variant, "_xsavec" ))
1634 output( "\tmovq %%rdx,0x218(%%r12)\n" );
1635 output( "\tmovq %%rdx,0x220(%%r12)\n" );
1636 output( "\tmovq %%rdx,0x228(%%r12)\n" );
1637 output( "\tmovq %%rdx,0x230(%%r12)\n" );
1638 output( "\tmovq %%rdx,0x238(%%r12)\n" );
1639 output( "\txsavec64 (%%r12)\n" );
1641 else
1642 output( "\txsave64 (%%r12)\n" );
1643 output( "\tmovq %%rsi,%%rdx\n" );
1645 output( "\tmovq %%gs:0x30,%%rcx\n" );
1646 output( "\tleaq -0x98(%%rbp),%%rbx\n" );
1647 output( "\tmovq %%rbx,0x328(%%rcx)\n" ); /* amd64_thread_data()->syscall_frame */
1648 output( "\tcmpq $%u,%%r11\n", count );
1649 output( "\tjae 3f\n" );
1650 output( "\tleaq .Lsyscall_args(%%rip),%%rcx\n" );
1651 output( "\tmovzbl (%%rcx,%%r11),%%ecx\n" );
1652 output( "\tsubq $0x20,%%rcx\n" );
1653 output( "\tjbe 1f\n" );
1654 output( "\tsubq %%rcx,%%rsp\n" );
1655 output( "\tshrq $3,%%rcx\n" );
1656 output( "\tleaq 0x38(%%rbp),%%rsi\n" );
1657 output( "\tandq $~15,%%rsp\n\t" );
1658 output( "\tmovq %%rsp,%%rdi\n" );
1659 output( "\tcld\n" );
1660 output( "\trep; movsq\n" );
1661 output( "1:\tmovq %%r10,%%rcx\n" );
1662 output( "\tsubq $0x20,%%rsp\n" );
1663 output( "\tleaq .Lsyscall_table(%%rip),%%r10\n" );
1664 output( "\tcallq *(%%r10,%%r11,8)\n" );
1665 output( "2:\tmovq %%gs:0x30,%%rcx\n" );
1666 output( "\tmovq $0,0x328(%%rcx)\n" );
1667 if (!*variant)
1669 output( "\tfxrstor64 (%%r12)\n" );
1671 else
1673 output( "\tmovq %%rax,%%r11\n" );
1674 output( "\tmovl $7,%%eax\n" );
1675 output( "\txorq %%rdx,%%rdx\n" );
1676 output( "\txrstor64 (%%r12)\n" );
1677 output( "\tmovq %%r11,%%rax\n" );
1679 output( "\tmovq -0x30(%%rbp),%%r15\n" );
1680 output( "\tmovq -0x38(%%rbp),%%r14\n" );
1681 output( "\tmovq -0x40(%%rbp),%%r13\n" );
1682 output( "\tmovq -0x48(%%rbp),%%r12\n" );
1683 output_cfi( ".cfi_same_value %%r12" );
1684 output( "\tmovq -0x70(%%rbp),%%rdi\n" );
1685 output_cfi( ".cfi_same_value %%rdi" );
1686 output( "\tmovq -0x78(%%rbp),%%rsi\n" );
1687 output_cfi( ".cfi_same_value %%rsi" );
1688 output( "\tmovq -0x90(%%rbp),%%rbx\n" );
1689 output_cfi( ".cfi_same_value %%rbx" );
1690 output( "\tleaq -0x28(%%rbp),%%rsp\n" );
1691 output_cfi( ".cfi_def_cfa_register %%rsp" );
1692 output_cfi( ".cfi_adjust_cfa_offset 40" );
1693 output( "\tmovq (%%rbp),%%rbp\n" );
1694 output_cfi( ".cfi_same_value %%rbp" );
1695 output( "\tiretq\n" );
1696 output( "3:\tmovl $0x%x,%%eax\n", invalid_param );
1697 output( "\tjmp 2b\n" );
1698 break;
1699 case CPU_ARM:
1700 output( "\tpush {r5-r11,lr}\n" );
1701 output( "\tadd r6, sp, #40\n" ); /* stack parameters */
1702 output( "\tldr r5, 6f+8\n" );
1703 output( "\tcmp r4, r5\n" );
1704 output( "\tbcs 5f\n" );
1705 output( "\tsub sp, sp, #8\n" );
1706 output( "\tmrc p15, 0, r7, c13, c0, 2\n" ); /* NtCurrentTeb() */
1707 output( "\tadd r7, #0x1d8\n" ); /* arm_thread_data()->syscall_frame */
1708 output( "\tmrs ip, CPSR\n" );
1709 output( "\tbfi ip, lr, #5, #1\n" ); /* set thumb bit */
1710 output( "\tstr ip, [sp, #4]\n" );
1711 output( "\tstr sp, [r7]\n" ); /* syscall frame */
1712 output( "\tldr r5, 6f+4\n");
1713 if (UsePIC) output( "1:\tadd r5, pc\n");
1714 output( "\tldrb r5, [r5, r4]\n" ); /* syscall args */
1715 output( "\tsubs r5, #16\n" ); /* first 4 args are in registers */
1716 output( "\tble 3f\n" );
1717 output( "\tsub ip, sp, r5\n" );
1718 output( "\tand ip, #~7\n" );
1719 output( "\tmov sp, ip\n" );
1720 output( "2:\tsubs r5, r5, #4\n" );
1721 output( "\tldr ip, [r6, r5]\n" );
1722 output( "\tstr ip, [sp, r5]\n" );
1723 output( "\tbgt 2b\n" );
1724 output( "3:\tldr r5, 6f\n");
1725 if (UsePIC) output( "4:\tadd r5, pc\n");
1726 output( "\tldr ip, [r5, r4, lsl #2]\n"); /* syscall table */
1727 output( "\tblx ip\n");
1728 output( "\tmov ip, #0\n" );
1729 output( "\tstr ip, [r7]\n" );
1730 output( "\tsub ip, r6, #40\n" );
1731 output( "\tmov sp, ip\n" );
1732 output( "\tpop {r5-r11,pc}\n" );
1733 output( "5:\tldr r0, 6f+12\n" );
1734 output( "\tpop {r5-r11,pc}\n" );
1735 if (UsePIC)
1737 output( "6:\t.long .Lsyscall_table-4b-%u\n", thumb_mode ? 4 : 8 );
1738 output( "\t.long .Lsyscall_args-1b-%u\n", thumb_mode ? 4 : 8 );
1740 else
1742 output( "6:\t.long .Lsyscall_table\n" );
1743 output( "\t.long .Lsyscall_args\n" );
1745 output( "\t.long %u\n", count );
1746 output( "\t.long 0x%x\n", invalid_param );
1747 break;
1748 case CPU_ARM64:
1749 output( "\tcmp x8, %u\n", count );
1750 output( "\tbcs 3f\n" );
1751 output( "\tstp x29, x30, [sp,#-160]!\n" );
1752 output_cfi( "\t.cfi_def_cfa_offset 160\n" );
1753 output_cfi( "\t.cfi_offset 29, -160\n" );
1754 output_cfi( "\t.cfi_offset 30, -152\n" );
1755 output( "\tmov x29, sp\n" );
1756 output_cfi( "\t.cfi_def_cfa_register 29\n" );
1757 output( "\tstp x27, x28, [sp, #144]\n" );
1758 output_cfi( "\t.cfi_offset 27, -16\n" );
1759 output_cfi( "\t.cfi_offset 28, -8\n" );
1760 output( "\tstp x25, x26, [sp, #128]\n" );
1761 output_cfi( "\t.cfi_offset 25, -32\n" );
1762 output_cfi( "\t.cfi_offset 26, -24\n" );
1763 output( "\tstp x23, x24, [sp, #112]\n" );
1764 output_cfi( "\t.cfi_offset 23, -48\n" );
1765 output_cfi( "\t.cfi_offset 24, -40\n" );
1766 output( "\tstp x21, x22, [sp, #96]\n" );
1767 output_cfi( "\t.cfi_offset 21, -64\n" );
1768 output_cfi( "\t.cfi_offset 22, -56\n" );
1769 output( "\tstp x19, x20, [sp, #80]\n" );
1770 output_cfi( "\t.cfi_offset 19, -80\n" );
1771 output_cfi( "\t.cfi_offset 20, -72\n" );
1772 output( "\tstp x6, x7, [sp, #64]\n" );
1773 output( "\tstp x4, x5, [sp, #48]\n" );
1774 output( "\tstp x2, x3, [sp, #32]\n" );
1775 output( "\tstp x0, x1, [sp, #16]\n" );
1776 output( "\tmov x20, x8\n" );
1777 output( "\tbl %s\n", asm_name("NtCurrentTeb") );
1778 output( "\tadd x19, x0, #0x2f8\n" ); /* arm64_thread_data()->syscall_frame */
1779 output( "\tstr x29, [x19]\n" );
1780 output( "\tldp x0, x1, [sp, #16]\n" );
1781 output( "\tldp x2, x3, [sp, #32]\n" );
1782 output( "\tldp x4, x5, [sp, #48]\n" );
1783 output( "\tldp x6, x7, [sp, #64]\n" );
1784 output( "\tadrp x16, %s\n", arm64_page(".Lsyscall_args") );
1785 output( "\tadd x16, x16, #%s\n", arm64_pageoff(".Lsyscall_args") );
1786 output( "\tldrb w9, [x16, x20]\n" );
1787 output( "\tsubs x9, x9, #64\n" );
1788 output( "\tbls 2f\n" );
1789 output( "\tadd x11, x29, #176\n" );
1790 output( "\tsub sp, sp, x9\n" );
1791 output( "\ttbz x9, #3, 1f\n" );
1792 output( "\tsub sp, sp, #8\n" );
1793 output( "1:\tsub x9, x9, #8\n" );
1794 output( "\tldr x10, [x11, x9]\n" );
1795 output( "\tstr x10, [sp, x9]\n" );
1796 output( "\tcbnz x9, 1b\n" );
1797 output( "2:\tadrp x16, %s\n", arm64_page(".Lsyscall_table") );
1798 output( "\tadd x16, x16, #%s\n", arm64_pageoff(".Lsyscall_table") );
1799 output( "\tldr x16, [x16, x20, lsl 3]\n" );
1800 output( "\tblr x16\n" );
1801 output( "\tmov sp, x29\n" );
1802 output( "\tstr xzr, [x19]\n" );
1803 output( "\tldp x19, x20, [sp, #80]\n" );
1804 output( "\tldp x21, x22, [sp, #96]\n" );
1805 output( "\tldp x23, x24, [sp, #112]\n" );
1806 output( "\tldp x25, x26, [sp, #128]\n" );
1807 output( "\tldp x27, x28, [sp, #144]\n" );
1808 output( "\tldp x29, x30, [sp], #160\n" );
1809 output( "\tret\n" );
1810 output( "3:\tmov x0, #0x%x\n", invalid_param & 0xffff0000 );
1811 output( "\tmovk x0, #0x%x\n", invalid_param & 0x0000ffff );
1812 output( "\tret\n" );
1813 break;
1814 default:
1815 assert(0);
1817 output_cfi( ".cfi_endproc" );
1818 output_function_size( symbol );
1822 /* output the functions for system calls */
1823 void output_syscalls( DLLSPEC *spec )
1825 int i, count;
1826 ORDDEF **syscalls = NULL;
1828 for (i = count = 0; i < spec->nb_entry_points; i++)
1830 ORDDEF *odp = &spec->entry_points[i];
1831 if (!(odp->flags & FLAG_SYSCALL)) continue;
1832 if (!syscalls) syscalls = xmalloc( (spec->nb_entry_points - i) * sizeof(*syscalls) );
1833 syscalls[count++] = odp;
1835 if (!count) return;
1836 count = sort_func_list( syscalls, count, cmp_link_name );
1838 output( "\n/* system calls */\n\n" );
1839 output( "\t.text\n" );
1841 if (unix_lib)
1843 output_syscall_dispatcher( count, "" );
1845 switch( target_cpu )
1847 case CPU_x86:
1848 output_syscall_dispatcher( count, "_fxsave" );
1849 output_syscall_dispatcher( count, "_xsave" );
1850 output_syscall_dispatcher( count, "_xsavec" );
1851 break;
1852 case CPU_x86_64:
1853 output_syscall_dispatcher( count, "_xsave" );
1854 output_syscall_dispatcher( count, "_xsavec" );
1855 break;
1856 default:
1857 break;
1860 output( "\t.data\n" );
1861 output( "\t.align %d\n", get_alignment( get_ptr_size() ) );
1862 output( ".Lsyscall_table:\n" );
1863 for (i = 0; i < count; i++)
1864 output( "\t%s %s\n", get_asm_ptr_keyword(), asm_name( get_link_name( syscalls[i] )));
1865 output( ".Lsyscall_args:\n" );
1866 for (i = 0; i < count; i++)
1867 output( "\t.byte %u\n", get_args_size( syscalls[i] ));
1868 return;
1871 for (i = 0; i < count; i++)
1873 ORDDEF *odp = syscalls[i];
1874 const char *name = get_link_name(odp);
1875 output( "\t.align %d\n", get_alignment(16) );
1876 output( "\t%s\n", func_declaration(name) );
1877 output( "%s\n", asm_globl(name) );
1878 output_cfi( ".cfi_startproc" );
1879 switch (target_cpu)
1881 case CPU_x86:
1882 if (UsePIC)
1884 output( "\tcall %s\n", asm_name("__wine_spec_get_pc_thunk_eax") );
1885 output( "1:\tmovl %s-1b(%%eax),%%edx\n", asm_name("__wine_syscall_dispatcher") );
1886 output( "\tmovl $%u,%%eax\n", i );
1887 needs_get_pc_thunk = 1;
1889 else
1891 output( "\tmovl $%u,%%eax\n", i );
1892 output( "\tmovl $%s,%%edx\n", asm_name("__wine_syscall") );
1894 output( "\tcall *%%edx\n" );
1895 output( "\tret $%u\n", odp->type == TYPE_STDCALL ? get_args_size( odp ) : 0 );
1896 break;
1897 case CPU_x86_64:
1898 /* Chromium depends on syscall thunks having the same form as on
1899 * Windows. For 64-bit systems the only viable form we can emulate is
1900 * having an int $0x2e fallback. Since actually using an interrupt is
1901 * expensive, and since for some reason Chromium doesn't actually
1902 * validate that instruction, we can just put a jmp there instead. */
1903 output( "\t.byte 0x4c,0x8b,0xd1\n" ); /* movq %rcx,%r10 */
1904 output( "\t.byte 0xb8\n" ); /* movl $i,%eax */
1905 output( "\t.long %u\n", i );
1906 output( "\t.byte 0xf6,0x04,0x25,0x08,0x03,0xfe,0x7f,0x01\n" ); /* testb $1,0x7ffe0308 */
1907 output( "\t.byte 0x75,0x03\n" ); /* jne 1f */
1908 output( "\t.byte 0x0f,0x05\n" ); /* syscall */
1909 output( "\t.byte 0xc3\n" ); /* ret */
1910 output( "\tjmp 1f\n" );
1911 output( "\t.byte 0xc3\n" ); /* ret */
1912 if (is_pe())
1914 output( "1:\t.byte 0xff,0x14,0x25\n" ); /* 1: callq *(0x7ffe1000) */
1915 output( "\t.long 0x7ffe1000\n" );
1917 else
1919 output( "\tnop\n" );
1920 output( "1:\tcallq *%s(%%rip)\n", asm_name("__wine_syscall_dispatcher") );
1922 output( "\tret\n" );
1923 break;
1924 case CPU_ARM:
1925 output( "\tpush {r4,lr}\n" );
1926 output( "\tmov r4, #%u\n", i );
1927 if (UsePIC)
1929 output( "\tldr ip, 2f\n");
1930 output( "1:\tadd ip, pc\n" );
1932 else
1934 output( "\tmovw ip, :lower16:%s\n", asm_name("__wine_syscall_dispatcher") );
1935 output( "\tmovt ip, :upper16:%s\n", asm_name("__wine_syscall_dispatcher") );
1937 output( "\tldr ip, [ip]\n");
1938 output( "\tblx ip\n");
1939 output( "\tpop {r4,pc}\n" );
1940 if (UsePIC) output( "2:\t.long %s-1b-%u\n", asm_name("__wine_syscall_dispatcher"), thumb_mode ? 4 : 8 );
1941 break;
1942 case CPU_ARM64:
1943 output( "\tstp x29, x30, [sp,#-16]!\n" );
1944 output_cfi( "\t.cfi_def_cfa_offset 16\n" );
1945 output_cfi( "\t.cfi_offset 29, -16\n" );
1946 output_cfi( "\t.cfi_offset 30, -8\n" );
1947 output( "\tmov x8, #%u\n", i );
1948 output( "\tadrp x16, %s\n", arm64_page( asm_name("__wine_syscall_dispatcher") ) );
1949 output( "\tldr x16, [x16, #%s]\n", arm64_pageoff( asm_name("__wine_syscall_dispatcher") ) );
1950 output( "\tblr x16\n");
1951 output( "\tldp x29, x30, [sp], #16\n" );
1952 output( "\tret\n" );
1953 break;
1954 default:
1955 assert(0);
1957 output_cfi( ".cfi_endproc" );
1958 output_function_size( name );
1961 if (target_cpu == CPU_x86 && !UsePIC)
1963 output( "\t.align %d\n", get_alignment(16) );
1964 output( "\t%s\n", func_declaration("__wine_syscall") );
1965 output( "%s:\n", asm_name("__wine_syscall") );
1966 output( "\tjmp *(%s)\n", asm_name("__wine_syscall_dispatcher") );
1967 output_function_size( "__wine_syscall" );
1969 output( "\t.data\n" );
1970 output( "\t.align %d\n", get_alignment( get_ptr_size() ) );
1971 output( "%s\n", asm_globl("__wine_syscall_dispatcher") );
1972 output( "\t%s 0\n", get_asm_ptr_keyword() );
1976 /* output the import and delayed import tables of a Win32 module */
1977 void output_imports( DLLSPEC *spec )
1979 if (is_pe()) return;
1980 output_immediate_imports();
1981 output_delayed_imports( spec );
1982 output_immediate_import_thunks();
1983 output_delayed_import_thunks( spec );
1984 output_external_link_imports( spec );
1987 /* create a new asm temp file */
1988 static void new_output_as_file(void)
1990 char *name;
1992 if (output_file) fclose( output_file );
1993 name = open_temp_output_file( ".s" );
1994 strarray_add( &as_files, name, NULL );
1997 /* assemble all the asm files */
1998 static void assemble_files( const char *prefix )
2000 unsigned int i;
2002 if (output_file) fclose( output_file );
2003 output_file = NULL;
2005 for (i = 0; i < as_files.count; i++)
2007 char *obj = get_temp_file_name( prefix, ".o" );
2008 assemble_file( as_files.str[i], obj );
2009 as_files.str[i] = obj;
2013 /* build a library from the current asm files and any additional object files in argv */
2014 static void build_library( const char *output_name, char **argv, int create )
2016 struct strarray args;
2018 if (!create || target_platform != PLATFORM_WINDOWS)
2020 args = find_tool( "ar", NULL );
2021 strarray_add( &args, create ? "rc" : "r", output_name, NULL );
2023 else
2025 args = find_link_tool();
2026 strarray_add( &args, "/lib", strmake( "-out:%s", output_name ), NULL );
2028 strarray_addall( &args, as_files );
2029 strarray_addv( &args, argv );
2030 if (create) unlink( output_name );
2031 spawn( args );
2033 if (target_platform != PLATFORM_WINDOWS)
2035 struct strarray ranlib = find_tool( "ranlib", NULL );
2036 strarray_add( &ranlib, output_name, NULL );
2037 spawn( ranlib );
2041 /* create a Windows-style import library */
2042 static void build_windows_import_lib( const char *lib_name, DLLSPEC *spec )
2044 struct strarray args;
2045 char *def_file;
2046 const char *as_flags, *m_flag;
2048 def_file = open_temp_output_file( ".def" );
2049 output_def_file( spec, 1 );
2050 fclose( output_file );
2052 args = find_tool( "dlltool", NULL );
2053 switch (target_cpu)
2055 case CPU_x86:
2056 m_flag = "i386";
2057 as_flags = "--as-flags=--32";
2058 break;
2059 case CPU_x86_64:
2060 m_flag = "i386:x86-64";
2061 as_flags = "--as-flags=--64";
2062 break;
2063 case CPU_ARM:
2064 m_flag = "arm";
2065 as_flags = NULL;
2066 break;
2067 case CPU_ARM64:
2068 m_flag = "arm64";
2069 as_flags = NULL;
2070 break;
2071 default:
2072 m_flag = NULL;
2073 break;
2076 strarray_add( &args, "-k", strendswith( lib_name, ".delay.a" ) ? "-y" : "-l",
2077 lib_name, "-d", def_file, NULL );
2078 if (m_flag)
2079 strarray_add( &args, "-m", m_flag, as_flags, NULL );
2080 spawn( args );
2083 /* create a Unix-style import library */
2084 static void build_unix_import_lib( DLLSPEC *spec )
2086 static const char valid_chars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789._@";
2087 int i, total;
2088 const char *name, *prefix;
2089 char *dll_name = xstrdup( spec->file_name );
2091 if (strendswith( dll_name, ".dll" )) dll_name[strlen(dll_name) - 4] = 0;
2092 if (strspn( dll_name, valid_chars ) < strlen( dll_name ))
2093 fatal_error( "%s contains invalid characters\n", spec->file_name );
2095 /* entry points */
2097 for (i = total = 0; i < spec->nb_entry_points; i++)
2099 const ORDDEF *odp = &spec->entry_points[i];
2101 if (odp->name) name = odp->name;
2102 else if (odp->export_name) name = odp->export_name;
2103 else continue;
2105 if (odp->flags & FLAG_PRIVATE) continue;
2106 total++;
2108 /* C++ mangled names cannot be imported */
2109 if (strpbrk( name, "?@" )) continue;
2111 switch(odp->type)
2113 case TYPE_VARARGS:
2114 case TYPE_CDECL:
2115 case TYPE_STDCALL:
2116 prefix = (!odp->name || (odp->flags & FLAG_ORDINAL)) ? import_ord_prefix : import_func_prefix;
2117 new_output_as_file();
2118 output( "\t.text\n" );
2119 output( "\n\t.align %d\n", get_alignment( get_ptr_size() ));
2120 output( "\t%s\n", func_declaration( name ) );
2121 output( "%s\n", asm_globl( name ) );
2122 output( "\t%s %s%s$%u$%s\n", get_asm_ptr_keyword(),
2123 asm_name( prefix ), dll_name, odp->ordinal, name );
2124 output_function_size( name );
2125 output_gnu_stack_note();
2126 break;
2128 default:
2129 break;
2132 if (!total) warning( "%s: Import library doesn't export anything\n", spec->file_name );
2134 if (!as_files.count) /* create a dummy file to avoid empty import libraries */
2136 new_output_as_file();
2137 output( "\t.text\n" );
2140 assemble_files( spec->file_name );
2141 free( dll_name );
2144 /* output an import library for a Win32 module and additional object files */
2145 void output_static_lib( DLLSPEC *spec, char **argv )
2147 if (is_pe())
2149 if (spec) build_windows_import_lib( output_file_name, spec );
2150 if (argv[0] || !spec) build_library( output_file_name, argv, !spec );
2152 else
2154 if (spec) build_unix_import_lib( spec );
2155 build_library( output_file_name, argv, 1 );