mfplat: Implement IMFMediaType_(Get|Free)Representation.
[wine.git] / tools / winebuild / import.c
blob9325837b7490910ae999a05253e39e457e6e87e9
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 "build.h"
32 #include "wine/list.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 for (i = 0; i < spec->nb_entry_points; i++)
502 ORDDEF *odp = &spec->entry_points[i];
503 if (odp->type == TYPE_STUB) return 1;
505 return 0;
508 /* add the extra undefined symbols that will be contained in the generated spec file itself */
509 static void add_extra_undef_symbols( DLLSPEC *spec )
511 add_extra_ld_symbol( spec->init_func );
512 if (spec->type == SPEC_WIN16) add_extra_ld_symbol( "DllMain" );
513 if (has_stubs( spec )) add_extra_ld_symbol( "__wine_spec_unimplemented_stub" );
514 if (delayed_imports.count) add_extra_ld_symbol( "__delayLoadHelper2" );
517 /* check if a given imported dll is not needed, taking forwards into account */
518 static int check_unused( const struct import* imp, const DLLSPEC *spec )
520 int i;
521 const char *file_name = imp->dll_name;
522 size_t len = strlen( file_name );
523 const char *p = strchr( file_name, '.' );
524 if (p && !strcasecmp( p, ".dll" )) len = p - file_name;
526 for (i = spec->base; i <= spec->limit; i++)
528 ORDDEF *odp = spec->ordinals[i];
529 if (!odp || !(odp->flags & FLAG_FORWARD)) continue;
530 if (!strncasecmp( odp->link_name, file_name, len ) &&
531 odp->link_name[len] == '.')
532 return 0; /* found a forward, it is used */
534 return 1;
537 /* check if a given forward does exist in one of the imported dlls */
538 static void check_undefined_forwards( DLLSPEC *spec )
540 struct import *imp;
541 char *link_name, *api_name, *dll_name, *p;
542 int i;
544 for (i = 0; i < spec->nb_entry_points; i++)
546 ORDDEF *odp = &spec->entry_points[i];
548 if (!(odp->flags & FLAG_FORWARD)) continue;
550 link_name = xstrdup( odp->link_name );
551 p = strrchr( link_name, '.' );
552 *p = 0;
553 api_name = p + 1;
554 dll_name = get_dll_name( link_name, NULL );
556 if ((imp = find_import_dll( dll_name )))
558 if (!find_export( api_name, imp->exports, imp->nb_exports ))
559 warning( "%s:%d: forward '%s' not found in %s\n",
560 spec->src_name, odp->lineno, odp->link_name, imp->dll_name );
562 else warning( "%s:%d: forward '%s' not found in the imported dll list\n",
563 spec->src_name, odp->lineno, odp->link_name );
564 free( link_name );
565 free( dll_name );
569 /* flag the dll exports that link to an undefined symbol */
570 static void check_undefined_exports( DLLSPEC *spec )
572 int i;
574 for (i = 0; i < spec->nb_entry_points; i++)
576 ORDDEF *odp = &spec->entry_points[i];
577 if (odp->type == TYPE_STUB || odp->type == TYPE_ABS || odp->type == TYPE_VARIABLE) continue;
578 if (odp->flags & FLAG_FORWARD) continue;
579 if (find_name( odp->link_name, undef_symbols ))
581 switch(odp->type)
583 case TYPE_PASCAL:
584 case TYPE_STDCALL:
585 case TYPE_CDECL:
586 case TYPE_VARARGS:
587 if (link_ext_symbols)
589 odp->flags |= FLAG_EXT_LINK;
590 strarray_add( &ext_link_imports, odp->link_name );
592 else error( "%s:%d: function '%s' not defined\n",
593 spec->src_name, odp->lineno, odp->link_name );
594 break;
595 default:
596 error( "%s:%d: external symbol '%s' is not a function\n",
597 spec->src_name, odp->lineno, odp->link_name );
598 break;
604 /* create a .o file that references all the undefined symbols we want to resolve */
605 static char *create_undef_symbols_file( DLLSPEC *spec )
607 char *as_file, *obj_file;
608 int i;
609 unsigned int j;
611 as_file = open_temp_output_file( ".s" );
612 output( "\t.data\n" );
614 for (i = 0; i < spec->nb_entry_points; i++)
616 ORDDEF *odp = &spec->entry_points[i];
617 if (odp->type == TYPE_STUB || odp->type == TYPE_ABS || odp->type == TYPE_VARIABLE) continue;
618 if (odp->flags & FLAG_FORWARD) continue;
619 output( "\t%s %s\n", get_asm_ptr_keyword(), asm_name( get_link_name( odp )));
621 for (j = 0; j < extra_ld_symbols.count; j++)
622 output( "\t%s %s\n", get_asm_ptr_keyword(), asm_name(extra_ld_symbols.str[j]) );
624 output_gnu_stack_note();
625 fclose( output_file );
627 obj_file = make_temp_file( output_file_name, ".o" );
628 assemble_file( as_file, obj_file );
629 return obj_file;
632 /* combine a list of object files with ld into a single object file */
633 /* returns the name of the combined file */
634 static const char *ldcombine_files( DLLSPEC *spec, struct strarray files )
636 char *ld_tmp_file, *undef_file;
637 struct strarray args = get_ld_command();
639 undef_file = create_undef_symbols_file( spec );
640 ld_tmp_file = make_temp_file( output_file_name, ".o" );
642 strarray_add( &args, "-r" );
643 strarray_add( &args, "-o" );
644 strarray_add( &args, ld_tmp_file );
645 if (undef_file) strarray_add( &args, undef_file );
646 strarray_addall( &args, files );
647 spawn( args );
648 return ld_tmp_file;
651 /* read in the list of undefined symbols */
652 void read_undef_symbols( DLLSPEC *spec, struct strarray files )
654 size_t prefix_len;
655 FILE *f;
656 const char *prog = get_nm_command();
657 char *cmd, buffer[1024], name_prefix[16];
658 int err;
659 const char *name;
661 if (!files.count) return;
663 add_extra_undef_symbols( spec );
665 strcpy( name_prefix, asm_name("") );
666 prefix_len = strlen( name_prefix );
668 name = ldcombine_files( spec, files );
670 cmd = strmake( "%s -u %s", prog, name );
671 if (verbose)
672 fprintf( stderr, "%s\n", cmd );
673 if (!(f = popen( cmd, "r" )))
674 fatal_error( "Cannot execute '%s'\n", cmd );
676 while (fgets( buffer, sizeof(buffer), f ))
678 char *p = buffer + strlen(buffer) - 1;
679 if (p < buffer) continue;
680 if (*p == '\n') *p-- = 0;
681 p = buffer;
682 while (*p == ' ') p++;
683 if (p[0] == 'U' && p[1] == ' ' && p[2]) p += 2;
684 if (prefix_len && !strncmp( p, name_prefix, prefix_len )) p += prefix_len;
685 if (!strncmp( p, import_func_prefix, strlen(import_func_prefix) ))
686 add_undef_import( p + strlen( import_func_prefix ), 0 );
687 else if (!strncmp( p, import_ord_prefix, strlen(import_ord_prefix) ))
688 add_undef_import( p + strlen( import_ord_prefix ), 1 );
689 else if (use_msvcrt || !find_name( p, stdc_functions ))
690 strarray_add( &undef_symbols, xstrdup( p ));
692 if ((err = pclose( f ))) warning( "%s failed with status %d\n", cmd, err );
693 free( cmd );
696 void resolve_dll_imports( DLLSPEC *spec, struct list *list )
698 unsigned int j;
699 struct import *imp, *next;
700 ORDDEF *odp;
702 LIST_FOR_EACH_ENTRY_SAFE( imp, next, list, struct import, entry )
704 for (j = 0; j < undef_symbols.count; j++)
706 odp = find_export( undef_symbols.str[j], imp->exports, imp->nb_exports );
707 if (odp)
709 if (odp->flags & FLAG_PRIVATE) continue;
710 if (odp->type != TYPE_STDCALL && odp->type != TYPE_CDECL)
711 warning( "winebuild: Data export '%s' cannot be imported from %s\n",
712 odp->link_name, imp->dll_name );
713 else
715 add_import_func( imp, (odp->flags & FLAG_NONAME) ? NULL : odp->name,
716 odp->export_name, odp->ordinal, odp->hint );
717 remove_name( &undef_symbols, j-- );
721 if (!imp->nb_imports)
723 /* the dll is not used, get rid of it */
724 if (check_unused( imp, spec ))
725 warning( "winebuild: %s imported but no symbols used\n", imp->dll_name );
726 list_remove( &imp->entry );
727 free_imports( imp );
732 /* resolve the imports for a Win32 module */
733 void resolve_imports( DLLSPEC *spec )
735 check_undefined_forwards( spec );
736 resolve_dll_imports( spec, &dll_imports );
737 resolve_dll_imports( spec, &dll_delayed );
738 sort_names( &undef_symbols );
739 check_undefined_exports( spec );
742 /* check if symbol is still undefined */
743 int is_undefined( const char *name )
745 return find_name( name, undef_symbols ) != NULL;
748 /* output the get_pc thunk if needed */
749 void output_get_pc_thunk(void)
751 assert( target.cpu == CPU_i386 );
752 output_function_header( "__wine_spec_get_pc_thunk_eax", 0 );
753 output( "\tmovl (%%esp),%%eax\n" );
754 output( "\tret\n" );
755 output_function_size( "__wine_spec_get_pc_thunk_eax" );
758 /* output a single import thunk */
759 static void output_import_thunk( const char *name, const char *table, int pos )
761 output_function_header( name, 1 );
763 switch (target.cpu)
765 case CPU_i386:
766 if (!UsePIC)
768 output( "\tjmp *(%s+%d)\n", table, pos );
770 else
772 output( "\tcall %s\n", asm_name("__wine_spec_get_pc_thunk_eax") );
773 output( "1:\tjmp *%s+%d-1b(%%eax)\n", table, pos );
774 needs_get_pc_thunk = 1;
776 break;
777 case CPU_x86_64:
778 output( "\tjmpq *%s+%d(%%rip)\n", table, pos );
779 break;
780 case CPU_ARM:
781 if (UsePIC)
783 output( "\tldr ip, 2f\n");
784 output( "1:\tadd ip, pc\n" );
785 output( "\tldr pc, [ip]\n");
786 output( "2:\t.long %s+%u-1b-%u\n", table, pos, thumb_mode ? 4 : 8 );
788 else
790 output( "\tldr ip, 1f\n");
791 output( "\tldr pc, [ip]\n");
792 output( "1:\t.long %s+%u\n", table, pos );
794 break;
795 case CPU_ARM64:
796 output( "\tadrp x16, %s\n", arm64_page( table ) );
797 output( "\tadd x16, x16, #%s\n", arm64_pageoff( table ) );
798 if (pos & ~0x7fff) output( "\tadd x16, x16, #%u\n", pos & ~0x7fff );
799 output( "\tldr x16, [x16, #%u]\n", pos & 0x7fff );
800 output( "\tbr x16\n" );
801 break;
802 case CPU_ARM64EC:
803 assert( 0 );
804 break;
806 output_function_size( name );
809 /* check if we need an import directory */
810 int has_imports(void)
812 return !list_empty( &dll_imports );
815 /* check if we need a delayed import directory */
816 int has_delay_imports(void)
818 return !list_empty( &dll_delayed );
821 /* output the import table of a Win32 module */
822 static void output_immediate_imports(void)
824 int i, j;
825 struct import *import;
827 if (list_empty( &dll_imports )) return; /* no immediate imports */
829 /* main import header */
831 output( "\n/* import table */\n" );
832 output( "\n\t.data\n" );
833 output( "\t.balign 4\n" );
834 output( ".L__wine_spec_imports:\n" );
836 /* list of dlls */
838 j = 0;
839 LIST_FOR_EACH_ENTRY( import, &dll_imports, struct import, entry )
841 output_rva( ".L__wine_spec_import_data_names + %d", j * get_ptr_size() ); /* OriginalFirstThunk */
842 output( "\t.long 0\n" ); /* TimeDateStamp */
843 output( "\t.long 0\n" ); /* ForwarderChain */
844 output_rva( ".L__wine_spec_import_name_%s", import->c_name ); /* Name */
845 output_rva( ".L__wine_spec_import_data_ptrs + %d", j * get_ptr_size() ); /* FirstThunk */
846 j += import->nb_imports + 1;
848 output( "\t.long 0\n" ); /* OriginalFirstThunk */
849 output( "\t.long 0\n" ); /* TimeDateStamp */
850 output( "\t.long 0\n" ); /* ForwarderChain */
851 output( "\t.long 0\n" ); /* Name */
852 output( "\t.long 0\n" ); /* FirstThunk */
854 output( "\n\t.balign %u\n", get_ptr_size() );
855 /* output the names twice, once for OriginalFirstThunk and once for FirstThunk */
856 for (i = 0; i < 2; i++)
858 output( ".L__wine_spec_import_data_%s:\n", i ? "ptrs" : "names" );
859 LIST_FOR_EACH_ENTRY( import, &dll_imports, struct import, entry )
861 for (j = 0; j < import->nb_imports; j++)
863 struct import_func *func = &import->imports[j];
864 if (i)
866 if (func->name) output( "__imp_%s:\n", asm_name( func->name ));
867 else if (func->export_name) output( "__imp_%s:\n", asm_name( func->export_name ));
869 output_thunk_rva( func->name ? -1 : func->ordinal,
870 ".L__wine_spec_import_data_%s_%s", import->c_name, func->name );
872 output( "\t%s 0\n", get_asm_ptr_keyword() );
875 output( ".L__wine_spec_imports_end:\n" );
877 LIST_FOR_EACH_ENTRY( import, &dll_imports, struct import, entry )
879 for (j = 0; j < import->nb_imports; j++)
881 struct import_func *func = &import->imports[j];
882 if (!func->name) continue;
883 output( "\t.balign 2\n" );
884 output( ".L__wine_spec_import_data_%s_%s:\n", import->c_name, func->name );
885 output( "\t.short %d\n", func->hint );
886 output( "\t%s \"%s\"\n", get_asm_string_keyword(), func->name );
890 LIST_FOR_EACH_ENTRY( import, &dll_imports, struct import, entry )
892 output( ".L__wine_spec_import_name_%s:\n\t%s \"%s\"\n",
893 import->c_name, get_asm_string_keyword(), import->dll_name );
897 /* output the import thunks of a Win32 module */
898 static void output_immediate_import_thunks(void)
900 int j, pos;
901 struct import *import;
902 static const char import_thunks[] = "__wine_spec_import_thunks";
904 if (list_empty( &dll_imports )) return;
906 output( "\n/* immediate import thunks */\n\n" );
907 output( "\t.text\n" );
908 output( "\t.balign 8\n" );
909 output( "%s:\n", asm_name(import_thunks));
911 pos = 0;
912 LIST_FOR_EACH_ENTRY( import, &dll_imports, struct import, entry )
914 for (j = 0; j < import->nb_imports; j++, pos += get_ptr_size())
916 struct import_func *func = &import->imports[j];
917 output_import_thunk( func->name ? func->name : func->export_name,
918 ".L__wine_spec_import_data_ptrs", pos );
920 pos += get_ptr_size();
922 output_function_size( import_thunks );
925 /* output the delayed import table of a Win32 module */
926 static void output_delayed_imports( const DLLSPEC *spec )
928 int j, iat_pos, int_pos, mod_pos;
929 struct import *import;
931 if (list_empty( &dll_delayed )) return;
933 output( "\n/* delayed imports */\n\n" );
934 output( "\t.data\n" );
935 output( "\t.balign %u\n", get_ptr_size() );
936 output( ".L__wine_spec_delay_imports:\n" );
938 /* list of dlls */
940 iat_pos = int_pos = mod_pos = 0;
941 LIST_FOR_EACH_ENTRY( import, &dll_delayed, struct import, entry )
943 output( "\t.long 1\n" ); /* Attributes */
944 output_rva( ".L__wine_delay_name_%s", import->c_name ); /* DllNameRVA */
945 output_rva( ".L__wine_delay_modules+%d", mod_pos ); /* ModuleHandleRVA */
946 output_rva( ".L__wine_delay_IAT+%d", iat_pos ); /* ImportAddressTableRVA */
947 output_rva( ".L__wine_delay_INT+%d", int_pos ); /* ImportNameTableRVA */
948 output( "\t.long 0\n" ); /* BoundImportAddressTableRVA */
949 output( "\t.long 0\n" ); /* UnloadInformationTableRVA */
950 output( "\t.long 0\n" ); /* TimeDateStamp */
951 iat_pos += import->nb_imports * get_ptr_size();
952 int_pos += (import->nb_imports + 1) * get_ptr_size();
953 mod_pos += get_ptr_size();
955 output( "\t.long 0,0,0,0,0,0,0,0\n" );
956 output( ".L__wine_spec_delay_imports_end:\n" );
958 output( "\n.L__wine_delay_IAT:\n" );
959 LIST_FOR_EACH_ENTRY( import, &dll_delayed, struct import, entry )
961 for (j = 0; j < import->nb_imports; j++)
963 struct import_func *func = &import->imports[j];
964 const char *name = func->name ? func->name : func->export_name;
965 output( "__imp_%s:\n", asm_name( name ));
966 output( "\t%s __wine_delay_imp_%s_%s\n",
967 get_asm_ptr_keyword(), import->c_name, name );
971 output( "\n.L__wine_delay_INT:\n" );
972 LIST_FOR_EACH_ENTRY( import, &dll_delayed, struct import, entry )
974 for (j = 0; j < import->nb_imports; j++)
976 struct import_func *func = &import->imports[j];
977 output_thunk_rva( func->name ? -1 : func->ordinal,
978 ".L__wine_delay_data_%s_%s", import->c_name, func->name );
980 output( "\t%s 0\n", get_asm_ptr_keyword() );
983 output( "\n.L__wine_delay_modules:\n" );
984 LIST_FOR_EACH_ENTRY( import, &dll_delayed, struct import, entry )
986 output( "\t%s 0\n", get_asm_ptr_keyword() );
989 LIST_FOR_EACH_ENTRY( import, &dll_delayed, struct import, entry )
991 output( ".L__wine_delay_name_%s:\n", import->c_name );
992 output( "\t%s \"%s\"\n", get_asm_string_keyword(), import->dll_name );
995 LIST_FOR_EACH_ENTRY( import, &dll_delayed, struct import, entry )
997 for (j = 0; j < import->nb_imports; j++)
999 struct import_func *func = &import->imports[j];
1000 if (!func->name) continue;
1001 output( "\t.balign 2\n" );
1002 output( ".L__wine_delay_data_%s_%s:\n", import->c_name, func->name );
1003 output( "\t.short %d\n", func->hint );
1004 output( "\t%s \"%s\"\n", get_asm_string_keyword(), func->name );
1009 /* output the delayed import thunks of a Win32 module */
1010 static void output_delayed_import_thunks( const DLLSPEC *spec )
1012 int j, pos, iat_pos;
1013 struct import *import;
1014 static const char delayed_import_loaders[] = "__wine_spec_delayed_import_loaders";
1015 static const char delayed_import_thunks[] = "__wine_spec_delayed_import_thunks";
1017 if (list_empty( &dll_delayed )) return;
1019 output( "\n/* delayed import thunks */\n\n" );
1020 output( "\t.text\n" );
1021 output( "\t.balign 8\n" );
1022 output( "%s:\n", asm_name(delayed_import_loaders));
1024 pos = iat_pos = 0;
1025 LIST_FOR_EACH_ENTRY( import, &dll_delayed, struct import, entry )
1027 char *module_func = strmake( "__wine_delay_load_asm_%s", import->c_name );
1028 output_function_header( module_func, 0 );
1029 output_cfi( ".cfi_startproc" );
1030 switch (target.cpu)
1032 case CPU_i386:
1033 output( "\tpushl %%ecx\n" );
1034 output_cfi( ".cfi_adjust_cfa_offset 4" );
1035 output( "\tpushl %%edx\n" );
1036 output_cfi( ".cfi_adjust_cfa_offset 4" );
1037 output( "\tpushl %%eax\n" );
1038 output_cfi( ".cfi_adjust_cfa_offset 4" );
1039 if (UsePIC)
1041 output( "\tcall %s\n", asm_name("__wine_spec_get_pc_thunk_eax") );
1042 output( "1:\tleal .L__wine_spec_delay_imports+%d-1b(%%eax),%%eax\n", pos );
1043 output( "\tpushl %%eax\n" );
1044 output_cfi( ".cfi_adjust_cfa_offset 4" );
1045 needs_get_pc_thunk = 1;
1047 else
1049 output( "\tpushl $.L__wine_spec_delay_imports+%d\n", pos );
1050 output_cfi( ".cfi_adjust_cfa_offset 4" );
1052 output( "\tcall %s\n", asm_name("__delayLoadHelper2") );
1053 output_cfi( ".cfi_adjust_cfa_offset -8" );
1054 output( "\tpopl %%edx\n" );
1055 output_cfi( ".cfi_adjust_cfa_offset -4" );
1056 output( "\tpopl %%ecx\n" );
1057 output_cfi( ".cfi_adjust_cfa_offset -4" );
1058 output( "\tjmp *%%eax\n" );
1059 break;
1060 case CPU_x86_64:
1061 output( "\tsubq $0x98,%%rsp\n" );
1062 output_cfi( ".cfi_adjust_cfa_offset 0x98" );
1063 output( "\tmovq %%rdx,0x88(%%rsp)\n" );
1064 output( "\tmovq %%rcx,0x80(%%rsp)\n" );
1065 output( "\tmovq %%r8,0x78(%%rsp)\n" );
1066 output( "\tmovq %%r9,0x70(%%rsp)\n" );
1067 output( "\tmovq %%r10,0x68(%%rsp)\n" );
1068 output( "\tmovq %%r11,0x60(%%rsp)\n" );
1069 output( "\tmovups %%xmm0,0x50(%%rsp)\n" );
1070 output( "\tmovups %%xmm1,0x40(%%rsp)\n" );
1071 output( "\tmovups %%xmm2,0x30(%%rsp)\n" );
1072 output( "\tmovups %%xmm3,0x20(%%rsp)\n" );
1073 output( "\tleaq .L__wine_spec_delay_imports+%d(%%rip),%%rcx\n", pos );
1074 output( "\tmovq %%rax,%%rdx\n" );
1075 output( "\tcall %s\n", asm_name("__delayLoadHelper2") );
1076 output( "\tmovups 0x20(%%rsp),%%xmm3\n" );
1077 output( "\tmovups 0x30(%%rsp),%%xmm2\n" );
1078 output( "\tmovups 0x40(%%rsp),%%xmm1\n" );
1079 output( "\tmovups 0x50(%%rsp),%%xmm0\n" );
1080 output( "\tmovq 0x60(%%rsp),%%r11\n" );
1081 output( "\tmovq 0x68(%%rsp),%%r10\n" );
1082 output( "\tmovq 0x70(%%rsp),%%r9\n" );
1083 output( "\tmovq 0x78(%%rsp),%%r8\n" );
1084 output( "\tmovq 0x80(%%rsp),%%rcx\n" );
1085 output( "\tmovq 0x88(%%rsp),%%rdx\n" );
1086 output( "\taddq $0x98,%%rsp\n" );
1087 output_cfi( ".cfi_adjust_cfa_offset -0x98" );
1088 output( "\tjmp *%%rax\n" );
1089 break;
1090 case CPU_ARM:
1091 output( "\tpush {r0-r3,FP,LR}\n" );
1092 output( "\tmov r1,IP\n" );
1093 output( "\tldr r0, 1f\n");
1094 if (UsePIC) output( "2:\tadd r0, pc\n" );
1095 output( "\tbl %s\n", asm_name("__delayLoadHelper2") );
1096 output( "\tmov IP,r0\n");
1097 output( "\tpop {r0-r3,FP,LR}\n" );
1098 output( "\tbx IP\n");
1099 if (UsePIC)
1100 output( "1:\t.long .L__wine_spec_delay_imports+%u-2b-%u\n", pos, thumb_mode ? 4 : 8 );
1101 else
1102 output( "1:\t.long .L__wine_spec_delay_imports+%u\n", pos );
1103 break;
1104 case CPU_ARM64:
1105 output( "\tstp x29, x30, [sp,#-80]!\n" );
1106 output( "\tmov x29, sp\n" );
1107 output( "\tstp x0, x1, [sp,#16]\n" );
1108 output( "\tstp x2, x3, [sp,#32]\n" );
1109 output( "\tstp x4, x5, [sp,#48]\n" );
1110 output( "\tstp x6, x7, [sp,#64]\n" );
1111 output( "\tmov x1, x16\n" );
1112 output( "\tadrp x0, %s\n", arm64_page(".L__wine_spec_delay_imports") );
1113 output( "\tadd x0, x0, #%s\n", arm64_pageoff(".L__wine_spec_delay_imports") );
1114 if (pos) output( "\tadd x0, x0, #%u\n", pos );
1115 output( "\tbl %s\n", asm_name("__delayLoadHelper2") );
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;
1124 case CPU_ARM64EC:
1125 assert( 0 );
1126 break;
1128 output_cfi( ".cfi_endproc" );
1129 output_function_size( module_func );
1130 output( "\n" );
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 switch (target.cpu)
1141 case CPU_i386:
1142 if (UsePIC)
1144 output( "\tcall %s\n", asm_name("__wine_spec_get_pc_thunk_eax") );
1145 output( "1:\tleal .L__wine_delay_IAT+%d-1b(%%eax),%%eax\n", iat_pos );
1146 needs_get_pc_thunk = 1;
1148 else output( "\tmovl $.L__wine_delay_IAT+%d,%%eax\n", iat_pos );
1149 output( "\tjmp %s\n", asm_name(module_func) );
1150 break;
1151 case CPU_x86_64:
1152 output( "\tleaq .L__wine_delay_IAT+%d(%%rip),%%rax\n", iat_pos );
1153 output( "\tjmp %s\n", asm_name(module_func) );
1154 break;
1155 case CPU_ARM:
1156 if (UsePIC)
1158 output( "\tldr ip, 2f\n");
1159 output( "1:\tadd ip, pc\n" );
1160 output( "\tb %s\n", asm_name(module_func) );
1161 output( "2:\t.long .L__wine_delay_IAT+%u-1b-%u\n", iat_pos, thumb_mode ? 4 : 8 );
1163 else
1165 output( "\tldr ip, 1f\n");
1166 output( "\tb %s\n", asm_name(module_func) );
1167 output( "1:\t.long .L__wine_delay_IAT+%u\n", iat_pos );
1169 break;
1170 case CPU_ARM64:
1171 output( "\tadrp x16, %s\n", arm64_page(".L__wine_delay_IAT") );
1172 output( "\tadd x16, x16, #%s\n", arm64_pageoff(".L__wine_delay_IAT") );
1173 if (iat_pos) output( "\tadd x16, x16, #%u\n", iat_pos );
1174 output( "\tb %s\n", asm_name(module_func) );
1175 break;
1176 case CPU_ARM64EC:
1177 assert( 0 );
1178 break;
1180 iat_pos += get_ptr_size();
1182 pos += 8 * 4; /* IMAGE_DELAYLOAD_DESCRIPTOR is 8 DWORDs */
1184 output_function_size( delayed_import_loaders );
1186 output( "\n\t.balign %u\n", get_ptr_size() );
1187 output( "%s:\n", asm_name(delayed_import_thunks));
1188 pos = 0;
1189 LIST_FOR_EACH_ENTRY( import, &dll_delayed, struct import, entry )
1191 for (j = 0; j < import->nb_imports; j++, pos += get_ptr_size())
1193 struct import_func *func = &import->imports[j];
1194 output_import_thunk( func->name ? func->name : func->export_name,
1195 ".L__wine_delay_IAT", pos );
1198 output_function_size( delayed_import_thunks );
1201 /* output import stubs for exported entry points that link to external symbols */
1202 static void output_external_link_imports( DLLSPEC *spec )
1204 unsigned int i, pos;
1206 if (!ext_link_imports.count) return; /* nothing to do */
1208 sort_names( &ext_link_imports );
1210 /* get rid of duplicate names */
1211 for (i = 1; i < ext_link_imports.count; i++)
1213 if (!strcmp( ext_link_imports.str[i-1], ext_link_imports.str[i] ))
1214 remove_name( &ext_link_imports, i-- );
1217 output( "\n/* external link thunks */\n\n" );
1218 output( "\t.data\n" );
1219 output( "\t.balign %u\n", get_ptr_size() );
1220 output( ".L__wine_spec_external_links:\n" );
1221 for (i = 0; i < ext_link_imports.count; i++)
1222 output( "\t%s %s\n", get_asm_ptr_keyword(), asm_name(ext_link_imports.str[i]) );
1224 output( "\n\t.text\n" );
1225 output( "\t.balign %u\n", get_ptr_size() );
1226 output( "%s:\n", asm_name("__wine_spec_external_link_thunks") );
1228 for (i = pos = 0; i < ext_link_imports.count; i++)
1230 char *buffer = strmake( "__wine_spec_ext_link_%s", ext_link_imports.str[i] );
1231 output_import_thunk( buffer, ".L__wine_spec_external_links", pos );
1232 free( buffer );
1233 pos += get_ptr_size();
1235 output_function_size( "__wine_spec_external_link_thunks" );
1238 /*******************************************************************
1239 * output_stubs
1241 * Output the functions for stub entry points
1243 void output_stubs( DLLSPEC *spec )
1245 const char *name, *exp_name;
1246 int i;
1248 if (!has_stubs( spec )) return;
1250 output( "\n/* stub functions */\n\n" );
1252 for (i = 0; i < spec->nb_entry_points; i++)
1254 ORDDEF *odp = &spec->entry_points[i];
1255 if (odp->type != TYPE_STUB) continue;
1257 name = get_stub_name( odp, spec );
1258 exp_name = odp->name ? odp->name : odp->export_name;
1259 output_function_header( name, 0 );
1261 switch (target.cpu)
1263 case CPU_i386:
1264 output_cfi( ".cfi_startproc" );
1265 /* flesh out the stub a bit to make safedisc happy */
1266 output(" \tnop\n" );
1267 output(" \tnop\n" );
1268 output(" \tnop\n" );
1269 output(" \tnop\n" );
1270 output(" \tnop\n" );
1271 output(" \tnop\n" );
1272 output(" \tnop\n" );
1273 output(" \tnop\n" );
1274 output(" \tnop\n" );
1276 output( "\tsubl $12,%%esp\n" );
1277 output_cfi( ".cfi_adjust_cfa_offset 12" );
1278 if (UsePIC)
1280 output( "\tcall %s\n", asm_name("__wine_spec_get_pc_thunk_eax") );
1281 output( "1:" );
1282 needs_get_pc_thunk = 1;
1283 if (exp_name)
1285 output( "\tleal .L%s_string-1b(%%eax),%%ecx\n", name );
1286 output( "\tmovl %%ecx,4(%%esp)\n" );
1288 else
1289 output( "\tmovl $%d,4(%%esp)\n", odp->ordinal );
1290 output( "\tleal .L__wine_spec_file_name-1b(%%eax),%%ecx\n" );
1291 output( "\tmovl %%ecx,(%%esp)\n" );
1293 else
1295 if (exp_name)
1296 output( "\tmovl $.L%s_string,4(%%esp)\n", name );
1297 else
1298 output( "\tmovl $%d,4(%%esp)\n", odp->ordinal );
1299 output( "\tmovl $.L__wine_spec_file_name,(%%esp)\n" );
1301 output( "\tcall %s\n", asm_name("__wine_spec_unimplemented_stub") );
1302 output_cfi( ".cfi_endproc" );
1303 break;
1304 case CPU_x86_64:
1305 output_cfi( ".cfi_startproc" );
1306 output_seh( ".seh_proc %s", asm_name(name) );
1307 output( "\tsubq $0x28,%%rsp\n" );
1308 output_cfi( ".cfi_adjust_cfa_offset 0x28" );
1309 output_seh( ".seh_stackalloc 0x28" );
1310 output_seh( ".seh_endprologue" );
1311 output( "\tleaq .L__wine_spec_file_name(%%rip),%%rcx\n" );
1312 if (exp_name)
1313 output( "leaq .L%s_string(%%rip),%%rdx\n", name );
1314 else
1315 output( "\tmovq $%d,%%rdx\n", odp->ordinal );
1316 output( "\tcall %s\n", asm_name("__wine_spec_unimplemented_stub") );
1317 output_cfi( ".cfi_endproc" );
1318 output_seh( ".seh_endproc" );
1319 break;
1320 case CPU_ARM:
1321 if (UsePIC)
1323 output( "\tldr r0,3f\n");
1324 output( "1:\tadd r0,PC\n");
1325 output( "\tldr r1,3f+4\n");
1326 if (exp_name) output( "2:\tadd r1,PC\n");
1327 output( "\tbl %s\n", asm_name("__wine_spec_unimplemented_stub") );
1328 output( "3:\t.long .L__wine_spec_file_name-1b-%u\n", thumb_mode ? 4 : 8 );
1329 if (exp_name) output( "\t.long .L%s_string-2b-%u\n", name, thumb_mode ? 4 : 8 );
1330 else output( "\t.long %u\n", odp->ordinal );
1332 else
1334 output( "\tmovw r0,:lower16:.L__wine_spec_file_name\n");
1335 output( "\tmovt r0,:upper16:.L__wine_spec_file_name\n");
1336 if (exp_name)
1338 output( "\tmovw r1,:lower16:.L%s_string\n", name );
1339 output( "\tmovt r1,:upper16:.L%s_string\n", name );
1341 else output( "\tmov r1,#%u\n", odp->ordinal );
1342 output( "\tbl %s\n", asm_name("__wine_spec_unimplemented_stub") );
1344 break;
1345 case CPU_ARM64:
1346 case CPU_ARM64EC:
1347 output_seh( ".seh_proc %s", arm64_name(name) );
1348 output_seh( ".seh_endprologue" );
1349 output( "\tadrp x0, %s\n", arm64_page(".L__wine_spec_file_name") );
1350 output( "\tadd x0, x0, #%s\n", arm64_pageoff(".L__wine_spec_file_name") );
1351 if (exp_name)
1353 char *sym = strmake( ".L%s_string", name );
1354 output( "\tadrp x1, %s\n", arm64_page( sym ) );
1355 output( "\tadd x1, x1, #%s\n", arm64_pageoff( sym ) );
1356 free( sym );
1358 else
1359 output( "\tmov x1, %u\n", odp->ordinal );
1360 output( "\tb %s\n", arm64_name("__wine_spec_unimplemented_stub") );
1361 output_seh( ".seh_endproc" );
1362 break;
1364 output_function_size( name );
1367 output( "\t%s\n", get_asm_string_section() );
1368 output( ".L__wine_spec_file_name:\n" );
1369 output( "\t%s \"%s\"\n", get_asm_string_keyword(), spec->file_name );
1370 for (i = 0; i < spec->nb_entry_points; i++)
1372 ORDDEF *odp = &spec->entry_points[i];
1373 if (odp->type != TYPE_STUB) continue;
1374 exp_name = odp->name ? odp->name : odp->export_name;
1375 if (exp_name)
1377 name = get_stub_name( odp, spec );
1378 output( ".L%s_string:\n", name );
1379 output( "\t%s \"%s\"\n", get_asm_string_keyword(), exp_name );
1384 /* output the import and delayed import tables of a Win32 module */
1385 void output_imports( DLLSPEC *spec )
1387 if (is_pe()) return;
1388 output_immediate_imports();
1389 output_delayed_imports( spec );
1390 output_immediate_import_thunks();
1391 output_delayed_import_thunks( spec );
1392 output_external_link_imports( spec );
1395 /* create a new asm temp file */
1396 static void new_output_as_file(void)
1398 char *name;
1400 if (output_file) fclose( output_file );
1401 name = open_temp_output_file( ".s" );
1402 strarray_add( &as_files, name );
1405 /* assemble all the asm files */
1406 static void assemble_files( const char *prefix )
1408 unsigned int i;
1410 if (output_file) fclose( output_file );
1411 output_file = NULL;
1413 for (i = 0; i < as_files.count; i++)
1415 char *obj = make_temp_file( prefix, ".o" );
1416 assemble_file( as_files.str[i], obj );
1417 as_files.str[i] = obj;
1421 static const char *get_target_machine(void)
1423 static const char *machine_names[] =
1425 [CPU_i386] = "x86",
1426 [CPU_x86_64] = "x64",
1427 [CPU_ARM] = "arm",
1428 [CPU_ARM64] = "arm64",
1429 [CPU_ARM64EC] = "arm64ec",
1432 return machine_names[target.cpu];
1435 /* build a library from the current asm files and any additional object files in argv */
1436 void output_static_lib( const char *output_name, struct strarray files, int create )
1438 struct strarray args;
1440 if (!create || target.platform != PLATFORM_WINDOWS)
1442 args = find_tool( "ar", NULL );
1443 strarray_add( &args, create ? "rc" : "r" );
1444 strarray_add( &args, output_name );
1446 else
1448 args = find_link_tool();
1449 strarray_add( &args, "/lib" );
1450 strarray_add( &args, strmake( "-machine:%s", get_target_machine() ));
1451 strarray_add( &args, strmake( "-out:%s", output_name ));
1453 strarray_addall( &args, as_files );
1454 strarray_addall( &args, files );
1455 if (create) unlink( output_name );
1456 spawn( args );
1458 if (target.platform != PLATFORM_WINDOWS)
1460 struct strarray ranlib = find_tool( "ranlib", NULL );
1461 strarray_add( &ranlib, output_name );
1462 spawn( ranlib );
1466 /* create a Windows-style import library using dlltool */
1467 static void build_dlltool_import_lib( const char *lib_name, DLLSPEC *spec, struct strarray files )
1469 struct strarray args;
1470 char *def_file;
1472 def_file = open_temp_output_file( ".def" );
1473 output_def_file( spec, 1 );
1474 fclose( output_file );
1476 args = find_tool( "dlltool", NULL );
1477 strarray_add( &args, "-k" );
1478 strarray_add( &args, strendswith( lib_name, ".delay.a" ) ? "-y" : "-l" );
1479 strarray_add( &args, lib_name );
1480 strarray_add( &args, "-d" );
1481 strarray_add( &args, def_file );
1483 switch (target.cpu)
1485 case CPU_i386:
1486 strarray_add( &args, "-m" );
1487 strarray_add( &args, "i386" );
1488 strarray_add( &args, "--as-flags=--32" );
1489 break;
1490 case CPU_x86_64:
1491 strarray_add( &args, "-m" );
1492 strarray_add( &args, "i386:x86-64" );
1493 strarray_add( &args, "--as-flags=--64" );
1494 break;
1495 case CPU_ARM:
1496 strarray_add( &args, "-m" );
1497 strarray_add( &args, "arm" );
1498 break;
1499 case CPU_ARM64:
1500 strarray_add( &args, "-m" );
1501 strarray_add( &args, "arm64" );
1502 break;
1503 case CPU_ARM64EC:
1504 strarray_add( &args, "-m" );
1505 strarray_add( &args, "arm64ec" );
1506 break;
1507 default:
1508 break;
1511 spawn( args );
1513 if (files.count) output_static_lib( output_file_name, files, 0 );
1516 /* create a Windows-style import library */
1517 static void build_windows_import_lib( const char *lib_name, DLLSPEC *spec, struct strarray files )
1519 char *dll_name, *import_desc, *import_name, *delay_load;
1520 struct strarray objs = empty_strarray;
1521 int i, total, by_name;
1522 int is_delay = strendswith( lib_name, ".delay.a" );
1523 const char *name;
1525 /* make sure assemble_files doesn't strip suffixes */
1526 dll_name = encode_dll_name( spec->file_name );
1527 for (i = 0; i < strlen( dll_name ); ++i) if (dll_name[i] == '.') dll_name[i] = '_';
1529 import_desc = strmake( "__wine_import_%s_desc", dll_name );
1530 import_name = strmake( "__wine_import_%s_name", dll_name );
1531 delay_load = strmake( "__wine_delay_load_%s", dll_name );
1533 new_output_as_file();
1535 if (is_delay)
1537 output_function_header( delay_load, 1 );
1539 switch (target.cpu)
1541 case CPU_i386:
1542 output_cfi( ".cfi_startproc" );
1543 output( "\tpushl %%ecx\n" );
1544 output_cfi( ".cfi_adjust_cfa_offset 4" );
1545 output( "\tpushl %%edx\n" );
1546 output_cfi( ".cfi_adjust_cfa_offset 4" );
1547 output( "\tpushl %%eax\n" );
1548 output_cfi( ".cfi_adjust_cfa_offset 4" );
1549 output( "\tpushl $%s\n", asm_name( import_desc ) );
1550 output( "\tcalll ___delayLoadHelper2@8\n" );
1551 output_cfi( ".cfi_adjust_cfa_offset -8" );
1552 output( "\tpopl %%edx\n" );
1553 output_cfi( ".cfi_adjust_cfa_offset -4" );
1554 output( "\tpopl %%ecx\n" );
1555 output_cfi( ".cfi_adjust_cfa_offset -4" );
1556 output( "\tjmp *%%eax\n" );
1557 output_cfi( ".cfi_endproc" );
1558 break;
1559 case CPU_x86_64:
1560 output_seh( ".seh_proc %s", asm_name( delay_load ) );
1561 output( "\tsubq $0x48, %%rsp\n" );
1562 output_seh( ".seh_stackalloc 0x48" );
1563 output_seh( ".seh_endprologue" );
1564 output( "\tmovq %%rcx, 0x40(%%rsp)\n" );
1565 output( "\tmovq %%rdx, 0x38(%%rsp)\n" );
1566 output( "\tmovq %%r8, 0x30(%%rsp)\n" );
1567 output( "\tmovq %%r9, 0x28(%%rsp)\n" );
1568 output( "\tmovq %%rax, %%rdx\n" );
1569 output( "\tleaq %s(%%rip), %%rcx\n", asm_name( import_desc ) );
1570 output( "\tcall __delayLoadHelper2\n" );
1571 output( "\tmovq 0x28(%%rsp), %%r9\n" );
1572 output( "\tmovq 0x30(%%rsp), %%r8\n" );
1573 output( "\tmovq 0x38(%%rsp), %%rdx\n" );
1574 output( "\tmovq 0x40(%%rsp), %%rcx\n" );
1575 output( "\taddq $0x48, %%rsp\n" );
1576 output( "\tjmp *%%rax\n" );
1577 output_seh( ".seh_endproc" );
1578 break;
1579 case CPU_ARM:
1580 output( "\tpush {r0-r3, FP, LR}\n" );
1581 output( "\tmov r1, IP\n" );
1582 output( "\tldr r0, 1f\n" );
1583 output( "\tldr r0, [r0]\n" );
1584 output( "\tbl __delayLoadHelper2\n" );
1585 output( "\tmov IP, r0\n" );
1586 output( "\tpop {r0-r3, FP, LR}\n" );
1587 output( "\tbx IP\n" );
1588 output( "1:\t.long %s\n", asm_name( import_desc ) );
1589 break;
1590 case CPU_ARM64:
1591 output_seh( ".seh_proc %s", asm_name( delay_load ) );
1592 output( "\tstp x29, x30, [sp, #-80]!\n" );
1593 output_seh( ".seh_save_fplr_x 80" );
1594 output( "\tmov x29, sp\n" );
1595 output_seh( ".seh_set_fp" );
1596 output_seh( ".seh_endprologue" );
1597 output( "\tstp x0, x1, [sp, #16]\n" );
1598 output( "\tstp x2, x3, [sp, #32]\n" );
1599 output( "\tstp x4, x5, [sp, #48]\n" );
1600 output( "\tstp x6, x7, [sp, #64]\n" );
1601 output( "\tmov x1, x16\n" );
1602 output( "\tadrp x0, %s\n", asm_name( import_desc ) );
1603 output( "\tadd x0, x0, #%s\n", asm_name( import_desc ) );
1604 output( "\tbl __delayLoadHelper2\n" );
1605 output( "\tmov x16, x0\n" );
1606 output( "\tldp x0, x1, [sp, #16]\n" );
1607 output( "\tldp x2, x3, [sp, #32]\n" );
1608 output( "\tldp x4, x5, [sp, #48]\n" );
1609 output( "\tldp x6, x7, [sp, #64]\n" );
1610 output( "\tldp x29, x30, [sp], #80\n" );
1611 output( "\tbr x16\n" );
1612 output_seh( ".seh_endproc" );
1613 break;
1614 case CPU_ARM64EC:
1615 assert( 0 );
1616 break;
1618 output_function_size( delay_load );
1619 output_gnu_stack_note();
1621 output( "\n\t.data\n" );
1622 output( ".L__wine_delay_import_handle:\n" );
1623 output( "\t%s 0\n", get_asm_ptr_keyword() );
1625 output( "%s\n", asm_globl( import_desc ) );
1626 output( "\t.long 1\n" ); /* DllAttributes */
1627 output_rva( "%s", asm_name( import_name ) ); /* DllNameRVA */
1628 output_rva( ".L__wine_delay_import_handle" ); /* ModuleHandleRVA */
1629 output_rva( ".L__wine_import_addrs" ); /* ImportAddressTableRVA */
1630 output_rva( ".L__wine_import_names" ); /* ImportNameTableRVA */
1631 output( "\t.long 0\n" ); /* BoundImportAddressTableRVA */
1632 output( "\t.long 0\n" ); /* UnloadInformationTableRVA */
1633 output( "\t.long 0\n" ); /* TimeDateStamp */
1635 output( "\n\t.section .idata$5\n" );
1636 output( "\t%s 0\n", get_asm_ptr_keyword() ); /* FirstThunk tail */
1637 output( ".L__wine_import_addrs:\n" );
1639 output( "\n\t.section .idata$4\n" );
1640 output( "\t%s 0\n", get_asm_ptr_keyword() ); /* OriginalFirstThunk tail */
1641 output( ".L__wine_import_names:\n" );
1643 /* required to avoid internal linker errors with some binutils versions */
1644 output( "\n\t.section .idata$2\n" );
1646 else
1648 output( "\n\t.section .idata$2\n" );
1649 output( "%s\n", asm_globl( import_desc ) );
1650 output_rva( ".L__wine_import_names" ); /* OriginalFirstThunk */
1651 output( "\t.long 0\n" ); /* TimeDateStamp */
1652 output( "\t.long 0\n" ); /* ForwarderChain */
1653 output_rva( "%s", asm_name( import_name ) ); /* Name */
1654 output_rva( ".L__wine_import_addrs" ); /* FirstThunk */
1656 output( "\n\t.section .idata$4\n" );
1657 output( ".L__wine_import_names:\n" ); /* OriginalFirstThunk head */
1659 output( "\n\t.section .idata$5\n" );
1660 output( ".L__wine_import_addrs:\n" ); /* FirstThunk head */
1663 /* _head suffix to keep this object sections first */
1664 assemble_files( strmake( "%s_head", dll_name ) );
1665 strarray_addall( &objs, as_files );
1666 as_files = empty_strarray;
1668 new_output_as_file();
1670 output( "\n\t.section .idata$4\n" );
1671 output( "\t%s 0\n", get_asm_ptr_keyword() ); /* OriginalFirstThunk tail */
1672 output( "\n\t.section .idata$5\n" );
1673 output( "\t%s 0\n", get_asm_ptr_keyword() ); /* FirstThunk tail */
1674 output( "\n\t.section .idata$7\n" );
1675 output( "%s\n", asm_globl( import_name ) );
1676 output( "\t%s \"%s\"\n", get_asm_string_keyword(), spec->file_name );
1678 /* _tail suffix to keep this object sections last */
1679 assemble_files( strmake( "%s_tail", dll_name ) );
1680 strarray_addall( &objs, as_files );
1681 as_files = empty_strarray;
1683 for (i = total = 0; i < spec->nb_entry_points; i++)
1685 const ORDDEF *odp = &spec->entry_points[i];
1686 const char *abi_name;
1687 char *imp_name;
1689 if (odp->name) name = odp->name;
1690 else if (odp->export_name) name = odp->export_name;
1691 else continue;
1693 if (odp->flags & FLAG_PRIVATE) continue;
1694 total++;
1696 /* C++ mangled names cannot be imported */
1697 if (strpbrk( name, "?@" )) continue;
1699 switch (odp->type)
1701 case TYPE_VARARGS:
1702 case TYPE_CDECL:
1703 case TYPE_STDCALL:
1704 by_name = odp->name && !(odp->flags & FLAG_ORDINAL);
1705 abi_name = get_abi_name( odp, name );
1706 imp_name = strmake( "%s_imp_%s", target.cpu != CPU_i386 ? "_" : "",
1707 asm_name( abi_name ) );
1709 new_output_as_file();
1710 output_function_header( abi_name, 1 );
1712 switch (target.cpu)
1714 case CPU_i386:
1715 output( "\tjmp *%s\n", asm_name( imp_name ) );
1716 if (is_delay)
1718 output( "\n\t.section .text$1\n" );
1719 output( ".L__wine_delay_import:\n" );
1720 output( "\tmov $%s,%%eax\n", asm_name( imp_name ) );
1721 output( "\tjmp %s\n", asm_name( delay_load ) );
1723 break;
1724 case CPU_x86_64:
1725 output( "\tjmp *%s(%%rip)\n", asm_name( imp_name ) );
1726 if (is_delay)
1728 output( "\n\t.section .text$1\n" );
1729 output( ".L__wine_delay_import:\n" );
1730 output( "\tlea %s(%%rip),%%rax\n", asm_name( imp_name ) );
1731 output( "\tjmp %s\n", asm_name( delay_load ) );
1733 break;
1734 case CPU_ARM:
1735 output( "\tldr IP, 1f\n" );
1736 output( "\tldr PC, [IP]\n" );
1737 if (is_delay)
1739 output( "\n\t.section .text$1\n" );
1740 output( ".L__wine_delay_import:\n" );
1741 output( "\tldr IP, 1f\n" );
1742 output( "\tldr IP, [IP]\n" );
1743 output( "\tb %s\n", asm_name( delay_load ) );
1745 output( "1:\t.long %s\n", asm_name( imp_name ) );
1746 break;
1747 case CPU_ARM64:
1748 output( "\tadrp x16, %s\n", arm64_page( asm_name( imp_name ) ) );
1749 output( "\tadd x16, x16, #%s\n", arm64_pageoff( asm_name( imp_name ) ) );
1750 output( "\tbr x16\n" );
1751 if (is_delay)
1753 output( "\n\t.section .text$1\n" );
1754 output( ".L__wine_delay_import:\n" );
1755 output( "\tadrp x16, %s\n", arm64_page( asm_name( imp_name ) ) );
1756 output( "\tadd x16, x16, #%s\n", arm64_pageoff( asm_name( imp_name ) ) );
1757 output( "\tb %s\n", asm_name( delay_load ) );
1759 break;
1760 case CPU_ARM64EC:
1761 assert( 0 );
1762 break;
1765 output( "\n\t.section .idata$4\n" );
1766 output_thunk_rva( by_name ? -1 : odp->ordinal, ".L__wine_import_name" );
1768 output( "\n\t.section .idata$5\n" );
1769 output( "%s\n", asm_globl( imp_name ) );
1770 if (is_delay)
1771 output( "\t%s .L__wine_delay_import\n", get_asm_ptr_keyword() );
1772 else
1773 output_thunk_rva( by_name ? -1 : odp->ordinal, ".L__wine_import_name" );
1775 if (by_name)
1777 output( "\n\t.section .idata$6\n" );
1778 output( ".L__wine_import_name:\n" );
1779 output( "\t.short %d\n", odp->hint );
1780 output( "\t%s \"%s\"\n", get_asm_string_keyword(), name );
1783 /* reference head object to always pull its sections */
1784 output( "\n\t.section .idata$7\n" );
1785 output_rva( "%s", asm_name( import_desc ) );
1787 free( imp_name );
1788 break;
1790 default:
1791 break;
1795 /* _syms suffix to keep these objects sections in between _head and _tail */
1796 assemble_files( strmake( "%s_syms", dll_name ) );
1797 strarray_addall( &objs, as_files );
1798 as_files = objs;
1800 free( import_desc );
1801 free( import_name );
1802 free( delay_load );
1803 free( dll_name );
1805 output_static_lib( output_file_name, files, 1 );
1808 /* create a Unix-style import library */
1809 static void build_unix_import_lib( DLLSPEC *spec, struct strarray files )
1811 int i, total;
1812 const char *name, *prefix;
1813 char *dll_name = encode_dll_name( spec->file_name );
1815 /* entry points */
1817 for (i = total = 0; i < spec->nb_entry_points; i++)
1819 const ORDDEF *odp = &spec->entry_points[i];
1821 if (odp->name) name = odp->name;
1822 else if (odp->export_name) name = odp->export_name;
1823 else continue;
1825 if (odp->flags & FLAG_PRIVATE) continue;
1826 total++;
1828 /* C++ mangled names cannot be imported */
1829 if (strpbrk( name, "?@" )) continue;
1831 switch(odp->type)
1833 case TYPE_VARARGS:
1834 case TYPE_CDECL:
1835 case TYPE_STDCALL:
1836 prefix = (!odp->name || (odp->flags & FLAG_ORDINAL)) ? import_ord_prefix : import_func_prefix;
1837 new_output_as_file();
1838 output_function_header( name, 1 );
1839 output( "\t%s %s%s$%u$%s\n", get_asm_ptr_keyword(),
1840 asm_name( prefix ), dll_name, odp->ordinal, name );
1841 output_function_size( name );
1842 output_gnu_stack_note();
1843 break;
1845 default:
1846 break;
1849 if (!total) warning( "%s: Import library doesn't export anything\n", spec->file_name );
1851 if (!as_files.count) /* create a dummy file to avoid empty import libraries */
1853 new_output_as_file();
1854 output( "\t.text\n" );
1857 assemble_files( spec->file_name );
1858 free( dll_name );
1860 output_static_lib( output_file_name, files, 1 );
1863 /* output an import library for a Win32 module and additional object files */
1864 void output_import_lib( DLLSPEC *spec, struct strarray files )
1866 if (!is_pe()) build_unix_import_lib( spec, files );
1867 else if (use_dlltool) build_dlltool_import_lib( output_file_name, spec, files );
1868 else build_windows_import_lib( output_file_name, spec, files );