# Win32 Is The Only Stable ABI on Linux

In August 2022, glibc 2.36 shipped a change that broke games using Easy Anti-Cheat's EOS module on Linux. The culprit: glibc stopped emitting `DT_HASH` sections in its shared libraries, keeping only the newer `DT_GNU_HASH`. Software that walked the old hash table to count symbols — a reasonable thing to do, since `DT_HASH` is part of the SYSV generic ABI — started crashing.

The breakage wasn't limited to anti-cheat. libstrangle (an open-source frame limiter) and Shovel Knight also regressed. More was expected as distros picked up the new glibc.

## The two hash tables

ELF binaries can carry two kinds of symbol hash tables. `DT_HASH` is specified in the SYSV generic ABI and documented: it has a fixed layout, and you can read the symbol count directly from the header. `DT_GNU_HASH` is a glibc/GNU invention — faster lookups, smaller tables, but undocumented and missing some functionality. Getting the symbol count from `DT_GNU_HASH` requires parsing the entire table.

Glibc had been emitting both for years. The 2.36 release dropped `DT_HASH` from glibc's own libraries. The justification: glibc marks itself as `ELFOSABI_GNU`, so strictly speaking it isn't bound by the generic ABI's requirement to include `DT_HASH`. The savings: about 16 kB per library, under 1% of total size.

## Why distros made it worse

Most Linux distributions configured GCC with `--with-linker-hash-style=gnu`, which tells the linker to emit only `DT_GNU_HASH`. This was a leftover from when the GNU hash table was new and the linker defaulted to sysv-only — distros flipped the flag to get the performance benefit and never flipped it back. GNU ld itself defaults to `--hash-style=both` (emitting both tables), and mold defaults to `--hash-style=sysv`. But the distro GCC flag overrides the linker default, so most Linux binaries in practice have only `DT_GNU_HASH`.

Clang copies whatever the local GCC does through distro detection, propagating the choice further.

## The kernel rule glibc ignores

Linus Torvalds has a standing policy for the Linux kernel: changing ABI is fine as long as nobody noticed, but once someone notices breakage, it's a regression and gets reverted. The kernel treats user-visible behavior as a stability contract regardless of what the spec says.

Glibc doesn't operate this way. The glibc maintainers argued that `DT_HASH` was never part of their ABI, that the information is still available in a different format, and that distros should solve the problem themselves. Real software breaking was treated as those programs' fault for depending on undocumented layout.

## The punchline

The author's conclusion: Win32 via Wine is the only stable [[abi-stability|ABI]] on Linux. Wine commits to not breaking Windows applications. The Linux kernel commits to not breaking userspace. But glibc — the layer between them — doesn't make that promise, and it sits right where game developers need stability most. Targeting Windows and letting Wine handle the Linux side gives developers a more reliable contract than building native Linux binaries.

See also [[win32-weird-shaped-windows]] for an example of Win32's programming model stability — the same region APIs from Windows 95 work identically today.
