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
32 #include "wine/list.h"
34 /* standard C functions that are also exported from ntdll */
35 static const char *stdc_names
[] =
119 static const struct strarray stdc_functions
= { ARRAY_SIZE(stdc_names
), ARRAY_SIZE(stdc_names
), stdc_names
};
124 const char *export_name
;
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 */
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
) );
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
);
200 if (table
) res
= bsearch( &odp
, table
, size
, sizeof(*table
), func_cmp
);
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
)
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
);
226 /* decode a linker-compatible dll name */
227 static char *decode_dll_name( const char **name
)
229 const char *src
= *name
;
232 ret
= p
= xmalloc( strlen( src
) + 5 );
233 for ( ; *src
; src
++, p
++)
239 else if (src
[1] == 'x') /* hex escape */
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;
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;
255 else break; /* end of dll name */
258 if (!strchr( ret
, '.' )) strcpy( p
, ".dll" );
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
);
270 free( imp
->full_name
);
274 /* check whether a given dll is imported in delayed mode */
275 static int is_delayed_import( const char *name
)
279 for (i
= 0; i
< delayed_imports
.count
; i
++)
281 if (!strcmp( delayed_imports
.str
[i
], name
)) return 1;
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
;
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
)
304 buffer
= strmake( "%s/lib%s.def", path
, name
);
306 /* check if the file exists */
307 if ((fd
= open( buffer
, O_RDONLY
)) != -1)
316 /* find the .def import library for a given dll */
317 static char *find_library( const char *name
)
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
);
330 /* read in the list of exported symbols of an import library */
331 static DLLSPEC
*read_import_lib( struct import
*imp
)
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
);
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
)
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;
381 ret
= xmalloc( strlen(name
) + 5 );
384 if (!strchr( ret
, '.' )) strcat( ret
, ".dll" );
388 /* add a dll to the list of imports */
389 void add_import_dll( const char *name
, const char *filename
)
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
)))
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
);
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
)
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
);
452 list_add_tail( &dll_imports
, &import
->entry
);
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
;
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
);
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
);
489 add_import_func( import
, NULL
, xstrdup( name
), ordinal
, 0 );
491 add_import_func( import
, xstrdup( name
), NULL
, ordinal
, 0 );
495 /* check if the spec file exports any stubs */
496 static int has_stubs( const DLLSPEC
*spec
)
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;
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
)
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 */
537 /* check if a given forward does exist in one of the imported dlls */
538 static void check_undefined_forwards( DLLSPEC
*spec
)
541 char *link_name
, *api_name
, *dll_name
, *p
;
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
, '.' );
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
);
569 /* flag the dll exports that link to an undefined symbol */
570 static void check_undefined_exports( DLLSPEC
*spec
)
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
))
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
);
596 error( "%s:%d: external symbol '%s' is not a function\n",
597 spec
->src_name
, odp
->lineno
, odp
->link_name
);
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
;
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
);
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
);
651 /* read in the list of undefined symbols */
652 void read_undef_symbols( DLLSPEC
*spec
, struct strarray files
)
656 const char *prog
= get_nm_command();
657 char *cmd
, buffer
[1024], name_prefix
[16];
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
);
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;
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
);
696 void resolve_dll_imports( DLLSPEC
*spec
, struct list
*list
)
699 struct import
*imp
, *next
;
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
);
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
);
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
);
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" );
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 );
768 output( "\tjmp *(%s+%d)\n", table
, pos
);
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;
778 output( "\tjmpq *%s+%d(%%rip)\n", table
, pos
);
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 );
790 output( "\tldr ip, 1f\n");
791 output( "\tldr pc, [ip]\n");
792 output( "1:\t.long %s+%u\n", table
, pos
);
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" );
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)
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" );
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
];
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)
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
));
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" );
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
));
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" );
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" );
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;
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" );
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" );
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");
1100 output( "1:\t.long .L__wine_spec_delay_imports+%u-2b-%u\n", pos
, thumb_mode
? 4 : 8 );
1102 output( "1:\t.long .L__wine_spec_delay_imports+%u\n", pos
);
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" );
1128 output_cfi( ".cfi_endproc" );
1129 output_function_size( module_func
);
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
);
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
) );
1152 output( "\tleaq .L__wine_delay_IAT+%d(%%rip),%%rax\n", iat_pos
);
1153 output( "\tjmp %s\n", asm_name(module_func
) );
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 );
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
);
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
) );
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
));
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
);
1233 pos
+= get_ptr_size();
1235 output_function_size( "__wine_spec_external_link_thunks" );
1238 /*******************************************************************
1241 * Output the functions for stub entry points
1243 void output_stubs( DLLSPEC
*spec
)
1245 const char *name
, *exp_name
;
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 );
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" );
1280 output( "\tcall %s\n", asm_name("__wine_spec_get_pc_thunk_eax") );
1282 needs_get_pc_thunk
= 1;
1285 output( "\tleal .L%s_string-1b(%%eax),%%ecx\n", name
);
1286 output( "\tmovl %%ecx,4(%%esp)\n" );
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" );
1296 output( "\tmovl $.L%s_string,4(%%esp)\n", name
);
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" );
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" );
1313 output( "leaq .L%s_string(%%rip),%%rdx\n", name
);
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" );
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
);
1334 output( "\tmovw r0,:lower16:.L__wine_spec_file_name\n");
1335 output( "\tmovt r0,:upper16:.L__wine_spec_file_name\n");
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") );
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") );
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
) );
1359 output( "\tmov x1, %u\n", odp
->ordinal
);
1360 output( "\tb %s\n", arm64_name("__wine_spec_unimplemented_stub") );
1361 output_seh( ".seh_endproc" );
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
;
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)
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
)
1410 if (output_file
) fclose( output_file
);
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
[] =
1426 [CPU_x86_64
] = "x64",
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
);
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
);
1458 if (target
.platform
!= PLATFORM_WINDOWS
)
1460 struct strarray ranlib
= find_tool( "ranlib", NULL
);
1461 strarray_add( &ranlib
, output_name
);
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
;
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
);
1486 strarray_add( &args
, "-m" );
1487 strarray_add( &args
, "i386" );
1488 strarray_add( &args
, "--as-flags=--32" );
1491 strarray_add( &args
, "-m" );
1492 strarray_add( &args
, "i386:x86-64" );
1493 strarray_add( &args
, "--as-flags=--64" );
1496 strarray_add( &args
, "-m" );
1497 strarray_add( &args
, "arm" );
1500 strarray_add( &args
, "-m" );
1501 strarray_add( &args
, "arm64" );
1504 strarray_add( &args
, "-m" );
1505 strarray_add( &args
, "arm64ec" );
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" );
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();
1537 output_function_header( delay_load
, 1 );
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" );
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" );
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
) );
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" );
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" );
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
;
1689 if (odp
->name
) name
= odp
->name
;
1690 else if (odp
->export_name
) name
= odp
->export_name
;
1693 if (odp
->flags
& FLAG_PRIVATE
) continue;
1696 /* C++ mangled names cannot be imported */
1697 if (strpbrk( name
, "?@" )) continue;
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 );
1715 output( "\tjmp *%s\n", asm_name( imp_name
) );
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
) );
1725 output( "\tjmp *%s(%%rip)\n", asm_name( imp_name
) );
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
) );
1735 output( "\tldr IP, 1f\n" );
1736 output( "\tldr PC, [IP]\n" );
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
) );
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" );
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
) );
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
) );
1771 output( "\t%s .L__wine_delay_import\n", get_asm_ptr_keyword() );
1773 output_thunk_rva( by_name
? -1 : odp
->ordinal
, ".L__wine_import_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
) );
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
);
1800 free( import_desc
);
1801 free( import_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
)
1812 const char *name
, *prefix
;
1813 char *dll_name
= encode_dll_name( spec
->file_name
);
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
;
1825 if (odp
->flags
& FLAG_PRIVATE
) continue;
1828 /* C++ mangled names cannot be imported */
1829 if (strpbrk( name
, "?@" )) continue;
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();
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
);
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
);