ID Number: Q81889
5.0x 5.1x 5.20 5.30 | 5.0x 5.1x 5.20 | 5.0x 5.1x 5.20 5.30
MS-DOS | OS/2 | WINDOWS
Summary:
A segmented executable needs to have more information stored in its
executable header than an MS-DOS executable does. This expanded header
consists of the old MS-DOS executable header, and adds information in
a new executable header.
A 16-bit checksum is created by LINK and stored in bytes 12-13h of the
old executable header. MS-DOS does not use this value. Bytes 08-0Bh
are set aside for a 32-bit checksum in the new header. The 16-bit
checksum is calculated any time an MS-DOS program is created. This
value is ignored by Windows and OS/2. For almost any other type of
executable file (Windows .EXEs and DLLs, OS/2 1.x .EXEs and DLLs), the
32-bit checksum is calculated.
More Information:
The following information on how to calculate the 16-bit checksum is
from page 122 of the "MS-DOS Encyclopedia:"
12-13H (Complemented Checksum) This word contains the one's
complement of the summation of all words in the .EXE file. Current
versions of MS-DOS basically ignore this word when they load a .EXE
program; however, future versions might not. When LINK generates an
.EXE file, it adds together all the contents of the .EXE file
(including the .EXE header) by treating the entire file as a long
sequence of 16-bit words. During this addition, LINK gives the
Complemented Checksum word (12-13H) a temporary value of 0000H. If
the file consists of an odd number of bytes, then the final byte is
treated as a word with a high byte of 00H. Once LINK has totaled
all words in the .EXE file, it performs a one's complement
operation on the total and records the answer in the .EXE file
header at offsets 12-13H. The validity of a .EXE file can then be
checked by performing the same word-totaling process as LINK
performed. The total should be FFFFH, because the total will
include LINK's calculated complemented checksum, which is designed
to give the file the FFFFH total.
The sample code below is one implementation of this.
Page 1488 of the "MS-DOS Encyclopedia" indicates that the 32-bit
checksum should be zero. Link versions 5.2 and earlier do compute a
value, but it will not result in a total of FFFFh when doing a
word-totalling process similar to the one for a 16-bit checksum.
Starting with link 5.3, the 16-bit and 32-bit checksum is no
longer computed. The bytes reserved will be set to zero.
Sample Code
-----------
/* Compile options needed: none
*/
#include <stdio.h>
#include <stdlib.h>
#include <io.h>
void Calc16ChkSum( FILE *fp );
void main( int, char ** );
FILE *fp;
unsigned long NewHdrOffset, lPageCnt, FileSize = 0L;
unsigned int PageCnt;
unsigned char NewHdrIndc;
#define NEWHDRINDC 0x18 /* Location in old header for indicator
of new header in EXE */
#define NEWHDROFFSET 0x3C /* Location if new header offset */
void main( int argc, char * argv[] )
{
if( argc != 2 )
{
printf( "\n\nUsage: %s <EXEfilename>\n\n", argv[0] );
exit( -1 );
}
if( (fp = fopen (argv[1], "rb")) == NULL )
{
printf( "\n\nError: Unable to open file : %s\n\n", argv[1] );
exit( -1 );
}
fseek( fp, NEWHDRINDC, SEEK_SET );
fread( &NewHdrIndc, sizeof(char), 1, fp );
if( (int)NewHdrIndc >= 0x40 ) /* Then it's a new EXE header */
{
printf( "\n%s has new .EXE header information.\n",argv[1] );
printf( "32-bit checksum not available.\n" );
}
else /* Get size and calculate 16-bit checksum */
{
fseek( fp,0,SEEK_SET );
/* Read past the signature */
fread( &PageCnt, sizeof(int), 1, fp );
/* Read the last page size */
fread( &PageCnt, sizeof(int), 1, fp );
FileSize = PageCnt;
/* Read the full page count */
fread( &PageCnt, sizeof(int), 1, fp );
lPageCnt = (long) PageCnt; /* Considering large programs */
if( FileSize == 0L )
FileSize = lPageCnt * 512L;
else
FileSize += (lPageCnt - 1L) * 512L;
Calc16ChkSum( fp );
}
fcloseall( );
}
void Calc16ChkSum( FILE *fp )
{
unsigned int sum16, NxtInt, x;
unsigned char NxtChar;
sum16 = 0;
fseek( fp, 0, SEEK_SET );
for( x = 0L ; x < FileSize / 2L ; x++ )
{
fread( &NxtInt, sizeof(int), 1, fp );
sum16 += NxtInt;
}
/* Make sure and get the last byte if odd size. */
if( FileSize % 2 )
{
fread( &NxtChar, sizeof(char), 1, fp );
sum16 += (unsigned int) NxtChar;
}
printf( "\nThe 16 bit checksum should be FFFF\n" );
printf( "The calculated checksum is %X\n\n",sum16 );
}
Additional reference words: 5.01.2 5.01.20 5.01.21 5.02 5.03 5.05
5.1 5.10 5.11 5.13 5.15 5.2 5.20 5.30