d2d1: Create feature level 10.0 device context state objects.
[wine.git] / tools / winebuild / import.c
blobc876d51f8e6f1a0e3dea47695c371ef008abb10b
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]) );
634 fclose( output_file );
636 obj_file = get_temp_file_name( output_file_name, ".o" );
637 assemble_file( as_file, obj_file );
638 return obj_file;
641 /* combine a list of object files with ld into a single object file */
642 /* returns the name of the combined file */
643 static const char *ldcombine_files( DLLSPEC *spec, struct strarray files )
645 char *ld_tmp_file, *undef_file;
646 struct strarray args = get_ld_command();
648 undef_file = create_undef_symbols_file( spec );
649 ld_tmp_file = get_temp_file_name( output_file_name, ".o" );
651 strarray_add( &args, "-r" );
652 strarray_add( &args, "-o" );
653 strarray_add( &args, ld_tmp_file );
654 if (undef_file) strarray_add( &args, undef_file );
655 strarray_addall( &args, files );
656 spawn( args );
657 return ld_tmp_file;
660 /* read in the list of undefined symbols */
661 void read_undef_symbols( DLLSPEC *spec, struct strarray files )
663 size_t prefix_len;
664 FILE *f;
665 const char *prog = get_nm_command();
666 char *cmd, buffer[1024], name_prefix[16];
667 int err;
668 const char *name;
670 if (!files.count) return;
672 add_extra_undef_symbols( spec );
674 strcpy( name_prefix, asm_name("") );
675 prefix_len = strlen( name_prefix );
677 name = ldcombine_files( spec, files );
679 cmd = strmake( "%s -u %s", prog, name );
680 if (verbose)
681 fprintf( stderr, "%s\n", cmd );
682 if (!(f = popen( cmd, "r" )))
683 fatal_error( "Cannot execute '%s'\n", cmd );
685 while (fgets( buffer, sizeof(buffer), f ))
687 char *p = buffer + strlen(buffer) - 1;
688 if (p < buffer) continue;
689 if (*p == '\n') *p-- = 0;
690 p = buffer;
691 while (*p == ' ') p++;
692 if (p[0] == 'U' && p[1] == ' ' && p[2]) p += 2;
693 if (prefix_len && !strncmp( p, name_prefix, prefix_len )) p += prefix_len;
694 if (!strncmp( p, import_func_prefix, strlen(import_func_prefix) ))
695 add_undef_import( p + strlen( import_func_prefix ), 0 );
696 else if (!strncmp( p, import_ord_prefix, strlen(import_ord_prefix) ))
697 add_undef_import( p + strlen( import_ord_prefix ), 1 );
698 else if (use_msvcrt || !find_name( p, stdc_functions ))
699 strarray_add( &undef_symbols, xstrdup( p ));
701 if ((err = pclose( f ))) warning( "%s failed with status %d\n", cmd, err );
702 free( cmd );
705 void resolve_dll_imports( DLLSPEC *spec, struct list *list )
707 unsigned int j;
708 struct import *imp, *next;
709 ORDDEF *odp;
711 LIST_FOR_EACH_ENTRY_SAFE( imp, next, list, struct import, entry )
713 for (j = 0; j < undef_symbols.count; j++)
715 odp = find_export( undef_symbols.str[j], imp->exports, imp->nb_exports );
716 if (odp)
718 if (odp->flags & FLAG_PRIVATE) continue;
719 if (odp->type != TYPE_STDCALL && odp->type != TYPE_CDECL)
720 warning( "winebuild: Data export '%s' cannot be imported from %s\n",
721 odp->link_name, imp->dll_name );
722 else
724 add_import_func( imp, (odp->flags & FLAG_NONAME) ? NULL : odp->name,
725 odp->export_name, odp->ordinal, odp->hint );
726 remove_name( &undef_symbols, j-- );
730 if (!imp->nb_imports)
732 /* the dll is not used, get rid of it */
733 if (check_unused( imp, spec ))
734 warning( "winebuild: %s imported but no symbols used\n", imp->dll_name );
735 list_remove( &imp->entry );
736 free_imports( imp );
741 /* resolve the imports for a Win32 module */
742 void resolve_imports( DLLSPEC *spec )
744 check_undefined_forwards( spec );
745 resolve_dll_imports( spec, &dll_imports );
746 resolve_dll_imports( spec, &dll_delayed );
747 sort_names( &undef_symbols );
748 check_undefined_exports( spec );
751 /* check if symbol is still undefined */
752 int is_undefined( const char *name )
754 return find_name( name, undef_symbols ) != NULL;
757 /* output the get_pc thunk if needed */
758 void output_get_pc_thunk(void)
760 assert( target.cpu == CPU_i386 );
761 output( "\n\t.text\n" );
762 output( "\t.align %d\n", get_alignment(4) );
763 output( "\t%s\n", func_declaration("__wine_spec_get_pc_thunk_eax") );
764 output( "%s:\n", asm_name("__wine_spec_get_pc_thunk_eax") );
765 output_cfi( ".cfi_startproc" );
766 output( "\tmovl (%%esp),%%eax\n" );
767 output( "\tret\n" );
768 output_cfi( ".cfi_endproc" );
769 output_function_size( "__wine_spec_get_pc_thunk_eax" );
772 /* output a single import thunk */
773 static void output_import_thunk( const char *name, const char *table, int pos )
775 output( "\n\t.align %d\n", get_alignment(4) );
776 output( "\t%s\n", func_declaration(name) );
777 output( "%s\n", asm_globl(name) );
778 output_cfi( ".cfi_startproc" );
780 switch (target.cpu)
782 case CPU_i386:
783 if (!UsePIC)
785 output( "\tjmp *(%s+%d)\n", table, pos );
787 else
789 output( "\tcall %s\n", asm_name("__wine_spec_get_pc_thunk_eax") );
790 output( "1:\tjmp *%s+%d-1b(%%eax)\n", table, pos );
791 needs_get_pc_thunk = 1;
793 break;
794 case CPU_x86_64:
795 output( "\tjmpq *%s+%d(%%rip)\n", table, pos );
796 break;
797 case CPU_ARM:
798 if (UsePIC)
800 output( "\tldr ip, 2f\n");
801 output( "1:\tadd ip, pc\n" );
802 output( "\tldr pc, [ip]\n");
803 output( "2:\t.long %s+%u-1b-%u\n", table, pos, thumb_mode ? 4 : 8 );
805 else
807 output( "\tldr ip, 1f\n");
808 output( "\tldr pc, [ip]\n");
809 output( "1:\t.long %s+%u\n", table, pos );
811 break;
812 case CPU_ARM64:
813 output( "\tadrp x16, %s\n", arm64_page( table ) );
814 output( "\tadd x16, x16, #%s\n", arm64_pageoff( table ) );
815 if (pos & ~0x7fff) output( "\tadd x16, x16, #%u\n", pos & ~0x7fff );
816 output( "\tldr x16, [x16, #%u]\n", pos & 0x7fff );
817 output( "\tbr x16\n" );
818 break;
820 output_cfi( ".cfi_endproc" );
821 output_function_size( name );
824 /* check if we need an import directory */
825 int has_imports(void)
827 return !list_empty( &dll_imports );
830 /* output the import table of a Win32 module */
831 static void output_immediate_imports(void)
833 int i, j;
834 struct import *import;
836 if (list_empty( &dll_imports )) return; /* no immediate imports */
838 /* main import header */
840 output( "\n/* import table */\n" );
841 output( "\n\t.data\n" );
842 output( "\t.align %d\n", get_alignment(4) );
843 output( ".L__wine_spec_imports:\n" );
845 /* list of dlls */
847 j = 0;
848 LIST_FOR_EACH_ENTRY( import, &dll_imports, struct import, entry )
850 output_rva( ".L__wine_spec_import_data_names + %d", j * get_ptr_size() ); /* OriginalFirstThunk */
851 output( "\t.long 0\n" ); /* TimeDateStamp */
852 output( "\t.long 0\n" ); /* ForwarderChain */
853 output_rva( ".L__wine_spec_import_name_%s", import->c_name ); /* Name */
854 output_rva( ".L__wine_spec_import_data_ptrs + %d", j * get_ptr_size() ); /* FirstThunk */
855 j += import->nb_imports + 1;
857 output( "\t.long 0\n" ); /* OriginalFirstThunk */
858 output( "\t.long 0\n" ); /* TimeDateStamp */
859 output( "\t.long 0\n" ); /* ForwarderChain */
860 output( "\t.long 0\n" ); /* Name */
861 output( "\t.long 0\n" ); /* FirstThunk */
863 output( "\n\t.align %d\n", get_alignment(get_ptr_size()) );
864 /* output the names twice, once for OriginalFirstThunk and once for FirstThunk */
865 for (i = 0; i < 2; i++)
867 output( ".L__wine_spec_import_data_%s:\n", i ? "ptrs" : "names" );
868 LIST_FOR_EACH_ENTRY( import, &dll_imports, struct import, entry )
870 for (j = 0; j < import->nb_imports; j++)
872 struct import_func *func = &import->imports[j];
873 if (i)
875 if (func->name) output( "__imp_%s:\n", asm_name( func->name ));
876 else if (func->export_name) output( "__imp_%s:\n", asm_name( func->export_name ));
878 if (func->name)
879 output( "\t%s .L__wine_spec_import_data_%s_%s-.L__wine_spec_rva_base\n",
880 get_asm_ptr_keyword(), import->c_name, func->name );
881 else
883 if (get_ptr_size() == 8)
884 output( "\t.quad 0x800000000000%04x\n", func->ordinal );
885 else
886 output( "\t.long 0x8000%04x\n", func->ordinal );
889 output( "\t%s 0\n", get_asm_ptr_keyword() );
892 output( ".L__wine_spec_imports_end:\n" );
894 LIST_FOR_EACH_ENTRY( import, &dll_imports, struct import, entry )
896 for (j = 0; j < import->nb_imports; j++)
898 struct import_func *func = &import->imports[j];
899 if (!func->name) continue;
900 output( "\t.align %d\n", get_alignment(2) );
901 output( ".L__wine_spec_import_data_%s_%s:\n", import->c_name, func->name );
902 output( "\t.short %d\n", func->hint );
903 output( "\t%s \"%s\"\n", get_asm_string_keyword(), func->name );
907 LIST_FOR_EACH_ENTRY( import, &dll_imports, struct import, entry )
909 output( ".L__wine_spec_import_name_%s:\n\t%s \"%s\"\n",
910 import->c_name, get_asm_string_keyword(), import->dll_name );
914 /* output the import thunks of a Win32 module */
915 static void output_immediate_import_thunks(void)
917 int j, pos;
918 struct import *import;
919 static const char import_thunks[] = "__wine_spec_import_thunks";
921 if (list_empty( &dll_imports )) return;
923 output( "\n/* immediate import thunks */\n\n" );
924 output( "\t.text\n" );
925 output( "\t.align %d\n", get_alignment(8) );
926 output( "%s:\n", asm_name(import_thunks));
928 pos = 0;
929 LIST_FOR_EACH_ENTRY( import, &dll_imports, struct import, entry )
931 for (j = 0; j < import->nb_imports; j++, pos += get_ptr_size())
933 struct import_func *func = &import->imports[j];
934 output_import_thunk( func->name ? func->name : func->export_name,
935 ".L__wine_spec_import_data_ptrs", pos );
937 pos += get_ptr_size();
939 output_function_size( import_thunks );
942 /* output the delayed import table of a Win32 module */
943 static void output_delayed_imports( const DLLSPEC *spec )
945 int j, mod;
946 struct import *import;
948 if (list_empty( &dll_delayed )) return;
950 output( "\n/* delayed imports */\n\n" );
951 output( "\t.data\n" );
952 output( "\t.align %d\n", get_alignment(get_ptr_size()) );
953 output( "%s\n", asm_globl("__wine_spec_delay_imports") );
955 /* list of dlls */
957 j = mod = 0;
958 LIST_FOR_EACH_ENTRY( import, &dll_delayed, struct import, entry )
960 output( "\t%s 0\n", get_asm_ptr_keyword() ); /* grAttrs */
961 output( "\t%s .L__wine_delay_name_%s\n", /* szName */
962 get_asm_ptr_keyword(), import->c_name );
963 output( "\t%s .L__wine_delay_modules+%d\n", /* phmod */
964 get_asm_ptr_keyword(), mod * get_ptr_size() );
965 output( "\t%s .L__wine_delay_IAT+%d\n", /* pIAT */
966 get_asm_ptr_keyword(), j * get_ptr_size() );
967 output( "\t%s .L__wine_delay_INT+%d\n", /* pINT */
968 get_asm_ptr_keyword(), j * get_ptr_size() );
969 output( "\t%s 0\n", get_asm_ptr_keyword() ); /* pBoundIAT */
970 output( "\t%s 0\n", get_asm_ptr_keyword() ); /* pUnloadIAT */
971 output( "\t%s 0\n", get_asm_ptr_keyword() ); /* dwTimeStamp */
972 j += import->nb_imports;
973 mod++;
975 output( "\t%s 0\n", get_asm_ptr_keyword() ); /* grAttrs */
976 output( "\t%s 0\n", get_asm_ptr_keyword() ); /* szName */
977 output( "\t%s 0\n", get_asm_ptr_keyword() ); /* phmod */
978 output( "\t%s 0\n", get_asm_ptr_keyword() ); /* pIAT */
979 output( "\t%s 0\n", get_asm_ptr_keyword() ); /* pINT */
980 output( "\t%s 0\n", get_asm_ptr_keyword() ); /* pBoundIAT */
981 output( "\t%s 0\n", get_asm_ptr_keyword() ); /* pUnloadIAT */
982 output( "\t%s 0\n", get_asm_ptr_keyword() ); /* dwTimeStamp */
984 output( "\n.L__wine_delay_IAT:\n" );
985 LIST_FOR_EACH_ENTRY( import, &dll_delayed, struct import, entry )
987 for (j = 0; j < import->nb_imports; j++)
989 struct import_func *func = &import->imports[j];
990 const char *name = func->name ? func->name : func->export_name;
991 output( "__imp_%s:\n", asm_name( name ));
992 output( "\t%s __wine_delay_imp_%s_%s\n",
993 get_asm_ptr_keyword(), import->c_name, name );
997 output( "\n.L__wine_delay_INT:\n" );
998 LIST_FOR_EACH_ENTRY( import, &dll_delayed, struct import, entry )
1000 for (j = 0; j < import->nb_imports; j++)
1002 struct import_func *func = &import->imports[j];
1003 if (!func->name)
1004 output( "\t%s %d\n", get_asm_ptr_keyword(), func->ordinal );
1005 else
1006 output( "\t%s .L__wine_delay_data_%s_%s\n",
1007 get_asm_ptr_keyword(), import->c_name, func->name );
1011 output( "\n.L__wine_delay_modules:\n" );
1012 LIST_FOR_EACH_ENTRY( import, &dll_delayed, struct import, entry )
1014 output( "\t%s 0\n", get_asm_ptr_keyword() );
1017 LIST_FOR_EACH_ENTRY( import, &dll_delayed, struct import, entry )
1019 output( ".L__wine_delay_name_%s:\n", import->c_name );
1020 output( "\t%s \"%s\"\n", get_asm_string_keyword(), import->dll_name );
1023 LIST_FOR_EACH_ENTRY( import, &dll_delayed, struct import, entry )
1025 for (j = 0; j < import->nb_imports; j++)
1027 struct import_func *func = &import->imports[j];
1028 if (!func->name) continue;
1029 output( ".L__wine_delay_data_%s_%s:\n", import->c_name, func->name );
1030 output( "\t%s \"%s\"\n", get_asm_string_keyword(), func->name );
1033 output_function_size( "__wine_spec_delay_imports" );
1036 /* output the delayed import thunks of a Win32 module */
1037 static void output_delayed_import_thunks( const DLLSPEC *spec )
1039 int idx, j, pos;
1040 struct import *import;
1041 static const char delayed_import_loaders[] = "__wine_spec_delayed_import_loaders";
1042 static const char delayed_import_thunks[] = "__wine_spec_delayed_import_thunks";
1044 if (list_empty( &dll_delayed )) return;
1046 output( "\n/* delayed import thunks */\n\n" );
1047 output( "\t.text\n" );
1048 output( "\t.align %d\n", get_alignment(8) );
1049 output( "%s:\n", asm_name(delayed_import_loaders));
1050 output( "\t%s\n", func_declaration("__wine_delay_load_asm") );
1051 output( "%s:\n", asm_name("__wine_delay_load_asm") );
1052 output_cfi( ".cfi_startproc" );
1053 switch (target.cpu)
1055 case CPU_i386:
1056 output( "\tpushl %%ecx\n" );
1057 output_cfi( ".cfi_adjust_cfa_offset 4" );
1058 output( "\tpushl %%edx\n" );
1059 output_cfi( ".cfi_adjust_cfa_offset 4" );
1060 output( "\tpushl %%eax\n" );
1061 output_cfi( ".cfi_adjust_cfa_offset 4" );
1062 output( "\tcall %s\n", asm_name("__wine_spec_delay_load") );
1063 output_cfi( ".cfi_adjust_cfa_offset -4" );
1064 output( "\tpopl %%edx\n" );
1065 output_cfi( ".cfi_adjust_cfa_offset -4" );
1066 output( "\tpopl %%ecx\n" );
1067 output_cfi( ".cfi_adjust_cfa_offset -4" );
1068 output( "\tjmp *%%eax\n" );
1069 break;
1070 case CPU_x86_64:
1071 output( "\tsubq $0x98,%%rsp\n" );
1072 output_cfi( ".cfi_adjust_cfa_offset 0x98" );
1073 output( "\tmovq %%rdx,0x88(%%rsp)\n" );
1074 output( "\tmovq %%rcx,0x80(%%rsp)\n" );
1075 output( "\tmovq %%r8,0x78(%%rsp)\n" );
1076 output( "\tmovq %%r9,0x70(%%rsp)\n" );
1077 output( "\tmovq %%r10,0x68(%%rsp)\n" );
1078 output( "\tmovq %%r11,0x60(%%rsp)\n" );
1079 output( "\tmovups %%xmm0,0x50(%%rsp)\n" );
1080 output( "\tmovups %%xmm1,0x40(%%rsp)\n" );
1081 output( "\tmovups %%xmm2,0x30(%%rsp)\n" );
1082 output( "\tmovups %%xmm3,0x20(%%rsp)\n" );
1083 output( "\tmovq %%rax,%%rcx\n" );
1084 output( "\tcall %s\n", asm_name("__wine_spec_delay_load") );
1085 output( "\tmovups 0x20(%%rsp),%%xmm3\n" );
1086 output( "\tmovups 0x30(%%rsp),%%xmm2\n" );
1087 output( "\tmovups 0x40(%%rsp),%%xmm1\n" );
1088 output( "\tmovups 0x50(%%rsp),%%xmm0\n" );
1089 output( "\tmovq 0x60(%%rsp),%%r11\n" );
1090 output( "\tmovq 0x68(%%rsp),%%r10\n" );
1091 output( "\tmovq 0x70(%%rsp),%%r9\n" );
1092 output( "\tmovq 0x78(%%rsp),%%r8\n" );
1093 output( "\tmovq 0x80(%%rsp),%%rcx\n" );
1094 output( "\tmovq 0x88(%%rsp),%%rdx\n" );
1095 output( "\taddq $0x98,%%rsp\n" );
1096 output_cfi( ".cfi_adjust_cfa_offset -0x98" );
1097 output( "\tjmp *%%rax\n" );
1098 break;
1099 case CPU_ARM:
1100 output( "\tpush {r0-r3,FP,LR}\n" );
1101 output( "\tmov r0,IP\n" );
1102 output( "\tbl %s\n", asm_name("__wine_spec_delay_load") );
1103 output( "\tmov IP,r0\n");
1104 output( "\tpop {r0-r3,FP,LR}\n" );
1105 output( "\tbx IP\n");
1106 break;
1107 case CPU_ARM64:
1108 output( "\tstp x29, x30, [sp,#-80]!\n" );
1109 output( "\tmov x29, sp\n" );
1110 output( "\tstp x0, x1, [sp,#16]\n" );
1111 output( "\tstp x2, x3, [sp,#32]\n" );
1112 output( "\tstp x4, x5, [sp,#48]\n" );
1113 output( "\tstp x6, x7, [sp,#64]\n" );
1114 output( "\tmov x0, x16\n" );
1115 output( "\tbl %s\n", asm_name("__wine_spec_delay_load") );
1116 output( "\tmov x16, x0\n" );
1117 output( "\tldp x0, x1, [sp,#16]\n" );
1118 output( "\tldp x2, x3, [sp,#32]\n" );
1119 output( "\tldp x4, x5, [sp,#48]\n" );
1120 output( "\tldp x6, x7, [sp,#64]\n" );
1121 output( "\tldp x29, x30, [sp],#80\n" );
1122 output( "\tbr x16\n" );
1123 break;
1125 output_cfi( ".cfi_endproc" );
1126 output_function_size( "__wine_delay_load_asm" );
1127 output( "\n" );
1129 idx = 0;
1130 LIST_FOR_EACH_ENTRY( import, &dll_delayed, struct import, entry )
1132 for (j = 0; j < import->nb_imports; j++)
1134 struct import_func *func = &import->imports[j];
1135 const char *name = func->name ? func->name : func->export_name;
1137 if (thumb_mode) output( "\t.thumb_func\n" );
1138 output( "__wine_delay_imp_%s_%s:\n", import->c_name, name );
1139 output_cfi( ".cfi_startproc" );
1140 switch (target.cpu)
1142 case CPU_i386:
1143 case CPU_x86_64:
1144 output( "\tmovl $%d,%%eax\n", (idx << 16) | j );
1145 output( "\tjmp %s\n", asm_name("__wine_delay_load_asm") );
1146 break;
1147 case CPU_ARM:
1148 output( "\tmov ip, #%u\n", j );
1149 if (idx) output( "\tmovt ip, #%u\n", idx );
1150 output( "\tb %s\n", asm_name("__wine_delay_load_asm") );
1151 break;
1152 case CPU_ARM64:
1153 if (idx)
1155 output( "\tmov x16, #0x%x\n", idx << 16 );
1156 if (j) output( "\tmovk x16, #0x%x\n", j );
1158 else output( "\tmov x16, #0x%x\n", j );
1159 output( "\tb %s\n", asm_name("__wine_delay_load_asm") );
1160 break;
1162 output_cfi( ".cfi_endproc" );
1164 idx++;
1166 output_function_size( delayed_import_loaders );
1168 output( "\n\t.align %d\n", get_alignment(get_ptr_size()) );
1169 output( "%s:\n", asm_name(delayed_import_thunks));
1170 pos = 0;
1171 LIST_FOR_EACH_ENTRY( import, &dll_delayed, struct import, entry )
1173 for (j = 0; j < import->nb_imports; j++, pos += get_ptr_size())
1175 struct import_func *func = &import->imports[j];
1176 output_import_thunk( func->name ? func->name : func->export_name,
1177 ".L__wine_delay_IAT", pos );
1180 output_function_size( delayed_import_thunks );
1183 /* output import stubs for exported entry points that link to external symbols */
1184 static void output_external_link_imports( DLLSPEC *spec )
1186 unsigned int i, pos;
1188 if (!ext_link_imports.count) return; /* nothing to do */
1190 sort_names( &ext_link_imports );
1192 /* get rid of duplicate names */
1193 for (i = 1; i < ext_link_imports.count; i++)
1195 if (!strcmp( ext_link_imports.str[i-1], ext_link_imports.str[i] ))
1196 remove_name( &ext_link_imports, i-- );
1199 output( "\n/* external link thunks */\n\n" );
1200 output( "\t.data\n" );
1201 output( "\t.align %d\n", get_alignment(get_ptr_size()) );
1202 output( ".L__wine_spec_external_links:\n" );
1203 for (i = 0; i < ext_link_imports.count; i++)
1204 output( "\t%s %s\n", get_asm_ptr_keyword(), asm_name(ext_link_imports.str[i]) );
1206 output( "\n\t.text\n" );
1207 output( "\t.align %d\n", get_alignment(get_ptr_size()) );
1208 output( "%s:\n", asm_name("__wine_spec_external_link_thunks") );
1210 for (i = pos = 0; i < ext_link_imports.count; i++)
1212 char *buffer = strmake( "__wine_spec_ext_link_%s", ext_link_imports.str[i] );
1213 output_import_thunk( buffer, ".L__wine_spec_external_links", pos );
1214 free( buffer );
1215 pos += get_ptr_size();
1217 output_function_size( "__wine_spec_external_link_thunks" );
1220 /*******************************************************************
1221 * output_stubs
1223 * Output the functions for stub entry points
1225 void output_stubs( DLLSPEC *spec )
1227 const char *name, *exp_name;
1228 int i;
1230 if (!has_stubs( spec )) return;
1232 output( "\n/* stub functions */\n\n" );
1233 output( "\t.text\n" );
1235 for (i = 0; i < spec->nb_entry_points; i++)
1237 ORDDEF *odp = &spec->entry_points[i];
1238 if (odp->type != TYPE_STUB) continue;
1240 name = get_stub_name( odp, spec );
1241 exp_name = odp->name ? odp->name : odp->export_name;
1242 output( "\t.align %d\n", get_alignment(4) );
1243 output( "\t%s\n", func_declaration(name) );
1244 output( "%s:\n", asm_name(name) );
1245 output_cfi( ".cfi_startproc" );
1247 switch (target.cpu)
1249 case CPU_i386:
1250 /* flesh out the stub a bit to make safedisc happy */
1251 output(" \tnop\n" );
1252 output(" \tnop\n" );
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" );
1261 output( "\tsubl $12,%%esp\n" );
1262 output_cfi( ".cfi_adjust_cfa_offset 12" );
1263 if (UsePIC)
1265 output( "\tcall %s\n", asm_name("__wine_spec_get_pc_thunk_eax") );
1266 output( "1:" );
1267 needs_get_pc_thunk = 1;
1268 if (exp_name)
1270 output( "\tleal .L%s_string-1b(%%eax),%%ecx\n", name );
1271 output( "\tmovl %%ecx,4(%%esp)\n" );
1273 else
1274 output( "\tmovl $%d,4(%%esp)\n", odp->ordinal );
1275 output( "\tleal .L__wine_spec_file_name-1b(%%eax),%%ecx\n" );
1276 output( "\tmovl %%ecx,(%%esp)\n" );
1278 else
1280 if (exp_name)
1281 output( "\tmovl $.L%s_string,4(%%esp)\n", name );
1282 else
1283 output( "\tmovl $%d,4(%%esp)\n", odp->ordinal );
1284 output( "\tmovl $.L__wine_spec_file_name,(%%esp)\n" );
1286 output( "\tcall %s\n", asm_name("__wine_spec_unimplemented_stub") );
1287 break;
1288 case CPU_x86_64:
1289 output( "\tsubq $0x28,%%rsp\n" );
1290 output_cfi( ".cfi_adjust_cfa_offset 8" );
1291 output( "\tleaq .L__wine_spec_file_name(%%rip),%%rcx\n" );
1292 if (exp_name)
1293 output( "leaq .L%s_string(%%rip),%%rdx\n", name );
1294 else
1295 output( "\tmovq $%d,%%rdx\n", odp->ordinal );
1296 output( "\tcall %s\n", asm_name("__wine_spec_unimplemented_stub") );
1297 break;
1298 case CPU_ARM:
1299 if (UsePIC)
1301 output( "\tldr r0,3f\n");
1302 output( "1:\tadd r0,PC\n");
1303 output( "\tldr r1,3f+4\n");
1304 if (exp_name) output( "2:\tadd r1,PC\n");
1305 output( "\tbl %s\n", asm_name("__wine_spec_unimplemented_stub") );
1306 output( "3:\t.long .L__wine_spec_file_name-1b-%u\n", thumb_mode ? 4 : 8 );
1307 if (exp_name) output( "\t.long .L%s_string-2b-%u\n", name, thumb_mode ? 4 : 8 );
1308 else output( "\t.long %u\n", odp->ordinal );
1310 else
1312 output( "\tmovw r0,:lower16:.L__wine_spec_file_name\n");
1313 output( "\tmovt r0,:upper16:.L__wine_spec_file_name\n");
1314 if (exp_name)
1316 output( "\tmovw r1,:lower16:.L%s_string\n", name );
1317 output( "\tmovt r1,:upper16:.L%s_string\n", name );
1319 else output( "\tmov r1,#%u\n", odp->ordinal );
1320 output( "\tbl %s\n", asm_name("__wine_spec_unimplemented_stub") );
1322 break;
1323 case CPU_ARM64:
1324 output( "\tadrp x0, %s\n", arm64_page(".L__wine_spec_file_name") );
1325 output( "\tadd x0, x0, #%s\n", arm64_pageoff(".L__wine_spec_file_name") );
1326 if (exp_name)
1328 char *sym = strmake( ".L%s_string", name );
1329 output( "\tadrp x1, %s\n", arm64_page( sym ) );
1330 output( "\tadd x1, x1, #%s\n", arm64_pageoff( sym ) );
1331 free( sym );
1333 else
1334 output( "\tmov x1, %u\n", odp->ordinal );
1335 output( "\tbl %s\n", asm_name("__wine_spec_unimplemented_stub") );
1336 break;
1337 default:
1338 assert(0);
1340 output_cfi( ".cfi_endproc" );
1341 output_function_size( name );
1344 output( "\t%s\n", get_asm_string_section() );
1345 output( ".L__wine_spec_file_name:\n" );
1346 output( "\t%s \"%s\"\n", get_asm_string_keyword(), spec->file_name );
1347 for (i = 0; i < spec->nb_entry_points; i++)
1349 ORDDEF *odp = &spec->entry_points[i];
1350 if (odp->type != TYPE_STUB) continue;
1351 exp_name = odp->name ? odp->name : odp->export_name;
1352 if (exp_name)
1354 name = get_stub_name( odp, spec );
1355 output( ".L%s_string:\n", name );
1356 output( "\t%s \"%s\"\n", get_asm_string_keyword(), exp_name );
1361 static int cmp_link_name( const void *e1, const void *e2 )
1363 const ORDDEF *odp1 = *(const ORDDEF * const *)e1;
1364 const ORDDEF *odp2 = *(const ORDDEF * const *)e2;
1366 return strcmp( odp1->link_name, odp2->link_name );
1370 /* output the functions for system calls */
1371 void output_syscalls( DLLSPEC *spec )
1373 int i, count;
1374 ORDDEF **syscalls = NULL;
1376 if (unix_lib) return;
1378 for (i = count = 0; i < spec->nb_entry_points; i++)
1380 ORDDEF *odp = &spec->entry_points[i];
1381 if (!(odp->flags & FLAG_SYSCALL)) continue;
1382 if (!syscalls) syscalls = xmalloc( (spec->nb_entry_points - i) * sizeof(*syscalls) );
1383 syscalls[count++] = odp;
1385 if (!count) return;
1386 count = sort_func_list( syscalls, count, cmp_link_name );
1388 output( "\n/* system calls */\n\n" );
1389 output( "\t.text\n" );
1391 for (i = 0; i < count; i++)
1393 ORDDEF *odp = syscalls[i];
1394 const char *name = get_link_name(odp);
1395 unsigned int id = (spec->syscall_table << 12) + i;
1397 output( "\t.align %d\n", get_alignment(16) );
1398 output( "\t%s\n", func_declaration(name) );
1399 output( "%s\n", asm_globl(name) );
1400 output_cfi( ".cfi_startproc" );
1401 switch (target.cpu)
1403 case CPU_i386:
1404 if (UsePIC)
1406 output( "\tcall %s\n", asm_name("__wine_spec_get_pc_thunk_eax") );
1407 output( "1:\tmovl %s-1b(%%eax),%%edx\n", asm_name("__wine_syscall_dispatcher") );
1408 output( "\tmovl $%u,%%eax\n", id );
1409 needs_get_pc_thunk = 1;
1411 else
1413 output( "\tmovl $%u,%%eax\n", id );
1414 output( "\tmovl $%s,%%edx\n", asm_name("__wine_syscall") );
1416 output( "\tcall *%%edx\n" );
1417 output( "\tret $%u\n", odp->type == TYPE_STDCALL ? get_args_size( odp ) : 0 );
1418 break;
1419 case CPU_x86_64:
1420 /* Chromium depends on syscall thunks having the same form as on
1421 * Windows. For 64-bit systems the only viable form we can emulate is
1422 * having an int $0x2e fallback. Since actually using an interrupt is
1423 * expensive, and since for some reason Chromium doesn't actually
1424 * validate that instruction, we can just put a jmp there instead. */
1425 output( "\t.byte 0x4c,0x8b,0xd1\n" ); /* movq %rcx,%r10 */
1426 output( "\t.byte 0xb8\n" ); /* movl $i,%eax */
1427 output( "\t.long %u\n", id );
1428 output( "\t.byte 0xf6,0x04,0x25,0x08,0x03,0xfe,0x7f,0x01\n" ); /* testb $1,0x7ffe0308 */
1429 output( "\t.byte 0x75,0x03\n" ); /* jne 1f */
1430 output( "\t.byte 0x0f,0x05\n" ); /* syscall */
1431 output( "\t.byte 0xc3\n" ); /* ret */
1432 output( "\tjmp 1f\n" );
1433 output( "\t.byte 0xc3\n" ); /* ret */
1434 if (is_pe())
1436 output( "1:\t.byte 0xff,0x14,0x25\n" ); /* 1: callq *(0x7ffe1000) */
1437 output( "\t.long 0x7ffe1000\n" );
1439 else
1441 output( "\tnop\n" );
1442 output( "1:\tcallq *%s(%%rip)\n", asm_name("__wine_syscall_dispatcher") );
1444 output( "\tret\n" );
1445 break;
1446 case CPU_ARM:
1447 output( "\tpush {r0-r3}\n" );
1448 output( "\tmovw ip, #%u\n", id );
1449 output( "\tmov r3, lr\n" );
1450 output( "\tbl %s\n", asm_name("__wine_syscall") );
1451 output( "\tbx lr\n" );
1452 break;
1453 case CPU_ARM64:
1454 output( "\tmov x8, #%u\n", id );
1455 output( "\tmov x9, x30\n" );
1456 output( "\tbl %s\n", asm_name("__wine_syscall" ));
1457 output( "\tret\n" );
1458 break;
1459 default:
1460 assert(0);
1462 output_cfi( ".cfi_endproc" );
1463 output_function_size( name );
1466 switch (target.cpu)
1468 case CPU_i386:
1469 if (UsePIC) break;
1470 output( "\t.align %d\n", get_alignment(16) );
1471 output( "\t%s\n", func_declaration("__wine_syscall") );
1472 output( "%s:\n", asm_name("__wine_syscall") );
1473 output( "\tjmp *(%s)\n", asm_name("__wine_syscall_dispatcher") );
1474 output_function_size( "__wine_syscall" );
1475 break;
1476 case CPU_ARM:
1477 output( "\t.align %d\n", get_alignment(16) );
1478 output( "\t%s\n", func_declaration("__wine_syscall") );
1479 output( "%s:\n", asm_name("__wine_syscall") );
1480 if (UsePIC)
1482 output( "\tldr r0, 2f\n");
1483 output( "1:\tadd r0, pc\n" );
1485 else
1487 output( "\tmovw r0, :lower16:%s\n", asm_name("__wine_syscall_dispatcher") );
1488 output( "\tmovt r0, :upper16:%s\n", asm_name("__wine_syscall_dispatcher") );
1490 output( "\tldr r0, [r0]\n");
1491 output( "\tbx r0\n");
1492 if (UsePIC) output( "2:\t.long %s-1b-%u\n", asm_name("__wine_syscall_dispatcher"), thumb_mode ? 4 : 8 );
1493 output_function_size( "__wine_syscall" );
1494 break;
1495 case CPU_ARM64:
1496 output( "\t.align %d\n", get_alignment(16) );
1497 output( "\t%s\n", func_declaration("__wine_syscall") );
1498 output( "%s:\n", asm_name("__wine_syscall") );
1499 output( "\tadrp x16, %s\n", arm64_page( asm_name("__wine_syscall_dispatcher") ) );
1500 output( "\tldr x16, [x16, #%s]\n", arm64_pageoff( asm_name("__wine_syscall_dispatcher") ) );
1501 output( "\tbr x16\n");
1502 output_function_size( "__wine_syscall" );
1503 default:
1504 break;
1506 output( "\t.data\n" );
1507 output( "\t.align %d\n", get_alignment( get_ptr_size() ) );
1508 output( "%s\n", asm_globl("__wine_syscall_dispatcher") );
1509 output( "\t%s 0\n", get_asm_ptr_keyword() );
1510 output( "\t.short %u\n", count );
1511 for (i = 0; i < count; i++) output( "\t.byte %u\n", get_args_size( syscalls[i] ));
1515 /* output the import and delayed import tables of a Win32 module */
1516 void output_imports( DLLSPEC *spec )
1518 if (is_pe()) return;
1519 output_immediate_imports();
1520 output_delayed_imports( spec );
1521 output_immediate_import_thunks();
1522 output_delayed_import_thunks( spec );
1523 output_external_link_imports( spec );
1526 /* create a new asm temp file */
1527 static void new_output_as_file(void)
1529 char *name;
1531 if (output_file) fclose( output_file );
1532 name = open_temp_output_file( ".s" );
1533 strarray_add( &as_files, name );
1536 /* assemble all the asm files */
1537 static void assemble_files( const char *prefix )
1539 unsigned int i;
1541 if (output_file) fclose( output_file );
1542 output_file = NULL;
1544 for (i = 0; i < as_files.count; i++)
1546 char *obj = get_temp_file_name( prefix, ".o" );
1547 assemble_file( as_files.str[i], obj );
1548 as_files.str[i] = obj;
1552 /* build a library from the current asm files and any additional object files in argv */
1553 static void build_library( const char *output_name, struct strarray files, int create )
1555 struct strarray args;
1557 if (!create || target.platform != PLATFORM_WINDOWS)
1559 args = find_tool( "ar", NULL );
1560 strarray_add( &args, create ? "rc" : "r" );
1561 strarray_add( &args, output_name );
1563 else
1565 args = find_link_tool();
1566 strarray_add( &args, "/lib" );
1567 strarray_add( &args, strmake( "-out:%s", output_name ));
1569 strarray_addall( &args, as_files );
1570 strarray_addall( &args, files );
1571 if (create) unlink( output_name );
1572 spawn( args );
1574 if (target.platform != PLATFORM_WINDOWS)
1576 struct strarray ranlib = find_tool( "ranlib", NULL );
1577 strarray_add( &ranlib, output_name );
1578 spawn( ranlib );
1582 /* create a Windows-style import library */
1583 static void build_windows_import_lib( const char *lib_name, DLLSPEC *spec )
1585 struct strarray args;
1586 char *def_file;
1588 def_file = open_temp_output_file( ".def" );
1589 output_def_file( spec, 1 );
1590 fclose( output_file );
1592 args = find_tool( "dlltool", NULL );
1593 strarray_add( &args, "-k" );
1594 strarray_add( &args, strendswith( lib_name, ".delay.a" ) ? "-y" : "-l" );
1595 strarray_add( &args, lib_name );
1596 strarray_add( &args, "-d" );
1597 strarray_add( &args, def_file );
1599 switch (target.cpu)
1601 case CPU_i386:
1602 strarray_add( &args, "-m" );
1603 strarray_add( &args, "i386" );
1604 strarray_add( &args, "--as-flags=--32" );
1605 break;
1606 case CPU_x86_64:
1607 strarray_add( &args, "-m" );
1608 strarray_add( &args, "i386:x86-64" );
1609 strarray_add( &args, "--as-flags=--64" );
1610 break;
1611 case CPU_ARM:
1612 strarray_add( &args, "-m" );
1613 strarray_add( &args, "arm" );
1614 break;
1615 case CPU_ARM64:
1616 strarray_add( &args, "-m" );
1617 strarray_add( &args, "arm64" );
1618 break;
1619 default:
1620 break;
1623 spawn( args );
1626 /* create a Unix-style import library */
1627 static void build_unix_import_lib( DLLSPEC *spec )
1629 int i, total;
1630 const char *name, *prefix;
1631 char *dll_name = encode_dll_name( spec->file_name );
1633 /* entry points */
1635 for (i = total = 0; i < spec->nb_entry_points; i++)
1637 const ORDDEF *odp = &spec->entry_points[i];
1639 if (odp->name) name = odp->name;
1640 else if (odp->export_name) name = odp->export_name;
1641 else continue;
1643 if (odp->flags & FLAG_PRIVATE) continue;
1644 total++;
1646 /* C++ mangled names cannot be imported */
1647 if (strpbrk( name, "?@" )) continue;
1649 switch(odp->type)
1651 case TYPE_VARARGS:
1652 case TYPE_CDECL:
1653 case TYPE_STDCALL:
1654 prefix = (!odp->name || (odp->flags & FLAG_ORDINAL)) ? import_ord_prefix : import_func_prefix;
1655 new_output_as_file();
1656 output( "\t.text\n" );
1657 output( "\n\t.align %d\n", get_alignment( get_ptr_size() ));
1658 output( "\t%s\n", func_declaration( name ) );
1659 output( "%s\n", asm_globl( name ) );
1660 output( "\t%s %s%s$%u$%s\n", get_asm_ptr_keyword(),
1661 asm_name( prefix ), dll_name, odp->ordinal, name );
1662 output_function_size( name );
1663 output_gnu_stack_note();
1664 break;
1666 default:
1667 break;
1670 if (!total) warning( "%s: Import library doesn't export anything\n", spec->file_name );
1672 if (!as_files.count) /* create a dummy file to avoid empty import libraries */
1674 new_output_as_file();
1675 output( "\t.text\n" );
1678 assemble_files( spec->file_name );
1679 free( dll_name );
1682 /* output an import library for a Win32 module and additional object files */
1683 void output_static_lib( DLLSPEC *spec, struct strarray files )
1685 if (is_pe())
1687 if (spec) build_windows_import_lib( output_file_name, spec );
1688 if (files.count || !spec) build_library( output_file_name, files, !spec );
1690 else
1692 if (spec) build_unix_import_lib( spec );
1693 build_library( output_file_name, files, 1 );