This is slightly different from dlltool but I think it should be compatible. The transition is done by first replacing dlltool with its bugs, and fixing them in separate changes.
I based the ARM / AARCH64 implementation on the existing code around, but I have no idea if it is correct, and dlltool also doesn't include any delay load implementation for ARM.
-- v6: winebuild: Put the delay import descriptor in data section. winebuild: Fix import hint value for symbols imported by name. winebuild: Implement delay import lib generation without dlltool. winebuild: Enable unwind tables by default in PE files. winebuild: Implement import lib generation without dlltool. winebuild: Introduce a new --without-dlltool winebuild flag.
From: Rémi Bernon rbernon@codeweavers.com
Set it only when -Wl,--delay-load linker flag is not supported to keep using dlltool in LLVM builds, for MSVC-like import libs. --- tools/makedep.c | 1 + tools/winebuild/build.h | 1 + tools/winebuild/import.c | 12 ++++++++++-- tools/winebuild/main.c | 9 ++++++++- tools/winebuild/winebuild.man.in | 3 +++ 5 files changed, 23 insertions(+), 3 deletions(-)
diff --git a/tools/makedep.c b/tools/makedep.c index ca1efed4533..a042621cec7 100644 --- a/tools/makedep.c +++ b/tools/makedep.c @@ -3404,6 +3404,7 @@ static void output_import_lib( struct makefile *make, unsigned int arch ) output_filenames_obj_dir( make, make->implib_files[arch] ); output( "\n" ); output( "\t%s%s -w --implib -o $@", cmd_prefix( "BUILD" ), tools_path( make, "winebuild" ) ); + if (!delay_load_flags[arch]) output_filename( "--without-dlltool" ); output_filenames( target_flags[arch] ); if (make->is_win16) output_filename( "-m16" ); output_filename( "--export" ); diff --git a/tools/winebuild/build.h b/tools/winebuild/build.h index 7ce502143e3..accfa9a47dd 100644 --- a/tools/winebuild/build.h +++ b/tools/winebuild/build.h @@ -357,6 +357,7 @@ extern int verbose; extern int link_ext_symbols; extern int force_pointer_size; extern int unwind_tables; +extern int use_dlltool; extern int use_msvcrt; extern int unix_lib; extern int safe_seh; diff --git a/tools/winebuild/import.c b/tools/winebuild/import.c index a2ada71ae36..8d05b91ec9b 100644 --- a/tools/winebuild/import.c +++ b/tools/winebuild/import.c @@ -1581,8 +1581,8 @@ void output_static_lib( const char *output_name, struct strarray files, int crea } }
-/* create a Windows-style import library */ -static void build_windows_import_lib( const char *lib_name, DLLSPEC *spec, struct strarray files ) +/* create a Windows-style import library using dlltool */ +static void build_dlltool_import_lib( const char *lib_name, DLLSPEC *spec, struct strarray files ) { struct strarray args; char *def_file; @@ -1627,6 +1627,13 @@ static void build_windows_import_lib( const char *lib_name, DLLSPEC *spec, struc if (files.count) output_static_lib( output_file_name, files, 0 ); }
+/* create a Windows-style import library */ +static void build_windows_import_lib( const char *lib_name, DLLSPEC *spec, struct strarray files ) +{ + if (verbose) fprintf( stderr, "Not implemented, falling back to dlltool.\n" ); + build_dlltool_import_lib( output_file_name, spec, files ); +} + /* create a Unix-style import library */ static void build_unix_import_lib( DLLSPEC *spec, struct strarray files ) { @@ -1689,5 +1696,6 @@ static void build_unix_import_lib( DLLSPEC *spec, struct strarray files ) void output_import_lib( DLLSPEC *spec, struct strarray files ) { if (!is_pe()) build_unix_import_lib( spec, files ); + else if (use_dlltool) build_dlltool_import_lib( output_file_name, spec, files ); else build_windows_import_lib( output_file_name, spec, files ); } diff --git a/tools/winebuild/main.c b/tools/winebuild/main.c index cbe1e4669c1..01ceba9e516 100644 --- a/tools/winebuild/main.c +++ b/tools/winebuild/main.c @@ -42,6 +42,7 @@ int verbose = 0; int link_ext_symbols = 0; int force_pointer_size = 0; int unwind_tables = 0; +int use_dlltool = 1; int use_msvcrt = 0; int unix_lib = 0; int safe_seh = 0; @@ -233,6 +234,7 @@ static const char usage_str[] = " -v, --verbose Display the programs invoked\n" " --version Print the version and exit\n" " -w, --warnings Turn on warnings\n" +" --without-dlltool Generate import library without using dlltool\n" "\nMode options:\n" " --dll Build a library from a .spec file and object files\n" " --def Build a .def file from a .spec file\n" @@ -268,7 +270,8 @@ enum long_options_values LONG_OPT_STATICLIB, LONG_OPT_SUBSYSTEM, LONG_OPT_SYSCALL_TABLE, - LONG_OPT_VERSION + LONG_OPT_VERSION, + LONG_OPT_WITHOUT_DLLTOOL, };
static const char short_options[] = "B:C:D:E:F:H:I:K:L:M:N:b:d:e:f:hkl:m:o:r:u:vw"; @@ -300,6 +303,7 @@ static const struct long_option long_options[] = { "subsystem", 1, LONG_OPT_SUBSYSTEM }, { "syscall-table", 1, LONG_OPT_SYSCALL_TABLE }, { "version", 0, LONG_OPT_VERSION }, + { "without-dlltool", 0, LONG_OPT_WITHOUT_DLLTOOL }, /* aliases for short options */ { "target", 1, 'b' }, { "delay-lib", 1, 'd' }, @@ -531,6 +535,9 @@ static void option_callback( int optc, char *optarg ) case LONG_OPT_VERSION: printf( "winebuild version " PACKAGE_VERSION "\n" ); exit(0); + case LONG_OPT_WITHOUT_DLLTOOL: + use_dlltool = 0; + break; case '?': fprintf( stderr, "winebuild: %s\n\n", optarg ); usage(1); diff --git a/tools/winebuild/winebuild.man.in b/tools/winebuild/winebuild.man.in index 2637b5beb5f..7f93a5befdc 100644 --- a/tools/winebuild/winebuild.man.in +++ b/tools/winebuild/winebuild.man.in @@ -279,6 +279,9 @@ Display the program version and exit. .TP .B -w, --warnings Turn on warnings. +.TP +.B --without-dlltool +Generate import library without using dlltool. .SH "SPEC FILE SYNTAX" .SS "General syntax" A spec file should contain a list of ordinal declarations. The general
From: Rémi Bernon rbernon@codeweavers.com
--- tools/winebuild/build.h | 1 + tools/winebuild/import.c | 165 ++++++++++++++++++++++++++++++++++++++- tools/winebuild/utils.c | 2 +- 3 files changed, 165 insertions(+), 3 deletions(-)
diff --git a/tools/winebuild/build.h b/tools/winebuild/build.h index accfa9a47dd..a7ef23b199e 100644 --- a/tools/winebuild/build.h +++ b/tools/winebuild/build.h @@ -273,6 +273,7 @@ extern DLLSPEC *alloc_dll_spec(void); extern void free_dll_spec( DLLSPEC *spec ); extern char *make_c_identifier( const char *str ); extern const char *get_stub_name( const ORDDEF *odp, const DLLSPEC *spec ); +extern const char *get_abi_name( const ORDDEF *odp, const char *name ); extern const char *get_link_name( const ORDDEF *odp ); extern int sort_func_list( ORDDEF **list, int count, int (*compare)(const void *, const void *) ); extern unsigned int get_alignment(unsigned int align); diff --git a/tools/winebuild/import.c b/tools/winebuild/import.c index 8d05b91ec9b..35165f2b51e 100644 --- a/tools/winebuild/import.c +++ b/tools/winebuild/import.c @@ -1630,8 +1630,169 @@ static void build_dlltool_import_lib( const char *lib_name, DLLSPEC *spec, struc /* create a Windows-style import library */ static void build_windows_import_lib( const char *lib_name, DLLSPEC *spec, struct strarray files ) { - if (verbose) fprintf( stderr, "Not implemented, falling back to dlltool.\n" ); - build_dlltool_import_lib( output_file_name, spec, files ); + char *dll_name, *import_desc, *import_name; + struct strarray objs = empty_strarray; + int i, total, by_name; + const char *name; + + if (strendswith( lib_name, ".delay.a" )) + { + if (verbose) fprintf( stderr, "Not implemented, falling back to dlltool.\n" ); + build_dlltool_import_lib( output_file_name, spec, files ); + return; + } + + /* make sure assemble_files doesn't strip suffixes */ + dll_name = encode_dll_name( spec->file_name ); + for (i = 0; i < strlen( dll_name ); ++i) if (dll_name[i] == '.') dll_name[i] = '_'; + + import_desc = strmake( "__wine_import_%s_desc", dll_name ); + import_name = strmake( "__wine_import_%s_name", dll_name ); + + new_output_as_file(); + + output( "\n\t.section ".idata$2"\n" ); + output( "%s\n", asm_globl( import_desc ) ); + output_rva( ".L__wine_import_names" ); /* OriginalFirstThunk */ + output( "\t.long 0\n" ); /* TimeDateStamp */ + output( "\t.long 0\n" ); /* ForwarderChain */ + output_rva( "%s", asm_name( import_name ) ); /* Name */ + output_rva( ".L__wine_import_addrs" ); /* FirstThunk */ + + output( "\n\t.section ".idata$4"\n" ); + output( ".L__wine_import_names:\n" ); /* OriginalFirstThunk head */ + + output( "\n\t.section ".idata$5"\n" ); + output( ".L__wine_import_addrs:\n" ); /* FirstThunk head */ + + /* _head suffix to keep this object sections first */ + assemble_files( strmake( "%s_head", dll_name ) ); + strarray_addall( &objs, as_files ); + as_files = empty_strarray; + + new_output_as_file(); + + output( "\n\t.section ".idata$4"\n" ); + output( "\t%s 0\n", get_asm_ptr_keyword() ); /* OriginalFirstThunk tail */ + output( "\n\t.section ".idata$5"\n" ); + output( "\t%s 0\n", get_asm_ptr_keyword() ); /* FirstThunk tail */ + output( "\n\t.section ".idata$7"\n" ); + output( "%s\n", asm_globl( import_name ) ); + output( "\t%s "%s"\n", get_asm_string_keyword(), spec->file_name ); + + /* _tail suffix to keep this object sections last */ + assemble_files( strmake( "%s_tail", dll_name ) ); + strarray_addall( &objs, as_files ); + as_files = empty_strarray; + + for (i = total = 0; i < spec->nb_entry_points; i++) + { + const ORDDEF *odp = &spec->entry_points[i]; + const char *abi_name; + char *imp_name; + + if (odp->name) name = odp->name; + else if (odp->export_name) name = odp->export_name; + else continue; + + if (odp->flags & FLAG_PRIVATE) continue; + total++; + + /* C++ mangled names cannot be imported */ + if (strpbrk( name, "?@" )) continue; + + switch (odp->type) + { + case TYPE_VARARGS: + case TYPE_CDECL: + case TYPE_STDCALL: + by_name = odp->name && !(odp->flags & FLAG_ORDINAL); + abi_name = get_abi_name( odp, name ); + imp_name = strmake( "%s_imp_%s", target.cpu != CPU_i386 ? "_" : "", + asm_name( abi_name ) ); + + new_output_as_file(); + + output( "\n\t.text\n" ); + output( "\t.align %d\n", get_alignment( get_ptr_size() ) ); + output( "%s\n", asm_globl( abi_name ) ); + output( "\t%s\n", func_declaration( abi_name ) ); + + switch (target.cpu) + { + case CPU_i386: + output( "\tjmp *%s\n", asm_name( imp_name ) ); + break; + case CPU_x86_64: + output( "\tjmp *%s(%%rip)\n", asm_name( imp_name ) ); + break; + case CPU_ARM: + output( "\tldr IP, 1f\n" ); + output( "\tldr PC, [IP]\n" ); + output( "1:\t.long %s\n", asm_name( imp_name ) ); + break; + case CPU_ARM64: + output( "\tadrp x16, %s\n", arm64_page( asm_name( imp_name ) ) ); + output( "\tadd x16, x16, #%s\n", arm64_pageoff( asm_name( imp_name ) ) ); + output( "\tbr x16\n" ); + break; + } + + output( "\n\t.section ".idata$4"\n" ); + if (by_name) + { + output_rva( ".L__wine_import_name" ); + if (get_ptr_size() == 8) output( "\t.long 0\n" ); + } + else + { + if (get_ptr_size() == 4) output( "\t.long 0x8000%04x\n", odp->ordinal ); + else output( "\t.quad 0x800000000000%04x\n", odp->ordinal ); + } + + output( "\n\t.section ".idata$5"\n" ); + output( "%s\n", asm_globl( imp_name ) ); + if (by_name) + { + output_rva( ".L__wine_import_name" ); + if (get_ptr_size() == 8) output( "\t.long 0\n" ); + } + else + { + if (get_ptr_size() == 4) output( "\t.long 0x8000%04x\n", odp->ordinal ); + else output( "\t.quad 0x800000000000%04x\n", odp->ordinal ); + } + + if (by_name) + { + output( "\n\t.section ".idata$6"\n" ); + output( ".L__wine_import_name:\n" ); + output( "\t.short %d\n", odp->ordinal ); + output( "\t%s "%s"\n", get_asm_string_keyword(), name ); + } + + /* reference head object to always pull its sections */ + output( "\n\t.section ".idata$7"\n" ); + output_rva( "%s", asm_name( import_desc ) ); + + free( imp_name ); + break; + + default: + break; + } + } + + /* _syms suffix to keep these objects sections in between _head and _tail */ + assemble_files( strmake( "%s_syms", dll_name ) ); + strarray_addall( &objs, as_files ); + as_files = objs; + + free( import_desc ); + free( import_name ); + free( dll_name ); + + output_static_lib( output_file_name, files, 1 ); }
/* create a Unix-style import library */ diff --git a/tools/winebuild/utils.c b/tools/winebuild/utils.c index 16d9c28d918..ad2166b59a7 100644 --- a/tools/winebuild/utils.c +++ b/tools/winebuild/utils.c @@ -728,7 +728,7 @@ const char *get_stub_name( const ORDDEF *odp, const DLLSPEC *spec ) }
/* return the stdcall-decorated name for an entry point */ -static const char *get_abi_name( const ORDDEF *odp, const char *name ) +const char *get_abi_name( const ORDDEF *odp, const char *name ) { static char *buffer; char *ret;
From: Rémi Bernon rbernon@codeweavers.com
Making sure it also emits .cfi and .seh directives and generates unwind tables for the delay import thunks. --- tools/winebuild/main.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/tools/winebuild/main.c b/tools/winebuild/main.c index 01ceba9e516..77339b2b4e7 100644 --- a/tools/winebuild/main.c +++ b/tools/winebuild/main.c @@ -176,6 +176,7 @@ static void set_target( const char *name )
if (!parse_target( name, &target )) fatal_error( "Unrecognized target '%s'\n", name ); if (target.cpu == CPU_ARM && is_pe()) thumb_mode = 1; + if (is_pe()) unwind_tables = 1; }
/* cleanup on program exit */ @@ -623,6 +624,7 @@ int main(int argc, char **argv)
target = init_argv0_target( argv[0] ); if (target.platform == PLATFORM_CYGWIN) target.platform = PLATFORM_MINGW; + if (is_pe()) unwind_tables = 1;
files = parse_options( argc, argv, short_options, long_options, 0, option_callback );
From: Rémi Bernon rbernon@codeweavers.com
--- tools/winebuild/import.c | 175 ++++++++++++++++++++++++++++++++++----- 1 file changed, 155 insertions(+), 20 deletions(-)
diff --git a/tools/winebuild/import.c b/tools/winebuild/import.c index 35165f2b51e..6a2dffac9bc 100644 --- a/tools/winebuild/import.c +++ b/tools/winebuild/import.c @@ -1630,40 +1630,146 @@ static void build_dlltool_import_lib( const char *lib_name, DLLSPEC *spec, struc /* create a Windows-style import library */ static void build_windows_import_lib( const char *lib_name, DLLSPEC *spec, struct strarray files ) { - char *dll_name, *import_desc, *import_name; + char *dll_name, *import_desc, *import_name, *delay_load; struct strarray objs = empty_strarray; int i, total, by_name; const char *name;
- if (strendswith( lib_name, ".delay.a" )) - { - if (verbose) fprintf( stderr, "Not implemented, falling back to dlltool.\n" ); - build_dlltool_import_lib( output_file_name, spec, files ); - return; - } - /* make sure assemble_files doesn't strip suffixes */ dll_name = encode_dll_name( spec->file_name ); for (i = 0; i < strlen( dll_name ); ++i) if (dll_name[i] == '.') dll_name[i] = '_';
import_desc = strmake( "__wine_import_%s_desc", dll_name ); import_name = strmake( "__wine_import_%s_name", dll_name ); + delay_load = strmake( "__wine_delay_load_%s", dll_name );
new_output_as_file();
- output( "\n\t.section ".idata$2"\n" ); - output( "%s\n", asm_globl( import_desc ) ); - output_rva( ".L__wine_import_names" ); /* OriginalFirstThunk */ - output( "\t.long 0\n" ); /* TimeDateStamp */ - output( "\t.long 0\n" ); /* ForwarderChain */ - output_rva( "%s", asm_name( import_name ) ); /* Name */ - output_rva( ".L__wine_import_addrs" ); /* FirstThunk */ + if (strendswith( lib_name, ".delay.a" )) + { + output( "\n\t.text\n" ); + output( "\t.align %d\n", get_alignment( get_ptr_size() )); + output( "%s\n", asm_globl( delay_load ) ); + output( "\t%s\n", func_declaration( delay_load ) );
- output( "\n\t.section ".idata$4"\n" ); - output( ".L__wine_import_names:\n" ); /* OriginalFirstThunk head */ + output_cfi( ".cfi_startproc" ); + switch (target.cpu) + { + case CPU_i386: + output( "\tpushl %%ecx\n" ); + output_cfi( ".cfi_adjust_cfa_offset 4" ); + output( "\tpushl %%edx\n" ); + output_cfi( ".cfi_adjust_cfa_offset 4" ); + output( "\tpushl %%eax\n" ); + output_cfi( ".cfi_adjust_cfa_offset 4" ); + output( "\tpushl $%s\n", asm_name( import_desc ) ); + output( "\tcalll ___delayLoadHelper2@8\n" ); + output_cfi( ".cfi_adjust_cfa_offset -8" ); + output( "\tpopl %%edx\n" ); + output_cfi( ".cfi_adjust_cfa_offset -4" ); + output( "\tpopl %%ecx\n" ); + output_cfi( ".cfi_adjust_cfa_offset -4" ); + output( "\tjmp *%%eax\n" ); + break; + case CPU_x86_64: + output_cfi( ".seh_proc %s", asm_name( delay_load ) ); + output( "\tsubq $0x48, %%rsp\n" ); + output_cfi( ".cfi_adjust_cfa_offset 0x48" ); + output_cfi( ".seh_stackalloc 0x48" ); + output_cfi( ".seh_endprologue" ); + output( "\tmovq %%rcx, 0x40(%%rsp)\n" ); + output( "\tmovq %%rdx, 0x38(%%rsp)\n" ); + output( "\tmovq %%r8, 0x30(%%rsp)\n" ); + output( "\tmovq %%r9, 0x28(%%rsp)\n" ); + output( "\tmovq %%rax, %%rdx\n" ); + output( "\tleaq %s(%%rip), %%rcx\n", asm_name( import_desc ) ); + output( "\tcall __delayLoadHelper2\n" ); + output( "\tmovq 0x28(%%rsp), %%r9\n" ); + output( "\tmovq 0x30(%%rsp), %%r8\n" ); + output( "\tmovq 0x38(%%rsp), %%rdx\n" ); + output( "\tmovq 0x40(%%rsp), %%rcx\n" ); + output( "\taddq $0x48, %%rsp\n" ); + output_cfi( ".cfi_adjust_cfa_offset -0x48" ); + output( "\tjmp *%%rax\n" ); + output_cfi( ".seh_endproc" ); + break; + case CPU_ARM: + output( "\tpush {r0-r3, FP, LR}\n" ); + output( "\tmov r1, IP\n" ); + output( "\tldr r0, 1f\n" ); + output( "\tldr r0, [r0]\n" ); + output( "\tbl __delayLoadHelper2\n" ); + output( "\tmov IP, r0\n" ); + output( "\tpop {r0-r3, FP, LR}\n" ); + output( "\tbx IP\n" ); + output( "1:\t.long %s\n", asm_name( import_desc ) ); + break; + case CPU_ARM64: + output( "\tstp x29, x30, [sp, #-80]!\n" ); + output( "\tmov x29, sp\n" ); + output( "\tstp x0, x1, [sp, #16]\n" ); + output( "\tstp x2, x3, [sp, #32]\n" ); + output( "\tstp x4, x5, [sp, #48]\n" ); + output( "\tstp x6, x7, [sp, #64]\n" ); + output( "\tmov x1, x16\n" ); + output( "\tadrp x0, %s\n", asm_name( import_desc ) ); + output( "\tadd x0, x0, #%s\n", asm_name( import_desc ) ); + output( "\tbl __delayLoadHelper2\n" ); + output( "\tmov x16, x0\n" ); + output( "\tldp x0, x1, [sp, #16]\n" ); + output( "\tldp x2, x3, [sp, #32]\n" ); + output( "\tldp x4, x5, [sp, #48]\n" ); + output( "\tldp x6, x7, [sp, #64]\n" ); + output( "\tldp x29, x30, [sp], #80\n" ); + output( "\tbr x16\n" ); + break; + } + output_cfi( ".cfi_endproc" ); + output_function_size( delay_load ); + output_gnu_stack_note();
- output( "\n\t.section ".idata$5"\n" ); - output( ".L__wine_import_addrs:\n" ); /* FirstThunk head */ + output( "\n\t.data\n" ); + output( ".L__wine_delay_import_handle:\n" ); + output( "\t%s 0\n", get_asm_ptr_keyword() ); + + output( "\n\t.section ".text$2"\n" ); + output( "%s\n", asm_globl( import_desc ) ); + output( "\t.long 1\n" ); /* DllAttributes */ + output_rva( "%s", asm_name( import_name ) ); /* DllNameRVA */ + output_rva( ".L__wine_delay_import_handle" ); /* ModuleHandleRVA */ + output_rva( ".L__wine_import_addrs" ); /* ImportAddressTableRVA */ + output_rva( ".L__wine_import_names" ); /* ImportNameTableRVA */ + output( "\t.long 0\n" ); /* BoundImportAddressTableRVA */ + output( "\t.long 0\n" ); /* UnloadInformationTableRVA */ + output( "\t.long 0\n" ); /* TimeDateStamp */ + + output( "\n\t.section ".idata$5"\n" ); + output( "\t%s 0\n", get_asm_ptr_keyword() ); /* FirstThunk tail */ + output( ".L__wine_import_addrs:\n" ); + + output( "\n\t.section ".idata$4"\n" ); + output( "\t%s 0\n", get_asm_ptr_keyword() ); /* OriginalFirstThunk tail */ + output( ".L__wine_import_names:\n" ); + + /* required to avoid internal linker errors with some binutils versions */ + output( "\n\t.section ".idata$2"\n" ); + } + else + { + output( "\n\t.section ".idata$2"\n" ); + output( "%s\n", asm_globl( import_desc ) ); + output_rva( ".L__wine_import_names" ); /* OriginalFirstThunk */ + output( "\t.long 0\n" ); /* TimeDateStamp */ + output( "\t.long 0\n" ); /* ForwarderChain */ + output_rva( "%s", asm_name( import_name ) ); /* Name */ + output_rva( ".L__wine_import_addrs" ); /* FirstThunk */ + + output( "\n\t.section ".idata$4"\n" ); + output( ".L__wine_import_names:\n" ); /* OriginalFirstThunk head */ + + output( "\n\t.section ".idata$5"\n" ); + output( ".L__wine_import_addrs:\n" ); /* FirstThunk head */ + }
/* _head suffix to keep this object sections first */ assemble_files( strmake( "%s_head", dll_name ) ); @@ -1722,19 +1828,45 @@ static void build_windows_import_lib( const char *lib_name, DLLSPEC *spec, struc { case CPU_i386: output( "\tjmp *%s\n", asm_name( imp_name ) ); + if (strendswith( lib_name, ".delay.a" )) + { + output( ".L__wine_delay_import:\n" ); + output( "\tmov $%s,%%eax\n", asm_name( imp_name ) ); + output( "\tjmp %s\n", asm_name( delay_load ) ); + } break; case CPU_x86_64: output( "\tjmp *%s(%%rip)\n", asm_name( imp_name ) ); + if (strendswith( lib_name, ".delay.a" )) + { + output( ".L__wine_delay_import:\n" ); + output( "\tlea %s(%%rip),%%rax\n", asm_name( imp_name ) ); + output( "\tjmp %s\n", asm_name( delay_load ) ); + } break; case CPU_ARM: output( "\tldr IP, 1f\n" ); output( "\tldr PC, [IP]\n" ); + if (strendswith( lib_name, ".delay.a" )) + { + output( ".L__wine_delay_import:\n" ); + output( "\tldr IP, 1f\n" ); + output( "\tldr IP, [IP]\n" ); + output( "\tb %s\n", asm_name( delay_load ) ); + } output( "1:\t.long %s\n", asm_name( imp_name ) ); break; case CPU_ARM64: output( "\tadrp x16, %s\n", arm64_page( asm_name( imp_name ) ) ); output( "\tadd x16, x16, #%s\n", arm64_pageoff( asm_name( imp_name ) ) ); output( "\tbr x16\n" ); + if (strendswith( lib_name, ".delay.a" )) + { + output( ".L__wine_delay_import:\n" ); + output( "\tadrp x16, %s\n", arm64_page( asm_name( imp_name ) ) ); + output( "\tadd x16, x16, #%s\n", arm64_pageoff( asm_name( imp_name ) ) ); + output( "\tb %s\n", asm_name( delay_load ) ); + } break; }
@@ -1752,7 +1884,9 @@ static void build_windows_import_lib( const char *lib_name, DLLSPEC *spec, struc
output( "\n\t.section ".idata$5"\n" ); output( "%s\n", asm_globl( imp_name ) ); - if (by_name) + if (strendswith( lib_name, ".delay.a" )) + output( "\t%s .L__wine_delay_import\n", get_asm_ptr_keyword() ); + else if (by_name) { output_rva( ".L__wine_import_name" ); if (get_ptr_size() == 8) output( "\t.long 0\n" ); @@ -1790,6 +1924,7 @@ static void build_windows_import_lib( const char *lib_name, DLLSPEC *spec, struc
free( import_desc ); free( import_name ); + free( delay_load ); free( dll_name );
output_static_lib( output_file_name, files, 1 );
From: Rémi Bernon rbernon@codeweavers.com
This fixes incorrect hint values generated by dlltool: instead of the index in the name table, it used the ordinal value, which almost always ends up in a hint lookup failure and a fallback to binary search. --- tools/winebuild/import.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tools/winebuild/import.c b/tools/winebuild/import.c index 6a2dffac9bc..08139bfd48a 100644 --- a/tools/winebuild/import.c +++ b/tools/winebuild/import.c @@ -1901,7 +1901,7 @@ static void build_windows_import_lib( const char *lib_name, DLLSPEC *spec, struc { output( "\n\t.section ".idata$6"\n" ); output( ".L__wine_import_name:\n" ); - output( "\t.short %d\n", odp->ordinal ); + output( "\t.short %d\n", odp->hint ); output( "\t%s "%s"\n", get_asm_string_keyword(), name ); }
From: Rémi Bernon rbernon@codeweavers.com
This fixes incorrect .text section flags for any module using delay imports. The use of a custom .text$2 section as dlltool is doing causes the section to be flagged as DATA, and ends up with the .text section being writable, which triggers the anti tamper used in Forza Horizon. --- tools/winebuild/import.c | 1 - 1 file changed, 1 deletion(-)
diff --git a/tools/winebuild/import.c b/tools/winebuild/import.c index 08139bfd48a..160220db659 100644 --- a/tools/winebuild/import.c +++ b/tools/winebuild/import.c @@ -1732,7 +1732,6 @@ static void build_windows_import_lib( const char *lib_name, DLLSPEC *spec, struc output( ".L__wine_delay_import_handle:\n" ); output( "\t%s 0\n", get_asm_ptr_keyword() );
- output( "\n\t.section ".text$2"\n" ); output( "%s\n", asm_globl( import_desc ) ); output( "\t.long 1\n" ); /* DllAttributes */ output_rva( "%s", asm_name( import_name ) ); /* DllNameRVA */
In one of the many rebases the delay import function pointer went to the wrong `idata$4` section and not in the `__imp_` symbol which is in `idata$5`, should be fixed now.
Should this have copyright information from dlltool?
On Mon Nov 7 19:09:56 2022 +0000, Zebediah Figura wrote:
Should this have copyright information from dlltool?
I don't mind adding it though I haven't copied code from dlltool and worked mostly by comparing and disassembling the produced archives.
The code is also very similar to the existing delay load implementation for non-mingw builds, which I suspect was likely also inspired from dlltool.
Re-running the pipeline fixed the `quartz:systemclock` failure. I don't see it in the testbot pattern page, but I don't really see how it could be related, and perhaps it's only some very rare flaky test?