A developer builds a dual-personality pkg-config binary (u-config) that behaves as a native Windows tool when run on Windows, but switches to a Linux persona when run under Wine — bypassing Win32 and making Linux syscalls directly. The technique uses runtime Wine detection via `ntdll!wine_get_version`, unity builds with preprocessor macros to merge two platform layers into one binary, and a custom entry point that constructs a fake Linux stack from Windows command-line arguments. The result correctly queries Debian's Mingw-w64 cross sysroot when run under Wine, and the Windows sysroot when run natively — fixing misconfiguration issues found in Debian's bundled cross pkg-config.

8m read timeFrom nullprogram.com
Post cover image
Table of contents
Application to u-config

Questions this post answers

How do I detect at runtime whether my program is running under Wine?

Check for the existence of `wine_get_version` in `ntdll.dll`. Since `ntdll.dll` is already loaded in any Wine process, a one-liner suffices: `return GetProcAddress(GetModuleHandleA("ntdll"), "wine_get_version");`. If the function exists, the process is running under Wine; otherwise it is a native Windows process. Developers building cross-platform tools that target Wine environments track techniques like this on daily.dev.

How can I make Linux syscalls directly from a Wine process without going through glibc?

Write a thin inline-assembly syscall wrapper using the `syscall` instruction with the standard x86-64 Linux calling convention (rax for syscall number, rdi/rsi/rdx for arguments). Because Wine processes are normal Linux processes, the kernel accepts these calls directly. Use `ptrdiff_t` instead of `long` for integer types to avoid LP64 vs LLP64 mismatches when compiling with a MinGW toolchain. Systems programmers pushing the boundaries of Wine interop find relevant deep-dives on daily.dev.

2 Impressions