I've been thinking on emulating windows 32-bit games for some time and it's one of the projects I'm working on.
Here are some points and my opinions about it.
It's better to do dynamic recompilation (DR) than static recompilation (SR), unless you are doing some things in SR that can't be done in DR or you are using information specific to one executable.
Some windows executables don't contain relocation information without which doing SR is practically impossible and DR is possible only by loading the executable to the memory at an address specified in the executable.
Master of Orion 2 (my copy) doesn't contain relocation information.
If you use SR then you're tying the game to a single version of the executable. Game can have different versions (language, region, patches - official and unofficial, ...).
My copy of Master of Orion 2 has version number 1.31, but it's not the same executable as in the official patch to version 1.31.
If you use DR then it should work on any executable, but with SR you must do specific work for each executable.
Contrary to what you wrote some windows games do use self-modifying code (and I don't mean copy protections and PE compressors).
This is easier than in dos games, because self-modifying code can be only in memory block which are explicitly marked as writable and executable.
What you said about segment registers is mostly right. Registers cs, ds, es and ss have segment base 0 and segment limit 4GB and these registers shouldn't be changed by the application.
Register fs points to the TIB (
Thread Information Block) and also shouldn't be changed.
Register gs can be freely used by the application, but I don't know if some games use this register beside saving and restoring it's value.
(TIB is complicated by the fact that TIB contains pointer (with segment base 0) to itself which the application can read and use.)
For windows API you can make you own implementation (only implementing functions and parameters which are really used by the games you are recompiling) or you can try using winelib.
With your own implementation, you can implement the API as you want it - better/faster than winelib, but it's a lot of work and it's impractical if you want to recompile more games.
With winelib you have the API implemented, but potentially not the way you want/need it (for example Direct3D is wrapped to OpenGL which can't be used on Pandora).
And lastly, threads. Some windows games are multi-threaded. You can limit yourself to single-threaded applications or you can support multi-threaded applications from the start. (Starting with single-threaded applications and adding support for multi-threaded applications is not simple and definitely not ideal).
If you're curious, here's some information about my project.
I'm using dynamic recompilation.
I handle self-modifying code (SMC) by running memory blocks which are writable and executable in the interpreter instead of recompiling it. This makes SMC slow(er), but the normal code si just as fast as if I didn't support SMC. (Other solutions can make SMC faster, but normal code would be slower.)
I have my own implementation of windows API (there wasn't winelib for ARM when I started working on the project).
I'm only supporting single-threaded applications.
Because of this and windows API, only two games are working (a game and it's sequel to be precise).
I'm working on it to release a beta version, but I'm not planning to support more than the two games.
I'm thinking on starting a new project which will use winelib, it will support multi-threaded applications and it will use different dynamic recompiler.