While executing a clean-room compilation pipeline targeting the native Windows UCRT directly via llvm-mingw (LLVM 22.1.8 runtime environment), the linker (ld.lld) threw a sequence of undefined symbol errors regarding libmingw32.a(tlsthrd.o):
ld.lld: error: undefined symbol: __declspec(dllimport) EnterCriticalSection
ld.lld: error: undefined symbol: __declspec(dllimport) LeaveCriticalSection
ld.lld: error: undefined symbol: __declspec(dllimport) InitializeCriticalSection
ld.lld: error: undefined symbol: __declspec(dllimport) DeleteCriticalSection
Technical Root Cause
The standard regex pattern used to parse the raw text logs of system DLL headers strictly expects a hexadecimal memory address offset (0x[0-9a-fA-F]+) right before the function name string.
However, on modern 64-bit Windows environments, these critical thread-synchronization primitives are structured as Forwarded Exports that point straight to NTDLL (e.g., EnterCriticalSection (forwarded to NTDLL.RtlEnterCriticalSection)). Because they lack a standard hexadecimal RVA block in the export dump column, the strict regex completely filters them out, leading to missing entries in the resulting module-definition blueprint (.def) files.
The Solution: Automated Extraction Script
I updated the regex sequence to make the hexadecimal address block entirely optional ((0x[0-9a-fA-F]+\s+)?). This successfully captures both standard memory-addressed exports and blank-address forwarded symbols on the fly. here is the ps1 script code param (
[string]$InputLog,
[string]$DllName
)
if (-not $InputLog -or -not $DllName) {
Write-Error "Missing parameters! Usage: .\ParseExports.ps1 -InputLog .\kernel32_structure.log -DllName kernel32.dll"
exit 1
}
$OutputFile = $InputLog -replace '\.log$', '.def'
$DefContent = [System.Collections.Generic.List[string]]::new()
$DefContent.Add("LIBRARY $DllName")
$DefContent.Add("EXPORTS")
# Process the log file line by line
Get-Content -Path $InputLog | ForEach-Object {
# Match the typical clean export line pattern from llvm-objdump private headers:
# ordinal, RVA, name (ignoring any potential forwarder trailing string data)
if ($_ -match '^\s*(?<Ordinal>\d+)\s+0x[0-9a-fA-F]+\s+(?<Name>[a-zA-Z0-9_#@]+)(.*)?$') {
$Ord = $Matches['Ordinal']
$Name = $Matches['Name']
$DefContent.Add(" $Name @$Ord")
}
}
$DefContent | Set-Content -Path $OutputFile -Encoding utf8
Write-Host "[+] Extracted and compiled to $OutputFile successfully!" -ForegroundColor Green
i discovered: Capturing Forwarded Exports for UCRT/MinGW Linking
While executing a clean-room compilation pipeline targeting the native Windows UCRT directly via
llvm-mingw(LLVM 22.1.8 runtime environment), the linker (ld.lld) threw a sequence of undefined symbol errors regardinglibmingw32.a(tlsthrd.o):