open-watcom / open-watcom-v2

Open Watcom V2.0 - Source code repository, Wiki, Latest Binary build, Archived builds including all installers for download.
Other
987 stars 162 forks source link

Windows 1.0 support: Use GetProcAddress to look for __AHSHIFT instead of assuming real mode? #1310

Closed joncampbell123 closed 3 months ago

joncampbell123 commented 3 months ago

It just occurred to me that perhaps the C runtime for Windows 1.0 targets could use GetProcAddress to look for the AHSHIFT symbol (by ordinal) so that any logic to convert far pointers where AHSHIFT is needed will still run properly in the protected mode environment of later windows. Just use GetModuleHandle() and GetProcAddress() to read __AHSHIFT if available, assume real mode if not.

Sound like something I should submit as a pull request?

I will of course test it against real Windows 1.0 through 3.1 in DOSBox-X to make sure there's no ill effects, and that code would only exist in the Windows 1.0 builds of the C runtime startup code.

__AHSHIFT may not exist in Windows 1.0 but I'm pretty sure GETPROCADDRESS and GETMODULEHANDLE exist as part of the base Win16 API even back then.

jmalak commented 3 months ago

It is not a problem create special startup code for Windows 1.0 and setup linker to use this code for windows1 target only. But I know nothing about Windows 1.0 that I cannot comment anyway. I don't know history of __AHSHIFT. If you will have any idea that we can try to implement it.

joncampbell123 commented 3 months ago

I wasn't aware of __AHSHIFT until I looked at the C runtime startup ASM file. It looks like it's a constant provided by the Win16 kernel describing the arithmetic shift needed to convert far pointers properly.

In pseudocode the idea is:

ifdef WINDOWS10
    ax = call far GETMODULEHANDLE("KERNEL")
    dx:ax = call far GETPROCADDRESS(ax,114) ; "__AHINCR" by ordinal
    if dx:ax != 0
        _HShift = ax ; dx:ax is very likely FFFF:<AHINCR constant value>
    else
        _HShift = 12
    endif
else
    _HShift = __AHINCR ; existing code for Windows 2.0 and higher
endif

make sense?

Only Windows 1.x lacks ordinal 114. Using the EXENEDMP tool in DOSLIB, Kernel.exe in Windows 1.04 ordinal symbols only go up to 103 "NETBIOSCALL" and no higher.

joncampbell123 commented 3 months ago

I can confirm as well with EXENEDMP and the Windows 1.0 SDK that GetProcAddress() (ordinal 50) and GetModuleHandle() (ordinal 47) exist in Windows 1.04.

joncampbell123 commented 3 months ago

Speaking of which, I see a possible optimization in cstrtw16.c:

    mov     _HShift,al              ; ...
    cmp     al,12                   ; real mode?
    je      notprot                 ; yes, so leave osmode alone
    mov     al,1
    mov     _osmode,al              ; protected mode!

If you're going to load "1" into _osmode why not just "mov _osmode,1" instead of loading into AL just to then load to memory? I think the base 8086 instruction set is capable of supporting that.

EDIT: Unless of course this combination of instructions takes fewer bytes than the single MOV instruction...?

joncampbell123 commented 3 months ago

I'll make this change myself and submit a pull request. Sound good?

joncampbell123 commented 3 months ago

Uh, ok, never mind then.

I understand Windows 1.0 erroring out and crashing to DOS if any symbol in an EXE cannot be resolved, but to crash to DOS if GetProcAddress cannot find a symbol? Really?

If you can't conditionally refer to symbols with GetProcAddress() then what's the point of even using GetProcAddress()????????

Windows 1.0 doesn't have the SetErrorMode() function that 3.0 does when you don't want Windows showing error messages every time GetProcAddress can't find a symbol.

joncampbell123 commented 3 months ago

Never mind.

I'd write code to poke at data structures through the HINSTANCE value of "KERNEL" to figure out if __AHINCR exists but that's really not appropriate for C runtime startup code.

Ironically the ASM I wrote worked perfectly fine under Windows 2.0 and 3.0 but those already have __AHINCR anyway, making the test pointless if Windows 1.0 won't even allow GetProcAddress() to retrieve a symbol without making it hard dependency.

jmalak commented 3 months ago

Only note _osmode is mainly for OS/2 to differ between DOS real-mode and OS/2 16-bit protected mode. Generaly is used to signal 16-bit protected mode (DOS16M).