From: Rémi Bernon rbernon@codeweavers.com
--- tools/winebuild/import.c | 301 +++++++++++++++++++++++++++++++++++---- 1 file changed, 277 insertions(+), 24 deletions(-)
diff --git a/tools/winebuild/import.c b/tools/winebuild/import.c index 3f3775dc3bd..d4338cc3939 100644 --- a/tools/winebuild/import.c +++ b/tools/winebuild/import.c @@ -1584,45 +1584,298 @@ static void build_library( const char *output_name, struct strarray files, int c /* create a Windows-style import library */ static void build_windows_import_lib( const char *lib_name, DLLSPEC *spec ) { - struct strarray args; - char *def_file; + char *dll_name = encode_dll_name( spec->file_name ), *delay_load, *import_desc, *import_name; + struct strarray objs = empty_strarray; + int i, total, by_name; + const char *name;
- def_file = open_temp_output_file( ".def" ); - output_def_file( spec, 1 ); - fclose( output_file ); + /* make sure assemble_files doesn't strip suffixes */ + for (i = 0; i < strlen( dll_name ); ++i) if (dll_name[i] == '.') dll_name[i] = '_';
- args = find_tool( "dlltool", NULL ); - strarray_add( &args, "-k" ); - strarray_add( &args, strendswith( lib_name, ".delay.a" ) ? "-y" : "-l" ); - strarray_add( &args, lib_name ); - strarray_add( &args, "-d" ); - strarray_add( &args, def_file ); + 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 );
- switch (target.cpu) + new_output_as_file(); + + 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: - strarray_add( &args, "-m" ); - strarray_add( &args, "i386" ); - strarray_add( &args, "--as-flags=--32" ); + 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: - strarray_add( &args, "-m" ); - strarray_add( &args, "i386:x86-64" ); - strarray_add( &args, "--as-flags=--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: - strarray_add( &args, "-m" ); - strarray_add( &args, "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: - strarray_add( &args, "-m" ); - strarray_add( &args, "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() ); + } + + output( "\n\t.section ".idata$2","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","2"\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","2"\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" ); + } + + /* _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","2"\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","2"\n" ); + output( "\t%s 0\n", get_asm_ptr_keyword() ); /* OriginalFirstThunk tail */ + output( "\n\t.section ".idata$5","2"\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 ) ); + 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","2"\n" ); + output_rva( "%s", asm_name( import_desc ) ); + + output( "\n\t.section ".idata$4","2"\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","2"\n" ); + output( "%s\n", asm_globl( imp_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" ); + } + 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","1"\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; + } }
- spawn( args ); + /* _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 ); }
/* create a Unix-style import library */ @@ -1687,7 +1940,7 @@ void output_static_lib( DLLSPEC *spec, struct strarray files ) if (is_pe()) { if (spec) build_windows_import_lib( output_file_name, spec ); - if (files.count || !spec) build_library( output_file_name, files, !spec ); + build_library( output_file_name, files, 1 ); } else {