This currently only works with a simple Hello World program, but this is the
bulk of the work to 16-bit program support.
Still need some minor effort to get 16-bit DLLs working, and of course we
need to implement a ton of missing 16-bit API calls.
Although strictly speaking, it looks like the final OS/2 releases
will fail if the OS/2 .EXE is less than ~320 bytes, choosing to
launch it as a DOS program instead (giving you the "This is an
OS/2 executable" message from the DOS stub, comically).
This, with its fairly large (but incomplete) dictionary of system APIs, is
useful when you want to know that a module wants "VioWrtNCell" and not
"ordinal 52 in VIOCALLS.DLL". :)
This is just lx_dump for now, but if some work proves out, we can load these
with lx_loader, too, and bridge the 16-bit APIs to 32-bits the same as we
do anyhow, giving us access to 16-bit OS/2 binaries.
Obviously, this disables lx_loader, but you can compile a C program that
uses OS/2 APIs as a native 64-bit Linux app and run them.
So now we can do 2ine and 2inelib. :)
GLoaderState is moved to a new lib2ine library, which everything links
to and sets up what it can in a DLL constructor, so your app can just
link to doscalls or whatever and it'll have what it needs without
something like lx_loader doing a lot of heavy lifting before your
main() runs.
Now a perl script parses our headers and generates glue code, export tables,
etc. This automates all the macro nonsense and bridge code, and separates
out all the stuff you need for binary compat with OS/2, so you can remove it
all from the build if you want to just build native libraries that supply
the OS/2 API to native apps (like Winelib vs Wine).
This makes upkeep details less nasty, and easier to build native binaries
when implementing and improving APIs, so you can debug directly without
a lot of drama.
These don't do anything but exist and export no symbols for now, but if you
have something that links against, say, SOM.DLL, you can at least start it
up and have it fail when it calls into that library instead of failing to
start at all.
It's not syscall calling convention, and CSet/2 generates thunks that call
this function but expect %ecx to not be altered by it. Save off a bunch,
just in case.
This is the ring-3 32-bit linear address space's code segment, and it is
hardcoded on OS/2. Generally it isn't explicitly referenced, but things
like CSet/2 would generate thunks that hardcode jmps to it when returning
to 32-bit mode, so you have to patch those out (Linux also hardcodes a
code segment number, but doesn't promise the value won't change, and indeed,
it's different between x86, x86-64, and x86-on-x86-64 apps).
- Let allocateSelector() specify number of pages to allocate.
- Let findSelector() specify if this is a code or data segment.
- Let findSelector() choose if this is a code or data segment
if the caller doesn't know (DosFlatToSel(), etc).
Now we save off the stack pointer and immediately jmp back to 32-bit. This is
slightly easier to debug (gdb doesn't get confused by addresses, registers or
disassembly), and puts all the 32-bit registers in a 32-bit code segment, to
keep things sane.
Also: doesn't write duplicate instructions to update %ds and %es if they are
the same values in Linux land.
Finger (etc) also rely on MPTN\DLL\tnls32.dll, which I pulled out a copy of
OS/2 Warp 4.52, which loads and limps along enough to not be a problem.
Reimplementing that library is going to be a pain, so that's a job for another
day. Inexplicably, tnls32 references pmgpi.dll's GpiQueryTextBox(), so I put a
stub for that in, too, but we're nowhere near really implementing GPI yet.
This is enough to run "finger.exe icculus@icculus.org" and see my .plan file,
which I consider a victory. A few more TCP/IP command line tools aren't far
behind.