Based on mingw-w64.
System modules on Windows have load config available. In fact, all applications using the default MSVC for crt have it. mingw-w64 provides the load config, but it also requires linker to use it and currently only LLD supports it. This MR does the same in winecrt0. We will need it on both ARM64 and ARM64EC targets to support ARM64X (which requires LLD for other reasons anyway).
-- v4: winebuild: Output load config on PE targets.
From: Jacek Caban jacek@codeweavers.com
--- dlls/winecrt0/arm64ec.c | 22 ----------- tools/winebuild/spec32.c | 84 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+), 22 deletions(-)
diff --git a/dlls/winecrt0/arm64ec.c b/dlls/winecrt0/arm64ec.c index 949de0a4e0c..64bb001274a 100644 --- a/dlls/winecrt0/arm64ec.c +++ b/dlls/winecrt0/arm64ec.c @@ -102,26 +102,4 @@ asm( "\t.section .rdata,"dr"\n" "\t.rva __os_arm64x_helper7\n" "\t.rva __os_arm64x_helper8\n" );
-asm( "\t.section .rdata,"dr"\n" - "\t.globl _load_config_used\n" - "\t.balign 8\n" - "_load_config_used:\n" - "\t.word 0x140\n" - "\t.fill 0x54, 1, 0\n" - "\t.xword 0\n" /* FIXME: __security_cookie */ - "\t.fill 0x10, 1, 0\n" - "\t.xword __guard_check_icall_fptr\n" - "\t.xword __guard_dispatch_icall_fptr\n" - "\t.xword __guard_fids_table\n" - "\t.xword __guard_fids_count\n" - "\t.xword __guard_flags\n" - "\t.xword 0\n" - "\t.xword __guard_iat_table\n" - "\t.xword __guard_iat_count\n" - "\t.xword __guard_longjmp_table\n" - "\t.xword __guard_longjmp_count\n" - "\t.xword 0\n" - "\t.xword __chpe_metadata\n" - "\t.fill 0x78, 1, 0\n" ); - #endif /* __arm64ec__ */ diff --git a/tools/winebuild/spec32.c b/tools/winebuild/spec32.c index 7e41f2d5a3d..857985cb292 100644 --- a/tools/winebuild/spec32.c +++ b/tools/winebuild/spec32.c @@ -605,6 +605,89 @@ void output_exports( DLLSPEC *spec ) }
+/******************************************************************* + * output_load_config + * + * Output the load configuration structure. + */ +static void output_load_config(void) +{ + if (!is_pe()) return; + + output( "\n/* load_config */\n\n" ); + output( "\t%s\n", get_asm_rodata_section() ); + output( "\t.globl %s\n", asm_name( "_load_config_used" )); + output( "\t.balign %u\n", get_ptr_size() ); + output( "%s:\n", asm_name( "_load_config_used" )); + output( "\t.long %u\n", get_ptr_size() == 8 ? 0x140 : 0xc0 ); /* Size */ + output( "\t.long 0\n" ); /* TimeDateStamp */ + output( "\t.short 0\n" ); /* MajorVersion */ + output( "\t.short 0\n" ); /* MinorVersion */ + output( "\t.long 0\n" ); /* GlobalFlagsClear */ + output( "\t.long 0\n" ); /* GlobalFlagsSet */ + output( "\t.long 0\n" ); /* CriticalSectionDefaultTimeout */ + output( "\t%s 0\n", get_asm_ptr_keyword() ); /* DeCommitFreeBlockThreshold */ + output( "\t%s 0\n", get_asm_ptr_keyword() ); /* DeCommitTotalFreeThreshold */ + output( "\t%s 0\n", get_asm_ptr_keyword() ); /* LockPrefixTable */ + output( "\t%s 0\n", get_asm_ptr_keyword() ); /* MaximumAllocationSize */ + output( "\t%s 0\n", get_asm_ptr_keyword() ); /* VirtualMemoryThreshold */ + output( "\t%s 0\n", get_asm_ptr_keyword() ); /* ProcessAffinityMask */ + output( "\t.long 0\n" ); /* ProcessHeapFlags */ + output( "\t.short 0\n" ); /* CSDVersion */ + output( "\t.short 0\n" ); /* DependentLoadFlags */ + output( "\t%s 0\n", get_asm_ptr_keyword() ); /* EditList */ + output( "\t%s 0\n", get_asm_ptr_keyword() ); /* SecurityCookie */ + output( "\t%s 0\n", get_asm_ptr_keyword() ); /* SEHandlerTable */ + output( "\t%s 0\n", get_asm_ptr_keyword() ); /* SEHandlerCount */ + if (target.cpu == CPU_ARM64EC) + { + output( "\t%s %s\n", get_asm_ptr_keyword(), asm_name( "__guard_check_icall_fptr" )); + output( "\t%s %s\n", get_asm_ptr_keyword(), asm_name( "__guard_dispatch_icall_fptr" )); + } + else + { + output( "\t%s 0\n", get_asm_ptr_keyword() ); /* GuardCFCheckFunctionPointer */ + output( "\t%s 0\n", get_asm_ptr_keyword() ); /* GuardCFDispatchFunctionPointer */ + } + output( "\t%s 0\n", get_asm_ptr_keyword() ); /* GuardCFFunctionTable */ + output( "\t%s 0\n", get_asm_ptr_keyword() ); /* GuardCFFunctionCount */ + if (target.cpu == CPU_ARM64EC) + output( "\t.long %s\n", asm_name( "__guard_flags" )); + else + output( "\t.long 0\n" ); /* GuardFlags */ + output( "\t.short 0\n" ); /* CodeIntegrity.Flags */ + output( "\t.short 0\n" ); /* CodeIntegrity.Catalog */ + output( "\t.long 0\n" ); /* CodeIntegrity.CatalogOffset */ + output( "\t.long 0\n" ); /* CodeIntegrity.Reserved */ + output( "\t%s 0\n", get_asm_ptr_keyword() ); /* GuardAddressTakenIatEntryTable */ + output( "\t%s 0\n", get_asm_ptr_keyword() ); /* GuardAddressTakenIatEntryCount */ + output( "\t%s 0\n", get_asm_ptr_keyword() ); /* GuardLongJumpTargetTable */ + output( "\t%s 0\n", get_asm_ptr_keyword() ); /* GuardLongJumpTargetCount */ + output( "\t%s 0\n", get_asm_ptr_keyword() ); /* DynamicValueRelocTable */ + if (target.cpu == CPU_ARM64EC) + output( "\t%s %s\n", get_asm_ptr_keyword(), asm_name( "__chpe_metadata" )); + else + output( "\t%s 0\n", get_asm_ptr_keyword() ); /* CHPEMetadataPointer */ + output( "\t%s 0\n", get_asm_ptr_keyword() ); /* GuardRFFailureRoutine */ + output( "\t%s 0\n", get_asm_ptr_keyword() ); /* GuardRFFailureRoutineFunctionPointer */ + output( "\t.long 0\n" ); /* DynamicValueRelocTableOffset */ + output( "\t.short 0\n" ); /* DynamicValueRelocTableSection */ + output( "\t.short 0\n" ); /* Reserved2 */ + output( "\t%s 0\n", get_asm_ptr_keyword() ); /* GuardRFVerifyStackPointerFunctionPointer */ + output( "\t.long 0\n" ); /* HotPatchTableOffset */ + output( "\t.long 0\n" ); /* Reserved3 */ + output( "\t%s 0\n", get_asm_ptr_keyword() ); /* EnclaveConfigurationPointer */ + output( "\t%s 0\n", get_asm_ptr_keyword() ); /* VolatileMetadataPointer */ + output( "\t%s 0\n", get_asm_ptr_keyword() ); /* GuardEHContinuationTable */ + output( "\t%s 0\n", get_asm_ptr_keyword() ); /* GuardEHContinuationCount */ + output( "\t%s 0\n", get_asm_ptr_keyword() ); /* GuardXFGCheckFunctionPointer */ + output( "\t%s 0\n", get_asm_ptr_keyword() ); /* GuardXFGDispatchFunctionPointer */ + output( "\t%s 0\n", get_asm_ptr_keyword() ); /* GuardXFGTableDispatchFunctionPointer */ + output( "\t%s 0\n", get_asm_ptr_keyword() ); /* CastGuardOsDeterminedFailureMode */ + output( "\t%s 0\n", get_asm_ptr_keyword() ); /* GuardMemcpyFunctionPointer */ +} + + /******************************************************************* * output_module * @@ -744,6 +827,7 @@ void output_spec32_file( DLLSPEC *spec ) output_exports( spec ); output_imports( spec ); if (needs_get_pc_thunk) output_get_pc_thunk(); + output_load_config(); output_resources( spec ); output_gnu_stack_note(); close_output_file();
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details:
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=143545
Your paranoid android.
=== debian11b (64 bit WoW report) ===
comctl32: monthcal.c:495: Test failed: got 0 monthcal.c:498: Test failed: got 0x00000001 monthcal.c:499: Test failed: got 2024
On Wed Feb 28 20:24:21 2024 +0000, Alexandre Julliard wrote:
Or is there another reason to prefer having it in winebuild?
No, it's mostly because it seems to fit better. We already have all the needed support for generating that sort of thing, instead of using a C file with an asm statement and custom macros.
I pushed a version that uses winebuild. One downside I noticed is that now it's always pulled, even if the linker doesn't make use of it. For that a symbol in a static library symbol seems like an elegant way of just skipping it.
When it's pulled, its symbols need to be resolved and some of them are builtin linker symbols, not supported by binutils (because they don't make sense without load config support). We don't support CF guards yet, so I just filled that with zeroes, but supporting them at some point seems potentially interesting.
I pushed a version that uses winebuild. One downside I noticed is that now it's always pulled, even if the linker doesn't make use of it. For that a symbol in a static library symbol seems like an elegant way of just skipping it.
True. It solves the issue of winebuild generating empty input files though :wink:
When it's pulled, its symbols need to be resolved and some of them are builtin linker symbols, not supported by binutils (because they don't make sense without load config support). We don't support CF guards yet, so I just filled that with zeroes, but supporting them at some point seems potentially interesting.
Yes, we'll want that eventually.