winegstreamer: Synchronize concurrent access to the media source.
[wine.git] / tools / winebuild / import.c
blobfcf93addb5066469f8e5759954abf8eacb2e6e94
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 (odp->flags & FLAG_SYSCALL) continue;
580 if (find_name( odp->link_name, undef_symbols ))
582 switch(odp->type)
584 case TYPE_PASCAL:
585 case TYPE_STDCALL:
586 case TYPE_CDECL:
587 case TYPE_VARARGS:
588 if (link_ext_symbols)
590 odp->flags |= FLAG_EXT_LINK;
591 strarray_add( &ext_link_imports, odp->link_name );
593 else error( "%s:%d: function '%s' not defined\n",
594 spec->src_name, odp->lineno, odp->link_name );
595 break;
596 default:
597 if (!strcmp( odp->link_name, "__wine_syscall_dispatcher" )) break;
598 error( "%s:%d: external symbol '%s' is not a function\n",
599 spec->src_name, odp->lineno, odp->link_name );
600 break;
606 /* create a .o file that references all the undefined symbols we want to resolve */
607 static char *create_undef_symbols_file( DLLSPEC *spec )
609 char *as_file, *obj_file;
610 int i;
611 unsigned int j;
613 as_file = open_temp_output_file( ".s" );
614 output( "\t.data\n" );
616 for (i = 0; i < spec->nb_entry_points; i++)
618 ORDDEF *odp = &spec->entry_points[i];
619 if (odp->type == TYPE_STUB || odp->type == TYPE_ABS || odp->type == TYPE_VARIABLE) continue;
620 if (odp->flags & FLAG_FORWARD) continue;
621 if (odp->flags & FLAG_SYSCALL) continue;
622 output( "\t%s %s\n", get_asm_ptr_keyword(), asm_name( get_link_name( odp )));
624 for (j = 0; j < extra_ld_symbols.count; j++)
625 output( "\t%s %s\n", get_asm_ptr_keyword(), asm_name(extra_ld_symbols.str[j]) );
627 output_gnu_stack_note();
628 fclose( output_file );
630 obj_file = make_temp_file( output_file_name, ".o" );
631 assemble_file( as_file, obj_file );
632 return obj_file;
635 /* combine a list of object files with ld into a single object file */
636 /* returns the name of the combined file */
637 static const char *ldcombine_files( DLLSPEC *spec, struct strarray files )
639 char *ld_tmp_file, *undef_file;
640 struct strarray args = get_ld_command();
642 undef_file = create_undef_symbols_file( spec );
643 ld_tmp_file = make_temp_file( output_file_name, ".o" );
645 strarray_add( &args, "-r" );
646 strarray_add( &args, "-o" );
647 strarray_add( &args, ld_tmp_file );
648 if (undef_file) strarray_add( &args, undef_file );
649 strarray_addall( &args, files );
650 spawn( args );
651 return ld_tmp_file;
654 /* read in the list of undefined symbols */
655 void read_undef_symbols( DLLSPEC *spec, struct strarray files )
657 size_t prefix_len;
658 FILE *f;
659 const char *prog = get_nm_command();
660 char *cmd, buffer[1024], name_prefix[16];
661 int err;
662 const char *name;
664 if (!files.count) return;
666 add_extra_undef_symbols( spec );
668 strcpy( name_prefix, asm_name("") );
669 prefix_len = strlen( name_prefix );
671 name = ldcombine_files( spec, files );
673 cmd = strmake( "%s -u %s", prog, name );
674 if (verbose)
675 fprintf( stderr, "%s\n", cmd );
676 if (!(f = popen( cmd, "r" )))
677 fatal_error( "Cannot execute '%s'\n", cmd );
679 while (fgets( buffer, sizeof(buffer), f ))
681 char *p = buffer + strlen(buffer) - 1;
682 if (p < buffer) continue;
683 if (*p == '\n') *p-- = 0;
684 p = buffer;
685 while (*p == ' ') p++;
686 if (p[0] == 'U' && p[1] == ' ' && p[2]) p += 2;
687 if (prefix_len && !strncmp( p, name_prefix, prefix_len )) p += prefix_len;
688 if (!strncmp( p, import_func_prefix, strlen(import_func_prefix) ))
689 add_undef_import( p + strlen( import_func_prefix ), 0 );
690 else if (!strncmp( p, import_ord_prefix, strlen(import_ord_prefix) ))
691 add_undef_import( p + strlen( import_ord_prefix ), 1 );
692 else if (use_msvcrt || !find_name( p, stdc_functions ))
693 strarray_add( &undef_symbols, xstrdup( p ));
695 if ((err = pclose( f ))) warning( "%s failed with status %d\n", cmd, err );
696 free( cmd );
699 void resolve_dll_imports( DLLSPEC *spec, struct list *list )
701 unsigned int j;
702 struct import *imp, *next;
703 ORDDEF *odp;
705 LIST_FOR_EACH_ENTRY_SAFE( imp, next, list, struct import, entry )
707 for (j = 0; j < undef_symbols.count; j++)
709 odp = find_export( undef_symbols.str[j], imp->exports, imp->nb_exports );
710 if (odp)
712 if (odp->flags & FLAG_PRIVATE) continue;
713 if (odp->type != TYPE_STDCALL && odp->type != TYPE_CDECL)
714 warning( "winebuild: Data export '%s' cannot be imported from %s\n",
715 odp->link_name, imp->dll_name );
716 else
718 add_import_func( imp, (odp->flags & FLAG_NONAME) ? NULL : odp->name,
719 odp->export_name, odp->ordinal, odp->hint );
720 remove_name( &undef_symbols, j-- );
724 if (!imp->nb_imports)
726 /* the dll is not used, get rid of it */
727 if (check_unused( imp, spec ))
728 warning( "winebuild: %s imported but no symbols used\n", imp->dll_name );
729 list_remove( &imp->entry );
730 free_imports( imp );
735 /* resolve the imports for a Win32 module */
736 void resolve_imports( DLLSPEC *spec )
738 check_undefined_forwards( spec );
739 resolve_dll_imports( spec, &dll_imports );
740 resolve_dll_imports( spec, &dll_delayed );
741 sort_names( &undef_symbols );
742 check_undefined_exports( spec );
745 /* check if symbol is still undefined */
746 int is_undefined( const char *name )
748 return find_name( name, undef_symbols ) != NULL;
751 /* output the get_pc thunk if needed */
752 void output_get_pc_thunk(void)
754 assert( target.cpu == CPU_i386 );
755 output( "\n\t.text\n" );
756 output( "\t.align %d\n", get_alignment(4) );
757 output( "\t%s\n", func_declaration("__wine_spec_get_pc_thunk_eax") );
758 output( "%s:\n", asm_name("__wine_spec_get_pc_thunk_eax") );
759 output_cfi( ".cfi_startproc" );
760 output( "\tmovl (%%esp),%%eax\n" );
761 output( "\tret\n" );
762 output_cfi( ".cfi_endproc" );
763 output_function_size( "__wine_spec_get_pc_thunk_eax" );
766 /* output a single import thunk */
767 static void output_import_thunk( const char *name, const char *table, int pos )
769 output( "\n\t.align %d\n", get_alignment(4) );
770 output( "\t%s\n", func_declaration(name) );
771 output( "%s\n", asm_globl(name) );
772 output_cfi( ".cfi_startproc" );
774 switch (target.cpu)
776 case CPU_i386:
777 if (!UsePIC)
779 output( "\tjmp *(%s+%d)\n", table, pos );
781 else
783 output( "\tcall %s\n", asm_name("__wine_spec_get_pc_thunk_eax") );
784 output( "1:\tjmp *%s+%d-1b(%%eax)\n", table, pos );
785 needs_get_pc_thunk = 1;
787 break;
788 case CPU_x86_64:
789 output( "\tjmpq *%s+%d(%%rip)\n", table, pos );
790 break;
791 case CPU_ARM:
792 if (UsePIC)
794 output( "\tldr ip, 2f\n");
795 output( "1:\tadd ip, pc\n" );
796 output( "\tldr pc, [ip]\n");
797 output( "2:\t.long %s+%u-1b-%u\n", table, pos, thumb_mode ? 4 : 8 );
799 else
801 output( "\tldr ip, 1f\n");
802 output( "\tldr pc, [ip]\n");
803 output( "1:\t.long %s+%u\n", table, pos );
805 break;
806 case CPU_ARM64:
807 output( "\tadrp x16, %s\n", arm64_page( table ) );
808 output( "\tadd x16, x16, #%s\n", arm64_pageoff( table ) );
809 if (pos & ~0x7fff) output( "\tadd x16, x16, #%u\n", pos & ~0x7fff );
810 output( "\tldr x16, [x16, #%u]\n", pos & 0x7fff );
811 output( "\tbr x16\n" );
812 break;
814 output_cfi( ".cfi_endproc" );
815 output_function_size( name );
818 /* check if we need an import directory */
819 int has_imports(void)
821 return !list_empty( &dll_imports );
824 /* check if we need a delayed import directory */
825 int has_delay_imports(void)
827 return !list_empty( &dll_delayed );
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 output_thunk_rva( func->name ? -1 : func->ordinal,
879 ".L__wine_spec_import_data_%s_%s", import->c_name, func->name );
881 output( "\t%s 0\n", get_asm_ptr_keyword() );
884 output( ".L__wine_spec_imports_end:\n" );
886 LIST_FOR_EACH_ENTRY( import, &dll_imports, struct import, entry )
888 for (j = 0; j < import->nb_imports; j++)
890 struct import_func *func = &import->imports[j];
891 if (!func->name) continue;
892 output( "\t.align %d\n", get_alignment(2) );
893 output( ".L__wine_spec_import_data_%s_%s:\n", import->c_name, func->name );
894 output( "\t.short %d\n", func->hint );
895 output( "\t%s \"%s\"\n", get_asm_string_keyword(), func->name );
899 LIST_FOR_EACH_ENTRY( import, &dll_imports, struct import, entry )
901 output( ".L__wine_spec_import_name_%s:\n\t%s \"%s\"\n",
902 import->c_name, get_asm_string_keyword(), import->dll_name );
906 /* output the import thunks of a Win32 module */
907 static void output_immediate_import_thunks(void)
909 int j, pos;
910 struct import *import;
911 static const char import_thunks[] = "__wine_spec_import_thunks";
913 if (list_empty( &dll_imports )) return;
915 output( "\n/* immediate import thunks */\n\n" );
916 output( "\t.text\n" );
917 output( "\t.align %d\n", get_alignment(8) );
918 output( "%s:\n", asm_name(import_thunks));
920 pos = 0;
921 LIST_FOR_EACH_ENTRY( import, &dll_imports, struct import, entry )
923 for (j = 0; j < import->nb_imports; j++, pos += get_ptr_size())
925 struct import_func *func = &import->imports[j];
926 output_import_thunk( func->name ? func->name : func->export_name,
927 ".L__wine_spec_import_data_ptrs", pos );
929 pos += get_ptr_size();
931 output_function_size( import_thunks );
934 /* output the delayed import table of a Win32 module */
935 static void output_delayed_imports( const DLLSPEC *spec )
937 int j, iat_pos, int_pos, mod_pos;
938 struct import *import;
940 if (list_empty( &dll_delayed )) return;
942 output( "\n/* delayed imports */\n\n" );
943 output( "\t.data\n" );
944 output( "\t.align %d\n", get_alignment(get_ptr_size()) );
945 output( ".L__wine_spec_delay_imports:\n" );
947 /* list of dlls */
949 iat_pos = int_pos = mod_pos = 0;
950 LIST_FOR_EACH_ENTRY( import, &dll_delayed, struct import, entry )
952 output( "\t.long 1\n" ); /* Attributes */
953 output_rva( ".L__wine_delay_name_%s", import->c_name ); /* DllNameRVA */
954 output_rva( ".L__wine_delay_modules+%d", mod_pos ); /* ModuleHandleRVA */
955 output_rva( ".L__wine_delay_IAT+%d", iat_pos ); /* ImportAddressTableRVA */
956 output_rva( ".L__wine_delay_INT+%d", int_pos ); /* ImportNameTableRVA */
957 output( "\t.long 0\n" ); /* BoundImportAddressTableRVA */
958 output( "\t.long 0\n" ); /* UnloadInformationTableRVA */
959 output( "\t.long 0\n" ); /* TimeDateStamp */
960 iat_pos += import->nb_imports * get_ptr_size();
961 int_pos += (import->nb_imports + 1) * get_ptr_size();
962 mod_pos += get_ptr_size();
964 output( "\t.long 0,0,0,0,0,0,0,0\n" );
965 output( ".L__wine_spec_delay_imports_end:\n" );
967 output( "\n.L__wine_delay_IAT:\n" );
968 LIST_FOR_EACH_ENTRY( import, &dll_delayed, struct import, entry )
970 for (j = 0; j < import->nb_imports; j++)
972 struct import_func *func = &import->imports[j];
973 const char *name = func->name ? func->name : func->export_name;
974 output( "__imp_%s:\n", asm_name( name ));
975 output( "\t%s __wine_delay_imp_%s_%s\n",
976 get_asm_ptr_keyword(), import->c_name, name );
980 output( "\n.L__wine_delay_INT:\n" );
981 LIST_FOR_EACH_ENTRY( import, &dll_delayed, struct import, entry )
983 for (j = 0; j < import->nb_imports; j++)
985 struct import_func *func = &import->imports[j];
986 output_thunk_rva( func->name ? -1 : func->ordinal,
987 ".L__wine_delay_data_%s_%s", import->c_name, func->name );
989 output( "\t%s 0\n", get_asm_ptr_keyword() );
992 output( "\n.L__wine_delay_modules:\n" );
993 LIST_FOR_EACH_ENTRY( import, &dll_delayed, struct import, entry )
995 output( "\t%s 0\n", get_asm_ptr_keyword() );
998 LIST_FOR_EACH_ENTRY( import, &dll_delayed, struct import, entry )
1000 output( ".L__wine_delay_name_%s:\n", import->c_name );
1001 output( "\t%s \"%s\"\n", get_asm_string_keyword(), import->dll_name );
1004 LIST_FOR_EACH_ENTRY( import, &dll_delayed, struct import, entry )
1006 for (j = 0; j < import->nb_imports; j++)
1008 struct import_func *func = &import->imports[j];
1009 if (!func->name) continue;
1010 output( "\t.align %d\n", get_alignment(2) );
1011 output( ".L__wine_delay_data_%s_%s:\n", import->c_name, func->name );
1012 output( "\t.short %d\n", func->hint );
1013 output( "\t%s \"%s\"\n", get_asm_string_keyword(), func->name );
1018 /* output the delayed import thunks of a Win32 module */
1019 static void output_delayed_import_thunks( const DLLSPEC *spec )
1021 int j, pos, iat_pos;
1022 struct import *import;
1023 static const char delayed_import_loaders[] = "__wine_spec_delayed_import_loaders";
1024 static const char delayed_import_thunks[] = "__wine_spec_delayed_import_thunks";
1026 if (list_empty( &dll_delayed )) return;
1028 output( "\n/* delayed import thunks */\n\n" );
1029 output( "\t.text\n" );
1030 output( "\t.align %d\n", get_alignment(8) );
1031 output( "%s:\n", asm_name(delayed_import_loaders));
1033 pos = iat_pos = 0;
1034 LIST_FOR_EACH_ENTRY( import, &dll_delayed, struct import, entry )
1036 char *module_func = strmake( "__wine_delay_load_asm_%s", import->c_name );
1037 output( "\t.align %d\n", get_alignment(4) );
1038 output( "\t%s\n", func_declaration(module_func) );
1039 output( "%s:\n", asm_name(module_func) );
1040 output_cfi( ".cfi_startproc" );
1041 switch (target.cpu)
1043 case CPU_i386:
1044 output( "\tpushl %%ecx\n" );
1045 output_cfi( ".cfi_adjust_cfa_offset 4" );
1046 output( "\tpushl %%edx\n" );
1047 output_cfi( ".cfi_adjust_cfa_offset 4" );
1048 output( "\tpushl %%eax\n" );
1049 output_cfi( ".cfi_adjust_cfa_offset 4" );
1050 if (UsePIC)
1052 output( "\tcall %s\n", asm_name("__wine_spec_get_pc_thunk_eax") );
1053 output( "1:\tleal .L__wine_spec_delay_imports+%d-1b(%%eax),%%eax\n", pos );
1054 output( "\tpushl %%eax\n" );
1055 output_cfi( ".cfi_adjust_cfa_offset 4" );
1056 needs_get_pc_thunk = 1;
1058 else
1060 output( "\tpushl $.L__wine_spec_delay_imports+%d\n", pos );
1061 output_cfi( ".cfi_adjust_cfa_offset 4" );
1063 output( "\tcall %s\n", asm_name("__delayLoadHelper2") );
1064 output_cfi( ".cfi_adjust_cfa_offset -8" );
1065 output( "\tpopl %%edx\n" );
1066 output_cfi( ".cfi_adjust_cfa_offset -4" );
1067 output( "\tpopl %%ecx\n" );
1068 output_cfi( ".cfi_adjust_cfa_offset -4" );
1069 output( "\tjmp *%%eax\n" );
1070 break;
1071 case CPU_x86_64:
1072 output( "\tsubq $0x98,%%rsp\n" );
1073 output_cfi( ".cfi_adjust_cfa_offset 0x98" );
1074 output( "\tmovq %%rdx,0x88(%%rsp)\n" );
1075 output( "\tmovq %%rcx,0x80(%%rsp)\n" );
1076 output( "\tmovq %%r8,0x78(%%rsp)\n" );
1077 output( "\tmovq %%r9,0x70(%%rsp)\n" );
1078 output( "\tmovq %%r10,0x68(%%rsp)\n" );
1079 output( "\tmovq %%r11,0x60(%%rsp)\n" );
1080 output( "\tmovups %%xmm0,0x50(%%rsp)\n" );
1081 output( "\tmovups %%xmm1,0x40(%%rsp)\n" );
1082 output( "\tmovups %%xmm2,0x30(%%rsp)\n" );
1083 output( "\tmovups %%xmm3,0x20(%%rsp)\n" );
1084 output( "\tleaq .L__wine_spec_delay_imports+%d(%%rip),%%rcx\n", pos );
1085 output( "\tmovq %%rax,%%rdx\n" );
1086 output( "\tcall %s\n", asm_name("__delayLoadHelper2") );
1087 output( "\tmovups 0x20(%%rsp),%%xmm3\n" );
1088 output( "\tmovups 0x30(%%rsp),%%xmm2\n" );
1089 output( "\tmovups 0x40(%%rsp),%%xmm1\n" );
1090 output( "\tmovups 0x50(%%rsp),%%xmm0\n" );
1091 output( "\tmovq 0x60(%%rsp),%%r11\n" );
1092 output( "\tmovq 0x68(%%rsp),%%r10\n" );
1093 output( "\tmovq 0x70(%%rsp),%%r9\n" );
1094 output( "\tmovq 0x78(%%rsp),%%r8\n" );
1095 output( "\tmovq 0x80(%%rsp),%%rcx\n" );
1096 output( "\tmovq 0x88(%%rsp),%%rdx\n" );
1097 output( "\taddq $0x98,%%rsp\n" );
1098 output_cfi( ".cfi_adjust_cfa_offset -0x98" );
1099 output( "\tjmp *%%rax\n" );
1100 break;
1101 case CPU_ARM:
1102 output( "\tpush {r0-r3,FP,LR}\n" );
1103 output( "\tmov r1,IP\n" );
1104 output( "\tldr r0, 1f\n");
1105 if (UsePIC) output( "2:\tadd r0, pc\n" );
1106 output( "\tbl %s\n", asm_name("__delayLoadHelper2") );
1107 output( "\tmov IP,r0\n");
1108 output( "\tpop {r0-r3,FP,LR}\n" );
1109 output( "\tbx IP\n");
1110 if (UsePIC)
1111 output( "1:\t.long .L__wine_spec_delay_imports+%u-2b-%u\n", pos, thumb_mode ? 4 : 8 );
1112 else
1113 output( "1:\t.long .L__wine_spec_delay_imports+%u\n", pos );
1114 break;
1115 case CPU_ARM64:
1116 output( "\tstp x29, x30, [sp,#-80]!\n" );
1117 output( "\tmov x29, sp\n" );
1118 output( "\tstp x0, x1, [sp,#16]\n" );
1119 output( "\tstp x2, x3, [sp,#32]\n" );
1120 output( "\tstp x4, x5, [sp,#48]\n" );
1121 output( "\tstp x6, x7, [sp,#64]\n" );
1122 output( "\tmov x1, x16\n" );
1123 output( "\tadrp x0, %s\n", arm64_page(".L__wine_spec_delay_imports") );
1124 output( "\tadd x0, x0, #%s\n", arm64_pageoff(".L__wine_spec_delay_imports") );
1125 if (pos) output( "\tadd x0, x0, #%u\n", pos );
1126 output( "\tbl %s\n", asm_name("__delayLoadHelper2") );
1127 output( "\tmov x16, x0\n" );
1128 output( "\tldp x0, x1, [sp,#16]\n" );
1129 output( "\tldp x2, x3, [sp,#32]\n" );
1130 output( "\tldp x4, x5, [sp,#48]\n" );
1131 output( "\tldp x6, x7, [sp,#64]\n" );
1132 output( "\tldp x29, x30, [sp],#80\n" );
1133 output( "\tbr x16\n" );
1134 break;
1136 output_cfi( ".cfi_endproc" );
1137 output_function_size( module_func );
1138 output( "\n" );
1140 for (j = 0; j < import->nb_imports; j++)
1142 struct import_func *func = &import->imports[j];
1143 const char *name = func->name ? func->name : func->export_name;
1145 if (thumb_mode) output( "\t.thumb_func\n" );
1146 output( "__wine_delay_imp_%s_%s:\n", import->c_name, name );
1147 output_cfi( ".cfi_startproc" );
1148 switch (target.cpu)
1150 case CPU_i386:
1151 if (UsePIC)
1153 output( "\tcall %s\n", asm_name("__wine_spec_get_pc_thunk_eax") );
1154 output( "1:\tleal .L__wine_delay_IAT+%d-1b(%%eax),%%eax\n", iat_pos );
1155 needs_get_pc_thunk = 1;
1157 else output( "\tmovl $.L__wine_delay_IAT+%d,%%eax\n", iat_pos );
1158 output( "\tjmp %s\n", asm_name(module_func) );
1159 break;
1160 case CPU_x86_64:
1161 output( "\tleaq .L__wine_delay_IAT+%d(%%rip),%%rax\n", iat_pos );
1162 output( "\tjmp %s\n", asm_name(module_func) );
1163 break;
1164 case CPU_ARM:
1165 if (UsePIC)
1167 output( "\tldr ip, 2f\n");
1168 output( "1:\tadd ip, pc\n" );
1169 output( "\tb %s\n", asm_name(module_func) );
1170 output( "2:\t.long .L__wine_delay_IAT+%u-1b-%u\n", iat_pos, thumb_mode ? 4 : 8 );
1172 else
1174 output( "\tldr ip, 1f\n");
1175 output( "\tb %s\n", asm_name(module_func) );
1176 output( "1:\t.long .L__wine_delay_IAT+%u\n", iat_pos );
1178 break;
1179 case CPU_ARM64:
1180 output( "\tadrp x16, %s\n", arm64_page(".L__wine_delay_IAT") );
1181 output( "\tadd x16, x16, #%s\n", arm64_pageoff(".L__wine_delay_IAT") );
1182 if (iat_pos) output( "\tadd x16, x16, #%u\n", iat_pos );
1183 output( "\tb %s\n", asm_name(module_func) );
1184 break;
1186 output_cfi( ".cfi_endproc" );
1187 iat_pos += get_ptr_size();
1189 pos += 8 * 4; /* IMAGE_DELAYLOAD_DESCRIPTOR is 8 DWORDs */
1191 output_function_size( delayed_import_loaders );
1193 output( "\n\t.align %d\n", get_alignment(get_ptr_size()) );
1194 output( "%s:\n", asm_name(delayed_import_thunks));
1195 pos = 0;
1196 LIST_FOR_EACH_ENTRY( import, &dll_delayed, struct import, entry )
1198 for (j = 0; j < import->nb_imports; j++, pos += get_ptr_size())
1200 struct import_func *func = &import->imports[j];
1201 output_import_thunk( func->name ? func->name : func->export_name,
1202 ".L__wine_delay_IAT", pos );
1205 output_function_size( delayed_import_thunks );
1208 /* output import stubs for exported entry points that link to external symbols */
1209 static void output_external_link_imports( DLLSPEC *spec )
1211 unsigned int i, pos;
1213 if (!ext_link_imports.count) return; /* nothing to do */
1215 sort_names( &ext_link_imports );
1217 /* get rid of duplicate names */
1218 for (i = 1; i < ext_link_imports.count; i++)
1220 if (!strcmp( ext_link_imports.str[i-1], ext_link_imports.str[i] ))
1221 remove_name( &ext_link_imports, i-- );
1224 output( "\n/* external link thunks */\n\n" );
1225 output( "\t.data\n" );
1226 output( "\t.align %d\n", get_alignment(get_ptr_size()) );
1227 output( ".L__wine_spec_external_links:\n" );
1228 for (i = 0; i < ext_link_imports.count; i++)
1229 output( "\t%s %s\n", get_asm_ptr_keyword(), asm_name(ext_link_imports.str[i]) );
1231 output( "\n\t.text\n" );
1232 output( "\t.align %d\n", get_alignment(get_ptr_size()) );
1233 output( "%s:\n", asm_name("__wine_spec_external_link_thunks") );
1235 for (i = pos = 0; i < ext_link_imports.count; i++)
1237 char *buffer = strmake( "__wine_spec_ext_link_%s", ext_link_imports.str[i] );
1238 output_import_thunk( buffer, ".L__wine_spec_external_links", pos );
1239 free( buffer );
1240 pos += get_ptr_size();
1242 output_function_size( "__wine_spec_external_link_thunks" );
1245 /*******************************************************************
1246 * output_stubs
1248 * Output the functions for stub entry points
1250 void output_stubs( DLLSPEC *spec )
1252 const char *name, *exp_name;
1253 int i;
1255 if (!has_stubs( spec )) return;
1257 output( "\n/* stub functions */\n\n" );
1258 output( "\t.text\n" );
1260 for (i = 0; i < spec->nb_entry_points; i++)
1262 ORDDEF *odp = &spec->entry_points[i];
1263 if (odp->type != TYPE_STUB) continue;
1265 name = get_stub_name( odp, spec );
1266 exp_name = odp->name ? odp->name : odp->export_name;
1267 output( "\t.align %d\n", get_alignment(4) );
1268 output( "\t%s\n", func_declaration(name) );
1269 output( "%s:\n", asm_name(name) );
1270 output_cfi( ".cfi_startproc" );
1272 switch (target.cpu)
1274 case CPU_i386:
1275 /* flesh out the stub a bit to make safedisc happy */
1276 output(" \tnop\n" );
1277 output(" \tnop\n" );
1278 output(" \tnop\n" );
1279 output(" \tnop\n" );
1280 output(" \tnop\n" );
1281 output(" \tnop\n" );
1282 output(" \tnop\n" );
1283 output(" \tnop\n" );
1284 output(" \tnop\n" );
1286 output( "\tsubl $12,%%esp\n" );
1287 output_cfi( ".cfi_adjust_cfa_offset 12" );
1288 if (UsePIC)
1290 output( "\tcall %s\n", asm_name("__wine_spec_get_pc_thunk_eax") );
1291 output( "1:" );
1292 needs_get_pc_thunk = 1;
1293 if (exp_name)
1295 output( "\tleal .L%s_string-1b(%%eax),%%ecx\n", name );
1296 output( "\tmovl %%ecx,4(%%esp)\n" );
1298 else
1299 output( "\tmovl $%d,4(%%esp)\n", odp->ordinal );
1300 output( "\tleal .L__wine_spec_file_name-1b(%%eax),%%ecx\n" );
1301 output( "\tmovl %%ecx,(%%esp)\n" );
1303 else
1305 if (exp_name)
1306 output( "\tmovl $.L%s_string,4(%%esp)\n", name );
1307 else
1308 output( "\tmovl $%d,4(%%esp)\n", odp->ordinal );
1309 output( "\tmovl $.L__wine_spec_file_name,(%%esp)\n" );
1311 output( "\tcall %s\n", asm_name("__wine_spec_unimplemented_stub") );
1312 break;
1313 case CPU_x86_64:
1314 output( "\tsubq $0x28,%%rsp\n" );
1315 output_cfi( ".cfi_adjust_cfa_offset 8" );
1316 output( "\tleaq .L__wine_spec_file_name(%%rip),%%rcx\n" );
1317 if (exp_name)
1318 output( "leaq .L%s_string(%%rip),%%rdx\n", name );
1319 else
1320 output( "\tmovq $%d,%%rdx\n", odp->ordinal );
1321 output( "\tcall %s\n", asm_name("__wine_spec_unimplemented_stub") );
1322 break;
1323 case CPU_ARM:
1324 if (UsePIC)
1326 output( "\tldr r0,3f\n");
1327 output( "1:\tadd r0,PC\n");
1328 output( "\tldr r1,3f+4\n");
1329 if (exp_name) output( "2:\tadd r1,PC\n");
1330 output( "\tbl %s\n", asm_name("__wine_spec_unimplemented_stub") );
1331 output( "3:\t.long .L__wine_spec_file_name-1b-%u\n", thumb_mode ? 4 : 8 );
1332 if (exp_name) output( "\t.long .L%s_string-2b-%u\n", name, thumb_mode ? 4 : 8 );
1333 else output( "\t.long %u\n", odp->ordinal );
1335 else
1337 output( "\tmovw r0,:lower16:.L__wine_spec_file_name\n");
1338 output( "\tmovt r0,:upper16:.L__wine_spec_file_name\n");
1339 if (exp_name)
1341 output( "\tmovw r1,:lower16:.L%s_string\n", name );
1342 output( "\tmovt r1,:upper16:.L%s_string\n", name );
1344 else output( "\tmov r1,#%u\n", odp->ordinal );
1345 output( "\tbl %s\n", asm_name("__wine_spec_unimplemented_stub") );
1347 break;
1348 case CPU_ARM64:
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( "\tbl %s\n", asm_name("__wine_spec_unimplemented_stub") );
1361 break;
1362 default:
1363 assert(0);
1365 output_cfi( ".cfi_endproc" );
1366 output_function_size( name );
1369 output( "\t%s\n", get_asm_string_section() );
1370 output( ".L__wine_spec_file_name:\n" );
1371 output( "\t%s \"%s\"\n", get_asm_string_keyword(), spec->file_name );
1372 for (i = 0; i < spec->nb_entry_points; i++)
1374 ORDDEF *odp = &spec->entry_points[i];
1375 if (odp->type != TYPE_STUB) continue;
1376 exp_name = odp->name ? odp->name : odp->export_name;
1377 if (exp_name)
1379 name = get_stub_name( odp, spec );
1380 output( ".L%s_string:\n", name );
1381 output( "\t%s \"%s\"\n", get_asm_string_keyword(), exp_name );
1386 static int cmp_link_name( const void *e1, const void *e2 )
1388 const ORDDEF *odp1 = *(const ORDDEF * const *)e1;
1389 const ORDDEF *odp2 = *(const ORDDEF * const *)e2;
1391 return strcmp( odp1->link_name, odp2->link_name );
1395 /* output the functions for system calls */
1396 void output_syscalls( DLLSPEC *spec )
1398 int i, count;
1399 ORDDEF **syscalls = NULL;
1401 for (i = count = 0; i < spec->nb_entry_points; i++)
1403 ORDDEF *odp = &spec->entry_points[i];
1404 if (!(odp->flags & FLAG_SYSCALL)) continue;
1405 if (!syscalls) syscalls = xmalloc( (spec->nb_entry_points - i) * sizeof(*syscalls) );
1406 syscalls[count++] = odp;
1408 if (!count) return;
1409 count = sort_func_list( syscalls, count, cmp_link_name );
1411 output( "\n/* system calls */\n\n" );
1412 output( "\t.text\n" );
1414 for (i = 0; i < count; i++)
1416 ORDDEF *odp = syscalls[i];
1417 const char *name = get_link_name(odp);
1418 unsigned int id = (spec->syscall_table << 12) + i;
1420 output( "\t.align %d\n", get_alignment(16) );
1421 output( "\t%s\n", func_declaration(name) );
1422 output( "%s\n", asm_globl(name) );
1423 output_cfi( ".cfi_startproc" );
1424 switch (target.cpu)
1426 case CPU_i386:
1427 if (UsePIC)
1429 output( "\tcall %s\n", asm_name("__wine_spec_get_pc_thunk_eax") );
1430 output( "1:\tmovl %s-1b(%%eax),%%edx\n", asm_name("__wine_syscall_dispatcher") );
1431 output( "\tmovl $%u,%%eax\n", id );
1432 needs_get_pc_thunk = 1;
1434 else
1436 output( "\tmovl $%u,%%eax\n", id );
1437 output( "\tmovl $%s,%%edx\n", asm_name("__wine_syscall") );
1439 output( "\tcall *%%edx\n" );
1440 output( "\tret $%u\n", get_args_size( odp ));
1441 break;
1442 case CPU_x86_64:
1443 /* Chromium depends on syscall thunks having the same form as on
1444 * Windows. For 64-bit systems the only viable form we can emulate is
1445 * having an int $0x2e fallback. Since actually using an interrupt is
1446 * expensive, and since for some reason Chromium doesn't actually
1447 * validate that instruction, we can just put a jmp there instead. */
1448 output( "\t.byte 0x4c,0x8b,0xd1\n" ); /* movq %rcx,%r10 */
1449 output( "\t.byte 0xb8\n" ); /* movl $i,%eax */
1450 output( "\t.long %u\n", id );
1451 output( "\t.byte 0xf6,0x04,0x25,0x08,0x03,0xfe,0x7f,0x01\n" ); /* testb $1,0x7ffe0308 */
1452 output( "\t.byte 0x75,0x03\n" ); /* jne 1f */
1453 output( "\t.byte 0x0f,0x05\n" ); /* syscall */
1454 output( "\t.byte 0xc3\n" ); /* ret */
1455 output( "\tjmp 1f\n" );
1456 output( "\t.byte 0xc3\n" ); /* ret */
1457 if (is_pe())
1459 output( "1:\t.byte 0xff,0x14,0x25\n" ); /* 1: callq *(0x7ffe1000) */
1460 output( "\t.long 0x7ffe1000\n" );
1462 else
1464 output( "\tnop\n" );
1465 output( "1:\tcallq *%s(%%rip)\n", asm_name("__wine_syscall_dispatcher") );
1467 output( "\tret\n" );
1468 break;
1469 case CPU_ARM:
1470 output( "\tpush {r0-r3}\n" );
1471 output( "\tmovw ip, #%u\n", id );
1472 output( "\tmov r3, lr\n" );
1473 output( "\tbl %s\n", asm_name("__wine_syscall") );
1474 output( "\tbx lr\n" );
1475 break;
1476 case CPU_ARM64:
1477 output( "\tmov x8, #%u\n", id );
1478 output( "\tmov x9, x30\n" );
1479 output( "\tbl %s\n", asm_name("__wine_syscall" ));
1480 output( "\tret\n" );
1481 break;
1482 default:
1483 assert(0);
1485 output_cfi( ".cfi_endproc" );
1486 output_function_size( name );
1489 switch (target.cpu)
1491 case CPU_i386:
1492 if (UsePIC) break;
1493 output( "\t.align %d\n", get_alignment(16) );
1494 output( "\t%s\n", func_declaration("__wine_syscall") );
1495 output( "%s:\n", asm_name("__wine_syscall") );
1496 output( "\tjmp *(%s)\n", asm_name("__wine_syscall_dispatcher") );
1497 output_function_size( "__wine_syscall" );
1498 break;
1499 case CPU_ARM:
1500 output( "\t.align %d\n", get_alignment(16) );
1501 output( "\t%s\n", func_declaration("__wine_syscall") );
1502 output( "%s:\n", asm_name("__wine_syscall") );
1503 if (UsePIC)
1505 output( "\tldr r0, 2f\n");
1506 output( "1:\tadd r0, pc\n" );
1508 else
1510 output( "\tmovw r0, :lower16:%s\n", asm_name("__wine_syscall_dispatcher") );
1511 output( "\tmovt r0, :upper16:%s\n", asm_name("__wine_syscall_dispatcher") );
1513 output( "\tldr r0, [r0]\n");
1514 output( "\tbx r0\n");
1515 if (UsePIC) output( "2:\t.long %s-1b-%u\n", asm_name("__wine_syscall_dispatcher"), thumb_mode ? 4 : 8 );
1516 output_function_size( "__wine_syscall" );
1517 break;
1518 case CPU_ARM64:
1519 output( "\t.align %d\n", get_alignment(16) );
1520 output( "\t%s\n", func_declaration("__wine_syscall") );
1521 output( "%s:\n", asm_name("__wine_syscall") );
1522 output( "\tadrp x16, %s\n", arm64_page( asm_name("__wine_syscall_dispatcher") ) );
1523 output( "\tldr x16, [x16, #%s]\n", arm64_pageoff( asm_name("__wine_syscall_dispatcher") ) );
1524 output( "\tbr x16\n");
1525 output_function_size( "__wine_syscall" );
1526 default:
1527 break;
1529 output( "\t.data\n" );
1530 output( "\t.align %d\n", get_alignment( get_ptr_size() ) );
1531 output( "%s\n", asm_globl("__wine_syscall_dispatcher") );
1532 output( "\t%s 0\n", get_asm_ptr_keyword() );
1533 output( "\t.short %u\n", count );
1534 for (i = 0; i < count; i++) output( "\t.byte %u\n", get_args_size( syscalls[i] ));
1538 /* output the import and delayed import tables of a Win32 module */
1539 void output_imports( DLLSPEC *spec )
1541 if (is_pe()) return;
1542 output_immediate_imports();
1543 output_delayed_imports( spec );
1544 output_immediate_import_thunks();
1545 output_delayed_import_thunks( spec );
1546 output_external_link_imports( spec );
1549 /* create a new asm temp file */
1550 static void new_output_as_file(void)
1552 char *name;
1554 if (output_file) fclose( output_file );
1555 name = open_temp_output_file( ".s" );
1556 strarray_add( &as_files, name );
1559 /* assemble all the asm files */
1560 static void assemble_files( const char *prefix )
1562 unsigned int i;
1564 if (output_file) fclose( output_file );
1565 output_file = NULL;
1567 for (i = 0; i < as_files.count; i++)
1569 char *obj = make_temp_file( prefix, ".o" );
1570 assemble_file( as_files.str[i], obj );
1571 as_files.str[i] = obj;
1575 /* build a library from the current asm files and any additional object files in argv */
1576 void output_static_lib( const char *output_name, struct strarray files, int create )
1578 struct strarray args;
1580 if (!create || target.platform != PLATFORM_WINDOWS)
1582 args = find_tool( "ar", NULL );
1583 strarray_add( &args, create ? "rc" : "r" );
1584 strarray_add( &args, output_name );
1586 else
1588 args = find_link_tool();
1589 strarray_add( &args, "/lib" );
1590 strarray_add( &args, strmake( "-out:%s", output_name ));
1592 strarray_addall( &args, as_files );
1593 strarray_addall( &args, files );
1594 if (create) unlink( output_name );
1595 spawn( args );
1597 if (target.platform != PLATFORM_WINDOWS)
1599 struct strarray ranlib = find_tool( "ranlib", NULL );
1600 strarray_add( &ranlib, output_name );
1601 spawn( ranlib );
1605 /* create a Windows-style import library using dlltool */
1606 static void build_dlltool_import_lib( const char *lib_name, DLLSPEC *spec, struct strarray files )
1608 struct strarray args;
1609 char *def_file;
1611 def_file = open_temp_output_file( ".def" );
1612 output_def_file( spec, 1 );
1613 fclose( output_file );
1615 args = find_tool( "dlltool", NULL );
1616 strarray_add( &args, "-k" );
1617 strarray_add( &args, strendswith( lib_name, ".delay.a" ) ? "-y" : "-l" );
1618 strarray_add( &args, lib_name );
1619 strarray_add( &args, "-d" );
1620 strarray_add( &args, def_file );
1622 switch (target.cpu)
1624 case CPU_i386:
1625 strarray_add( &args, "-m" );
1626 strarray_add( &args, "i386" );
1627 strarray_add( &args, "--as-flags=--32" );
1628 break;
1629 case CPU_x86_64:
1630 strarray_add( &args, "-m" );
1631 strarray_add( &args, "i386:x86-64" );
1632 strarray_add( &args, "--as-flags=--64" );
1633 break;
1634 case CPU_ARM:
1635 strarray_add( &args, "-m" );
1636 strarray_add( &args, "arm" );
1637 break;
1638 case CPU_ARM64:
1639 strarray_add( &args, "-m" );
1640 strarray_add( &args, "arm64" );
1641 break;
1642 default:
1643 break;
1646 spawn( args );
1648 if (files.count) output_static_lib( output_file_name, files, 0 );
1651 /* create a Windows-style import library */
1652 static void build_windows_import_lib( const char *lib_name, DLLSPEC *spec, struct strarray files )
1654 char *dll_name, *import_desc, *import_name, *delay_load;
1655 struct strarray objs = empty_strarray;
1656 int i, total, by_name;
1657 int is_delay = strendswith( lib_name, ".delay.a" );
1658 const char *name;
1660 /* make sure assemble_files doesn't strip suffixes */
1661 dll_name = encode_dll_name( spec->file_name );
1662 for (i = 0; i < strlen( dll_name ); ++i) if (dll_name[i] == '.') dll_name[i] = '_';
1664 import_desc = strmake( "__wine_import_%s_desc", dll_name );
1665 import_name = strmake( "__wine_import_%s_name", dll_name );
1666 delay_load = strmake( "__wine_delay_load_%s", dll_name );
1668 new_output_as_file();
1670 if (is_delay)
1672 output( "\n\t.text\n" );
1673 output( "\t.align %d\n", get_alignment( get_ptr_size() ));
1674 output( "%s\n", asm_globl( delay_load ) );
1675 output( "\t%s\n", func_declaration( delay_load ) );
1677 output_cfi( ".cfi_startproc" );
1678 switch (target.cpu)
1680 case CPU_i386:
1681 output( "\tpushl %%ecx\n" );
1682 output_cfi( ".cfi_adjust_cfa_offset 4" );
1683 output( "\tpushl %%edx\n" );
1684 output_cfi( ".cfi_adjust_cfa_offset 4" );
1685 output( "\tpushl %%eax\n" );
1686 output_cfi( ".cfi_adjust_cfa_offset 4" );
1687 output( "\tpushl $%s\n", asm_name( import_desc ) );
1688 output( "\tcalll ___delayLoadHelper2@8\n" );
1689 output_cfi( ".cfi_adjust_cfa_offset -8" );
1690 output( "\tpopl %%edx\n" );
1691 output_cfi( ".cfi_adjust_cfa_offset -4" );
1692 output( "\tpopl %%ecx\n" );
1693 output_cfi( ".cfi_adjust_cfa_offset -4" );
1694 output( "\tjmp *%%eax\n" );
1695 break;
1696 case CPU_x86_64:
1697 output_cfi( ".seh_proc %s", asm_name( delay_load ) );
1698 output( "\tsubq $0x48, %%rsp\n" );
1699 output_cfi( ".cfi_adjust_cfa_offset 0x48" );
1700 output_cfi( ".seh_stackalloc 0x48" );
1701 output_cfi( ".seh_endprologue" );
1702 output( "\tmovq %%rcx, 0x40(%%rsp)\n" );
1703 output( "\tmovq %%rdx, 0x38(%%rsp)\n" );
1704 output( "\tmovq %%r8, 0x30(%%rsp)\n" );
1705 output( "\tmovq %%r9, 0x28(%%rsp)\n" );
1706 output( "\tmovq %%rax, %%rdx\n" );
1707 output( "\tleaq %s(%%rip), %%rcx\n", asm_name( import_desc ) );
1708 output( "\tcall __delayLoadHelper2\n" );
1709 output( "\tmovq 0x28(%%rsp), %%r9\n" );
1710 output( "\tmovq 0x30(%%rsp), %%r8\n" );
1711 output( "\tmovq 0x38(%%rsp), %%rdx\n" );
1712 output( "\tmovq 0x40(%%rsp), %%rcx\n" );
1713 output( "\taddq $0x48, %%rsp\n" );
1714 output_cfi( ".cfi_adjust_cfa_offset -0x48" );
1715 output( "\tjmp *%%rax\n" );
1716 output_cfi( ".seh_endproc" );
1717 break;
1718 case CPU_ARM:
1719 output( "\tpush {r0-r3, FP, LR}\n" );
1720 output( "\tmov r1, IP\n" );
1721 output( "\tldr r0, 1f\n" );
1722 output( "\tldr r0, [r0]\n" );
1723 output( "\tbl __delayLoadHelper2\n" );
1724 output( "\tmov IP, r0\n" );
1725 output( "\tpop {r0-r3, FP, LR}\n" );
1726 output( "\tbx IP\n" );
1727 output( "1:\t.long %s\n", asm_name( import_desc ) );
1728 break;
1729 case CPU_ARM64:
1730 output( "\tstp x29, x30, [sp, #-80]!\n" );
1731 output( "\tmov x29, sp\n" );
1732 output( "\tstp x0, x1, [sp, #16]\n" );
1733 output( "\tstp x2, x3, [sp, #32]\n" );
1734 output( "\tstp x4, x5, [sp, #48]\n" );
1735 output( "\tstp x6, x7, [sp, #64]\n" );
1736 output( "\tmov x1, x16\n" );
1737 output( "\tadrp x0, %s\n", asm_name( import_desc ) );
1738 output( "\tadd x0, x0, #%s\n", asm_name( import_desc ) );
1739 output( "\tbl __delayLoadHelper2\n" );
1740 output( "\tmov x16, x0\n" );
1741 output( "\tldp x0, x1, [sp, #16]\n" );
1742 output( "\tldp x2, x3, [sp, #32]\n" );
1743 output( "\tldp x4, x5, [sp, #48]\n" );
1744 output( "\tldp x6, x7, [sp, #64]\n" );
1745 output( "\tldp x29, x30, [sp], #80\n" );
1746 output( "\tbr x16\n" );
1747 break;
1749 output_cfi( ".cfi_endproc" );
1750 output_function_size( delay_load );
1751 output_gnu_stack_note();
1753 output( "\n\t.data\n" );
1754 output( ".L__wine_delay_import_handle:\n" );
1755 output( "\t%s 0\n", get_asm_ptr_keyword() );
1757 output( "%s\n", asm_globl( import_desc ) );
1758 output( "\t.long 1\n" ); /* DllAttributes */
1759 output_rva( "%s", asm_name( import_name ) ); /* DllNameRVA */
1760 output_rva( ".L__wine_delay_import_handle" ); /* ModuleHandleRVA */
1761 output_rva( ".L__wine_import_addrs" ); /* ImportAddressTableRVA */
1762 output_rva( ".L__wine_import_names" ); /* ImportNameTableRVA */
1763 output( "\t.long 0\n" ); /* BoundImportAddressTableRVA */
1764 output( "\t.long 0\n" ); /* UnloadInformationTableRVA */
1765 output( "\t.long 0\n" ); /* TimeDateStamp */
1767 output( "\n\t.section .idata$5\n" );
1768 output( "\t%s 0\n", get_asm_ptr_keyword() ); /* FirstThunk tail */
1769 output( ".L__wine_import_addrs:\n" );
1771 output( "\n\t.section .idata$4\n" );
1772 output( "\t%s 0\n", get_asm_ptr_keyword() ); /* OriginalFirstThunk tail */
1773 output( ".L__wine_import_names:\n" );
1775 /* required to avoid internal linker errors with some binutils versions */
1776 output( "\n\t.section .idata$2\n" );
1778 else
1780 output( "\n\t.section .idata$2\n" );
1781 output( "%s\n", asm_globl( import_desc ) );
1782 output_rva( ".L__wine_import_names" ); /* OriginalFirstThunk */
1783 output( "\t.long 0\n" ); /* TimeDateStamp */
1784 output( "\t.long 0\n" ); /* ForwarderChain */
1785 output_rva( "%s", asm_name( import_name ) ); /* Name */
1786 output_rva( ".L__wine_import_addrs" ); /* FirstThunk */
1788 output( "\n\t.section .idata$4\n" );
1789 output( ".L__wine_import_names:\n" ); /* OriginalFirstThunk head */
1791 output( "\n\t.section .idata$5\n" );
1792 output( ".L__wine_import_addrs:\n" ); /* FirstThunk head */
1795 /* _head suffix to keep this object sections first */
1796 assemble_files( strmake( "%s_head", dll_name ) );
1797 strarray_addall( &objs, as_files );
1798 as_files = empty_strarray;
1800 new_output_as_file();
1802 output( "\n\t.section .idata$4\n" );
1803 output( "\t%s 0\n", get_asm_ptr_keyword() ); /* OriginalFirstThunk tail */
1804 output( "\n\t.section .idata$5\n" );
1805 output( "\t%s 0\n", get_asm_ptr_keyword() ); /* FirstThunk tail */
1806 output( "\n\t.section .idata$7\n" );
1807 output( "%s\n", asm_globl( import_name ) );
1808 output( "\t%s \"%s\"\n", get_asm_string_keyword(), spec->file_name );
1810 /* _tail suffix to keep this object sections last */
1811 assemble_files( strmake( "%s_tail", dll_name ) );
1812 strarray_addall( &objs, as_files );
1813 as_files = empty_strarray;
1815 for (i = total = 0; i < spec->nb_entry_points; i++)
1817 const ORDDEF *odp = &spec->entry_points[i];
1818 const char *abi_name;
1819 char *imp_name;
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 by_name = odp->name && !(odp->flags & FLAG_ORDINAL);
1837 abi_name = get_abi_name( odp, name );
1838 imp_name = strmake( "%s_imp_%s", target.cpu != CPU_i386 ? "_" : "",
1839 asm_name( abi_name ) );
1841 new_output_as_file();
1843 output( "\n\t.text\n" );
1844 output( "\t.align %d\n", get_alignment( get_ptr_size() ) );
1845 output( "%s\n", asm_globl( abi_name ) );
1846 output( "\t%s\n", func_declaration( abi_name ) );
1848 switch (target.cpu)
1850 case CPU_i386:
1851 output( "\tjmp *%s\n", asm_name( imp_name ) );
1852 if (is_delay)
1854 output( "\n\t.section .text$1\n" );
1855 output( ".L__wine_delay_import:\n" );
1856 output( "\tmov $%s,%%eax\n", asm_name( imp_name ) );
1857 output( "\tjmp %s\n", asm_name( delay_load ) );
1859 break;
1860 case CPU_x86_64:
1861 output( "\tjmp *%s(%%rip)\n", asm_name( imp_name ) );
1862 if (is_delay)
1864 output( "\n\t.section .text$1\n" );
1865 output( ".L__wine_delay_import:\n" );
1866 output( "\tlea %s(%%rip),%%rax\n", asm_name( imp_name ) );
1867 output( "\tjmp %s\n", asm_name( delay_load ) );
1869 break;
1870 case CPU_ARM:
1871 output( "\tldr IP, 1f\n" );
1872 output( "\tldr PC, [IP]\n" );
1873 if (is_delay)
1875 output( "\n\t.section .text$1\n" );
1876 output( ".L__wine_delay_import:\n" );
1877 output( "\tldr IP, 1f\n" );
1878 output( "\tldr IP, [IP]\n" );
1879 output( "\tb %s\n", asm_name( delay_load ) );
1881 output( "1:\t.long %s\n", asm_name( imp_name ) );
1882 break;
1883 case CPU_ARM64:
1884 output( "\tadrp x16, %s\n", arm64_page( asm_name( imp_name ) ) );
1885 output( "\tadd x16, x16, #%s\n", arm64_pageoff( asm_name( imp_name ) ) );
1886 output( "\tbr x16\n" );
1887 if (is_delay)
1889 output( "\n\t.section .text$1\n" );
1890 output( ".L__wine_delay_import:\n" );
1891 output( "\tadrp x16, %s\n", arm64_page( asm_name( imp_name ) ) );
1892 output( "\tadd x16, x16, #%s\n", arm64_pageoff( asm_name( imp_name ) ) );
1893 output( "\tb %s\n", asm_name( delay_load ) );
1895 break;
1898 output( "\n\t.section .idata$4\n" );
1899 output_thunk_rva( by_name ? -1 : odp->ordinal, ".L__wine_import_name" );
1901 output( "\n\t.section .idata$5\n" );
1902 output( "%s\n", asm_globl( imp_name ) );
1903 if (is_delay)
1904 output( "\t%s .L__wine_delay_import\n", get_asm_ptr_keyword() );
1905 else
1906 output_thunk_rva( by_name ? -1 : odp->ordinal, ".L__wine_import_name" );
1908 if (by_name)
1910 output( "\n\t.section .idata$6\n" );
1911 output( ".L__wine_import_name:\n" );
1912 output( "\t.short %d\n", odp->hint );
1913 output( "\t%s \"%s\"\n", get_asm_string_keyword(), name );
1916 /* reference head object to always pull its sections */
1917 output( "\n\t.section .idata$7\n" );
1918 output_rva( "%s", asm_name( import_desc ) );
1920 free( imp_name );
1921 break;
1923 default:
1924 break;
1928 /* _syms suffix to keep these objects sections in between _head and _tail */
1929 assemble_files( strmake( "%s_syms", dll_name ) );
1930 strarray_addall( &objs, as_files );
1931 as_files = objs;
1933 free( import_desc );
1934 free( import_name );
1935 free( delay_load );
1936 free( dll_name );
1938 output_static_lib( output_file_name, files, 1 );
1941 /* create a Unix-style import library */
1942 static void build_unix_import_lib( DLLSPEC *spec, struct strarray files )
1944 int i, total;
1945 const char *name, *prefix;
1946 char *dll_name = encode_dll_name( spec->file_name );
1948 /* entry points */
1950 for (i = total = 0; i < spec->nb_entry_points; i++)
1952 const ORDDEF *odp = &spec->entry_points[i];
1954 if (odp->name) name = odp->name;
1955 else if (odp->export_name) name = odp->export_name;
1956 else continue;
1958 if (odp->flags & FLAG_PRIVATE) continue;
1959 total++;
1961 /* C++ mangled names cannot be imported */
1962 if (strpbrk( name, "?@" )) continue;
1964 switch(odp->type)
1966 case TYPE_VARARGS:
1967 case TYPE_CDECL:
1968 case TYPE_STDCALL:
1969 prefix = (!odp->name || (odp->flags & FLAG_ORDINAL)) ? import_ord_prefix : import_func_prefix;
1970 new_output_as_file();
1971 output( "\t.text\n" );
1972 output( "\n\t.align %d\n", get_alignment( get_ptr_size() ));
1973 output( "\t%s\n", func_declaration( name ) );
1974 output( "%s\n", asm_globl( name ) );
1975 output( "\t%s %s%s$%u$%s\n", get_asm_ptr_keyword(),
1976 asm_name( prefix ), dll_name, odp->ordinal, name );
1977 output_function_size( name );
1978 output_gnu_stack_note();
1979 break;
1981 default:
1982 break;
1985 if (!total) warning( "%s: Import library doesn't export anything\n", spec->file_name );
1987 if (!as_files.count) /* create a dummy file to avoid empty import libraries */
1989 new_output_as_file();
1990 output( "\t.text\n" );
1993 assemble_files( spec->file_name );
1994 free( dll_name );
1996 output_static_lib( output_file_name, files, 1 );
1999 /* output an import library for a Win32 module and additional object files */
2000 void output_import_lib( DLLSPEC *spec, struct strarray files )
2002 if (!is_pe()) build_unix_import_lib( spec, files );
2003 else if (use_dlltool) build_dlltool_import_lib( output_file_name, spec, files );
2004 else build_windows_import_lib( output_file_name, spec, files );