Author: hbelusca
Date: Thu Sep 17 23:04:05 2015
New Revision: 69261
URL:
http://svn.reactos.org/svn/reactos?rev=69261&view=rev
Log:
[NTVDM]
- Support loading executables with the old EXE signature ('ZM' instead of
'MZ').
- Fix the EXE loader so that:
* we can load programs of >= 1Mb size, by exploiting the fact that on real DOS, the
computed exe size (which uses the number of 512-byte blocks, stored in the EXE header) is
stored in a WORD variable.
This has as an effect to truncate the value, and if it is such that the truncated
value is less than the size of available memory, the EXE can be loaded (partly, of
course). Some apps expect this behaviour,
for example, Turbo C++ IDE.
* Simplify the memory limits computation, according to
http://www.tavi.co.uk/phobos/exeformat.html , which is the correct algorithm used by DOS
(and confirmed by FreeDOS also).
Modified:
trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/process.c
Modified: trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/process.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/subsystems/mvdm/ntvdm/dos/…
==============================================================================
--- trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/process.c [iso-8859-1] (original)
+++ trunk/reactos/subsystems/mvdm/ntvdm/dos/dos32krnl/process.c [iso-8859-1] Thu Sep 17
23:04:05 2015
@@ -334,6 +334,7 @@
DWORD Result = ERROR_SUCCESS;
WORD Segment = 0;
WORD EnvBlock = 0;
+ WORD ExeSignature;
WORD LoadSegment;
WORD MaxAllocSize;
@@ -428,62 +429,84 @@
}
}
- /* Check if this is an EXE file or a COM file */
- if (ExeBuffer[0] == 'M' && ExeBuffer[1] == 'Z')
+ /*
+ * Check if this is an EXE file or a COM file by looking
+ * at the MZ signature:
+ * 0x4D5A 'MZ': old signature (stored as 0x5A, 0x4D)
+ * 0x5A4D 'ZM': new signature (stored as 0x4D, 0x5A)
+ */
+ ExeSignature = *(PWORD)ExeBuffer;
+ if (ExeSignature == 'MZ' || ExeSignature == 'ZM')
{
/* EXE file */
PIMAGE_DOS_HEADER Header;
- DWORD BaseSize, i;
+ DWORD BaseSize;
PDWORD RelocationTable;
PWORD RelocWord;
WORD RelocFactor;
- BOOLEAN LoadHigh = FALSE;
+ WORD i;
/* Get the MZ header */
Header = (PIMAGE_DOS_HEADER)ExeBuffer;
/* Get the base size of the file, in paragraphs (rounded up) */
- BaseSize = ((((Header->e_cp - (Header->e_cblp != 0)) * 512)
- + Header->e_cblp + 0x0F) >> 4) - Header->e_cparhdr;
+#if 0 // Normally this is not needed to check for the number of bytes in the last
pages.
+ BaseSize = ((((Header->e_cp - (Header->e_cblp != 0)) * 512) +
Header->e_cblp) >> 4)
+ - Header->e_cparhdr;
+#else
+ // e_cp is the number of 512-byte blocks. 512 == (1 << 9)
+ // so this corresponds to (1 << 5) number of paragraphs.
+ //
+ // For DOS compatibility we need to truncate BaseSize to a WORD value.
+ // This fact is exploited by some EXEs which are bigger than 1 Mb while
+ // being able to load on DOS, the main EXE code loads the remaining data.
+
+ BaseSize = ((Header->e_cp << 5) - Header->e_cparhdr) & 0xFFFF;
+#endif
if (LoadType != DOS_LOAD_OVERLAY)
{
- DWORD TotalSize = BaseSize;
-
- /* Add the PSP size, in paragraphs */
- TotalSize += sizeof(DOS_PSP) >> 4;
-
- /* Add the maximum size that should be allocated */
- TotalSize += Header->e_maxalloc;
-
+ BOOLEAN LoadHigh = FALSE;
+ DWORD TotalSize;
+
+ /* Find the maximum amount of memory that can be allocated */
+ DosAllocateMemory(0xFFFF, &MaxAllocSize);
+
+ /* Compute the total needed size, in paragraphs */
+ TotalSize = BaseSize + (sizeof(DOS_PSP) >> 4);
+
+ /* We must have the required minimum amount of memory. If not, bail out. */
+ if (MaxAllocSize < TotalSize + Header->e_minalloc)
+ {
+ Result = ERROR_NOT_ENOUGH_MEMORY;
+ goto Cleanup;
+ }
+
+ /* Check if the program should be loaded high */
if (Header->e_minalloc == 0 && Header->e_maxalloc == 0)
{
- /* This program should be loaded high */
- LoadHigh = TRUE;
- TotalSize = 0xFFFF;
- }
-
- /* Make sure it does not pass 0xFFFF */
- if (TotalSize > 0xFFFF) TotalSize = 0xFFFF;
+ /* Yes it should. Use all the available memory. */
+ LoadHigh = TRUE;
+ TotalSize = MaxAllocSize;
+ }
+ else
+ {
+ /* Compute the maximum memory size that can be allocated */
+ if (Header->e_maxalloc != 0)
+ TotalSize = min(TotalSize + Header->e_maxalloc, MaxAllocSize);
+ else
+ TotalSize = MaxAllocSize; // Use all the available memory
+ }
/* Try to allocate that much memory */
- Segment = DosAllocateMemory((WORD)TotalSize, &MaxAllocSize);
+ Segment = DosAllocateMemory((WORD)TotalSize, NULL);
if (Segment == 0)
{
- /* Check if there's at least enough memory for the minimum size */
- if (MaxAllocSize < (BaseSize + (sizeof(DOS_PSP) >> 4) +
Header->e_minalloc))
- {
- Result = Sda->LastErrorCode;
- goto Cleanup;
- }
-
- /* Allocate that minimum amount */
- TotalSize = MaxAllocSize;
- Segment = DosAllocateMemory((WORD)TotalSize, NULL);
- ASSERT(Segment != 0);
- }
-
- /* The process owns its own memory */
+ Result = Sda->LastErrorCode;
+ goto Cleanup;
+ }
+
+ /* The process owns its memory */
DosChangeMemoryOwner(Segment , Segment);
DosChangeMemoryOwner(EnvBlock, Segment);
@@ -560,7 +583,7 @@
goto Cleanup;
}
- /* The process owns its own memory */
+ /* The process owns its memory */
DosChangeMemoryOwner(Segment , Segment);
DosChangeMemoryOwner(EnvBlock, Segment);