home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
DP Tool Club 24
/
CD_ASCQ_24_0995.iso
/
dos
/
prg
/
dsik205
/
dsik.dat
/
SOURCE
/
PE.C
< prev
next >
Wrap
C/C++ Source or Header
|
1995-04-10
|
11KB
|
362 lines
/****************************************************************************
*
* Digital Sound Interface Kit (DSIK)
* Version 2.00
*
* by Carlos Hasan
*
* Filename: pe.c
* Version: Revision 1.0 (EXPERIMENTAL)
*
* Language: WATCOM C
* Environment: IBM PC (DOS/4GW)
*
* Description: Portable Executable (PE) Dynamic Link Library loader.
*
* Revision History:
* ----------------
*
* Revision 1.0 94/12/18 14:33:14 chv
* Initial revision
*
****************************************************************************/
#include <io.h>
#include <fcntl.h>
#include <malloc.h>
#include <string.h>
#include <stdio.h>
#include "audio.h"
#include "pe.h"
/*#define DEBUG*/
#ifdef DEBUG
#define DBG0(fmt) printf("LOADER: "fmt)
#define DBG1(fmt,a) printf("LOADER: "fmt,a)
#define DBG2(fmt,a,b) printf("LOADER: "fmt,a,b)
#else
#define DBG0(fmt)
#define DBG1(fmt,a)
#define DBG2(fmt,a,b)
#endif
/****************************************************************************
*
* Function: dGetLibrarySection
* Parameters: Pe - PE library handler
* Name - section name
*
* Returns: PE section header address or NULL if error.
*
* Description: This routine will search the specified section structure
* by name. It returns NULL if the section is not found.
*
****************************************************************************/
static PESCN *dGetLibrarySection(HANDLE Pe, char *Name)
{
int I;
DBG1("searching section %s.\n",Name);
for (I = 0; I < Pe->Hdr.NumScns; I++)
if (!strcmp(Name,Pe->Scn[I].Name))
return &Pe->Scn[I];
return NULL;
}
/****************************************************************************
*
* Function: dGetLinearAddress
* Parameters: Pe - PE library handler
* VAddr - virtual address
*
* Returns: Linear address or NULL if address does not exist.
*
* Description: This routine translates relative virtual addresses (RVA)
* to actual linear addresses. If the RVA is not found within
* the module virtual space then it returns NULL.
*
****************************************************************************/
static DWORD dGetLinearAddress(HANDLE Pe, DWORD VAddr)
{
PESCN *Scn;
int I;
for (I = 0, Scn = Pe->Scn; I < Pe->Hdr.NumScns; I++, Scn++)
if (VAddr >= Scn->VAddr && VAddr < (Scn->VAddr+Scn->Size))
return VAddr+Scn->PAddr-Scn->VAddr;
return 0L;
}
/****************************************************************************
*
* Function: dRelocateLibrary
* Parameters: Pe - PE library handler
*
* Description: This routine performs the fixups or relocations of the
* dynamic link library. Must be called when the module
* is loaded from disk.
*
****************************************************************************/
static HANDLE dRelocateLibrary(HANDLE Pe)
{
PESCN *Scn;
PERLC *Rlc;
DWORD PagePtr;
WORD *TypePtr;
DWORD *TargetPtr;
int I;
DBG0("relocating DLL library core.\n");
if (!(Scn = dGetLibrarySection(Pe,PE_RELOC))) {
DBG0("relocation section not found.\n");
return Pe;
}
Rlc = (PERLC*)Scn->PAddr;
while (Rlc->VAddr && Scn->Size) {
DBG2("vaddr: 0x%08lx size: 0x%08lx\n",Rlc->VAddr,Rlc->Size);
Scn->Size -= Rlc->Size;
PagePtr = Rlc->VAddr;
TypePtr = Rlc->Type;
Rlc = (PERLC*)((BYTE*)Rlc+Rlc->Size);
if (!(PagePtr = dGetLinearAddress(Pe,PagePtr))) {
DBG0("relocation target page not found!\n");
continue;
}
while (TypePtr < (WORD*)Rlc) {
if (((I = *TypePtr++) & PE_R_MASK) != PE_R_HIGHLOW) {
DBG0("ERROR: skipping relocation!\n");
continue;
}
TargetPtr = (DWORD*)(PagePtr+(I & PE_R_OFFMASK));
*TargetPtr -= Pe->NtHdr.ImageBase;
DBG2("offset: 0x%04lx target: 0x%08lx\n",
(I & PE_R_OFFMASK),*TargetPtr);
if (!(*TargetPtr = dGetLinearAddress(Pe,*TargetPtr))) {
DBG0("target address not found!\n");
}
}
DBG0("\n");
}
return Pe;
}
/****************************************************************************
*
* Function: dGetProcAddress
* Parameters: Pe - PE library handler
* Name - procedure name
*
* Returns: Procedure address or NULL if not found.
*
* Description: This routine returns the address of the specified exported
* procedure name. It returns NULL if the procedure is not
* found in the export directory of the module.
*
****************************************************************************/
FARPROC dGetProcAddress(HANDLE Pe, char *Name)
{
PESCN *Scn;
PEEXP *Exp;
DWORD *NamePtr,*FuncPtr,ProcName,ProcAddr;
int I;
DBG1("searching export procedure '%s'.\n",Name);
if (!(Scn = dGetLibrarySection(Pe,PE_EDATA))) {
DBG0("export section not found!\n");
return NULL;
}
Exp = (PEEXP*)Scn->PAddr;
DBG2("DLL module '%s', %d functions.\n",
(char*)dGetLinearAddress(Pe,Exp->NamePtr), Exp->NumFuncs);
NamePtr = (DWORD*)((BYTE*)Exp+(Exp->NameTabPtr-Scn->VAddr));
FuncPtr = (DWORD*)((BYTE*)Exp+(Exp->FuncTabPtr-Scn->VAddr));
for (I = 0; I < Exp->NumFuncs; I++) {
ProcName = *NamePtr++;
ProcAddr = *FuncPtr++;
if (!(ProcName = dGetLinearAddress(Pe,ProcName))) {
DBG0("ERROR: procedure name address not found!\n");
continue;
}
DBG2("vaddr: 0x%08lx name: %s\n", ProcAddr, (char*)ProcName);
if (!strcmp(Name,(char*)ProcName)) {
if (!(ProcAddr = dGetLinearAddress(Pe,ProcAddr))) {
DBG0("ERROR: entry point not found!\n");
}
return (FARPROC)ProcAddr;
}
}
DBG0("procedure not found!\n");
return NULL;
}
/****************************************************************************
*
* Function: dLoadLibrary
* Parameters: Filename - PE dynamic link library path name
*
* Returns: PE dynamic link library handler or NULL if error.
*
* Description: This routine load Portable Executable (PE) dynamic link
* libraries from disk. This loader is not complete and have
* not been fully tested yet.
*
****************************************************************************/
HANDLE dLoadLibrary(char *Filename)
{
DOSHDR DosHdr;
HANDLE Pe;
PESCN *Scn;
int Handle,I;
DBG0("opening DLL library file.\n");
if ((Handle = open(Filename,O_RDONLY|O_BINARY)) < 0)
return NULL;
if (!(Pe = (HANDLE)calloc(1,sizeof(PEDLL)))) {
close(Handle);
return NULL;
}
DBG0("reading MS-DOS executable header.\n");
if (read(Handle,&DosHdr,sizeof(DosHdr)) != sizeof(DosHdr)) {
dFreeLibrary(Pe);
close(Handle);
return NULL;
}
if (DosHdr.Magic != DOS_MAGIC ||
lseek(Handle,DosHdr.NewHdrPtr,SEEK_SET) < 0) {
dFreeLibrary(Pe);
close(Handle);
return NULL;
}
DBG0("reading PE executable headers.\n");
if (read(Handle,&Pe->Hdr,sizeof(PEHDR)) != sizeof(PEHDR)) {
dFreeLibrary(Pe);
close(Handle);
return NULL;
}
if (read(Handle,&Pe->NtHdr,sizeof(PENTHDR)) != sizeof(PENTHDR)) {
dFreeLibrary(Pe);
close(Handle);
return NULL;
}
if (Pe->Hdr.Magic != PE_MAGIC || Pe->Hdr.Machine != PE_M_I386 ||
!(Pe->Hdr.Flags & PE_F_DLL) || !(Pe->Hdr.Flags & PE_F_EXEC) ||
!(Pe->Hdr.Flags & PE_F_AR32WR) ||
lseek(Handle,Pe->Hdr.NtHdrSize-sizeof(PENTHDR),SEEK_CUR) < 0) {
dFreeLibrary(Pe);
close(Handle);
return NULL;
}
DBG0("reading PE section headers.\n");
if (!(Pe->Scn = (PESCN*)calloc(Pe->Hdr.NumScns,sizeof(PESCN)))) {
dFreeLibrary(Pe);
close(Handle);
return NULL;
}
if (read(Handle,Pe->Scn,Pe->Hdr.NumScns*sizeof(PESCN)) !=
Pe->Hdr.NumScns*sizeof(PESCN)) {
memset(Pe->Scn,0,Pe->Hdr.NumScns*sizeof(PESCN));
dFreeLibrary(Pe);
close(Handle);
return NULL;
}
DBG0("reading PE section images.\n");
for (I = 0; I < Pe->Hdr.NumScns; I++)
Pe->Scn[I].PAddr = 0;
for (I = 0, Scn = Pe->Scn; I < Pe->Hdr.NumScns; I++, Scn++) {
DBG2("reading PE section '%s' (0x%08lx bytes)\n",
Scn->Name, Scn->Size);
if (!Scn->Size)
continue;
if (!(Scn->PAddr = (DWORD)malloc(Scn->Size))) {
dFreeLibrary(Pe);
close(Handle);
return NULL;
}
if (lseek(Handle,Scn->ScnPtr,SEEK_SET) < 0) {
dFreeLibrary(Pe);
close(Handle);
return NULL;
}
if (read(Handle,(void*)Scn->PAddr,Scn->Size) != Scn->Size) {
dFreeLibrary(Pe);
close(Handle);
return NULL;
}
}
DBG0("closing DLL library file.\n");
close(Handle);
return dRelocateLibrary(Pe);
}
/****************************************************************************
*
* Function: dFreeLibrary
* Parameters: Pe - PE library handler
*
* Description: This routine releases the memory used by PE DLL modules.
*
****************************************************************************/
void dFreeLibrary(HANDLE Pe)
{
int I;
DBG0("releasing DLL library from memory.\n");
if (Pe) {
if (Pe->Scn) {
for (I = 0; I < Pe->Hdr.NumScns; I++)
if (Pe->Scn[I].PAddr) free((void*)Pe->Scn[I].PAddr);
free(Pe->Scn);
}
free(Pe);
}
}
/****************************************************************************
*
* Function: dLoadDriver
* Parameters: SC - soundcard structure
*
* Returns: Audio Driver structure or NULL if error.
*
* Description: Used to load dynamic link audio drivers from disk. It uses
* the Portable Executable (PE) dynamic link loader.
*
****************************************************************************/
Driver *dLoadDriver(SoundCard *SC)
{
HANDLE H;
FARPROC DrvProc;
Driver *DrvPtr;
if (!(DrvPtr = dGetDriverStruc(SC->ID))) {
if (!(H = dLoadLibrary(SC->DriverName)))
return NULL;
if (!(DrvProc = dGetProcAddress(H,"DriverProc"))) {
dFreeLibrary(H);
return NULL;
}
DrvPtr = (Driver*)(*DrvProc)();
}
return DrvPtr;
}