emu48-mirror/Sources/Emu48/SYMBFILE.C
Gwenhael Le Moine 8c29c1313b
2015-08-15: Updated to version 1.57
Signed-off-by: Gwenhael Le Moine <gwenhael.le.moine@gmail.com>
2024-03-19 23:35:30 +01:00

257 lines
6.3 KiB
C

/*
* symbfile.c
*
* This file is part of Emu48
*
* Copyright (C) 2008 Christoph Gießelink
*
*/
#include "pch.h"
#include "Emu48.h"
//################
//#
//# Saturn Object File Reading
//#
//################
#define RECORD_BLOCK 256 // block size
#define OS_RESOLVED 0x8000 // resolved symbol
#define OS_RELOCATABLE 0x4000 // relocatable symbol
#define SAT_ID "Saturn3" // saturn block header
#define SYMB_ID "Symb" // symbol block header
#define HASHENTRIES 199 // size of hash table
typedef struct _REFDATA
{
LPTSTR lpszName; // symbol name
DWORD dwAddr; // resolved address
struct _REFDATA* pNext;
} REFDATA, *PREFDATA;
static PREFDATA ppsBase[HASHENTRIES]; // base of symbol references (initialized with NULL)
static __inline DWORD GetHash(DWORD dwVal)
{
return dwVal % HASHENTRIES; // hash function
}
static DWORD GetBigEndian(LPBYTE pbyData, INT nSize)
{
DWORD dwVal = 0;
while (nSize-- > 0)
{
dwVal <<= 8;
dwVal += *pbyData++;
}
return dwVal;
}
//
// check if entry table is empty
//
BOOL RplTableEmpty(VOID)
{
DWORD i;
BOOL bEmpty = TRUE;
// check if hash table is empty
for (i = 0; bEmpty && i < ARRAYSIZEOF(ppsBase); ++i)
{
bEmpty = (ppsBase[i] == NULL); // check if empty
}
return bEmpty;
}
//
// load entry table
//
BOOL RplLoadTable(LPCTSTR lpszFilename)
{
BYTE byPage[RECORD_BLOCK]; // record page size
HANDLE hFile;
DWORD dwFileLength,dwCodeLength,dwNoSymbols,dwNoReferences;
DWORD dwFilePos,dwBytesRead,dwSymb,dwPageIndex,dwResolvedSymb;
BOOL bSymbol,bSucc;
bSucc = FALSE;
hFile = CreateFile(lpszFilename,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_FLAG_SEQUENTIAL_SCAN,NULL);
if (hFile != INVALID_HANDLE_VALUE)
{
dwResolvedSymb = 0; // no resolved symbols added
bSymbol = TRUE; // next set is a symbol
// read first page
ReadFile(hFile,byPage,sizeof(byPage),&dwBytesRead,NULL);
if (dwBytesRead == sizeof(byPage) && memcmp(byPage,SAT_ID,7) == 0)
{
// file length in bytes
dwFileLength = GetBigEndian(byPage+7,sizeof(WORD)) * sizeof(byPage);
// code area in nibbles
dwCodeLength = GetBigEndian(byPage+9,sizeof(DWORD));
// no. of symbols & references
dwNoSymbols = GetBigEndian(byPage+13,sizeof(WORD));
// no. of references
dwNoReferences = GetBigEndian(byPage+15,sizeof(WORD));
// convert code area length into no. of pages
dwPageIndex = (dwCodeLength + (2 * sizeof(byPage) - 1)) / (2 * sizeof(byPage));
// calculate no. of code pages
dwFilePos = dwPageIndex * sizeof(byPage);
// jump to begin of symbols by skipping no. of code pages
bSucc = SetFilePointer(hFile,dwFilePos,NULL,FILE_CURRENT) != INVALID_SET_FILE_POINTER;
dwFilePos += sizeof(byPage); // actual file position
}
// read all symbol pages
for (dwPageIndex = 256, dwSymb = 0; bSucc && dwSymb < dwNoSymbols; dwPageIndex += 42)
{
if (dwPageIndex >= 256) // read complete page
{
// read new symbol page
ReadFile(hFile,byPage,sizeof(byPage),&dwBytesRead,NULL);
dwFilePos += dwBytesRead; // update file position
if ( dwFilePos > dwFileLength
|| dwBytesRead != sizeof(byPage)
|| memcmp(byPage,SYMB_ID,4) != 0)
{
bSucc = FALSE;
break;
}
dwPageIndex = 4; // begin of new symbol
}
if (bSymbol) // this is the 42 byte symbol set
{
WORD wSymbolType = (WORD) GetBigEndian(byPage+dwPageIndex+36,sizeof(WORD));
// check if it's a resolved or relocatable symbol
bSymbol = (wSymbolType & OS_RESOLVED) != 0;
if (bSymbol) ++dwResolvedSymb; // added resolved symbol
if (wSymbolType == OS_RESOLVED) // resolved symbol type
{
TCHAR szSymbolName[36+1],*pcPtr;
PREFDATA pData;
DWORD dwHash;
#if defined _UNICODE
{
MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED,(LPCSTR)byPage+dwPageIndex,36,
szSymbolName,ARRAYSIZEOF(szSymbolName));
szSymbolName[36] = 0; // set EOS
}
#else
{
lstrcpyn(szSymbolName,(LPCSTR)byPage+dwPageIndex,ARRAYSIZEOF(szSymbolName));
}
#endif
// cut symbol name at first space character
if ((pcPtr = _tcschr(szSymbolName,_T(' '))) != NULL)
*pcPtr = 0; // set EOS
// allocate symbol memory
VERIFY(pData = (PREFDATA) malloc(sizeof(*pData)));
pData->lpszName = DuplicateString(szSymbolName);
pData->dwAddr = GetBigEndian(byPage+dwPageIndex+38,sizeof(DWORD));
// add to hash table
dwHash = GetHash(pData->dwAddr);
pData->pNext = ppsBase[dwHash];
ppsBase[dwHash] = pData;
}
++dwSymb; // got symbol
}
else // 42 byte fill reference
{
bSymbol = TRUE; // nothing to do, next is a symbol set
}
}
bSucc = bSucc && (dwFilePos <= dwFileLength)
&& (dwNoSymbols == (dwResolvedSymb + dwNoReferences));
CloseHandle(hFile);
}
if (!bSucc) RplDeleteTable(); // delete current table
return bSucc;
}
//
// delete entry table
//
VOID RplDeleteTable(VOID)
{
PREFDATA pData;
DWORD i;
// clear hash entries
for (i = 0; i < ARRAYSIZEOF(ppsBase); ++i)
{
while (ppsBase[i] != NULL) // walk through all datasets
{
pData = ppsBase[i]->pNext;
free(ppsBase[i]->lpszName);
free(ppsBase[i]);
ppsBase[i] = pData;
}
}
return;
}
//
// return name for given entry address
//
LPCTSTR RplGetName(DWORD dwAddr)
{
PREFDATA pData = ppsBase[GetHash(dwAddr)];
// walk through all datasets of hash entry
for (; pData != NULL; pData = pData->pNext)
{
if (pData->dwAddr == dwAddr) // found address
return pData->lpszName; // return symbol name
}
return NULL;
}
//
// return entry address for given name
//
BOOL RplGetAddr(LPCTSTR lpszName, DWORD *pdwAddr)
{
PREFDATA pData;
DWORD i;
// check for every dataset in hash table
for (i = 0; i < ARRAYSIZEOF(ppsBase); ++i)
{
// walk through all datasets of hash entry
for (pData = ppsBase[i]; pData != NULL; pData = pData->pNext)
{
// found symbol name
if (lstrcmp(lpszName,pData->lpszName) == 0)
{
*pdwAddr = pData->dwAddr; // return address
return FALSE; // found
}
}
}
return TRUE; // not found
}