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
31 #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 if (unix_lib
) return 0;
502 for (i
= 0; i
< spec
->nb_entry_points
; i
++)
504 ORDDEF
*odp
= &spec
->entry_points
[i
];
505 if (odp
->type
== TYPE_STUB
) return 1;
510 /* add the extra undefined symbols that will be contained in the generated spec file itself */
511 static void add_extra_undef_symbols( DLLSPEC
*spec
)
513 add_extra_ld_symbol( spec
->init_func
);
514 if (spec
->type
== SPEC_WIN16
) add_extra_ld_symbol( "DllMain" );
515 if (has_stubs( spec
)) add_extra_ld_symbol( "__wine_spec_unimplemented_stub" );
516 if (delayed_imports
.count
) add_extra_ld_symbol( "__wine_spec_delay_load" );
519 /* check if a given imported dll is not needed, taking forwards into account */
520 static int check_unused( const struct import
* imp
, const DLLSPEC
*spec
)
523 const char *file_name
= imp
->dll_name
;
524 size_t len
= strlen( file_name
);
525 const char *p
= strchr( file_name
, '.' );
526 if (p
&& !strcasecmp( p
, ".dll" )) len
= p
- file_name
;
528 for (i
= spec
->base
; i
<= spec
->limit
; i
++)
530 ORDDEF
*odp
= spec
->ordinals
[i
];
531 if (!odp
|| !(odp
->flags
& FLAG_FORWARD
)) continue;
532 if (!strncasecmp( odp
->link_name
, file_name
, len
) &&
533 odp
->link_name
[len
] == '.')
534 return 0; /* found a forward, it is used */
539 /* check if a given forward does exist in one of the imported dlls */
540 static void check_undefined_forwards( DLLSPEC
*spec
)
543 char *link_name
, *api_name
, *dll_name
, *p
;
546 if (unix_lib
) return;
548 for (i
= 0; i
< spec
->nb_entry_points
; i
++)
550 ORDDEF
*odp
= &spec
->entry_points
[i
];
552 if (!(odp
->flags
& FLAG_FORWARD
)) continue;
554 link_name
= xstrdup( odp
->link_name
);
555 p
= strrchr( link_name
, '.' );
558 dll_name
= get_dll_name( link_name
, NULL
);
560 if ((imp
= find_import_dll( dll_name
)))
562 if (!find_export( api_name
, imp
->exports
, imp
->nb_exports
))
563 warning( "%s:%d: forward '%s' not found in %s\n",
564 spec
->src_name
, odp
->lineno
, odp
->link_name
, imp
->dll_name
);
566 else warning( "%s:%d: forward '%s' not found in the imported dll list\n",
567 spec
->src_name
, odp
->lineno
, odp
->link_name
);
573 /* flag the dll exports that link to an undefined symbol */
574 static void check_undefined_exports( DLLSPEC
*spec
)
578 if (unix_lib
) return;
580 for (i
= 0; i
< spec
->nb_entry_points
; i
++)
582 ORDDEF
*odp
= &spec
->entry_points
[i
];
583 if (odp
->type
== TYPE_STUB
|| odp
->type
== TYPE_ABS
|| odp
->type
== TYPE_VARIABLE
) continue;
584 if (odp
->flags
& FLAG_FORWARD
) continue;
585 if (odp
->flags
& FLAG_SYSCALL
) continue;
586 if (find_name( odp
->link_name
, undef_symbols
))
594 if (link_ext_symbols
)
596 odp
->flags
|= FLAG_EXT_LINK
;
597 strarray_add( &ext_link_imports
, odp
->link_name
);
599 else error( "%s:%d: function '%s' not defined\n",
600 spec
->src_name
, odp
->lineno
, odp
->link_name
);
603 if (!strcmp( odp
->link_name
, "__wine_syscall_dispatcher" )) break;
604 error( "%s:%d: external symbol '%s' is not a function\n",
605 spec
->src_name
, odp
->lineno
, odp
->link_name
);
612 /* create a .o file that references all the undefined symbols we want to resolve */
613 static char *create_undef_symbols_file( DLLSPEC
*spec
)
615 char *as_file
, *obj_file
;
619 if (unix_lib
) return NULL
;
621 as_file
= open_temp_output_file( ".s" );
622 output( "\t.data\n" );
624 for (i
= 0; i
< spec
->nb_entry_points
; i
++)
626 ORDDEF
*odp
= &spec
->entry_points
[i
];
627 if (odp
->type
== TYPE_STUB
|| odp
->type
== TYPE_ABS
|| odp
->type
== TYPE_VARIABLE
) continue;
628 if (odp
->flags
& FLAG_FORWARD
) continue;
629 if (odp
->flags
& FLAG_SYSCALL
) continue;
630 output( "\t%s %s\n", get_asm_ptr_keyword(), asm_name( get_link_name( odp
)));
632 for (j
= 0; j
< extra_ld_symbols
.count
; j
++)
633 output( "\t%s %s\n", get_asm_ptr_keyword(), asm_name(extra_ld_symbols
.str
[j
]) );
635 output_gnu_stack_note();
636 fclose( output_file
);
638 obj_file
= get_temp_file_name( output_file_name
, ".o" );
639 assemble_file( as_file
, obj_file
);
643 /* combine a list of object files with ld into a single object file */
644 /* returns the name of the combined file */
645 static const char *ldcombine_files( DLLSPEC
*spec
, struct strarray files
)
647 char *ld_tmp_file
, *undef_file
;
648 struct strarray args
= get_ld_command();
650 undef_file
= create_undef_symbols_file( spec
);
651 ld_tmp_file
= get_temp_file_name( output_file_name
, ".o" );
653 strarray_add( &args
, "-r" );
654 strarray_add( &args
, "-o" );
655 strarray_add( &args
, ld_tmp_file
);
656 if (undef_file
) strarray_add( &args
, undef_file
);
657 strarray_addall( &args
, files
);
662 /* read in the list of undefined symbols */
663 void read_undef_symbols( DLLSPEC
*spec
, struct strarray files
)
667 const char *prog
= get_nm_command();
668 char *cmd
, buffer
[1024], name_prefix
[16];
672 if (!files
.count
) return;
674 add_extra_undef_symbols( spec
);
676 strcpy( name_prefix
, asm_name("") );
677 prefix_len
= strlen( name_prefix
);
679 name
= ldcombine_files( spec
, files
);
681 cmd
= strmake( "%s -u %s", prog
, name
);
683 fprintf( stderr
, "%s\n", cmd
);
684 if (!(f
= popen( cmd
, "r" )))
685 fatal_error( "Cannot execute '%s'\n", cmd
);
687 while (fgets( buffer
, sizeof(buffer
), f
))
689 char *p
= buffer
+ strlen(buffer
) - 1;
690 if (p
< buffer
) continue;
691 if (*p
== '\n') *p
-- = 0;
693 while (*p
== ' ') p
++;
694 if (p
[0] == 'U' && p
[1] == ' ' && p
[2]) p
+= 2;
695 if (prefix_len
&& !strncmp( p
, name_prefix
, prefix_len
)) p
+= prefix_len
;
696 if (!strncmp( p
, import_func_prefix
, strlen(import_func_prefix
) ))
697 add_undef_import( p
+ strlen( import_func_prefix
), 0 );
698 else if (!strncmp( p
, import_ord_prefix
, strlen(import_ord_prefix
) ))
699 add_undef_import( p
+ strlen( import_ord_prefix
), 1 );
700 else if (use_msvcrt
|| !find_name( p
, stdc_functions
))
701 strarray_add( &undef_symbols
, xstrdup( p
));
703 if ((err
= pclose( f
))) warning( "%s failed with status %d\n", cmd
, err
);
707 void resolve_dll_imports( DLLSPEC
*spec
, struct list
*list
)
710 struct import
*imp
, *next
;
713 LIST_FOR_EACH_ENTRY_SAFE( imp
, next
, list
, struct import
, entry
)
715 for (j
= 0; j
< undef_symbols
.count
; j
++)
717 odp
= find_export( undef_symbols
.str
[j
], imp
->exports
, imp
->nb_exports
);
720 if (odp
->flags
& FLAG_PRIVATE
) continue;
721 if (odp
->type
!= TYPE_STDCALL
&& odp
->type
!= TYPE_CDECL
)
722 warning( "winebuild: Data export '%s' cannot be imported from %s\n",
723 odp
->link_name
, imp
->dll_name
);
726 add_import_func( imp
, (odp
->flags
& FLAG_NONAME
) ? NULL
: odp
->name
,
727 odp
->export_name
, odp
->ordinal
, odp
->hint
);
728 remove_name( &undef_symbols
, j
-- );
732 if (!imp
->nb_imports
)
734 /* the dll is not used, get rid of it */
735 if (check_unused( imp
, spec
))
736 warning( "winebuild: %s imported but no symbols used\n", imp
->dll_name
);
737 list_remove( &imp
->entry
);
743 /* resolve the imports for a Win32 module */
744 void resolve_imports( DLLSPEC
*spec
)
746 check_undefined_forwards( spec
);
747 resolve_dll_imports( spec
, &dll_imports
);
748 resolve_dll_imports( spec
, &dll_delayed
);
749 sort_names( &undef_symbols
);
750 check_undefined_exports( spec
);
753 /* check if symbol is still undefined */
754 int is_undefined( const char *name
)
756 return find_name( name
, undef_symbols
) != NULL
;
759 /* output the get_pc thunk if needed */
760 void output_get_pc_thunk(void)
762 assert( target
.cpu
== CPU_i386
);
763 output( "\n\t.text\n" );
764 output( "\t.align %d\n", get_alignment(4) );
765 output( "\t%s\n", func_declaration("__wine_spec_get_pc_thunk_eax") );
766 output( "%s:\n", asm_name("__wine_spec_get_pc_thunk_eax") );
767 output_cfi( ".cfi_startproc" );
768 output( "\tmovl (%%esp),%%eax\n" );
770 output_cfi( ".cfi_endproc" );
771 output_function_size( "__wine_spec_get_pc_thunk_eax" );
774 /* output a single import thunk */
775 static void output_import_thunk( const char *name
, const char *table
, int pos
)
777 output( "\n\t.align %d\n", get_alignment(4) );
778 output( "\t%s\n", func_declaration(name
) );
779 output( "%s\n", asm_globl(name
) );
780 output_cfi( ".cfi_startproc" );
787 output( "\tjmp *(%s+%d)\n", table
, pos
);
791 output( "\tcall %s\n", asm_name("__wine_spec_get_pc_thunk_eax") );
792 output( "1:\tjmp *%s+%d-1b(%%eax)\n", table
, pos
);
793 needs_get_pc_thunk
= 1;
797 output( "\tjmpq *%s+%d(%%rip)\n", table
, pos
);
802 output( "\tldr ip, 2f\n");
803 output( "1:\tadd ip, pc\n" );
804 output( "\tldr pc, [ip]\n");
805 output( "2:\t.long %s+%u-1b-%u\n", table
, pos
, thumb_mode
? 4 : 8 );
809 output( "\tldr ip, 1f\n");
810 output( "\tldr pc, [ip]\n");
811 output( "1:\t.long %s+%u\n", table
, pos
);
815 output( "\tadrp x16, %s\n", arm64_page( table
) );
816 output( "\tadd x16, x16, #%s\n", arm64_pageoff( table
) );
817 if (pos
& ~0x7fff) output( "\tadd x16, x16, #%u\n", pos
& ~0x7fff );
818 output( "\tldr x16, [x16, #%u]\n", pos
& 0x7fff );
819 output( "\tbr x16\n" );
822 output_cfi( ".cfi_endproc" );
823 output_function_size( name
);
826 /* check if we need an import directory */
827 int has_imports(void)
829 return !list_empty( &dll_imports
);
832 /* output the import table of a Win32 module */
833 static void output_immediate_imports(void)
836 struct import
*import
;
838 if (list_empty( &dll_imports
)) return; /* no immediate imports */
840 /* main import header */
842 output( "\n/* import table */\n" );
843 output( "\n\t.data\n" );
844 output( "\t.align %d\n", get_alignment(4) );
845 output( ".L__wine_spec_imports:\n" );
850 LIST_FOR_EACH_ENTRY( import
, &dll_imports
, struct import
, entry
)
852 output_rva( ".L__wine_spec_import_data_names + %d", j
* get_ptr_size() ); /* OriginalFirstThunk */
853 output( "\t.long 0\n" ); /* TimeDateStamp */
854 output( "\t.long 0\n" ); /* ForwarderChain */
855 output_rva( ".L__wine_spec_import_name_%s", import
->c_name
); /* Name */
856 output_rva( ".L__wine_spec_import_data_ptrs + %d", j
* get_ptr_size() ); /* FirstThunk */
857 j
+= import
->nb_imports
+ 1;
859 output( "\t.long 0\n" ); /* OriginalFirstThunk */
860 output( "\t.long 0\n" ); /* TimeDateStamp */
861 output( "\t.long 0\n" ); /* ForwarderChain */
862 output( "\t.long 0\n" ); /* Name */
863 output( "\t.long 0\n" ); /* FirstThunk */
865 output( "\n\t.align %d\n", get_alignment(get_ptr_size()) );
866 /* output the names twice, once for OriginalFirstThunk and once for FirstThunk */
867 for (i
= 0; i
< 2; i
++)
869 output( ".L__wine_spec_import_data_%s:\n", i
? "ptrs" : "names" );
870 LIST_FOR_EACH_ENTRY( import
, &dll_imports
, struct import
, entry
)
872 for (j
= 0; j
< import
->nb_imports
; j
++)
874 struct import_func
*func
= &import
->imports
[j
];
877 if (func
->name
) output( "__imp_%s:\n", asm_name( func
->name
));
878 else if (func
->export_name
) output( "__imp_%s:\n", asm_name( func
->export_name
));
881 output( "\t%s .L__wine_spec_import_data_%s_%s-.L__wine_spec_rva_base\n",
882 get_asm_ptr_keyword(), import
->c_name
, func
->name
);
885 if (get_ptr_size() == 8)
886 output( "\t.quad 0x800000000000%04x\n", func
->ordinal
);
888 output( "\t.long 0x8000%04x\n", func
->ordinal
);
891 output( "\t%s 0\n", get_asm_ptr_keyword() );
894 output( ".L__wine_spec_imports_end:\n" );
896 LIST_FOR_EACH_ENTRY( import
, &dll_imports
, struct import
, entry
)
898 for (j
= 0; j
< import
->nb_imports
; j
++)
900 struct import_func
*func
= &import
->imports
[j
];
901 if (!func
->name
) continue;
902 output( "\t.align %d\n", get_alignment(2) );
903 output( ".L__wine_spec_import_data_%s_%s:\n", import
->c_name
, func
->name
);
904 output( "\t.short %d\n", func
->hint
);
905 output( "\t%s \"%s\"\n", get_asm_string_keyword(), func
->name
);
909 LIST_FOR_EACH_ENTRY( import
, &dll_imports
, struct import
, entry
)
911 output( ".L__wine_spec_import_name_%s:\n\t%s \"%s\"\n",
912 import
->c_name
, get_asm_string_keyword(), import
->dll_name
);
916 /* output the import thunks of a Win32 module */
917 static void output_immediate_import_thunks(void)
920 struct import
*import
;
921 static const char import_thunks
[] = "__wine_spec_import_thunks";
923 if (list_empty( &dll_imports
)) return;
925 output( "\n/* immediate import thunks */\n\n" );
926 output( "\t.text\n" );
927 output( "\t.align %d\n", get_alignment(8) );
928 output( "%s:\n", asm_name(import_thunks
));
931 LIST_FOR_EACH_ENTRY( import
, &dll_imports
, struct import
, entry
)
933 for (j
= 0; j
< import
->nb_imports
; j
++, pos
+= get_ptr_size())
935 struct import_func
*func
= &import
->imports
[j
];
936 output_import_thunk( func
->name
? func
->name
: func
->export_name
,
937 ".L__wine_spec_import_data_ptrs", pos
);
939 pos
+= get_ptr_size();
941 output_function_size( import_thunks
);
944 /* output the delayed import table of a Win32 module */
945 static void output_delayed_imports( const DLLSPEC
*spec
)
948 struct import
*import
;
950 if (list_empty( &dll_delayed
)) return;
952 output( "\n/* delayed imports */\n\n" );
953 output( "\t.data\n" );
954 output( "\t.align %d\n", get_alignment(get_ptr_size()) );
955 output( "%s\n", asm_globl("__wine_spec_delay_imports") );
960 LIST_FOR_EACH_ENTRY( import
, &dll_delayed
, struct import
, entry
)
962 output( "\t%s 0\n", get_asm_ptr_keyword() ); /* grAttrs */
963 output( "\t%s .L__wine_delay_name_%s\n", /* szName */
964 get_asm_ptr_keyword(), import
->c_name
);
965 output( "\t%s .L__wine_delay_modules+%d\n", /* phmod */
966 get_asm_ptr_keyword(), mod
* get_ptr_size() );
967 output( "\t%s .L__wine_delay_IAT+%d\n", /* pIAT */
968 get_asm_ptr_keyword(), j
* get_ptr_size() );
969 output( "\t%s .L__wine_delay_INT+%d\n", /* pINT */
970 get_asm_ptr_keyword(), j
* get_ptr_size() );
971 output( "\t%s 0\n", get_asm_ptr_keyword() ); /* pBoundIAT */
972 output( "\t%s 0\n", get_asm_ptr_keyword() ); /* pUnloadIAT */
973 output( "\t%s 0\n", get_asm_ptr_keyword() ); /* dwTimeStamp */
974 j
+= import
->nb_imports
;
977 output( "\t%s 0\n", get_asm_ptr_keyword() ); /* grAttrs */
978 output( "\t%s 0\n", get_asm_ptr_keyword() ); /* szName */
979 output( "\t%s 0\n", get_asm_ptr_keyword() ); /* phmod */
980 output( "\t%s 0\n", get_asm_ptr_keyword() ); /* pIAT */
981 output( "\t%s 0\n", get_asm_ptr_keyword() ); /* pINT */
982 output( "\t%s 0\n", get_asm_ptr_keyword() ); /* pBoundIAT */
983 output( "\t%s 0\n", get_asm_ptr_keyword() ); /* pUnloadIAT */
984 output( "\t%s 0\n", get_asm_ptr_keyword() ); /* dwTimeStamp */
986 output( "\n.L__wine_delay_IAT:\n" );
987 LIST_FOR_EACH_ENTRY( import
, &dll_delayed
, struct import
, entry
)
989 for (j
= 0; j
< import
->nb_imports
; j
++)
991 struct import_func
*func
= &import
->imports
[j
];
992 const char *name
= func
->name
? func
->name
: func
->export_name
;
993 output( "__imp_%s:\n", asm_name( name
));
994 output( "\t%s __wine_delay_imp_%s_%s\n",
995 get_asm_ptr_keyword(), import
->c_name
, name
);
999 output( "\n.L__wine_delay_INT:\n" );
1000 LIST_FOR_EACH_ENTRY( import
, &dll_delayed
, struct import
, entry
)
1002 for (j
= 0; j
< import
->nb_imports
; j
++)
1004 struct import_func
*func
= &import
->imports
[j
];
1006 output( "\t%s %d\n", get_asm_ptr_keyword(), func
->ordinal
);
1008 output( "\t%s .L__wine_delay_data_%s_%s\n",
1009 get_asm_ptr_keyword(), import
->c_name
, func
->name
);
1013 output( "\n.L__wine_delay_modules:\n" );
1014 LIST_FOR_EACH_ENTRY( import
, &dll_delayed
, struct import
, entry
)
1016 output( "\t%s 0\n", get_asm_ptr_keyword() );
1019 LIST_FOR_EACH_ENTRY( import
, &dll_delayed
, struct import
, entry
)
1021 output( ".L__wine_delay_name_%s:\n", import
->c_name
);
1022 output( "\t%s \"%s\"\n", get_asm_string_keyword(), import
->dll_name
);
1025 LIST_FOR_EACH_ENTRY( import
, &dll_delayed
, struct import
, entry
)
1027 for (j
= 0; j
< import
->nb_imports
; j
++)
1029 struct import_func
*func
= &import
->imports
[j
];
1030 if (!func
->name
) continue;
1031 output( ".L__wine_delay_data_%s_%s:\n", import
->c_name
, func
->name
);
1032 output( "\t%s \"%s\"\n", get_asm_string_keyword(), func
->name
);
1035 output_function_size( "__wine_spec_delay_imports" );
1038 /* output the delayed import thunks of a Win32 module */
1039 static void output_delayed_import_thunks( const DLLSPEC
*spec
)
1042 struct import
*import
;
1043 static const char delayed_import_loaders
[] = "__wine_spec_delayed_import_loaders";
1044 static const char delayed_import_thunks
[] = "__wine_spec_delayed_import_thunks";
1046 if (list_empty( &dll_delayed
)) return;
1048 output( "\n/* delayed import thunks */\n\n" );
1049 output( "\t.text\n" );
1050 output( "\t.align %d\n", get_alignment(8) );
1051 output( "%s:\n", asm_name(delayed_import_loaders
));
1052 output( "\t%s\n", func_declaration("__wine_delay_load_asm") );
1053 output( "%s:\n", asm_name("__wine_delay_load_asm") );
1054 output_cfi( ".cfi_startproc" );
1058 output( "\tpushl %%ecx\n" );
1059 output_cfi( ".cfi_adjust_cfa_offset 4" );
1060 output( "\tpushl %%edx\n" );
1061 output_cfi( ".cfi_adjust_cfa_offset 4" );
1062 output( "\tpushl %%eax\n" );
1063 output_cfi( ".cfi_adjust_cfa_offset 4" );
1064 output( "\tcall %s\n", asm_name("__wine_spec_delay_load") );
1065 output_cfi( ".cfi_adjust_cfa_offset -4" );
1066 output( "\tpopl %%edx\n" );
1067 output_cfi( ".cfi_adjust_cfa_offset -4" );
1068 output( "\tpopl %%ecx\n" );
1069 output_cfi( ".cfi_adjust_cfa_offset -4" );
1070 output( "\tjmp *%%eax\n" );
1073 output( "\tsubq $0x98,%%rsp\n" );
1074 output_cfi( ".cfi_adjust_cfa_offset 0x98" );
1075 output( "\tmovq %%rdx,0x88(%%rsp)\n" );
1076 output( "\tmovq %%rcx,0x80(%%rsp)\n" );
1077 output( "\tmovq %%r8,0x78(%%rsp)\n" );
1078 output( "\tmovq %%r9,0x70(%%rsp)\n" );
1079 output( "\tmovq %%r10,0x68(%%rsp)\n" );
1080 output( "\tmovq %%r11,0x60(%%rsp)\n" );
1081 output( "\tmovups %%xmm0,0x50(%%rsp)\n" );
1082 output( "\tmovups %%xmm1,0x40(%%rsp)\n" );
1083 output( "\tmovups %%xmm2,0x30(%%rsp)\n" );
1084 output( "\tmovups %%xmm3,0x20(%%rsp)\n" );
1085 output( "\tmovq %%rax,%%rcx\n" );
1086 output( "\tcall %s\n", asm_name("__wine_spec_delay_load") );
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 r0,IP\n" );
1104 output( "\tbl %s\n", asm_name("__wine_spec_delay_load") );
1105 output( "\tmov IP,r0\n");
1106 output( "\tpop {r0-r3,FP,LR}\n" );
1107 output( "\tbx IP\n");
1110 output( "\tstp x29, x30, [sp,#-80]!\n" );
1111 output( "\tmov x29, sp\n" );
1112 output( "\tstp x0, x1, [sp,#16]\n" );
1113 output( "\tstp x2, x3, [sp,#32]\n" );
1114 output( "\tstp x4, x5, [sp,#48]\n" );
1115 output( "\tstp x6, x7, [sp,#64]\n" );
1116 output( "\tmov x0, x16\n" );
1117 output( "\tbl %s\n", asm_name("__wine_spec_delay_load") );
1118 output( "\tmov x16, x0\n" );
1119 output( "\tldp x0, x1, [sp,#16]\n" );
1120 output( "\tldp x2, x3, [sp,#32]\n" );
1121 output( "\tldp x4, x5, [sp,#48]\n" );
1122 output( "\tldp x6, x7, [sp,#64]\n" );
1123 output( "\tldp x29, x30, [sp],#80\n" );
1124 output( "\tbr x16\n" );
1127 output_cfi( ".cfi_endproc" );
1128 output_function_size( "__wine_delay_load_asm" );
1132 LIST_FOR_EACH_ENTRY( import
, &dll_delayed
, struct import
, entry
)
1134 for (j
= 0; j
< import
->nb_imports
; j
++)
1136 struct import_func
*func
= &import
->imports
[j
];
1137 const char *name
= func
->name
? func
->name
: func
->export_name
;
1139 if (thumb_mode
) output( "\t.thumb_func\n" );
1140 output( "__wine_delay_imp_%s_%s:\n", import
->c_name
, name
);
1141 output_cfi( ".cfi_startproc" );
1146 output( "\tmovl $%d,%%eax\n", (idx
<< 16) | j
);
1147 output( "\tjmp %s\n", asm_name("__wine_delay_load_asm") );
1150 output( "\tmov ip, #%u\n", j
);
1151 if (idx
) output( "\tmovt ip, #%u\n", idx
);
1152 output( "\tb %s\n", asm_name("__wine_delay_load_asm") );
1157 output( "\tmov x16, #0x%x\n", idx
<< 16 );
1158 if (j
) output( "\tmovk x16, #0x%x\n", j
);
1160 else output( "\tmov x16, #0x%x\n", j
);
1161 output( "\tb %s\n", asm_name("__wine_delay_load_asm") );
1164 output_cfi( ".cfi_endproc" );
1168 output_function_size( delayed_import_loaders
);
1170 output( "\n\t.align %d\n", get_alignment(get_ptr_size()) );
1171 output( "%s:\n", asm_name(delayed_import_thunks
));
1173 LIST_FOR_EACH_ENTRY( import
, &dll_delayed
, struct import
, entry
)
1175 for (j
= 0; j
< import
->nb_imports
; j
++, pos
+= get_ptr_size())
1177 struct import_func
*func
= &import
->imports
[j
];
1178 output_import_thunk( func
->name
? func
->name
: func
->export_name
,
1179 ".L__wine_delay_IAT", pos
);
1182 output_function_size( delayed_import_thunks
);
1185 /* output import stubs for exported entry points that link to external symbols */
1186 static void output_external_link_imports( DLLSPEC
*spec
)
1188 unsigned int i
, pos
;
1190 if (!ext_link_imports
.count
) return; /* nothing to do */
1192 sort_names( &ext_link_imports
);
1194 /* get rid of duplicate names */
1195 for (i
= 1; i
< ext_link_imports
.count
; i
++)
1197 if (!strcmp( ext_link_imports
.str
[i
-1], ext_link_imports
.str
[i
] ))
1198 remove_name( &ext_link_imports
, i
-- );
1201 output( "\n/* external link thunks */\n\n" );
1202 output( "\t.data\n" );
1203 output( "\t.align %d\n", get_alignment(get_ptr_size()) );
1204 output( ".L__wine_spec_external_links:\n" );
1205 for (i
= 0; i
< ext_link_imports
.count
; i
++)
1206 output( "\t%s %s\n", get_asm_ptr_keyword(), asm_name(ext_link_imports
.str
[i
]) );
1208 output( "\n\t.text\n" );
1209 output( "\t.align %d\n", get_alignment(get_ptr_size()) );
1210 output( "%s:\n", asm_name("__wine_spec_external_link_thunks") );
1212 for (i
= pos
= 0; i
< ext_link_imports
.count
; i
++)
1214 char *buffer
= strmake( "__wine_spec_ext_link_%s", ext_link_imports
.str
[i
] );
1215 output_import_thunk( buffer
, ".L__wine_spec_external_links", pos
);
1217 pos
+= get_ptr_size();
1219 output_function_size( "__wine_spec_external_link_thunks" );
1222 /*******************************************************************
1225 * Output the functions for stub entry points
1227 void output_stubs( DLLSPEC
*spec
)
1229 const char *name
, *exp_name
;
1232 if (!has_stubs( spec
)) return;
1234 output( "\n/* stub functions */\n\n" );
1235 output( "\t.text\n" );
1237 for (i
= 0; i
< spec
->nb_entry_points
; i
++)
1239 ORDDEF
*odp
= &spec
->entry_points
[i
];
1240 if (odp
->type
!= TYPE_STUB
) continue;
1242 name
= get_stub_name( odp
, spec
);
1243 exp_name
= odp
->name
? odp
->name
: odp
->export_name
;
1244 output( "\t.align %d\n", get_alignment(4) );
1245 output( "\t%s\n", func_declaration(name
) );
1246 output( "%s:\n", asm_name(name
) );
1247 output_cfi( ".cfi_startproc" );
1252 /* flesh out the stub a bit to make safedisc happy */
1253 output(" \tnop\n" );
1254 output(" \tnop\n" );
1255 output(" \tnop\n" );
1256 output(" \tnop\n" );
1257 output(" \tnop\n" );
1258 output(" \tnop\n" );
1259 output(" \tnop\n" );
1260 output(" \tnop\n" );
1261 output(" \tnop\n" );
1263 output( "\tsubl $12,%%esp\n" );
1264 output_cfi( ".cfi_adjust_cfa_offset 12" );
1267 output( "\tcall %s\n", asm_name("__wine_spec_get_pc_thunk_eax") );
1269 needs_get_pc_thunk
= 1;
1272 output( "\tleal .L%s_string-1b(%%eax),%%ecx\n", name
);
1273 output( "\tmovl %%ecx,4(%%esp)\n" );
1276 output( "\tmovl $%d,4(%%esp)\n", odp
->ordinal
);
1277 output( "\tleal .L__wine_spec_file_name-1b(%%eax),%%ecx\n" );
1278 output( "\tmovl %%ecx,(%%esp)\n" );
1283 output( "\tmovl $.L%s_string,4(%%esp)\n", name
);
1285 output( "\tmovl $%d,4(%%esp)\n", odp
->ordinal
);
1286 output( "\tmovl $.L__wine_spec_file_name,(%%esp)\n" );
1288 output( "\tcall %s\n", asm_name("__wine_spec_unimplemented_stub") );
1291 output( "\tsubq $0x28,%%rsp\n" );
1292 output_cfi( ".cfi_adjust_cfa_offset 8" );
1293 output( "\tleaq .L__wine_spec_file_name(%%rip),%%rcx\n" );
1295 output( "leaq .L%s_string(%%rip),%%rdx\n", name
);
1297 output( "\tmovq $%d,%%rdx\n", odp
->ordinal
);
1298 output( "\tcall %s\n", asm_name("__wine_spec_unimplemented_stub") );
1303 output( "\tldr r0,3f\n");
1304 output( "1:\tadd r0,PC\n");
1305 output( "\tldr r1,3f+4\n");
1306 if (exp_name
) output( "2:\tadd r1,PC\n");
1307 output( "\tbl %s\n", asm_name("__wine_spec_unimplemented_stub") );
1308 output( "3:\t.long .L__wine_spec_file_name-1b-%u\n", thumb_mode
? 4 : 8 );
1309 if (exp_name
) output( "\t.long .L%s_string-2b-%u\n", name
, thumb_mode
? 4 : 8 );
1310 else output( "\t.long %u\n", odp
->ordinal
);
1314 output( "\tmovw r0,:lower16:.L__wine_spec_file_name\n");
1315 output( "\tmovt r0,:upper16:.L__wine_spec_file_name\n");
1318 output( "\tmovw r1,:lower16:.L%s_string\n", name
);
1319 output( "\tmovt r1,:upper16:.L%s_string\n", name
);
1321 else output( "\tmov r1,#%u\n", odp
->ordinal
);
1322 output( "\tbl %s\n", asm_name("__wine_spec_unimplemented_stub") );
1326 output( "\tadrp x0, %s\n", arm64_page(".L__wine_spec_file_name") );
1327 output( "\tadd x0, x0, #%s\n", arm64_pageoff(".L__wine_spec_file_name") );
1330 char *sym
= strmake( ".L%s_string", name
);
1331 output( "\tadrp x1, %s\n", arm64_page( sym
) );
1332 output( "\tadd x1, x1, #%s\n", arm64_pageoff( sym
) );
1336 output( "\tmov x1, %u\n", odp
->ordinal
);
1337 output( "\tbl %s\n", asm_name("__wine_spec_unimplemented_stub") );
1342 output_cfi( ".cfi_endproc" );
1343 output_function_size( name
);
1346 output( "\t%s\n", get_asm_string_section() );
1347 output( ".L__wine_spec_file_name:\n" );
1348 output( "\t%s \"%s\"\n", get_asm_string_keyword(), spec
->file_name
);
1349 for (i
= 0; i
< spec
->nb_entry_points
; i
++)
1351 ORDDEF
*odp
= &spec
->entry_points
[i
];
1352 if (odp
->type
!= TYPE_STUB
) continue;
1353 exp_name
= odp
->name
? odp
->name
: odp
->export_name
;
1356 name
= get_stub_name( odp
, spec
);
1357 output( ".L%s_string:\n", name
);
1358 output( "\t%s \"%s\"\n", get_asm_string_keyword(), exp_name
);
1363 static int cmp_link_name( const void *e1
, const void *e2
)
1365 const ORDDEF
*odp1
= *(const ORDDEF
* const *)e1
;
1366 const ORDDEF
*odp2
= *(const ORDDEF
* const *)e2
;
1368 return strcmp( odp1
->link_name
, odp2
->link_name
);
1372 /* output the functions for system calls */
1373 void output_syscalls( DLLSPEC
*spec
)
1376 ORDDEF
**syscalls
= NULL
;
1378 if (unix_lib
) return;
1380 for (i
= count
= 0; i
< spec
->nb_entry_points
; i
++)
1382 ORDDEF
*odp
= &spec
->entry_points
[i
];
1383 if (!(odp
->flags
& FLAG_SYSCALL
)) continue;
1384 if (!syscalls
) syscalls
= xmalloc( (spec
->nb_entry_points
- i
) * sizeof(*syscalls
) );
1385 syscalls
[count
++] = odp
;
1388 count
= sort_func_list( syscalls
, count
, cmp_link_name
);
1390 output( "\n/* system calls */\n\n" );
1391 output( "\t.text\n" );
1393 for (i
= 0; i
< count
; i
++)
1395 ORDDEF
*odp
= syscalls
[i
];
1396 const char *name
= get_link_name(odp
);
1397 unsigned int id
= (spec
->syscall_table
<< 12) + i
;
1399 output( "\t.align %d\n", get_alignment(16) );
1400 output( "\t%s\n", func_declaration(name
) );
1401 output( "%s\n", asm_globl(name
) );
1402 output_cfi( ".cfi_startproc" );
1408 output( "\tcall %s\n", asm_name("__wine_spec_get_pc_thunk_eax") );
1409 output( "1:\tmovl %s-1b(%%eax),%%edx\n", asm_name("__wine_syscall_dispatcher") );
1410 output( "\tmovl $%u,%%eax\n", id
);
1411 needs_get_pc_thunk
= 1;
1415 output( "\tmovl $%u,%%eax\n", id
);
1416 output( "\tmovl $%s,%%edx\n", asm_name("__wine_syscall") );
1418 output( "\tcall *%%edx\n" );
1419 output( "\tret $%u\n", odp
->type
== TYPE_STDCALL
? get_args_size( odp
) : 0 );
1422 /* Chromium depends on syscall thunks having the same form as on
1423 * Windows. For 64-bit systems the only viable form we can emulate is
1424 * having an int $0x2e fallback. Since actually using an interrupt is
1425 * expensive, and since for some reason Chromium doesn't actually
1426 * validate that instruction, we can just put a jmp there instead. */
1427 output( "\t.byte 0x4c,0x8b,0xd1\n" ); /* movq %rcx,%r10 */
1428 output( "\t.byte 0xb8\n" ); /* movl $i,%eax */
1429 output( "\t.long %u\n", id
);
1430 output( "\t.byte 0xf6,0x04,0x25,0x08,0x03,0xfe,0x7f,0x01\n" ); /* testb $1,0x7ffe0308 */
1431 output( "\t.byte 0x75,0x03\n" ); /* jne 1f */
1432 output( "\t.byte 0x0f,0x05\n" ); /* syscall */
1433 output( "\t.byte 0xc3\n" ); /* ret */
1434 output( "\tjmp 1f\n" );
1435 output( "\t.byte 0xc3\n" ); /* ret */
1438 output( "1:\t.byte 0xff,0x14,0x25\n" ); /* 1: callq *(0x7ffe1000) */
1439 output( "\t.long 0x7ffe1000\n" );
1443 output( "\tnop\n" );
1444 output( "1:\tcallq *%s(%%rip)\n", asm_name("__wine_syscall_dispatcher") );
1446 output( "\tret\n" );
1449 output( "\tpush {r0-r3}\n" );
1450 output( "\tmovw ip, #%u\n", id
);
1451 output( "\tmov r3, lr\n" );
1452 output( "\tbl %s\n", asm_name("__wine_syscall") );
1453 output( "\tbx lr\n" );
1456 output( "\tmov x8, #%u\n", id
);
1457 output( "\tmov x9, x30\n" );
1458 output( "\tbl %s\n", asm_name("__wine_syscall" ));
1459 output( "\tret\n" );
1464 output_cfi( ".cfi_endproc" );
1465 output_function_size( name
);
1472 output( "\t.align %d\n", get_alignment(16) );
1473 output( "\t%s\n", func_declaration("__wine_syscall") );
1474 output( "%s:\n", asm_name("__wine_syscall") );
1475 output( "\tjmp *(%s)\n", asm_name("__wine_syscall_dispatcher") );
1476 output_function_size( "__wine_syscall" );
1479 output( "\t.align %d\n", get_alignment(16) );
1480 output( "\t%s\n", func_declaration("__wine_syscall") );
1481 output( "%s:\n", asm_name("__wine_syscall") );
1484 output( "\tldr r0, 2f\n");
1485 output( "1:\tadd r0, pc\n" );
1489 output( "\tmovw r0, :lower16:%s\n", asm_name("__wine_syscall_dispatcher") );
1490 output( "\tmovt r0, :upper16:%s\n", asm_name("__wine_syscall_dispatcher") );
1492 output( "\tldr r0, [r0]\n");
1493 output( "\tbx r0\n");
1494 if (UsePIC
) output( "2:\t.long %s-1b-%u\n", asm_name("__wine_syscall_dispatcher"), thumb_mode
? 4 : 8 );
1495 output_function_size( "__wine_syscall" );
1498 output( "\t.align %d\n", get_alignment(16) );
1499 output( "\t%s\n", func_declaration("__wine_syscall") );
1500 output( "%s:\n", asm_name("__wine_syscall") );
1501 output( "\tadrp x16, %s\n", arm64_page( asm_name("__wine_syscall_dispatcher") ) );
1502 output( "\tldr x16, [x16, #%s]\n", arm64_pageoff( asm_name("__wine_syscall_dispatcher") ) );
1503 output( "\tbr x16\n");
1504 output_function_size( "__wine_syscall" );
1508 output( "\t.data\n" );
1509 output( "\t.align %d\n", get_alignment( get_ptr_size() ) );
1510 output( "%s\n", asm_globl("__wine_syscall_dispatcher") );
1511 output( "\t%s 0\n", get_asm_ptr_keyword() );
1512 output( "\t.short %u\n", count
);
1513 for (i
= 0; i
< count
; i
++) output( "\t.byte %u\n", get_args_size( syscalls
[i
] ));
1517 /* output the import and delayed import tables of a Win32 module */
1518 void output_imports( DLLSPEC
*spec
)
1520 if (is_pe()) return;
1521 output_immediate_imports();
1522 output_delayed_imports( spec
);
1523 output_immediate_import_thunks();
1524 output_delayed_import_thunks( spec
);
1525 output_external_link_imports( spec
);
1528 /* create a new asm temp file */
1529 static void new_output_as_file(void)
1533 if (output_file
) fclose( output_file
);
1534 name
= open_temp_output_file( ".s" );
1535 strarray_add( &as_files
, name
);
1538 /* assemble all the asm files */
1539 static void assemble_files( const char *prefix
)
1543 if (output_file
) fclose( output_file
);
1546 for (i
= 0; i
< as_files
.count
; i
++)
1548 char *obj
= get_temp_file_name( prefix
, ".o" );
1549 assemble_file( as_files
.str
[i
], obj
);
1550 as_files
.str
[i
] = obj
;
1554 /* build a library from the current asm files and any additional object files in argv */
1555 static void build_library( const char *output_name
, struct strarray files
, int create
)
1557 struct strarray args
;
1559 if (!create
|| target
.platform
!= PLATFORM_WINDOWS
)
1561 args
= find_tool( "ar", NULL
);
1562 strarray_add( &args
, create
? "rc" : "r" );
1563 strarray_add( &args
, output_name
);
1567 args
= find_link_tool();
1568 strarray_add( &args
, "/lib" );
1569 strarray_add( &args
, strmake( "-out:%s", output_name
));
1571 strarray_addall( &args
, as_files
);
1572 strarray_addall( &args
, files
);
1573 if (create
) unlink( output_name
);
1576 if (target
.platform
!= PLATFORM_WINDOWS
)
1578 struct strarray ranlib
= find_tool( "ranlib", NULL
);
1579 strarray_add( &ranlib
, output_name
);
1584 /* create a Windows-style import library */
1585 static void build_windows_import_lib( const char *lib_name
, DLLSPEC
*spec
)
1587 struct strarray args
;
1590 def_file
= open_temp_output_file( ".def" );
1591 output_def_file( spec
, 1 );
1592 fclose( output_file
);
1594 args
= find_tool( "dlltool", NULL
);
1595 strarray_add( &args
, "-k" );
1596 strarray_add( &args
, strendswith( lib_name
, ".delay.a" ) ? "-y" : "-l" );
1597 strarray_add( &args
, lib_name
);
1598 strarray_add( &args
, "-d" );
1599 strarray_add( &args
, def_file
);
1604 strarray_add( &args
, "-m" );
1605 strarray_add( &args
, "i386" );
1606 strarray_add( &args
, "--as-flags=--32" );
1609 strarray_add( &args
, "-m" );
1610 strarray_add( &args
, "i386:x86-64" );
1611 strarray_add( &args
, "--as-flags=--64" );
1614 strarray_add( &args
, "-m" );
1615 strarray_add( &args
, "arm" );
1618 strarray_add( &args
, "-m" );
1619 strarray_add( &args
, "arm64" );
1628 /* create a Unix-style import library */
1629 static void build_unix_import_lib( DLLSPEC
*spec
)
1632 const char *name
, *prefix
;
1633 char *dll_name
= encode_dll_name( spec
->file_name
);
1637 for (i
= total
= 0; i
< spec
->nb_entry_points
; i
++)
1639 const ORDDEF
*odp
= &spec
->entry_points
[i
];
1641 if (odp
->name
) name
= odp
->name
;
1642 else if (odp
->export_name
) name
= odp
->export_name
;
1645 if (odp
->flags
& FLAG_PRIVATE
) continue;
1648 /* C++ mangled names cannot be imported */
1649 if (strpbrk( name
, "?@" )) continue;
1656 prefix
= (!odp
->name
|| (odp
->flags
& FLAG_ORDINAL
)) ? import_ord_prefix
: import_func_prefix
;
1657 new_output_as_file();
1658 output( "\t.text\n" );
1659 output( "\n\t.align %d\n", get_alignment( get_ptr_size() ));
1660 output( "\t%s\n", func_declaration( name
) );
1661 output( "%s\n", asm_globl( name
) );
1662 output( "\t%s %s%s$%u$%s\n", get_asm_ptr_keyword(),
1663 asm_name( prefix
), dll_name
, odp
->ordinal
, name
);
1664 output_function_size( name
);
1665 output_gnu_stack_note();
1672 if (!total
) warning( "%s: Import library doesn't export anything\n", spec
->file_name
);
1674 if (!as_files
.count
) /* create a dummy file to avoid empty import libraries */
1676 new_output_as_file();
1677 output( "\t.text\n" );
1680 assemble_files( spec
->file_name
);
1684 /* output an import library for a Win32 module and additional object files */
1685 void output_static_lib( DLLSPEC
*spec
, struct strarray files
)
1689 if (spec
) build_windows_import_lib( output_file_name
, spec
);
1690 if (files
.count
|| !spec
) build_library( output_file_name
, files
, !spec
);
1694 if (spec
) build_unix_import_lib( spec
);
1695 build_library( output_file_name
, files
, 1 );