Microsoft a passé des années à construire WSL — Windows Subsystem for Linux — pour que les devs puissent faire tourner un vrai kernel Linux sous Windows sans dual-boot. C’est propre, c’est intégré, c’est devenu presque indispensable. Maintenant imagine l’inverse : un sous-système Windows 9x qui tourne directement sous Linux. Pas une VM, pas Wine version allégée — un vrai sous-système qui intercepete les appels système Win9x et les traduit à la volée pour le kernel Linux.
C’est exactement ce qu’a publié Hailey sur Mastodon, dans un projet qui a explosé sur Hacker News avec près de 1 000 points. Et contrairement à ce qu’on pourrait croire en lisant le titre, ce n’est pas une blague de dev le vendredi soir. C’est un projet sérieux, techniquement dense, avec une vraie question architecturale au cœur : peut-on implémenter une couche de compatibilité Win9x dans l’espace utilisateur Linux sans toucher au kernel ?
Spoiler : oui. Et c’est fascinant.
TL;DR — Un développeur a créé un sous-système Windows 9x pour Linux qui intercepte les appels Win32/9x dans l’espace utilisateur et les traduit en appels POSIX. Ce n’est ni Wine, ni une VM — c’est une approche architecturale différente qui éclaire comment fonctionnent vraiment les couches de compatibilité, et pourquoi c’est bien plus compliqué qu’il n’y paraît.
Ce que fait le projet concrètement
Le Windows 9x Subsystem for Linux — appelons-le W9xSL pour gagner du temps — vise à faire tourner des binaires Win9x (format PE, APIs Win32 de l’époque) directement sous un kernel Linux moderne, sans couche de virtualisation complète. L’idée centrale : intercepter les appels à l’API Windows 9x au niveau du loader, avant même qu’ils n’atteignent quoi que ce soit d’un vrai OS Windows, et les router vers des équivalents Linux.
Concrètement, quand un vieux binaire compilé pour Windows 98 appelle CreateFile() ou MessageBoxA(), le sous-système intercepte ces appels et décide quoi en faire. Pour les I/O fichiers, la traduction vers les syscalls POSIX est relativement directe. Pour les appels GDI, DirectDraw ou les messages de fenêtre Win32 — c’est là que ça devient sportif.
Ce qui distingue cette approche de Wine, c’est l’angle : Wine cherche à être une implémentation complète et stable de l’API Windows, compatible avec des milliers d’applications actuelles. W9xSL cible un scope beaucoup plus étroit — Windows 9x uniquement, APIs d’avant 2000 — ce qui permet des choix d’implémentation plus radicaux et une architecture plus lisible.
L’architecture technique : espace utilisateur vs kernel space
Le choix le plus intéressant du projet, c’est de rester entièrement dans l’espace utilisateur. Pas de module kernel, pas de patch, pas de hack qui nécessiterait des droits root à l’installation. Tout passe par le mécanisme binfmt_misc de Linux, qui permet de déclarer des handlers pour certains formats d’exécutables.
En gros, tu enregistres ton sous-système comme interpréteur des fichiers PE (le format exécutable Windows), et Linux appellera automatiquement ton loader quand quelqu’un essaie d’exécuter un .exe. À partir de là, c’est ton loader qui prend la main : il mappe le binaire en mémoire, résout les imports de DLLs (qui sont les tiennes, pas celles de Windows), et configure le thread initial.
# Exemple d'enregistrement binfmt_misc pour les PE
echo ':win9x:M::MZ::/usr/local/bin/w9x-loader:' > /proc/sys/fs/binfmt_misc/register
Cette approche a un avantage massif : la portabilité et la maintenabilité. Tout le sous-système est un processus Linux ordinaire. Il peut être débogué avec GDB, profilé avec perf, et n’a besoin d’aucun privilège particulier à l’exécution. C’est exactement comme ça que WSL 1 fonctionnait côté Microsoft — une translation layer en espace utilisateur, avant que WSL 2 ne bascule sur une vraie VM légère.
Le vrai défi : le modèle de threading Win9x
Win9x n’avait pas de vrai multithreading préemptif. Recréer ce comportement sous Linux, qui fait exactement l’inverse, c’est l’enfer architectural par excellence.
Windows 9x avait un modèle de concurrence très particulier. Le kernel Win9x n’était pas vraiment préemptif pour le code 16 bits, et la gestion des threads 32 bits reposait sur des mécanismes qui n’ont aucun équivalent direct sous Linux. Les applications Win9x faisaient souvent des hypothèses implicites sur l’ordonnancement — hypothèses qui explosent face au scheduler CFS de Linux.
DÉCOUVREZ NOS RÉALISATIONS

Ostium Group
Site vitrine bilingue pour une startup medtech a Saint-Herblain (44). Presentation de l'entreprise et de ses innovations en dispositifs medicaux.
Voir le projet →Le projet doit donc simuler ces comportements : la message queue Windows (GetMessage/DispatchMessage), le modèle de fenêtres HWND, et surtout la boucle d’événements qui était au cœur de toute application Win32 de l’époque. Chaque fenêtre avait sa propre WndProc, un callback qui recevait les messages — souris, clavier, redessinage. Recréer ça proprement au-dessus de X11 ou Wayland demande un travail conséquent.
C’est d’ailleurs là que Wine a mis des années à être stable. La gestion des messages Windows est pleine de cas limites documentés nulle part officiellement — ils ont dû reverse-engineer le comportement exact à partir de milliers d’applications réelles.
Ce que ce projet enseigne vraiment : implémenter une couche de compatibilité OS, c’est implémenter tous les bugs et comportements non-documentés de l’original. Pas juste l’API officielle — tout ce que les développeurs de l’époque ont appris à contourner ou exploiter.
Pourquoi c’est différent de Wine (et pas si différent)
La question la plus posée dans les commentaires HN était logiquement : « En quoi c’est différent de Wine ? » La réponse courte : le scope et les ambitions. Wine vise la compatibilité maximale avec Windows moderne — XP, 7, 10, les APIs COM, .NET via Mono, DirectX via DXVK. C’est 30 ans de travail, des millions de lignes de code, et une communauté massive.
W9xSL choisit délibérément un périmètre réduit pour explorer une architecture différente. En se limitant à Win9x, le projet peut faire des simplifications radicales : pas de registry NT complexe, pas de modèle de sécurité ACL, pas d’APIs COM étendues. Le résultat est un code plus court, plus lisible, qui permet de comprendre comment une translation layer fonctionne de l’intérieur.
Il y a aussi une dimension pédagogique évidente. Ce genre de projet, c’est l’équivalent d’implémenter un compilateur pour apprendre comment les compilateurs fonctionnent — tu ne vas pas remplacer GCC, mais tu vas comprendre des choses que la doc officielle ne t’apprendra jamais. Si tu construis des applications sur mesure qui doivent tourner dans des environnements contraints ou legacy, comprendre comment une translation layer est architecturée peut changer radicalement ta façon d’aborder les problèmes de compatibilité.
WSL comme miroir inversé
Ce qui rend ce projet particulièrement savoureux, c’est qu’il inverse exactement la logique de WSL. Microsoft a eu besoin de plusieurs versions pour converger vers quelque chose de stable : WSL 1 (translation layer pure en espace utilisateur) s’est heurté aux mêmes problèmes — les comportements non-documentés du kernel Linux étaient impossibles à émuler parfaitement. WSL 2 a tranché le nœud gordien en embarquant un vrai kernel Linux dans une VM légère Hyper-V.
W9xSL suit le chemin inverse, et fait face aux mêmes dilemmes architecturaux dans l’autre sens. Est-ce qu’on traduit les appels un à un (approche WSL 1) ou est-ce qu’on embarque quelque chose de plus lourd pour avoir une compatibilité réelle (approche WSL 2) ? Pour Win9x, la première option est beaucoup plus viable qu’elle ne l’était pour Linux : le kernel Win9x était bien plus simple, et son surface d’API bien plus réduite qu’un kernel Linux moderne.
Il y a quelque chose d’intellectuellement satisfaisant à voir les deux projets se faire écho à 25 ans d’intervalle. Les problèmes fondamentaux de compatibilité OS n’ont pas changé — seul le sens de la traduction diffère.
À noter : si tu penses à Win9x et que tu te dis « c’est du vieux code mort », rappelle-toi que des systèmes critiques dans l’industrie, la santé ou la logistique tournent encore sur Windows XP ou NT. La problématique de compatibilité legacy n’est pas qu’un exercice académique — c’est un vrai sujet pour quiconque gère de l’hébergement et de la maintenance sur des parcs hétérogènes.
Ce que la communauté HN en a retenu
Les 224 commentaires sur Hacker News ont suivi un schéma assez prévisible : 30% de « mais c’est pas juste Wine ça ? », 30% de nostalgie Win98 assumée, et 40% de discussions techniques genuinement intéressantes sur les choix d’implémentation. Ce qui ressort des échanges les plus denses, c’est la question de la fidélité comportementale versus la fidélité fonctionnelle.
WESTCODE BY LEB
Studio web en Mayenne — On crée des outils numériques qui transforment
Fidélité fonctionnelle : l’application fait ce qu’elle est censée faire. Le bouton cliqué déclenche la bonne action. Le fichier est bien sauvegardé. Fidélité comportementale : l’application réagit exactement comme sous le vrai Win9x — mêmes timings, même comportement en cas d’erreur, même rendu pixel-perfect. La première est atteignable avec un effort raisonnable. La seconde est un puits sans fond, comme Wine l’a découvert.
Plusieurs commentateurs ont souligné un angle intéressant : pour certaines applications de niche (vieux logiciels CAD, outils d’automatisation industrielle, interfaces de matériel ancien), la fidélité fonctionnelle seule suffit. Et là, un sous-système ciblé Win9x a un avantage réel sur Wine : il peut faire des hypothèses plus fortes et donc des optimisations plus agressives sur ce scope restreint.
Mon avis : ce projet mérite bien plus que 15 minutes de notoriété HN
On est face à un projet qui fait exactement ce que le bon software expérimental doit faire : poser une question architecturale précise, y répondre proprement dans un périmètre contrôlé, et rendre le résultat lisible. Est-ce que W9xSL va remplacer Wine ou devenir un outil de prod ? Non, et ce n’est pas l’objectif. Mais il illustre mieux qu’un cours magistral comment une translation layer OS est construite, quelles sont ses limites intrinsèques, et pourquoi Microsoft a fini par choisir la VM pour WSL 2.
Ce qui me frappe, c’est que ce type de projet « inutile mais brillant » est exactement ce qui fait avancer la compréhension collective. Les gens qui construisent ce genre de chose comprennent les couches basses mieux que la plupart — et cette compréhension finit toujours par servir quelque part, souvent là où on ne l’attendait pas. Si tu construis des produits web et que tu te demandes pourquoi tu devrais t’intéresser à des projets comme celui-là, la réponse tient en une phrase : les abstractions ne durent pas, les fondations si.
La vraie question que pose ce projet en filigrane : à l’heure où on empile des couches d’abstraction à vitesse industrielle, combien de devs actifs sont encore capables de descendre aussi bas dans la pile ? Mon pari : de moins en moins — et c’est exactement pourquoi les rares qui le font ont une valeur qui ne se voit pas dans un CV rempli de buzzwords.



