# Frankenwine: Multiple personas in a Wine process

DevFeed: [Frankenwine: Multiple personas in a Wine process](<https://devfeed.tech/articles/frankenwine-multiple-personas-in-a-wine-process-20510.md>)

Original publisher: [Read original article](<https://nullprogram.com/blog/2026/01/19/>)

Published: 2026-01-19T21:51:38Z

Content type: article

Language: en

Sources: [Chris Wellons](<https://devfeed.tech/sources/chris-wellons.md>)

Topics: [WINE](<https://devfeed.tech/topics/wine.md>), [Linux](<https://devfeed.tech/topics/linux.md>), [Processes](<https://devfeed.tech/topics/processes.md>), [toolchain](<https://devfeed.tech/topics/toolchain.md>), [C](<https://devfeed.tech/topics/c.md>), [Assembly](<https://devfeed.tech/topics/assembly.md>), [Git](<https://devfeed.tech/topics/git.md>)

Tags: [assembly](<https://devfeed.tech/tags/assembly.md>), [c](<https://devfeed.tech/tags/c.md>), [git](<https://devfeed.tech/tags/git.md>), [linux](<https://devfeed.tech/tags/linux.md>), [processes](<https://devfeed.tech/tags/processes.md>), [toolchain](<https://devfeed.tech/tags/toolchain.md>), [win32](<https://devfeed.tech/tags/win32.md>), [wine](<https://devfeed.tech/tags/wine.md>), [x86](<https://devfeed.tech/tags/x86.md>), [x86-64](<https://devfeed.tech/tags/x86-64.md>)

## AI overview

This article describes building a Windows binary that behaves as a native pkg-config program on Windows but adopts a Linux-program persona when run under Wine. It detects Wine, invokes Linux system calls directly through x86-64 inline assembly, and applies the approach to u-config as a cross-toolchain pkg-config implementation.

## Source excerpt

I came across a recent article on making Linux system calls from a Wine process. Windows programs running under Wine are still normal Linux processes and may interact with the Linux kernel like any other process. None of this was surprising, and the demonstration works just as I expect. Still, it got the wheels spinning and I realized an almost practical application: build my pkg-config implementation such that on Windows pkg-config.exe behaves as a native pkg-config, but when run under Wine this same binary takes the persona of a Linux program and becomes a cross toolchain pkg-config, bypassing Win32 and talking directly with the Linux kernel. Cosmopolitan Libc cleverly does this out-of-the-box, but in this article we'll mash together a couple existing sources with a bit of glue. The results are in the merge-demo branch of u-config, and took hardly any work: $ git show --stat ... main_linux_amd64.c | 8 ++--- main_wine.c | 101 +++++++++++++++++++++++++++++++++++++++++ src/linux_noarch.c | 16 ++++----- src/u-config.c | 1 + 4 files changed, 114 insertions(+), 12 deletions(-) A platform layer, main_wine.c, is a merge of two existing platform layers, one of which required unavoidable tweaks. We'll get to those details in a moment. First we'll need to detect if we're running under Wine, and the best solution I found was to locate ntdll!wine_get_version. If this function exists, we're in Wine. That works out to a pretty one-liner because ntdll.dll is already loaded: bool running_on_wine() { return GetProcAddress(GetModuleHandleA("ntdll"), "wine_get_version"); } An x86-64 Linux syscall wrapper with thorough inline assembly: ptrdiff_t syscall3(int n, ptrdiff_t a, ptrdiff_t b, ptrdiff_t c) { ptrdiff_t r; asm volatile ( "syscall" : "=a"(r) : "a"(n), "D"(a), "S"(b), "d"(c) : "rcx", "r11", "memory" ); return r; } ptrdiff_t write(int fd, void *buf, ptrdiff_t len) { return syscall3(SYS_write, fd, (ptrdiff_t)buf, len); } I'd normally use long for all these integers because Linux i