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 (odp
->flags
& FLAG_SYSCALL
) continue;
580 if (find_name( odp
->link_name
, undef_symbols
))
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
);
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
);
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
;
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
);
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
);
654 /* read in the list of undefined symbols */
655 void read_undef_symbols( DLLSPEC
*spec
, struct strarray files
)
659 const char *prog
= get_nm_command();
660 char *cmd
, buffer
[1024], name_prefix
[16];
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
);
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;
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
);
699 void resolve_dll_imports( DLLSPEC
*spec
, struct list
*list
)
702 struct import
*imp
, *next
;
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
);
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
);
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
);
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" );
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" );
779 output( "\tjmp *(%s+%d)\n", table
, pos
);
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;
789 output( "\tjmpq *%s+%d(%%rip)\n", table
, pos
);
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 );
801 output( "\tldr ip, 1f\n");
802 output( "\tldr pc, [ip]\n");
803 output( "1:\t.long %s+%u\n", table
, pos
);
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" );
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)
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" );
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
];
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)
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
));
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" );
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
));
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" );
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" );
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;
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" );
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" );
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");
1111 output( "1:\t.long .L__wine_spec_delay_imports+%u-2b-%u\n", pos
, thumb_mode
? 4 : 8 );
1113 output( "1:\t.long .L__wine_spec_delay_imports+%u\n", pos
);
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" );
1136 output_cfi( ".cfi_endproc" );
1137 output_function_size( module_func
);
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" );
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
) );
1161 output( "\tleaq .L__wine_delay_IAT+%d(%%rip),%%rax\n", iat_pos
);
1162 output( "\tjmp %s\n", asm_name(module_func
) );
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 );
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
);
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
) );
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
));
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
);
1240 pos
+= get_ptr_size();
1242 output_function_size( "__wine_spec_external_link_thunks" );
1245 /*******************************************************************
1248 * Output the functions for stub entry points
1250 void output_stubs( DLLSPEC
*spec
)
1252 const char *name
, *exp_name
;
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" );
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" );
1290 output( "\tcall %s\n", asm_name("__wine_spec_get_pc_thunk_eax") );
1292 needs_get_pc_thunk
= 1;
1295 output( "\tleal .L%s_string-1b(%%eax),%%ecx\n", name
);
1296 output( "\tmovl %%ecx,4(%%esp)\n" );
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" );
1306 output( "\tmovl $.L%s_string,4(%%esp)\n", name
);
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") );
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" );
1318 output( "leaq .L%s_string(%%rip),%%rdx\n", name
);
1320 output( "\tmovq $%d,%%rdx\n", odp
->ordinal
);
1321 output( "\tcall %s\n", asm_name("__wine_spec_unimplemented_stub") );
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
);
1337 output( "\tmovw r0,:lower16:.L__wine_spec_file_name\n");
1338 output( "\tmovt r0,:upper16:.L__wine_spec_file_name\n");
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") );
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( "\tbl %s\n", asm_name("__wine_spec_unimplemented_stub") );
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
;
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
)
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
;
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" );
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;
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
));
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 */
1459 output( "1:\t.byte 0xff,0x14,0x25\n" ); /* 1: callq *(0x7ffe1000) */
1460 output( "\t.long 0x7ffe1000\n" );
1464 output( "\tnop\n" );
1465 output( "1:\tcallq *%s(%%rip)\n", asm_name("__wine_syscall_dispatcher") );
1467 output( "\tret\n" );
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" );
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" );
1485 output_cfi( ".cfi_endproc" );
1486 output_function_size( name
);
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" );
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") );
1505 output( "\tldr r0, 2f\n");
1506 output( "1:\tadd r0, pc\n" );
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" );
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" );
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)
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
)
1564 if (output_file
) fclose( output_file
);
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
);
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
);
1597 if (target
.platform
!= PLATFORM_WINDOWS
)
1599 struct strarray ranlib
= find_tool( "ranlib", NULL
);
1600 strarray_add( &ranlib
, output_name
);
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
;
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
);
1625 strarray_add( &args
, "-m" );
1626 strarray_add( &args
, "i386" );
1627 strarray_add( &args
, "--as-flags=--32" );
1630 strarray_add( &args
, "-m" );
1631 strarray_add( &args
, "i386:x86-64" );
1632 strarray_add( &args
, "--as-flags=--64" );
1635 strarray_add( &args
, "-m" );
1636 strarray_add( &args
, "arm" );
1639 strarray_add( &args
, "-m" );
1640 strarray_add( &args
, "arm64" );
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" );
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();
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" );
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" );
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" );
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
) );
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" );
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" );
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
;
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 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
) );
1851 output( "\tjmp *%s\n", asm_name( imp_name
) );
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
) );
1861 output( "\tjmp *%s(%%rip)\n", asm_name( imp_name
) );
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
) );
1871 output( "\tldr IP, 1f\n" );
1872 output( "\tldr PC, [IP]\n" );
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
) );
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" );
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
) );
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
) );
1904 output( "\t%s .L__wine_delay_import\n", get_asm_ptr_keyword() );
1906 output_thunk_rva( by_name
? -1 : odp
->ordinal
, ".L__wine_import_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
) );
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
);
1933 free( import_desc
);
1934 free( import_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
)
1945 const char *name
, *prefix
;
1946 char *dll_name
= encode_dll_name( spec
->file_name
);
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
;
1958 if (odp
->flags
& FLAG_PRIVATE
) continue;
1961 /* C++ mangled names cannot be imported */
1962 if (strpbrk( name
, "?@" )) continue;
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();
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
);
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
);