winebuild: Add GNU stack note also to the undefined symbols file.
[wine.git] / tools / winebuild / import.c
blobb1c14db9cabf12d2fbbed3b7dcffcbea09ba1e98
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"
24 #include <assert.h>
25 #include <ctype.h>
26 #include <fcntl.h>
27 #include <stdio.h>
28 #include <string.h>
29 #include <stdarg.h>
31 #include "wine/list.h"
32 #include "build.h"
34 /* standard C functions that are also exported from ntdll */
35 static const char *stdc_names[] =
37 "abs",
38 "atan",
39 "atoi",
40 "atol",
41 "bsearch",
42 "ceil",
43 "cos",
44 "fabs",
45 "floor",
46 "isalnum",
47 "isalpha",
48 "iscntrl",
49 "isdigit",
50 "isgraph",
51 "islower",
52 "isprint",
53 "ispunct",
54 "isspace",
55 "isupper",
56 "iswalpha",
57 "iswctype",
58 "iswdigit",
59 "iswlower",
60 "iswspace",
61 "iswxdigit",
62 "isxdigit",
63 "labs",
64 "log",
65 "mbstowcs",
66 "memchr",
67 "memcmp",
68 "memcpy",
69 "memmove",
70 "memset",
71 "pow",
72 "qsort",
73 "sin",
74 "sprintf",
75 "sqrt",
76 "sscanf",
77 "strcat",
78 "strchr",
79 "strcmp",
80 "strcpy",
81 "strcspn",
82 "strlen",
83 "strncat",
84 "strncmp",
85 "strncpy",
86 "strnlen",
87 "strpbrk",
88 "strrchr",
89 "strspn",
90 "strstr",
91 "strtol",
92 "strtoul",
93 "swprintf",
94 "tan",
95 "tolower",
96 "toupper",
97 "towlower",
98 "towupper",
99 "vsprintf",
100 "wcscat",
101 "wcschr",
102 "wcscmp",
103 "wcscpy",
104 "wcscspn",
105 "wcslen",
106 "wcsncat",
107 "wcsncmp",
108 "wcsncpy",
109 "wcspbrk",
110 "wcsrchr",
111 "wcsspn",
112 "wcsstr",
113 "wcstok",
114 "wcstol",
115 "wcstombs",
116 "wcstoul"
119 static const struct strarray stdc_functions = { ARRAY_SIZE(stdc_names), ARRAY_SIZE(stdc_names), stdc_names };
121 struct import_func
123 const char *name;
124 const char *export_name;
125 int ordinal;
126 int hint;
129 struct import
131 struct list entry; /* entry in global dll list */
132 char *dll_name; /* exported file name of the dll */
133 char *c_name; /* dll name as a C-compatible identifier */
134 char *full_name; /* full name of the input file */
135 dev_t dev; /* device/inode of the input file */
136 ino_t ino;
137 ORDDEF **exports; /* functions exported from this dll */
138 int nb_exports; /* number of exported functions */
139 struct import_func *imports; /* functions we want to import from this dll */
140 int nb_imports; /* number of imported functions */
141 int max_imports; /* size of imports array */
144 static struct strarray undef_symbols; /* list of undefined symbols */
145 static struct strarray extra_ld_symbols; /* list of extra symbols that ld should resolve */
146 static struct strarray delayed_imports; /* list of delayed import dlls */
147 static struct strarray ext_link_imports; /* list of external symbols to link to */
149 static struct list dll_imports = LIST_INIT( dll_imports );
150 static struct list dll_delayed = LIST_INIT( dll_delayed );
152 static struct strarray as_files;
154 static const char import_func_prefix[] = "__wine$func$";
155 static const char import_ord_prefix[] = "__wine$ord$";
157 /* compare function names; helper for resolve_imports */
158 static int name_cmp( const char **name, const char **entry )
160 return strcmp( *name, *entry );
163 /* compare function names; helper for resolve_imports */
164 static int func_cmp( const void *func1, const void *func2 )
166 const ORDDEF *odp1 = *(const ORDDEF * const *)func1;
167 const ORDDEF *odp2 = *(const ORDDEF * const *)func2;
168 return strcmp( odp1->name ? odp1->name : odp1->export_name,
169 odp2->name ? odp2->name : odp2->export_name );
172 /* remove a name from a name table */
173 static inline void remove_name( struct strarray *table, unsigned int idx )
175 assert( idx < table->count );
176 memmove( table->str + idx, table->str + idx + 1,
177 (table->count - idx - 1) * sizeof(*table->str) );
178 table->count--;
181 /* locate a name in a (sorted) list */
182 static inline const char *find_name( const char *name, struct strarray table )
184 return strarray_bsearch( &table, name, name_cmp );
187 /* sort a name table */
188 static inline void sort_names( struct strarray *table )
190 strarray_qsort( table, name_cmp );
193 /* locate an export in a (sorted) export list */
194 static inline ORDDEF *find_export( const char *name, ORDDEF **table, int size )
196 ORDDEF func, *odp, **res = NULL;
198 func.name = func.export_name = xstrdup(name);
199 odp = &func;
200 if (table) res = bsearch( &odp, table, size, sizeof(*table), func_cmp );
201 free( func.name );
202 return res ? *res : NULL;
205 static const char valid_chars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_.";
207 /* encode a dll name into a linker-compatible name */
208 static char *encode_dll_name( const char *name )
210 char *p, *ret;
211 int len = strlen(name);
213 if (strendswith( name, ".dll" )) len -= 4;
214 if (strspn( name, valid_chars ) >= len) return strmake( "%.*s", len, name );
216 ret = p = xmalloc( len * 4 + 1 );
217 for ( ; len > 0; len--, name++)
219 if (!strchr( valid_chars, *name )) p += sprintf( p, "$x%02x", *name );
220 else *p++ = *name;
222 *p = 0;
223 return ret;
226 /* decode a linker-compatible dll name */
227 static char *decode_dll_name( const char **name )
229 const char *src = *name;
230 char *p, *ret;
232 ret = p = xmalloc( strlen( src ) + 5 );
233 for ( ; *src; src++, p++)
235 if (*src != '$')
237 *p = *src;
239 else if (src[1] == 'x') /* hex escape */
241 int val = 0;
242 src += 2;
243 if (*src >= '0' && *src <= '9') val += *src - '0';
244 else if (*src >= 'A' && *src <= 'F') val += *src - 'A' + 10;
245 else if (*src >= 'a' && *src <= 'f') val += *src - 'a' + 10;
246 else return NULL;
247 val *= 16;
248 src++;
249 if (*src >= '0' && *src <= '9') val += *src - '0';
250 else if (*src >= 'A' && *src <= 'F') val += *src - 'A' + 10;
251 else if (*src >= 'a' && *src <= 'f') val += *src - 'a' + 10;
252 else return NULL;
253 *p = val;
255 else break; /* end of dll name */
257 *p = 0;
258 if (!strchr( ret, '.' )) strcpy( p, ".dll" );
259 *name = src;
260 return ret;
263 /* free an import structure */
264 static void free_imports( struct import *imp )
266 free( imp->exports );
267 free( imp->imports );
268 free( imp->dll_name );
269 free( imp->c_name );
270 free( imp->full_name );
271 free( imp );
274 /* check whether a given dll is imported in delayed mode */
275 static int is_delayed_import( const char *name )
277 unsigned int i;
279 for (i = 0; i < delayed_imports.count; i++)
281 if (!strcmp( delayed_imports.str[i], name )) return 1;
283 return 0;
286 /* find an imported dll from its name */
287 static struct import *find_import_dll( const char *name )
289 struct import *import;
291 LIST_FOR_EACH_ENTRY( import, &dll_imports, struct import, entry )
292 if (!strcasecmp( import->dll_name, name )) return import;
293 LIST_FOR_EACH_ENTRY( import, &dll_delayed, struct import, entry )
294 if (!strcasecmp( import->dll_name, name )) return import;
295 return NULL;
298 /* open the .so library for a given dll in a specified path */
299 static char *try_library_path( const char *path, const char *name )
301 char *buffer;
302 int fd;
304 buffer = strmake( "%s/lib%s.def", path, name );
306 /* check if the file exists */
307 if ((fd = open( buffer, O_RDONLY )) != -1)
309 close( fd );
310 return buffer;
312 free( buffer );
313 return NULL;
316 /* find the .def import library for a given dll */
317 static char *find_library( const char *name )
319 char *fullname;
320 unsigned int i;
322 for (i = 0; i < lib_path.count; i++)
324 if ((fullname = try_library_path( lib_path.str[i], name ))) return fullname;
326 fatal_error( "could not open .def file for %s\n", name );
327 return NULL;
330 /* read in the list of exported symbols of an import library */
331 static DLLSPEC *read_import_lib( struct import *imp )
333 FILE *f;
334 int i;
335 struct stat stat;
336 struct import *prev_imp;
337 DLLSPEC *spec = alloc_dll_spec();
339 f = open_input_file( NULL, imp->full_name );
340 fstat( fileno(f), &stat );
341 imp->dev = stat.st_dev;
342 imp->ino = stat.st_ino;
343 if (!parse_def_file( f, spec )) exit( 1 );
344 close_input_file( f );
346 /* check if we already imported that library from a different file */
347 if ((prev_imp = find_import_dll( spec->file_name )))
349 if (prev_imp->dev != imp->dev || prev_imp->ino != imp->ino)
350 fatal_error( "%s and %s have the same export name '%s'\n",
351 prev_imp->full_name, imp->full_name, spec->file_name );
352 free_dll_spec( spec );
353 return NULL; /* the same file was already loaded, ignore this one */
356 if (spec->nb_entry_points)
358 imp->exports = xmalloc( spec->nb_entry_points * sizeof(*imp->exports) );
359 for (i = 0; i < spec->nb_entry_points; i++)
360 imp->exports[imp->nb_exports++] = &spec->entry_points[i];
361 qsort( imp->exports, imp->nb_exports, sizeof(*imp->exports), func_cmp );
363 return spec;
366 /* build the dll exported name from the import lib name or path */
367 static char *get_dll_name( const char *name, const char *filename )
369 char *ret;
371 if (filename)
373 const char *basename = get_basename( filename );
374 if (!strncmp( basename, "lib", 3 )) basename += 3;
375 ret = xmalloc( strlen(basename) + 5 );
376 strcpy( ret, basename );
377 if (strendswith( ret, ".def" )) ret[strlen(ret)-4] = 0;
379 else
381 ret = xmalloc( strlen(name) + 5 );
382 strcpy( ret, name );
384 if (!strchr( ret, '.' )) strcat( ret, ".dll" );
385 return ret;
388 /* add a dll to the list of imports */
389 void add_import_dll( const char *name, const char *filename )
391 DLLSPEC *spec;
392 char *dll_name = get_dll_name( name, filename );
393 struct import *imp = xmalloc( sizeof(*imp) );
395 memset( imp, 0, sizeof(*imp) );
397 if (filename) imp->full_name = xstrdup( filename );
398 else imp->full_name = find_library( name );
400 if (!(spec = read_import_lib( imp )))
402 free_imports( imp );
403 return;
406 imp->dll_name = spec->file_name ? spec->file_name : dll_name;
407 imp->c_name = make_c_identifier( imp->dll_name );
409 if (is_delayed_import( imp->dll_name ))
410 list_add_tail( &dll_delayed, &imp->entry );
411 else
412 list_add_tail( &dll_imports, &imp->entry );
415 /* add a library to the list of delayed imports */
416 void add_delayed_import( const char *name )
418 struct import *imp;
419 char *fullname = get_dll_name( name, NULL );
421 strarray_add( &delayed_imports, fullname );
422 if ((imp = find_import_dll( fullname )))
424 list_remove( &imp->entry );
425 list_add_tail( &dll_delayed, &imp->entry );
429 /* add a symbol to the list of extra symbols that ld must resolve */
430 void add_extra_ld_symbol( const char *name )
432 strarray_add( &extra_ld_symbols, name );
435 /* retrieve an imported dll, adding one if necessary */
436 static struct import *add_static_import_dll( const char *name )
438 struct import *import;
440 if ((import = find_import_dll( name ))) return import;
442 import = xmalloc( sizeof(*import) );
443 memset( import, 0, sizeof(*import) );
445 import->dll_name = xstrdup( name );
446 import->full_name = xstrdup( name );
447 import->c_name = make_c_identifier( name );
449 if (is_delayed_import( name ))
450 list_add_tail( &dll_delayed, &import->entry );
451 else
452 list_add_tail( &dll_imports, &import->entry );
453 return import;
456 /* add a function to the list of imports from a given dll */
457 static void add_import_func( struct import *imp, const char *name, const char *export_name,
458 int ordinal, int hint )
460 if (imp->nb_imports == imp->max_imports)
462 imp->max_imports *= 2;
463 if (imp->max_imports < 32) imp->max_imports = 32;
464 imp->imports = xrealloc( imp->imports, imp->max_imports * sizeof(*imp->imports) );
466 imp->imports[imp->nb_imports].name = name;
467 imp->imports[imp->nb_imports].export_name = export_name;
468 imp->imports[imp->nb_imports].ordinal = ordinal;
469 imp->imports[imp->nb_imports].hint = hint;
470 imp->nb_imports++;
473 /* add an import for an undefined function of the form __wine$func$ */
474 static void add_undef_import( const char *name, int is_ordinal )
476 char *dll_name = decode_dll_name( &name );
477 int ordinal = 0;
478 struct import *import;
480 if (!dll_name) return;
481 if (*name++ != '$') return;
482 while (*name >= '0' && *name <= '9') ordinal = 10 * ordinal + *name++ - '0';
483 if (*name++ != '$') return;
485 if (!use_msvcrt && find_name( name, stdc_functions )) return;
487 import = add_static_import_dll( dll_name );
488 if (is_ordinal)
489 add_import_func( import, NULL, xstrdup( name ), ordinal, 0 );
490 else
491 add_import_func( import, xstrdup( name ), NULL, ordinal, 0 );
492 free( dll_name );
495 /* check if the spec file exports any stubs */
496 static int has_stubs( const DLLSPEC *spec )
498 int i;
500 if (unix_lib) return 0;
502 for (i = 0; i < spec->nb_entry_points; i++)
504 ORDDEF *odp = &spec->entry_points[i];
505 if (odp->type == TYPE_STUB) return 1;
507 return 0;
510 /* add the extra undefined symbols that will be contained in the generated spec file itself */
511 static void add_extra_undef_symbols( DLLSPEC *spec )
513 add_extra_ld_symbol( spec->init_func );
514 if (spec->type == SPEC_WIN16) add_extra_ld_symbol( "DllMain" );
515 if (has_stubs( spec )) add_extra_ld_symbol( "__wine_spec_unimplemented_stub" );
516 if (delayed_imports.count) add_extra_ld_symbol( "__wine_spec_delay_load" );
519 /* check if a given imported dll is not needed, taking forwards into account */
520 static int check_unused( const struct import* imp, const DLLSPEC *spec )
522 int i;
523 const char *file_name = imp->dll_name;
524 size_t len = strlen( file_name );
525 const char *p = strchr( file_name, '.' );
526 if (p && !strcasecmp( p, ".dll" )) len = p - file_name;
528 for (i = spec->base; i <= spec->limit; i++)
530 ORDDEF *odp = spec->ordinals[i];
531 if (!odp || !(odp->flags & FLAG_FORWARD)) continue;
532 if (!strncasecmp( odp->link_name, file_name, len ) &&
533 odp->link_name[len] == '.')
534 return 0; /* found a forward, it is used */
536 return 1;
539 /* check if a given forward does exist in one of the imported dlls */
540 static void check_undefined_forwards( DLLSPEC *spec )
542 struct import *imp;
543 char *link_name, *api_name, *dll_name, *p;
544 int i;
546 if (unix_lib) return;
548 for (i = 0; i < spec->nb_entry_points; i++)
550 ORDDEF *odp = &spec->entry_points[i];
552 if (!(odp->flags & FLAG_FORWARD)) continue;
554 link_name = xstrdup( odp->link_name );
555 p = strrchr( link_name, '.' );
556 *p = 0;
557 api_name = p + 1;
558 dll_name = get_dll_name( link_name, NULL );
560 if ((imp = find_import_dll( dll_name )))
562 if (!find_export( api_name, imp->exports, imp->nb_exports ))
563 warning( "%s:%d: forward '%s' not found in %s\n",
564 spec->src_name, odp->lineno, odp->link_name, imp->dll_name );
566 else warning( "%s:%d: forward '%s' not found in the imported dll list\n",
567 spec->src_name, odp->lineno, odp->link_name );
568 free( link_name );
569 free( dll_name );
573 /* flag the dll exports that link to an undefined symbol */
574 static void check_undefined_exports( DLLSPEC *spec )
576 int i;
578 if (unix_lib) return;
580 for (i = 0; i < spec->nb_entry_points; i++)
582 ORDDEF *odp = &spec->entry_points[i];
583 if (odp->type == TYPE_STUB || odp->type == TYPE_ABS || odp->type == TYPE_VARIABLE) continue;
584 if (odp->flags & FLAG_FORWARD) continue;
585 if (odp->flags & FLAG_SYSCALL) continue;
586 if (find_name( odp->link_name, undef_symbols ))
588 switch(odp->type)
590 case TYPE_PASCAL:
591 case TYPE_STDCALL:
592 case TYPE_CDECL:
593 case TYPE_VARARGS:
594 if (link_ext_symbols)
596 odp->flags |= FLAG_EXT_LINK;
597 strarray_add( &ext_link_imports, odp->link_name );
599 else error( "%s:%d: function '%s' not defined\n",
600 spec->src_name, odp->lineno, odp->link_name );
601 break;
602 default:
603 if (!strcmp( odp->link_name, "__wine_syscall_dispatcher" )) break;
604 error( "%s:%d: external symbol '%s' is not a function\n",
605 spec->src_name, odp->lineno, odp->link_name );
606 break;
612 /* create a .o file that references all the undefined symbols we want to resolve */
613 static char *create_undef_symbols_file( DLLSPEC *spec )
615 char *as_file, *obj_file;
616 int i;
617 unsigned int j;
619 if (unix_lib) return NULL;
621 as_file = open_temp_output_file( ".s" );
622 output( "\t.data\n" );
624 for (i = 0; i < spec->nb_entry_points; i++)
626 ORDDEF *odp = &spec->entry_points[i];
627 if (odp->type == TYPE_STUB || odp->type == TYPE_ABS || odp->type == TYPE_VARIABLE) continue;
628 if (odp->flags & FLAG_FORWARD) continue;
629 if (odp->flags & FLAG_SYSCALL) continue;
630 output( "\t%s %s\n", get_asm_ptr_keyword(), asm_name( get_link_name( odp )));
632 for (j = 0; j < extra_ld_symbols.count; j++)
633 output( "\t%s %s\n", get_asm_ptr_keyword(), asm_name(extra_ld_symbols.str[j]) );
635 output_gnu_stack_note();
636 fclose( output_file );
638 obj_file = get_temp_file_name( output_file_name, ".o" );
639 assemble_file( as_file, obj_file );
640 return obj_file;
643 /* combine a list of object files with ld into a single object file */
644 /* returns the name of the combined file */
645 static const char *ldcombine_files( DLLSPEC *spec, struct strarray files )
647 char *ld_tmp_file, *undef_file;
648 struct strarray args = get_ld_command();
650 undef_file = create_undef_symbols_file( spec );
651 ld_tmp_file = get_temp_file_name( output_file_name, ".o" );
653 strarray_add( &args, "-r" );
654 strarray_add( &args, "-o" );
655 strarray_add( &args, ld_tmp_file );
656 if (undef_file) strarray_add( &args, undef_file );
657 strarray_addall( &args, files );
658 spawn( args );
659 return ld_tmp_file;
662 /* read in the list of undefined symbols */
663 void read_undef_symbols( DLLSPEC *spec, struct strarray files )
665 size_t prefix_len;
666 FILE *f;
667 const char *prog = get_nm_command();
668 char *cmd, buffer[1024], name_prefix[16];
669 int err;
670 const char *name;
672 if (!files.count) return;
674 add_extra_undef_symbols( spec );
676 strcpy( name_prefix, asm_name("") );
677 prefix_len = strlen( name_prefix );
679 name = ldcombine_files( spec, files );
681 cmd = strmake( "%s -u %s", prog, name );
682 if (verbose)
683 fprintf( stderr, "%s\n", cmd );
684 if (!(f = popen( cmd, "r" )))
685 fatal_error( "Cannot execute '%s'\n", cmd );
687 while (fgets( buffer, sizeof(buffer), f ))
689 char *p = buffer + strlen(buffer) - 1;
690 if (p < buffer) continue;
691 if (*p == '\n') *p-- = 0;
692 p = buffer;
693 while (*p == ' ') p++;
694 if (p[0] == 'U' && p[1] == ' ' && p[2]) p += 2;
695 if (prefix_len && !strncmp( p, name_prefix, prefix_len )) p += prefix_len;
696 if (!strncmp( p, import_func_prefix, strlen(import_func_prefix) ))
697 add_undef_import( p + strlen( import_func_prefix ), 0 );
698 else if (!strncmp( p, import_ord_prefix, strlen(import_ord_prefix) ))
699 add_undef_import( p + strlen( import_ord_prefix ), 1 );
700 else if (use_msvcrt || !find_name( p, stdc_functions ))
701 strarray_add( &undef_symbols, xstrdup( p ));
703 if ((err = pclose( f ))) warning( "%s failed with status %d\n", cmd, err );
704 free( cmd );
707 void resolve_dll_imports( DLLSPEC *spec, struct list *list )
709 unsigned int j;
710 struct import *imp, *next;
711 ORDDEF *odp;
713 LIST_FOR_EACH_ENTRY_SAFE( imp, next, list, struct import, entry )
715 for (j = 0; j < undef_symbols.count; j++)
717 odp = find_export( undef_symbols.str[j], imp->exports, imp->nb_exports );
718 if (odp)
720 if (odp->flags & FLAG_PRIVATE) continue;
721 if (odp->type != TYPE_STDCALL && odp->type != TYPE_CDECL)
722 warning( "winebuild: Data export '%s' cannot be imported from %s\n",
723 odp->link_name, imp->dll_name );
724 else
726 add_import_func( imp, (odp->flags & FLAG_NONAME) ? NULL : odp->name,
727 odp->export_name, odp->ordinal, odp->hint );
728 remove_name( &undef_symbols, j-- );
732 if (!imp->nb_imports)
734 /* the dll is not used, get rid of it */
735 if (check_unused( imp, spec ))
736 warning( "winebuild: %s imported but no symbols used\n", imp->dll_name );
737 list_remove( &imp->entry );
738 free_imports( imp );
743 /* resolve the imports for a Win32 module */
744 void resolve_imports( DLLSPEC *spec )
746 check_undefined_forwards( spec );
747 resolve_dll_imports( spec, &dll_imports );
748 resolve_dll_imports( spec, &dll_delayed );
749 sort_names( &undef_symbols );
750 check_undefined_exports( spec );
753 /* check if symbol is still undefined */
754 int is_undefined( const char *name )
756 return find_name( name, undef_symbols ) != NULL;
759 /* output the get_pc thunk if needed */
760 void output_get_pc_thunk(void)
762 assert( target.cpu == CPU_i386 );
763 output( "\n\t.text\n" );
764 output( "\t.align %d\n", get_alignment(4) );
765 output( "\t%s\n", func_declaration("__wine_spec_get_pc_thunk_eax") );
766 output( "%s:\n", asm_name("__wine_spec_get_pc_thunk_eax") );
767 output_cfi( ".cfi_startproc" );
768 output( "\tmovl (%%esp),%%eax\n" );
769 output( "\tret\n" );
770 output_cfi( ".cfi_endproc" );
771 output_function_size( "__wine_spec_get_pc_thunk_eax" );
774 /* output a single import thunk */
775 static void output_import_thunk( const char *name, const char *table, int pos )
777 output( "\n\t.align %d\n", get_alignment(4) );
778 output( "\t%s\n", func_declaration(name) );
779 output( "%s\n", asm_globl(name) );
780 output_cfi( ".cfi_startproc" );
782 switch (target.cpu)
784 case CPU_i386:
785 if (!UsePIC)
787 output( "\tjmp *(%s+%d)\n", table, pos );
789 else
791 output( "\tcall %s\n", asm_name("__wine_spec_get_pc_thunk_eax") );
792 output( "1:\tjmp *%s+%d-1b(%%eax)\n", table, pos );
793 needs_get_pc_thunk = 1;
795 break;
796 case CPU_x86_64:
797 output( "\tjmpq *%s+%d(%%rip)\n", table, pos );
798 break;
799 case CPU_ARM:
800 if (UsePIC)
802 output( "\tldr ip, 2f\n");
803 output( "1:\tadd ip, pc\n" );
804 output( "\tldr pc, [ip]\n");
805 output( "2:\t.long %s+%u-1b-%u\n", table, pos, thumb_mode ? 4 : 8 );
807 else
809 output( "\tldr ip, 1f\n");
810 output( "\tldr pc, [ip]\n");
811 output( "1:\t.long %s+%u\n", table, pos );
813 break;
814 case CPU_ARM64:
815 output( "\tadrp x16, %s\n", arm64_page( table ) );
816 output( "\tadd x16, x16, #%s\n", arm64_pageoff( table ) );
817 if (pos & ~0x7fff) output( "\tadd x16, x16, #%u\n", pos & ~0x7fff );
818 output( "\tldr x16, [x16, #%u]\n", pos & 0x7fff );
819 output( "\tbr x16\n" );
820 break;
822 output_cfi( ".cfi_endproc" );
823 output_function_size( name );
826 /* check if we need an import directory */
827 int has_imports(void)
829 return !list_empty( &dll_imports );
832 /* output the import table of a Win32 module */
833 static void output_immediate_imports(void)
835 int i, j;
836 struct import *import;
838 if (list_empty( &dll_imports )) return; /* no immediate imports */
840 /* main import header */
842 output( "\n/* import table */\n" );
843 output( "\n\t.data\n" );
844 output( "\t.align %d\n", get_alignment(4) );
845 output( ".L__wine_spec_imports:\n" );
847 /* list of dlls */
849 j = 0;
850 LIST_FOR_EACH_ENTRY( import, &dll_imports, struct import, entry )
852 output_rva( ".L__wine_spec_import_data_names + %d", j * get_ptr_size() ); /* OriginalFirstThunk */
853 output( "\t.long 0\n" ); /* TimeDateStamp */
854 output( "\t.long 0\n" ); /* ForwarderChain */
855 output_rva( ".L__wine_spec_import_name_%s", import->c_name ); /* Name */
856 output_rva( ".L__wine_spec_import_data_ptrs + %d", j * get_ptr_size() ); /* FirstThunk */
857 j += import->nb_imports + 1;
859 output( "\t.long 0\n" ); /* OriginalFirstThunk */
860 output( "\t.long 0\n" ); /* TimeDateStamp */
861 output( "\t.long 0\n" ); /* ForwarderChain */
862 output( "\t.long 0\n" ); /* Name */
863 output( "\t.long 0\n" ); /* FirstThunk */
865 output( "\n\t.align %d\n", get_alignment(get_ptr_size()) );
866 /* output the names twice, once for OriginalFirstThunk and once for FirstThunk */
867 for (i = 0; i < 2; i++)
869 output( ".L__wine_spec_import_data_%s:\n", i ? "ptrs" : "names" );
870 LIST_FOR_EACH_ENTRY( import, &dll_imports, struct import, entry )
872 for (j = 0; j < import->nb_imports; j++)
874 struct import_func *func = &import->imports[j];
875 if (i)
877 if (func->name) output( "__imp_%s:\n", asm_name( func->name ));
878 else if (func->export_name) output( "__imp_%s:\n", asm_name( func->export_name ));
880 if (func->name)
881 output( "\t%s .L__wine_spec_import_data_%s_%s-.L__wine_spec_rva_base\n",
882 get_asm_ptr_keyword(), import->c_name, func->name );
883 else
885 if (get_ptr_size() == 8)
886 output( "\t.quad 0x800000000000%04x\n", func->ordinal );
887 else
888 output( "\t.long 0x8000%04x\n", func->ordinal );
891 output( "\t%s 0\n", get_asm_ptr_keyword() );
894 output( ".L__wine_spec_imports_end:\n" );
896 LIST_FOR_EACH_ENTRY( import, &dll_imports, struct import, entry )
898 for (j = 0; j < import->nb_imports; j++)
900 struct import_func *func = &import->imports[j];
901 if (!func->name) continue;
902 output( "\t.align %d\n", get_alignment(2) );
903 output( ".L__wine_spec_import_data_%s_%s:\n", import->c_name, func->name );
904 output( "\t.short %d\n", func->hint );
905 output( "\t%s \"%s\"\n", get_asm_string_keyword(), func->name );
909 LIST_FOR_EACH_ENTRY( import, &dll_imports, struct import, entry )
911 output( ".L__wine_spec_import_name_%s:\n\t%s \"%s\"\n",
912 import->c_name, get_asm_string_keyword(), import->dll_name );
916 /* output the import thunks of a Win32 module */
917 static void output_immediate_import_thunks(void)
919 int j, pos;
920 struct import *import;
921 static const char import_thunks[] = "__wine_spec_import_thunks";
923 if (list_empty( &dll_imports )) return;
925 output( "\n/* immediate import thunks */\n\n" );
926 output( "\t.text\n" );
927 output( "\t.align %d\n", get_alignment(8) );
928 output( "%s:\n", asm_name(import_thunks));
930 pos = 0;
931 LIST_FOR_EACH_ENTRY( import, &dll_imports, struct import, entry )
933 for (j = 0; j < import->nb_imports; j++, pos += get_ptr_size())
935 struct import_func *func = &import->imports[j];
936 output_import_thunk( func->name ? func->name : func->export_name,
937 ".L__wine_spec_import_data_ptrs", pos );
939 pos += get_ptr_size();
941 output_function_size( import_thunks );
944 /* output the delayed import table of a Win32 module */
945 static void output_delayed_imports( const DLLSPEC *spec )
947 int j, mod;
948 struct import *import;
950 if (list_empty( &dll_delayed )) return;
952 output( "\n/* delayed imports */\n\n" );
953 output( "\t.data\n" );
954 output( "\t.align %d\n", get_alignment(get_ptr_size()) );
955 output( "%s\n", asm_globl("__wine_spec_delay_imports") );
957 /* list of dlls */
959 j = mod = 0;
960 LIST_FOR_EACH_ENTRY( import, &dll_delayed, struct import, entry )
962 output( "\t%s 0\n", get_asm_ptr_keyword() ); /* grAttrs */
963 output( "\t%s .L__wine_delay_name_%s\n", /* szName */
964 get_asm_ptr_keyword(), import->c_name );
965 output( "\t%s .L__wine_delay_modules+%d\n", /* phmod */
966 get_asm_ptr_keyword(), mod * get_ptr_size() );
967 output( "\t%s .L__wine_delay_IAT+%d\n", /* pIAT */
968 get_asm_ptr_keyword(), j * get_ptr_size() );
969 output( "\t%s .L__wine_delay_INT+%d\n", /* pINT */
970 get_asm_ptr_keyword(), j * get_ptr_size() );
971 output( "\t%s 0\n", get_asm_ptr_keyword() ); /* pBoundIAT */
972 output( "\t%s 0\n", get_asm_ptr_keyword() ); /* pUnloadIAT */
973 output( "\t%s 0\n", get_asm_ptr_keyword() ); /* dwTimeStamp */
974 j += import->nb_imports;
975 mod++;
977 output( "\t%s 0\n", get_asm_ptr_keyword() ); /* grAttrs */
978 output( "\t%s 0\n", get_asm_ptr_keyword() ); /* szName */
979 output( "\t%s 0\n", get_asm_ptr_keyword() ); /* phmod */
980 output( "\t%s 0\n", get_asm_ptr_keyword() ); /* pIAT */
981 output( "\t%s 0\n", get_asm_ptr_keyword() ); /* pINT */
982 output( "\t%s 0\n", get_asm_ptr_keyword() ); /* pBoundIAT */
983 output( "\t%s 0\n", get_asm_ptr_keyword() ); /* pUnloadIAT */
984 output( "\t%s 0\n", get_asm_ptr_keyword() ); /* dwTimeStamp */
986 output( "\n.L__wine_delay_IAT:\n" );
987 LIST_FOR_EACH_ENTRY( import, &dll_delayed, struct import, entry )
989 for (j = 0; j < import->nb_imports; j++)
991 struct import_func *func = &import->imports[j];
992 const char *name = func->name ? func->name : func->export_name;
993 output( "__imp_%s:\n", asm_name( name ));
994 output( "\t%s __wine_delay_imp_%s_%s\n",
995 get_asm_ptr_keyword(), import->c_name, name );
999 output( "\n.L__wine_delay_INT:\n" );
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)
1006 output( "\t%s %d\n", get_asm_ptr_keyword(), func->ordinal );
1007 else
1008 output( "\t%s .L__wine_delay_data_%s_%s\n",
1009 get_asm_ptr_keyword(), import->c_name, func->name );
1013 output( "\n.L__wine_delay_modules:\n" );
1014 LIST_FOR_EACH_ENTRY( import, &dll_delayed, struct import, entry )
1016 output( "\t%s 0\n", get_asm_ptr_keyword() );
1019 LIST_FOR_EACH_ENTRY( import, &dll_delayed, struct import, entry )
1021 output( ".L__wine_delay_name_%s:\n", import->c_name );
1022 output( "\t%s \"%s\"\n", get_asm_string_keyword(), import->dll_name );
1025 LIST_FOR_EACH_ENTRY( import, &dll_delayed, struct import, entry )
1027 for (j = 0; j < import->nb_imports; j++)
1029 struct import_func *func = &import->imports[j];
1030 if (!func->name) continue;
1031 output( ".L__wine_delay_data_%s_%s:\n", import->c_name, func->name );
1032 output( "\t%s \"%s\"\n", get_asm_string_keyword(), func->name );
1035 output_function_size( "__wine_spec_delay_imports" );
1038 /* output the delayed import thunks of a Win32 module */
1039 static void output_delayed_import_thunks( const DLLSPEC *spec )
1041 int idx, j, pos;
1042 struct import *import;
1043 static const char delayed_import_loaders[] = "__wine_spec_delayed_import_loaders";
1044 static const char delayed_import_thunks[] = "__wine_spec_delayed_import_thunks";
1046 if (list_empty( &dll_delayed )) return;
1048 output( "\n/* delayed import thunks */\n\n" );
1049 output( "\t.text\n" );
1050 output( "\t.align %d\n", get_alignment(8) );
1051 output( "%s:\n", asm_name(delayed_import_loaders));
1052 output( "\t%s\n", func_declaration("__wine_delay_load_asm") );
1053 output( "%s:\n", asm_name("__wine_delay_load_asm") );
1054 output_cfi( ".cfi_startproc" );
1055 switch (target.cpu)
1057 case CPU_i386:
1058 output( "\tpushl %%ecx\n" );
1059 output_cfi( ".cfi_adjust_cfa_offset 4" );
1060 output( "\tpushl %%edx\n" );
1061 output_cfi( ".cfi_adjust_cfa_offset 4" );
1062 output( "\tpushl %%eax\n" );
1063 output_cfi( ".cfi_adjust_cfa_offset 4" );
1064 output( "\tcall %s\n", asm_name("__wine_spec_delay_load") );
1065 output_cfi( ".cfi_adjust_cfa_offset -4" );
1066 output( "\tpopl %%edx\n" );
1067 output_cfi( ".cfi_adjust_cfa_offset -4" );
1068 output( "\tpopl %%ecx\n" );
1069 output_cfi( ".cfi_adjust_cfa_offset -4" );
1070 output( "\tjmp *%%eax\n" );
1071 break;
1072 case CPU_x86_64:
1073 output( "\tsubq $0x98,%%rsp\n" );
1074 output_cfi( ".cfi_adjust_cfa_offset 0x98" );
1075 output( "\tmovq %%rdx,0x88(%%rsp)\n" );
1076 output( "\tmovq %%rcx,0x80(%%rsp)\n" );
1077 output( "\tmovq %%r8,0x78(%%rsp)\n" );
1078 output( "\tmovq %%r9,0x70(%%rsp)\n" );
1079 output( "\tmovq %%r10,0x68(%%rsp)\n" );
1080 output( "\tmovq %%r11,0x60(%%rsp)\n" );
1081 output( "\tmovups %%xmm0,0x50(%%rsp)\n" );
1082 output( "\tmovups %%xmm1,0x40(%%rsp)\n" );
1083 output( "\tmovups %%xmm2,0x30(%%rsp)\n" );
1084 output( "\tmovups %%xmm3,0x20(%%rsp)\n" );
1085 output( "\tmovq %%rax,%%rcx\n" );
1086 output( "\tcall %s\n", asm_name("__wine_spec_delay_load") );
1087 output( "\tmovups 0x20(%%rsp),%%xmm3\n" );
1088 output( "\tmovups 0x30(%%rsp),%%xmm2\n" );
1089 output( "\tmovups 0x40(%%rsp),%%xmm1\n" );
1090 output( "\tmovups 0x50(%%rsp),%%xmm0\n" );
1091 output( "\tmovq 0x60(%%rsp),%%r11\n" );
1092 output( "\tmovq 0x68(%%rsp),%%r10\n" );
1093 output( "\tmovq 0x70(%%rsp),%%r9\n" );
1094 output( "\tmovq 0x78(%%rsp),%%r8\n" );
1095 output( "\tmovq 0x80(%%rsp),%%rcx\n" );
1096 output( "\tmovq 0x88(%%rsp),%%rdx\n" );
1097 output( "\taddq $0x98,%%rsp\n" );
1098 output_cfi( ".cfi_adjust_cfa_offset -0x98" );
1099 output( "\tjmp *%%rax\n" );
1100 break;
1101 case CPU_ARM:
1102 output( "\tpush {r0-r3,FP,LR}\n" );
1103 output( "\tmov r0,IP\n" );
1104 output( "\tbl %s\n", asm_name("__wine_spec_delay_load") );
1105 output( "\tmov IP,r0\n");
1106 output( "\tpop {r0-r3,FP,LR}\n" );
1107 output( "\tbx IP\n");
1108 break;
1109 case CPU_ARM64:
1110 output( "\tstp x29, x30, [sp,#-80]!\n" );
1111 output( "\tmov x29, sp\n" );
1112 output( "\tstp x0, x1, [sp,#16]\n" );
1113 output( "\tstp x2, x3, [sp,#32]\n" );
1114 output( "\tstp x4, x5, [sp,#48]\n" );
1115 output( "\tstp x6, x7, [sp,#64]\n" );
1116 output( "\tmov x0, x16\n" );
1117 output( "\tbl %s\n", asm_name("__wine_spec_delay_load") );
1118 output( "\tmov x16, x0\n" );
1119 output( "\tldp x0, x1, [sp,#16]\n" );
1120 output( "\tldp x2, x3, [sp,#32]\n" );
1121 output( "\tldp x4, x5, [sp,#48]\n" );
1122 output( "\tldp x6, x7, [sp,#64]\n" );
1123 output( "\tldp x29, x30, [sp],#80\n" );
1124 output( "\tbr x16\n" );
1125 break;
1127 output_cfi( ".cfi_endproc" );
1128 output_function_size( "__wine_delay_load_asm" );
1129 output( "\n" );
1131 idx = 0;
1132 LIST_FOR_EACH_ENTRY( import, &dll_delayed, struct import, entry )
1134 for (j = 0; j < import->nb_imports; j++)
1136 struct import_func *func = &import->imports[j];
1137 const char *name = func->name ? func->name : func->export_name;
1139 if (thumb_mode) output( "\t.thumb_func\n" );
1140 output( "__wine_delay_imp_%s_%s:\n", import->c_name, name );
1141 output_cfi( ".cfi_startproc" );
1142 switch (target.cpu)
1144 case CPU_i386:
1145 case CPU_x86_64:
1146 output( "\tmovl $%d,%%eax\n", (idx << 16) | j );
1147 output( "\tjmp %s\n", asm_name("__wine_delay_load_asm") );
1148 break;
1149 case CPU_ARM:
1150 output( "\tmov ip, #%u\n", j );
1151 if (idx) output( "\tmovt ip, #%u\n", idx );
1152 output( "\tb %s\n", asm_name("__wine_delay_load_asm") );
1153 break;
1154 case CPU_ARM64:
1155 if (idx)
1157 output( "\tmov x16, #0x%x\n", idx << 16 );
1158 if (j) output( "\tmovk x16, #0x%x\n", j );
1160 else output( "\tmov x16, #0x%x\n", j );
1161 output( "\tb %s\n", asm_name("__wine_delay_load_asm") );
1162 break;
1164 output_cfi( ".cfi_endproc" );
1166 idx++;
1168 output_function_size( delayed_import_loaders );
1170 output( "\n\t.align %d\n", get_alignment(get_ptr_size()) );
1171 output( "%s:\n", asm_name(delayed_import_thunks));
1172 pos = 0;
1173 LIST_FOR_EACH_ENTRY( import, &dll_delayed, struct import, entry )
1175 for (j = 0; j < import->nb_imports; j++, pos += get_ptr_size())
1177 struct import_func *func = &import->imports[j];
1178 output_import_thunk( func->name ? func->name : func->export_name,
1179 ".L__wine_delay_IAT", pos );
1182 output_function_size( delayed_import_thunks );
1185 /* output import stubs for exported entry points that link to external symbols */
1186 static void output_external_link_imports( DLLSPEC *spec )
1188 unsigned int i, pos;
1190 if (!ext_link_imports.count) return; /* nothing to do */
1192 sort_names( &ext_link_imports );
1194 /* get rid of duplicate names */
1195 for (i = 1; i < ext_link_imports.count; i++)
1197 if (!strcmp( ext_link_imports.str[i-1], ext_link_imports.str[i] ))
1198 remove_name( &ext_link_imports, i-- );
1201 output( "\n/* external link thunks */\n\n" );
1202 output( "\t.data\n" );
1203 output( "\t.align %d\n", get_alignment(get_ptr_size()) );
1204 output( ".L__wine_spec_external_links:\n" );
1205 for (i = 0; i < ext_link_imports.count; i++)
1206 output( "\t%s %s\n", get_asm_ptr_keyword(), asm_name(ext_link_imports.str[i]) );
1208 output( "\n\t.text\n" );
1209 output( "\t.align %d\n", get_alignment(get_ptr_size()) );
1210 output( "%s:\n", asm_name("__wine_spec_external_link_thunks") );
1212 for (i = pos = 0; i < ext_link_imports.count; i++)
1214 char *buffer = strmake( "__wine_spec_ext_link_%s", ext_link_imports.str[i] );
1215 output_import_thunk( buffer, ".L__wine_spec_external_links", pos );
1216 free( buffer );
1217 pos += get_ptr_size();
1219 output_function_size( "__wine_spec_external_link_thunks" );
1222 /*******************************************************************
1223 * output_stubs
1225 * Output the functions for stub entry points
1227 void output_stubs( DLLSPEC *spec )
1229 const char *name, *exp_name;
1230 int i;
1232 if (!has_stubs( spec )) return;
1234 output( "\n/* stub functions */\n\n" );
1235 output( "\t.text\n" );
1237 for (i = 0; i < spec->nb_entry_points; i++)
1239 ORDDEF *odp = &spec->entry_points[i];
1240 if (odp->type != TYPE_STUB) continue;
1242 name = get_stub_name( odp, spec );
1243 exp_name = odp->name ? odp->name : odp->export_name;
1244 output( "\t.align %d\n", get_alignment(4) );
1245 output( "\t%s\n", func_declaration(name) );
1246 output( "%s:\n", asm_name(name) );
1247 output_cfi( ".cfi_startproc" );
1249 switch (target.cpu)
1251 case CPU_i386:
1252 /* flesh out the stub a bit to make safedisc happy */
1253 output(" \tnop\n" );
1254 output(" \tnop\n" );
1255 output(" \tnop\n" );
1256 output(" \tnop\n" );
1257 output(" \tnop\n" );
1258 output(" \tnop\n" );
1259 output(" \tnop\n" );
1260 output(" \tnop\n" );
1261 output(" \tnop\n" );
1263 output( "\tsubl $12,%%esp\n" );
1264 output_cfi( ".cfi_adjust_cfa_offset 12" );
1265 if (UsePIC)
1267 output( "\tcall %s\n", asm_name("__wine_spec_get_pc_thunk_eax") );
1268 output( "1:" );
1269 needs_get_pc_thunk = 1;
1270 if (exp_name)
1272 output( "\tleal .L%s_string-1b(%%eax),%%ecx\n", name );
1273 output( "\tmovl %%ecx,4(%%esp)\n" );
1275 else
1276 output( "\tmovl $%d,4(%%esp)\n", odp->ordinal );
1277 output( "\tleal .L__wine_spec_file_name-1b(%%eax),%%ecx\n" );
1278 output( "\tmovl %%ecx,(%%esp)\n" );
1280 else
1282 if (exp_name)
1283 output( "\tmovl $.L%s_string,4(%%esp)\n", name );
1284 else
1285 output( "\tmovl $%d,4(%%esp)\n", odp->ordinal );
1286 output( "\tmovl $.L__wine_spec_file_name,(%%esp)\n" );
1288 output( "\tcall %s\n", asm_name("__wine_spec_unimplemented_stub") );
1289 break;
1290 case CPU_x86_64:
1291 output( "\tsubq $0x28,%%rsp\n" );
1292 output_cfi( ".cfi_adjust_cfa_offset 8" );
1293 output( "\tleaq .L__wine_spec_file_name(%%rip),%%rcx\n" );
1294 if (exp_name)
1295 output( "leaq .L%s_string(%%rip),%%rdx\n", name );
1296 else
1297 output( "\tmovq $%d,%%rdx\n", odp->ordinal );
1298 output( "\tcall %s\n", asm_name("__wine_spec_unimplemented_stub") );
1299 break;
1300 case CPU_ARM:
1301 if (UsePIC)
1303 output( "\tldr r0,3f\n");
1304 output( "1:\tadd r0,PC\n");
1305 output( "\tldr r1,3f+4\n");
1306 if (exp_name) output( "2:\tadd r1,PC\n");
1307 output( "\tbl %s\n", asm_name("__wine_spec_unimplemented_stub") );
1308 output( "3:\t.long .L__wine_spec_file_name-1b-%u\n", thumb_mode ? 4 : 8 );
1309 if (exp_name) output( "\t.long .L%s_string-2b-%u\n", name, thumb_mode ? 4 : 8 );
1310 else output( "\t.long %u\n", odp->ordinal );
1312 else
1314 output( "\tmovw r0,:lower16:.L__wine_spec_file_name\n");
1315 output( "\tmovt r0,:upper16:.L__wine_spec_file_name\n");
1316 if (exp_name)
1318 output( "\tmovw r1,:lower16:.L%s_string\n", name );
1319 output( "\tmovt r1,:upper16:.L%s_string\n", name );
1321 else output( "\tmov r1,#%u\n", odp->ordinal );
1322 output( "\tbl %s\n", asm_name("__wine_spec_unimplemented_stub") );
1324 break;
1325 case CPU_ARM64:
1326 output( "\tadrp x0, %s\n", arm64_page(".L__wine_spec_file_name") );
1327 output( "\tadd x0, x0, #%s\n", arm64_pageoff(".L__wine_spec_file_name") );
1328 if (exp_name)
1330 char *sym = strmake( ".L%s_string", name );
1331 output( "\tadrp x1, %s\n", arm64_page( sym ) );
1332 output( "\tadd x1, x1, #%s\n", arm64_pageoff( sym ) );
1333 free( sym );
1335 else
1336 output( "\tmov x1, %u\n", odp->ordinal );
1337 output( "\tbl %s\n", asm_name("__wine_spec_unimplemented_stub") );
1338 break;
1339 default:
1340 assert(0);
1342 output_cfi( ".cfi_endproc" );
1343 output_function_size( name );
1346 output( "\t%s\n", get_asm_string_section() );
1347 output( ".L__wine_spec_file_name:\n" );
1348 output( "\t%s \"%s\"\n", get_asm_string_keyword(), spec->file_name );
1349 for (i = 0; i < spec->nb_entry_points; i++)
1351 ORDDEF *odp = &spec->entry_points[i];
1352 if (odp->type != TYPE_STUB) continue;
1353 exp_name = odp->name ? odp->name : odp->export_name;
1354 if (exp_name)
1356 name = get_stub_name( odp, spec );
1357 output( ".L%s_string:\n", name );
1358 output( "\t%s \"%s\"\n", get_asm_string_keyword(), exp_name );
1363 static int cmp_link_name( const void *e1, const void *e2 )
1365 const ORDDEF *odp1 = *(const ORDDEF * const *)e1;
1366 const ORDDEF *odp2 = *(const ORDDEF * const *)e2;
1368 return strcmp( odp1->link_name, odp2->link_name );
1372 /* output the functions for system calls */
1373 void output_syscalls( DLLSPEC *spec )
1375 int i, count;
1376 ORDDEF **syscalls = NULL;
1378 if (unix_lib) return;
1380 for (i = count = 0; i < spec->nb_entry_points; i++)
1382 ORDDEF *odp = &spec->entry_points[i];
1383 if (!(odp->flags & FLAG_SYSCALL)) continue;
1384 if (!syscalls) syscalls = xmalloc( (spec->nb_entry_points - i) * sizeof(*syscalls) );
1385 syscalls[count++] = odp;
1387 if (!count) return;
1388 count = sort_func_list( syscalls, count, cmp_link_name );
1390 output( "\n/* system calls */\n\n" );
1391 output( "\t.text\n" );
1393 for (i = 0; i < count; i++)
1395 ORDDEF *odp = syscalls[i];
1396 const char *name = get_link_name(odp);
1397 unsigned int id = (spec->syscall_table << 12) + i;
1399 output( "\t.align %d\n", get_alignment(16) );
1400 output( "\t%s\n", func_declaration(name) );
1401 output( "%s\n", asm_globl(name) );
1402 output_cfi( ".cfi_startproc" );
1403 switch (target.cpu)
1405 case CPU_i386:
1406 if (UsePIC)
1408 output( "\tcall %s\n", asm_name("__wine_spec_get_pc_thunk_eax") );
1409 output( "1:\tmovl %s-1b(%%eax),%%edx\n", asm_name("__wine_syscall_dispatcher") );
1410 output( "\tmovl $%u,%%eax\n", id );
1411 needs_get_pc_thunk = 1;
1413 else
1415 output( "\tmovl $%u,%%eax\n", id );
1416 output( "\tmovl $%s,%%edx\n", asm_name("__wine_syscall") );
1418 output( "\tcall *%%edx\n" );
1419 output( "\tret $%u\n", odp->type == TYPE_STDCALL ? get_args_size( odp ) : 0 );
1420 break;
1421 case CPU_x86_64:
1422 /* Chromium depends on syscall thunks having the same form as on
1423 * Windows. For 64-bit systems the only viable form we can emulate is
1424 * having an int $0x2e fallback. Since actually using an interrupt is
1425 * expensive, and since for some reason Chromium doesn't actually
1426 * validate that instruction, we can just put a jmp there instead. */
1427 output( "\t.byte 0x4c,0x8b,0xd1\n" ); /* movq %rcx,%r10 */
1428 output( "\t.byte 0xb8\n" ); /* movl $i,%eax */
1429 output( "\t.long %u\n", id );
1430 output( "\t.byte 0xf6,0x04,0x25,0x08,0x03,0xfe,0x7f,0x01\n" ); /* testb $1,0x7ffe0308 */
1431 output( "\t.byte 0x75,0x03\n" ); /* jne 1f */
1432 output( "\t.byte 0x0f,0x05\n" ); /* syscall */
1433 output( "\t.byte 0xc3\n" ); /* ret */
1434 output( "\tjmp 1f\n" );
1435 output( "\t.byte 0xc3\n" ); /* ret */
1436 if (is_pe())
1438 output( "1:\t.byte 0xff,0x14,0x25\n" ); /* 1: callq *(0x7ffe1000) */
1439 output( "\t.long 0x7ffe1000\n" );
1441 else
1443 output( "\tnop\n" );
1444 output( "1:\tcallq *%s(%%rip)\n", asm_name("__wine_syscall_dispatcher") );
1446 output( "\tret\n" );
1447 break;
1448 case CPU_ARM:
1449 output( "\tpush {r0-r3}\n" );
1450 output( "\tmovw ip, #%u\n", id );
1451 output( "\tmov r3, lr\n" );
1452 output( "\tbl %s\n", asm_name("__wine_syscall") );
1453 output( "\tbx lr\n" );
1454 break;
1455 case CPU_ARM64:
1456 output( "\tmov x8, #%u\n", id );
1457 output( "\tmov x9, x30\n" );
1458 output( "\tbl %s\n", asm_name("__wine_syscall" ));
1459 output( "\tret\n" );
1460 break;
1461 default:
1462 assert(0);
1464 output_cfi( ".cfi_endproc" );
1465 output_function_size( name );
1468 switch (target.cpu)
1470 case CPU_i386:
1471 if (UsePIC) break;
1472 output( "\t.align %d\n", get_alignment(16) );
1473 output( "\t%s\n", func_declaration("__wine_syscall") );
1474 output( "%s:\n", asm_name("__wine_syscall") );
1475 output( "\tjmp *(%s)\n", asm_name("__wine_syscall_dispatcher") );
1476 output_function_size( "__wine_syscall" );
1477 break;
1478 case CPU_ARM:
1479 output( "\t.align %d\n", get_alignment(16) );
1480 output( "\t%s\n", func_declaration("__wine_syscall") );
1481 output( "%s:\n", asm_name("__wine_syscall") );
1482 if (UsePIC)
1484 output( "\tldr r0, 2f\n");
1485 output( "1:\tadd r0, pc\n" );
1487 else
1489 output( "\tmovw r0, :lower16:%s\n", asm_name("__wine_syscall_dispatcher") );
1490 output( "\tmovt r0, :upper16:%s\n", asm_name("__wine_syscall_dispatcher") );
1492 output( "\tldr r0, [r0]\n");
1493 output( "\tbx r0\n");
1494 if (UsePIC) output( "2:\t.long %s-1b-%u\n", asm_name("__wine_syscall_dispatcher"), thumb_mode ? 4 : 8 );
1495 output_function_size( "__wine_syscall" );
1496 break;
1497 case CPU_ARM64:
1498 output( "\t.align %d\n", get_alignment(16) );
1499 output( "\t%s\n", func_declaration("__wine_syscall") );
1500 output( "%s:\n", asm_name("__wine_syscall") );
1501 output( "\tadrp x16, %s\n", arm64_page( asm_name("__wine_syscall_dispatcher") ) );
1502 output( "\tldr x16, [x16, #%s]\n", arm64_pageoff( asm_name("__wine_syscall_dispatcher") ) );
1503 output( "\tbr x16\n");
1504 output_function_size( "__wine_syscall" );
1505 default:
1506 break;
1508 output( "\t.data\n" );
1509 output( "\t.align %d\n", get_alignment( get_ptr_size() ) );
1510 output( "%s\n", asm_globl("__wine_syscall_dispatcher") );
1511 output( "\t%s 0\n", get_asm_ptr_keyword() );
1512 output( "\t.short %u\n", count );
1513 for (i = 0; i < count; i++) output( "\t.byte %u\n", get_args_size( syscalls[i] ));
1517 /* output the import and delayed import tables of a Win32 module */
1518 void output_imports( DLLSPEC *spec )
1520 if (is_pe()) return;
1521 output_immediate_imports();
1522 output_delayed_imports( spec );
1523 output_immediate_import_thunks();
1524 output_delayed_import_thunks( spec );
1525 output_external_link_imports( spec );
1528 /* create a new asm temp file */
1529 static void new_output_as_file(void)
1531 char *name;
1533 if (output_file) fclose( output_file );
1534 name = open_temp_output_file( ".s" );
1535 strarray_add( &as_files, name );
1538 /* assemble all the asm files */
1539 static void assemble_files( const char *prefix )
1541 unsigned int i;
1543 if (output_file) fclose( output_file );
1544 output_file = NULL;
1546 for (i = 0; i < as_files.count; i++)
1548 char *obj = get_temp_file_name( prefix, ".o" );
1549 assemble_file( as_files.str[i], obj );
1550 as_files.str[i] = obj;
1554 /* build a library from the current asm files and any additional object files in argv */
1555 static void build_library( const char *output_name, struct strarray files, int create )
1557 struct strarray args;
1559 if (!create || target.platform != PLATFORM_WINDOWS)
1561 args = find_tool( "ar", NULL );
1562 strarray_add( &args, create ? "rc" : "r" );
1563 strarray_add( &args, output_name );
1565 else
1567 args = find_link_tool();
1568 strarray_add( &args, "/lib" );
1569 strarray_add( &args, strmake( "-out:%s", output_name ));
1571 strarray_addall( &args, as_files );
1572 strarray_addall( &args, files );
1573 if (create) unlink( output_name );
1574 spawn( args );
1576 if (target.platform != PLATFORM_WINDOWS)
1578 struct strarray ranlib = find_tool( "ranlib", NULL );
1579 strarray_add( &ranlib, output_name );
1580 spawn( ranlib );
1584 /* create a Windows-style import library */
1585 static void build_windows_import_lib( const char *lib_name, DLLSPEC *spec )
1587 struct strarray args;
1588 char *def_file;
1590 def_file = open_temp_output_file( ".def" );
1591 output_def_file( spec, 1 );
1592 fclose( output_file );
1594 args = find_tool( "dlltool", NULL );
1595 strarray_add( &args, "-k" );
1596 strarray_add( &args, strendswith( lib_name, ".delay.a" ) ? "-y" : "-l" );
1597 strarray_add( &args, lib_name );
1598 strarray_add( &args, "-d" );
1599 strarray_add( &args, def_file );
1601 switch (target.cpu)
1603 case CPU_i386:
1604 strarray_add( &args, "-m" );
1605 strarray_add( &args, "i386" );
1606 strarray_add( &args, "--as-flags=--32" );
1607 break;
1608 case CPU_x86_64:
1609 strarray_add( &args, "-m" );
1610 strarray_add( &args, "i386:x86-64" );
1611 strarray_add( &args, "--as-flags=--64" );
1612 break;
1613 case CPU_ARM:
1614 strarray_add( &args, "-m" );
1615 strarray_add( &args, "arm" );
1616 break;
1617 case CPU_ARM64:
1618 strarray_add( &args, "-m" );
1619 strarray_add( &args, "arm64" );
1620 break;
1621 default:
1622 break;
1625 spawn( args );
1628 /* create a Unix-style import library */
1629 static void build_unix_import_lib( DLLSPEC *spec )
1631 int i, total;
1632 const char *name, *prefix;
1633 char *dll_name = encode_dll_name( spec->file_name );
1635 /* entry points */
1637 for (i = total = 0; i < spec->nb_entry_points; i++)
1639 const ORDDEF *odp = &spec->entry_points[i];
1641 if (odp->name) name = odp->name;
1642 else if (odp->export_name) name = odp->export_name;
1643 else continue;
1645 if (odp->flags & FLAG_PRIVATE) continue;
1646 total++;
1648 /* C++ mangled names cannot be imported */
1649 if (strpbrk( name, "?@" )) continue;
1651 switch(odp->type)
1653 case TYPE_VARARGS:
1654 case TYPE_CDECL:
1655 case TYPE_STDCALL:
1656 prefix = (!odp->name || (odp->flags & FLAG_ORDINAL)) ? import_ord_prefix : import_func_prefix;
1657 new_output_as_file();
1658 output( "\t.text\n" );
1659 output( "\n\t.align %d\n", get_alignment( get_ptr_size() ));
1660 output( "\t%s\n", func_declaration( name ) );
1661 output( "%s\n", asm_globl( name ) );
1662 output( "\t%s %s%s$%u$%s\n", get_asm_ptr_keyword(),
1663 asm_name( prefix ), dll_name, odp->ordinal, name );
1664 output_function_size( name );
1665 output_gnu_stack_note();
1666 break;
1668 default:
1669 break;
1672 if (!total) warning( "%s: Import library doesn't export anything\n", spec->file_name );
1674 if (!as_files.count) /* create a dummy file to avoid empty import libraries */
1676 new_output_as_file();
1677 output( "\t.text\n" );
1680 assemble_files( spec->file_name );
1681 free( dll_name );
1684 /* output an import library for a Win32 module and additional object files */
1685 void output_static_lib( DLLSPEC *spec, struct strarray files )
1687 if (is_pe())
1689 if (spec) build_windows_import_lib( output_file_name, spec );
1690 if (files.count || !spec) build_library( output_file_name, files, !spec );
1692 else
1694 if (spec) build_unix_import_lib( spec );
1695 build_library( output_file_name, files, 1 );