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.
-- v3: 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. makedep: Pass DLLFLAGS to winebuild --implib invocations. 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 supported to keep support for MSVC-like import libs, as generated by LLVM dlltool. --- 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 | 179 ++++++++++++++++++++++++++++++++++++++- tools/winebuild/utils.c | 2 +- 3 files changed, 179 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..ce9aabc2293 100644 --- a/tools/winebuild/import.c +++ b/tools/winebuild/import.c @@ -1630,8 +1630,183 @@ 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, *delay_load, *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] = '_'; + + delay_load = strmake( "__wine_delay_load_%s", dll_name ); + 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( "\n\t.align 4\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( "\n\t.align 4\n" ); + output( ".L__wine_import_names:\n" ); /* OriginalFirstThunk head */ + + output( "\n\t.section ".idata$5"\n" ); + output( "\n\t.align 4\n" ); + output( ".L__wine_import_addrs:\n" ); /* FirstThunk head */ + + /* reference name symbol from tail object */ + output( "\n\t.globl %s\n", asm_name( import_name ) ); + + /* _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$7"\n" ); + output( "\n\t.align 4\n" ); + output( "%s\n", asm_globl( import_name ) ); + output( "\t%s "%s"\n", get_asm_string_keyword(), spec->file_name ); + output( "\n\t.section ".idata$4"\n" ); + output( "\n\t.align 4\n" ); + output( "\t%s 0\n", get_asm_ptr_keyword() ); /* OriginalFirstThunk tail */ + output( "\n\t.section ".idata$5"\n" ); + output( "\n\t.align 4\n" ); + output( "\t%s 0\n", get_asm_ptr_keyword() ); /* FirstThunk tail */ + + /* _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( "\n\t.align %d\n", get_alignment( get_ptr_size() ) ); + output( "%s\n", asm_globl( 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; + } + + /* reference head object to always pull its sections */ + output( "\n\t.section ".idata$7"\n" ); + output( "\n\t.align 4\n" ); + output_rva( "%s", asm_name( import_desc ) ); + + output( "\n\t.section ".idata$4"\n" ); + output( "\n\t.align 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( "\n\t.align 4\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( "\n\t.align 2\n" ); + output( "\t.L__wine_import_name:\n" ); + output( "\t.short %d\n", odp->ordinal ); + output( "\t%s "%s"\n", get_asm_string_keyword(), name ); + } + + 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( delay_load ); + 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/makedep.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/tools/makedep.c b/tools/makedep.c index a042621cec7..5b06c8c2c26 100644 --- a/tools/makedep.c +++ b/tools/makedep.c @@ -3410,6 +3410,7 @@ static void output_import_lib( struct makefile *make, unsigned int arch ) output_filename( "--export" ); output_filename( spec_file ); output_filenames_obj_dir( make, make->implib_files[arch] ); + if (arch) output_filenames( dll_flags ); output( "\n" );
if (!arch && is_native_arch_disabled( make )) return;
From: Rémi Bernon rbernon@codeweavers.com
--- tools/winebuild/import.c | 174 ++++++++++++++++++++++++++++++++++----- 1 file changed, 154 insertions(+), 20 deletions(-)
diff --git a/tools/winebuild/import.c b/tools/winebuild/import.c index ce9aabc2293..450496ab037 100644 --- a/tools/winebuild/import.c +++ b/tools/winebuild/import.c @@ -1635,13 +1635,6 @@ static void build_windows_import_lib( const char *lib_name, DLLSPEC *spec, struc 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] = '_'; @@ -1652,22 +1645,132 @@ static void build_windows_import_lib( const char *lib_name, DLLSPEC *spec, struc
new_output_as_file();
- output( "\n\t.section ".idata$2"\n" ); - output( "\n\t.align 4\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( "\t.text\n" ); + output( "\n\t.align %d\n", get_alignment( get_ptr_size() )); + output( "%s\n", asm_globl( delay_load ) ); + + 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 $.L__wine_delay_import_desc\n" ); + output( "\tcall ___delayLoadHelper2@8\n" ); + output_cfi( ".cfi_adjust_cfa_offset -4" ); + 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( "\tsub $0x48, %%rsp\n" ); + output_cfi( ".cfi_adjust_cfa_offset 0x48" ); + output_cfi( ".seh_stackalloc 0x48" ); + output_cfi( ".seh_endprologue" ); + output( "\tmov %%rcx, 0x40(%%rsp)\n" ); + output( "\tmov %%rdx, 0x38(%%rsp)\n" ); + output( "\tmov %%r8, 0x30(%%rsp)\n" ); + output( "\tmov %%r9, 0x28(%%rsp)\n" ); + output( "\tmov %%rax, %%rdx\n" ); + output( "\tlea .L__wine_delay_import_desc(%%rip), %%rcx\n" ); + output( "\tcall __delayLoadHelper2\n" ); + output( "\tmov 0x28(%%rsp), %%r9\n" ); + output( "\tmov 0x30(%%rsp), %%r8\n" ); + output( "\tmov 0x38(%%rsp), %%rdx\n" ); + output( "\tmov 0x40(%%rsp), %%rcx\n" ); + output( "\tadd $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 .L__wine_delay_import_desc\n" ); + 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, .L__wine_delay_import_desc\n" ); + output( "\tadd x0, x0, #.L__wine_delay_import_desc\n" ); + 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 ".text$2"\n" ); + output( ".L__wine_delay_import_desc:\n" ); + output( "\t.long 1\n" ); /* DllAttributes */ + output_rva( "%s\n", asm_name( import_name ) ); /* DllNameRVA */ + output_rva( ".L__wine_delay_import_handle\n" ); /* ModuleHandleRVA */ + output_rva( ".L__wine_delay_import_IAT\n" ); /* ImportAddressTableRVA */ + output_rva( ".L__wine_delay_import_INT\n" ); /* ImportNameTableRVA */ + output( "\t.long 0\n" ); /* BoundImportAddressTableRVA */ + output( "\t.long 0\n" ); /* UnloadInformationTableRVA */ + output( "\t.long 0\n" ); /* TimeDateStamp */ + + output( "\t.data\n" ); + output( ".L__wine_delay_import_handle:\n" ); + output( "\t%s 0\n", get_asm_ptr_keyword() ); + } + else + { + output( "\n\t.section ".idata$2"\n" ); + output( "\n\t.align 4\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( "\n\t.align 4\n" ); output( ".L__wine_import_names:\n" ); /* OriginalFirstThunk head */ + if (strendswith( lib_name, ".delay.a" )) + { + output( "\t%s 0\n", get_asm_ptr_keyword() ); /* OriginalFirstThunk tail */ + output( ".L__wine_delay_import_INT:\n" ); + }
output( "\n\t.section ".idata$5"\n" ); output( "\n\t.align 4\n" ); output( ".L__wine_import_addrs:\n" ); /* FirstThunk head */ + if (strendswith( lib_name, ".delay.a" )) + { + output( "\t%s 0\n", get_asm_ptr_keyword() ); /* FirstThunk tail */ + output( ".L__wine_delay_import_IAT:\n" ); + }
/* reference name symbol from tail object */ output( "\n\t.globl %s\n", asm_name( import_name ) ); @@ -1731,26 +1834,55 @@ 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( "\t.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( "\t.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( "\t.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( "\t.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; }
- /* reference head object to always pull its sections */ - output( "\n\t.section ".idata$7"\n" ); - output( "\n\t.align 4\n" ); - output_rva( "%s", asm_name( import_desc ) ); + if (!strendswith( lib_name, ".delay.a" )) + { + /* reference head object to always pull its sections */ + output( "\n\t.section ".idata$7"\n" ); + output( "\n\t.align 4\n" ); + output_rva( "%s", asm_name( import_desc ) ); + }
output( "\n\t.section ".idata$4"\n" ); output( "\n\t.align 4\n" ); @@ -1768,7 +1900,9 @@ static void build_windows_import_lib( const char *lib_name, DLLSPEC *spec, struc output( "\n\t.section ".idata$5"\n" ); output( "\n\t.align 4\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" );
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 450496ab037..a3aa091b233 100644 --- a/tools/winebuild/import.c +++ b/tools/winebuild/import.c @@ -1918,7 +1918,7 @@ static void build_windows_import_lib( const char *lib_name, DLLSPEC *spec, struc output( "\n\t.section ".idata$6"\n" ); output( "\n\t.align 2\n" ); output( "\t.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 | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/tools/winebuild/import.c b/tools/winebuild/import.c index a3aa091b233..3871861d7c2 100644 --- a/tools/winebuild/import.c +++ b/tools/winebuild/import.c @@ -1727,7 +1727,7 @@ static void build_windows_import_lib( const char *lib_name, DLLSPEC *spec, struc output_function_size( delay_load ); output_gnu_stack_note();
- output( "\n\t.section ".text$2"\n" ); + output( "\t.data\n" ); output( ".L__wine_delay_import_desc:\n" ); output( "\t.long 1\n" ); /* DllAttributes */ output_rva( "%s\n", asm_name( import_name ) ); /* DllNameRVA */ @@ -1738,7 +1738,6 @@ static void build_windows_import_lib( const char *lib_name, DLLSPEC *spec, struc output( "\t.long 0\n" ); /* UnloadInformationTableRVA */ output( "\t.long 0\n" ); /* TimeDateStamp */
- output( "\t.data\n" ); output( ".L__wine_delay_import_handle:\n" ); output( "\t%s 0\n", get_asm_ptr_keyword() ); }
I'm not completely sure what is best, but I added an explicit `--without-dlltool` flag to `winebuild`, so that it keeps its current behavior unless explicitly requested to avoid dlltool. Wine build does that but maybe we do not want to make it the default yet?
If it's fine to make it the default already I can reverse the flag to a `--force-dlltool` like I initially intended, used when LLVM or MSVC-like dlltool is available, until we are able and willing to replace them too.
On Fri Nov 4 10:31:04 2022 +0000, Rémi Bernon wrote:
I'm not completely sure what is best, but I added an explicit `--without-dlltool` flag to `winebuild`, so that it keeps its current behavior unless explicitly requested to avoid dlltool. Wine build does that but maybe we do not want to make it the default yet? If it's fine to make it the default already I can reverse the flag to a `--force-dlltool` like I initially intended, used when LLVM or MSVC-like dlltool is available, until we are able and willing to replace them too.
Just saw that the first commit message details are now outdated, well... let's see how this goes and I'll then fix it.
Alexandre Julliard (@julliard) commented about tools/makedep.c:
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" ); output_filename( spec_file ); output_filenames_obj_dir( make, make->implib_files[arch] );
- if (arch) output_filenames( dll_flags ); output( "\n" );
This looks wrong, DLLFLAGS is for the native compiler.
If the goal is to check for CFI support it should be tested on the PE cross-assembler, or otherwise assume that it's always available.
On Fri Nov 4 17:54:37 2022 +0000, Alexandre Julliard wrote:
This looks wrong, DLLFLAGS is for the native compiler. If the goal is to check for CFI support it should be tested on the PE cross-assembler, or otherwise assume that it's always available.
I must admit that I'm a bit lost which one is which between `DLLFLAGS`, `UNIXDLLFLAGS` and `LDDLLFLAGS`. So if it's fine to tie winebuild `unwind_tables` to `is_pe` unless forced otherwise I'll do that.
I must admit that I'm a bit lost which one is which between `DLLFLAGS`, `UNIXDLLFLAGS` and `LDDLLFLAGS`. So if it's fine to tie winebuild `unwind_tables` to `is_pe` unless forced otherwise I'll do that.
Basically `DLLFLAGS` is for compiling and `LDDLLFLAGS` for linking. `UNIXDLLFLAGS` is a hack to bypass the `-fno-PIC` flag we use on i386, I'm hoping to get rid of it eventually.