major version 4 must have their imported modules checked to determine whether they are Windows or OS/2 or Multitasking DOS 4 executables.
Tested on Fedora 26 x86 --- dlls/krnl386.exe16/ne_module.c | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+)
diff --git a/dlls/krnl386.exe16/ne_module.c b/dlls/krnl386.exe16/ne_module.c index 14f8075166..e9009677d0 100644 --- a/dlls/krnl386.exe16/ne_module.c +++ b/dlls/krnl386.exe16/ne_module.c @@ -697,6 +697,46 @@ static HMODULE16 build_module( const void *mapping, SIZE_T mapping_size, LPCSTR ne_header->ne_enttab - ne_header->ne_imptab )) goto failed; pData += ne_header->ne_enttab - ne_header->ne_imptab;
+ /* If the linker version is 4.x or the executable type is unknown, it is necessary to check the import table for + known Windows and OS/2 libraries to determine whether it's a Windows executable. Executables with no module table + or which don't import known Windows or OS/2 libraries are also assumed to be Windows. */ + if (((ne_header->ne_ver == 0x04) || (ne_header->ne_exetyp == 0x00)) && pModule->ne_modtab) + { + /* Array of offsets into the imported names table where module names are located */ + WORD* module_table; + + /* Series of Pascal strings containing the module names */ + LPCSTR imported_names; + + int i; + BOOL importsDosCalls = FALSE; + BOOL importsKernel = FALSE; + + /* Get address of module table and imported names table from their offsets */ + module_table = (WORD*)(((BYTE*)pModule) + pModule->ne_modtab); + imported_names = (LPCSTR)(((BYTE*)pModule) + pModule->ne_imptab); + + /* Look for imports from DOSCALLS and KERNEL */ + for (i = 0; i < pModule->ne_cmod; i++) + { + /* Module name is a Pascal string with byte length prefix */ + LPCSTR module_name = imported_names + module_table[i]; + + if (!importsDosCalls && !strncmp("DOSCALLS", &module_name[1], module_name[0])) + importsDosCalls = TRUE; + + else if (!importsKernel && !strncmp("KERNEL", &module_name[1], module_name[0])) + importsKernel = TRUE; + + if (importsDosCalls && importsKernel) + break; + } + + /* If the module has imports from DOSCALLS but not KERNEL, assume it's for OS/2 or Multitasking DOS 4. */ + if (importsDosCalls && !importsKernel) + goto failed; + } + /* Load entry table, convert it to the optimized version used by Windows */
pModule->ne_enttab = pData - (BYTE *)pModule;
version 4 may also be Windows executables. Don't try to load NE files with OS type of Windows/386. Even Windows/386 doesn't recognise these as Windows executables.
Tested on Fedora 26 x86 --- dlls/krnl386.exe16/ne_module.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/dlls/krnl386.exe16/ne_module.c b/dlls/krnl386.exe16/ne_module.c index e9009677d0..673b627208 100644 --- a/dlls/krnl386.exe16/ne_module.c +++ b/dlls/krnl386.exe16/ne_module.c @@ -597,11 +597,10 @@ static HMODULE16 build_module( const void *mapping, SIZE_T mapping_size, LPCSTR
/* We now have a valid NE header */
- /* check to be able to fall back to loading OS/2 programs as DOS - * FIXME: should this check be reversed in order to be less strict? - * (only fail for OS/2 ne_exetyp 0x01 here?) */ + /* check to be able to fall back to loading OS/2 programs as DOS */ if ((ne_header->ne_exetyp != 0x02 /* Windows */) - && (ne_header->ne_exetyp != 0x04) /* Windows 386 */) + && (ne_header->ne_exetyp != 0x00 /* Unknown - possible early 1.x or 2.x app */) + && (ne_header->ne_ver == 0x04 /* link4 version 4.x has no ne_exetyp field - possible early 1.x app */)) return ERROR_BAD_FORMAT;
size = sizeof(NE_MODULE) +
expected version set, or if the linker major version is 4.
Tested on Fedora 26 x86 --- dlls/krnl386.exe16/ne_module.c | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/dlls/krnl386.exe16/ne_module.c b/dlls/krnl386.exe16/ne_module.c index 673b627208..b3c0b75a4d 100644 --- a/dlls/krnl386.exe16/ne_module.c +++ b/dlls/krnl386.exe16/ne_module.c @@ -648,6 +648,11 @@ static HMODULE16 build_module( const void *mapping, SIZE_T mapping_size, LPCSTR
pModule->ne_flags &= ~(NE_FFLAGS_BUILTIN | NE_FFLAGS_WIN32);
+ /* The original NE spec (which link4 version 4.x follows) doesn't have an ne_expver field and reserves it for + future use. Other early executables have the version set to 0.0. Assume Windows 1.01 in either case. */ + if ((ne_header->ne_ver == 0x04) || (ne_header->ne_expver == 0x0000)) + pModule->ne_expver = 0x0101; + /* Get the segment table */
pModule->ne_segtab = pData - (BYTE *)pModule;
priority rather than a DISCARDABLE flag.
Tested on Fedora 26 x86 --- dlls/krnl386.exe16/ne_module.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+)
diff --git a/dlls/krnl386.exe16/ne_module.c b/dlls/krnl386.exe16/ne_module.c index b3c0b75a4d..72043a90ff 100644 --- a/dlls/krnl386.exe16/ne_module.c +++ b/dlls/krnl386.exe16/ne_module.c @@ -662,6 +662,24 @@ static HMODULE16 build_module( const void *mapping, SIZE_T mapping_size, LPCSTR for (i = ne_header->ne_cseg; i > 0; i--, pSeg++) { memcpy( pData, pSeg, sizeof(*pSeg) ); + + /* The original NE spec (which link4 version 4.x follows) uses the top four bits of the segment flags to set a + discard priority (0 = not discardable, 15 = highest priority). Later specs repurpose the top three bits and + use a single bit for the discardable flag. The top three bits must be masked off and discardable flag set + appropriately, otherwise a discard priority could get misinterpreted as a 32 bit segment flag which results + in an application crash. */ + if (ne_header->ne_ver == 0x04) + { + WORD* seg_flags; + BOOL isDiscardable; + + seg_flags = (WORD*)(pData + FIELD_OFFSET(SEGTABLEENTRY, flags)); + isDiscardable = ((*seg_flags & 0xF000) > 0); + + if (isDiscardable) + *seg_flags = ((*seg_flags & 0x0FFF) | NE_SEGFLAGS_DISCARDABLE); + } + pData += sizeof(SEGTABLEENTRY); }
Hi,
I realise I've lost my "signed off by" line in the process of splitting the patch up. Do you need me to resubmit with the signoff?
Regards, Martin
Am 2017-12-17 um 11:01 schrieb Martin Payne:
Hi,
I realise I've lost my "signed off by" line in the process of splitting the patch up. Do you need me to resubmit with the signoff?
Yes, please re-send them with the signoff.
Stefan
Stefan Dösinger stefandoesinger@gmail.com writes:
Am 2017-12-17 um 11:01 schrieb Martin Payne:
Hi,
I realise I've lost my "signed off by" line in the process of splitting the patch up. Do you need me to resubmit with the signoff?
Yes, please re-send them with the signoff.
And if you could, please also write subject lines that summarize the patch in one line. You can add a longer explanation in the mail body if needed, but the subject line should stand by itself.