home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
dosdisas.zip
/
dccsrcoo.zip
/
ExeLoader.cpp
< prev
next >
Wrap
C/C++ Source or Header
|
1997-10-14
|
6KB
|
213 lines
/* EXE binary file format.
This file implements the class ExeLoader, derived from class Loader.
See ExeLoader.h and Loader.h for details
MVE 08/10/97
*/
#include "ExeLoader.h"
ExeLoader::ExeLoader()
{
}
int ExeLoader::Load(const char* sName)
{
FILE *fp;
int i, cb;
byte buf[4];
int fCOM;
// Always just 3 sections
m_pSections = new SECTIONINFO[3];
if (m_pSections == 0)
{
printf("Could not allocate section information\n");
return 0;
}
m_iNumSections = 3;
m_pHeader = new HEADER;
if (m_pHeader == 0)
{
printf("Could not allocate header memory\n");
return 0;
}
/* Open the input file */
if ((fp = fopen(sName, "rb")) == NULL)
{
printf("Could not open file %s\n", sName);
return 0;
}
/* Read in first 2 bytes to check EXE signature */
if (fread(m_pHeader, 1, 2, fp) != 2)
{
printf("Cannot read file %s\n", sName);
return 0;
}
// Check for the "MZ" exe header
if (! (fCOM = (m_pHeader->sigLo != 0x4D || m_pHeader->sigHi != 0x5A)))
{
/* Read rest of m_pHeader */
fseek(fp, 0, SEEK_SET);
if (fread(m_pHeader, sizeof(HEADER), 1, fp) != 1)
{
printf("Cannot read file %s\n", sName);
return 0;
}
/* This is a typical DOS kludge! */
if (LH(&m_pHeader->relocTabOffset) == 0x40)
{
printf("Error - NE format executable\n");
return 0;
}
/* Calculate the load module size.
* This is the number of pages in the file
* less the length of the m_pHeader and reloc table
* less the number of bytes unused on last page
*/
cb = (dword)LH(&m_pHeader->numPages) * 512 -
(dword)LH(&m_pHeader->numParaHeader) * 16;
if (m_pHeader->lastPageSize)
{
cb -= 512 - LH(&m_pHeader->lastPageSize);
}
/* We quietly ignore minAlloc and maxAlloc since for our
* purposes it doesn't really matter where in real memory
* the m_am would end up. EXE m_ams can't really rely on
* their load location so setting the PSP segment to 0 is fine.
* Certainly m_ams that prod around in DOS or BIOS are going
* to have to load DS from a constant so it'll be pretty
* obvious.
*/
m_cReloc = (int16)LH(&m_pHeader->numReloc);
/* Allocate the relocation table */
if (m_cReloc)
{
m_pRelocTable = new dword[m_cReloc];
if (m_pRelocTable == 0)
{
printf("Could not allocate relocation table (%d entries)\n",
m_cReloc);
return 0;
}
fseek(fp, LH(&m_pHeader->relocTabOffset), SEEK_SET);
/* Read in seg:offset pairs and convert to Image ptrs */
for (i = 0; i < m_cReloc; i++)
{
fread(buf, 1, 4, fp);
m_pRelocTable[i] = LH(buf) +
(((int)LH(buf+2) + EXE_RELOCATION)<<4);
}
}
/* Seek to start of image */
fseek(fp, (int)LH(&m_pHeader->numParaHeader) * 16, SEEK_SET);
// Initial PC and SP. Note that we fake the seg:offset by putting
// the segment in the top half, and offset int he bottom
m_uInitPC = (LH(&m_pHeader->initCS) + EXE_RELOCATION) << 16 +
LH(&m_pHeader->initIP);
m_uInitSP = (LH(&m_pHeader->initSS) + EXE_RELOCATION) << 16 +
LH(&m_pHeader->initSP);
}
else
{ /* COM file
* In this case the load module size is just the file length
*/
fseek(fp, 0, SEEK_END);
cb = ftell(fp);
/* COM programs start off with an ORG 100H (to leave room for a PSP)
* This is also the implied start address so if we load the image
* at offset 100H addresses should all line up properly again.
*/
m_uInitPC = 0x100;
m_uInitSP = 0xFFFE;
m_cReloc = 0;
fseek(fp, 0, SEEK_SET);
}
/* Allocate a block of memory for the image. */
m_cbImage = cb + sizeof(PSP);
m_pImage = new byte[m_cbImage];
m_pImage[0] = 0xCD; /* Fill in PSP int 20h location */
m_pImage[1] = 0x20; /* for termination checking */
/* Read in the image past where a PSP would go */
#ifdef __DOSWIN__
if (cb > 0xFFFF)
{
printf("Image size of %ld bytes too large for fread!\n", cb);
return 0;
}
#endif
if (cb != (int)fread(m_pImage + sizeof(PSP), 1, (size_t)cb, fp))
{
printf("Cannot read file %s\n", sName);
return 0;
}
/* Relocate segment constants */
if (m_cReloc)
{
for (i = 0; i < m_cReloc; i++)
{
byte *p = &m_pImage[m_pRelocTable[i]];
word w = (word)LH(p) + EXE_RELOCATION;
*p++ = (byte)(w & 0x00FF);
*p = (byte)((w & 0xFF00) >> 8);
}
}
fclose(fp);
m_pSections[0].pSectionName = "$HEADER"; // Special header section
m_pSections[0].fSectionFlags = ST_HEADER;
m_pSections[0].uNativeAddr = 0; // Not applicable
m_pSections[0].uHostAddr = (unsigned)m_pHeader;
m_pSections[0].uSectionSize = sizeof(HEADER);
m_pSections[0].uSectionEntrySize = 1; // Not applicable
m_pSections[1].pSectionName = ".text"; // The text and data section
m_pSections[1].fSectionFlags = ST_CODE | ST_DATA | ST_PRIMARY;
m_pSections[1].uNativeAddr = 0x00100000; // x86 address 0010:0000
m_pSections[1].uHostAddr = (unsigned)m_pImage;
m_pSections[1].uSectionSize = m_cbImage;
m_pSections[1].uSectionEntrySize = 1; // Not applicable
m_pSections[2].pSectionName = "$RELOC"; // Special relocation section
m_pSections[2].fSectionFlags = ST_RELOC; // Give it a special flag
m_pSections[2].uNativeAddr = 0; // Not applicable
m_pSections[2].uHostAddr = (unsigned)m_pRelocTable;
m_pSections[2].uSectionSize = sizeof(dword) * m_cReloc;
m_pSections[2].uSectionEntrySize = sizeof(dword);
return 1;
}
int ExeLoader::GetNextPart()
{
// Never another part
return 0;
}
// Clean up and unload the binary image
void ExeLoader::UnLoad()
{
if (m_pHeader) delete m_pHeader;
if (m_pImage) delete [] m_pImage;
if (m_pRelocTable) delete [] m_pRelocTable;
}