Files
harbour-core/harbour/source/compiler/genobj32.c
Antonio Linares 4709c9cc08 _parinfa() support
1999-05-14 10:35:55 +00:00

691 lines
17 KiB
C

#include <stdio.h>
#include <string.h>
#include <types.h>
#include <compiler.h>
#include <extend.h>
#include <pcode.h>
static void CompiledFileName( FILE * hObjFile, char * szFileName );
static void CompilerVersion( FILE * hObjFile, char * szVersion );
static void LocalNames( FILE * hObjFile, char * szNames[] );
static void ExternalNames( FILE * hObjFile, char * szNames[] );
static void Fixup( FILE * hObjFile, BYTE bType, WORD wOffset, BYTE bFlags, BYTE bSymbol );
static void DefineSegment( FILE * hObjFile, BYTE bName, BYTE bClass, WORD wLen );
static void PubDef( FILE * hObjFile, char * szName, WORD wSegment, WORD wOffset );
static void EnumeratedData( FILE * hObjFile, BYTE bSegment, BYTE * pData, WORD wLen, WORD wOffset );
static void GroupDef( FILE * hObjFile, BYTE bName, BYTE * aSegs );
static void End( FILE * hObjFile );
static void CodeSegment( FILE * hObjFile, BYTE * prgCode, ULONG ulPrgLen,
WORD wFunctions );
static void DataSegment( FILE * hObjFile, BYTE * symbol, WORD wSymLen,
WORD wSymbols, ULONG ulTotalSize );
static void GenerateLocalNames( FILE * hObjFile );
static void GenerateExternals( FILE * hObjFile );
static void GenerateCodeSegment( FILE * hObjFile );
static void GenerateDataSegment( FILE * hObjFile );
static void GenerateSymbolsSegment( FILE * hObjFile );
extern FUNCTIONS functions, funcalls;
extern SYMBOLS symbols;
extern int _iQuiet, _iStartProc;
static BYTE prgFunction[] = { 0x68, 0x00, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00,
0x00, 0xE8, 0x00, 0x00, 0x00, 0x00, 0x83, 0xC4, 0x08, 0xC3 };
static char * * externNames = 0;
WORD wExternals = 1; /* _VirtualMachine is always added */
void GenObj32( char * szObjFileName, char * szFileName )
{
FILE * hObjFile; /* file handle for OBJ output */
if( ! ( hObjFile = fopen( szObjFileName, "wb" ) ) )
{
printf( "Error opening file %s\n", szObjFileName );
return;
}
if( ! _iQuiet )
printf( "\ngenerating Windows/Dos OBJ 32 bits..." );
CompiledFileName( hObjFile, szFileName );
CompilerVersion( hObjFile, "Harbour" );
GenerateLocalNames( hObjFile );
GenerateExternals( hObjFile );
GenerateCodeSegment( hObjFile );
GenerateDataSegment( hObjFile );
GenerateSymbolsSegment( hObjFile );
End( hObjFile );
fclose( hObjFile );
if( ! _iQuiet )
printf( "\n%s -> done!\n", szObjFileName );
}
static ULONG GetSymbolsSize( void )
{
return ( symbols.iCount - ( _iStartProc ? 0: 1 ) ) * sizeof( SYMBOL );
}
static PCOMSYMBOL GetFirstSymbol( void )
{
PCOMSYMBOL pSymbol = symbols.pFirst;
if( ! _iStartProc )
pSymbol = pSymbol->pNext;
return pSymbol;
}
static char * GetSymbolName( ULONG ulPos )
{
PCOMSYMBOL pSymbol = GetFirstSymbol();
ULONG ul = 0;
while( pSymbol && ( ul++ < ulPos ) )
pSymbol = pSymbol->pNext;
return pSymbol->szName;
}
static ULONG GetPCodesSize( void )
{
ULONG ulTotal = 0;
PFUNCTION pFunction = functions.pFirst;
if( ! _iStartProc )
pFunction = pFunction->pNext;
while( pFunction )
{
ulTotal += pFunction->lPCodePos + 1; /* _ENDPROC !!! */
pFunction = pFunction->pNext;
}
return ulTotal;
}
ULONG GetSymbolsAmount( void )
{
PCOMSYMBOL pSymbol = GetFirstSymbol();
ULONG ulAmount = 1;
while( pSymbol->pNext )
{
ulAmount++;
pSymbol = pSymbol->pNext;
}
return ulAmount;
}
BOOL IsExternal( ULONG ulSymbol )
{
PCOMSYMBOL pSymbol = GetFirstSymbol();
ULONG ul = 0;
while( ul++ < ulSymbol )
pSymbol = pSymbol->pNext;
return ! GetFunction( pSymbol->szName );
}
WORD GetExternalPos( char * szExternal )
{
WORD w = 0;
while( w < wExternals )
{
if( ! strcmp( szExternal, externNames[ w ] ) )
break;
w++;
}
return w;
}
static void GenerateLocalNames( FILE * hObjFile )
{
char * localNames[] = { "_TEXT", "CODE", "_DATA", "DATA",
"HB_SYMBOLS", "HB_STARTSYMBOLS", "HB_ENDSYMBOLS", "SYMGROUP", 0 };
LocalNames( hObjFile, localNames );
}
static void GenerateSymbolsSegment( FILE * hObjFile )
{
BYTE symbolsData[] = { 0, 0, 0, 0, 0, 0 };
BYTE groupSegments[] = { 3, 4, 5, 0 }; /* segments order for HB_... */
DefineSegment( hObjFile, 7, 5, 0 ); /* 7 = HB_STARTSYMBOLS, 5 = DATA */
DefineSegment( hObjFile, 6, /* "HB_SYMBOLS" position + 1 into localNames */
5, /* "DATA" position + 1 into localNames */
6 ); /* segment length */
DefineSegment( hObjFile, 8, 5, 0 ); /* 8 = HB_ENDSYMBOLS, 5 = DATA */
GroupDef( hObjFile, 8, groupSegments ); /* 8 = "SYMGROUP" localNames position */
* ( WORD * ) symbolsData = GetSymbolsAmount();
EnumeratedData( hObjFile, 4, symbolsData, sizeof( symbolsData ), 0 ); /* 4 = HB_SYMBOLS defined segment */
Fixup( hObjFile, 0xE4, 2, 0x54, 2 ); /* Data: symbols location */
}
static void GenerateDataSegment( FILE * hObjFile )
{
SYMBOL symbol;
ULONG ulSize = GetSymbolsSize();
PCOMSYMBOL pSymbol = GetFirstSymbol();
ULONG ulSymbols = GetSymbolsAmount(), ul;
while( pSymbol )
{
ulSize += strlen( pSymbol->szName ) + 1;
pSymbol = pSymbol->pNext;
}
ulSize += GetPCodesSize();
DefineSegment( hObjFile, 4, /* "_DATA" position + 1 into localNames */
5, /* "DATA" position + 1 into localNames */
ulSize ); /* segment length */
memset( &symbol, 0, sizeof( symbol ) );
DataSegment( hObjFile, (BYTE *) &symbol,
sizeof( symbol ), GetSymbolsAmount(), ulSize );
pSymbol = GetFirstSymbol();
for( ul = 0; ul < ulSymbols; ul++ )
{
Fixup( hObjFile, 0xE4, ( ul * sizeof( SYMBOL ) ), 0x54, 2 ); /* Data symbol name location */
if( IsExternal( ul ) )
{
if( ! ( pSymbol->cScope & FS_MESSAGE ) )
Fixup( hObjFile, 0xE4, ( ul * sizeof( SYMBOL ) ) + 5, 0x56,
GetExternalPos( GetSymbolName( ul ) ) + 1 );
}
else
{
/* if( ! ( pSymbol->cScope & FS_MESSAGE ) ) */
Fixup( hObjFile, 0xE4, ( ul * sizeof( SYMBOL ) ) + 5, 0x54, 1 ); /* function address location */
}
pSymbol = pSymbol->pNext;
}
}
static void GenerateCodeSegment( FILE * hObjFile )
{
WORD wFunctions = functions.iCount - ( _iStartProc ? 0: 1 );
ULONG ulSize = wFunctions * sizeof( prgFunction );
PFUNCTION pFunc = ( _iStartProc ? functions.pFirst: functions.pFirst->pNext );
WORD w = 0;
DefineSegment( hObjFile, 2, /* "_TEXT" position + 1 into localNames */
3, /* "CODE" position + 1 into localNames */
ulSize ); /* segment length */
while( pFunc )
{
if( !( pFunc->cScope & ( FS_STATIC | FS_INIT | FS_EXIT ) ) )
PubDef( hObjFile, pFunc->szName, 1, w * sizeof( prgFunction ) );
w++;
pFunc = pFunc->pNext;
}
CodeSegment( hObjFile, prgFunction, sizeof( prgFunction ), wFunctions );
for( w = 0; w < wFunctions; w++ )
{
/* prgFunction fixups */
Fixup( hObjFile, 0xE4, ( w * sizeof( prgFunction ) ) + 1,
0x54, 2 ); /* Data: symbols location */
Fixup( hObjFile, 0xE4, ( w * sizeof( prgFunction ) ) + 6,
0x54, 2 ); /* Data pcode location */
Fixup( hObjFile, 0xA4, ( w * sizeof( prgFunction ) ) + 11,
0x56, 1 ); /* External: _VirtualMachine */
}
}
static void GenerateExternals( FILE * hObjFile )
{
WORD w;
PFUNCTION pFunc, pFTemp;
/* calculate amount of externals */
pFunc = funcalls.pFirst;
while( pFunc )
{
if( ! ( pFTemp = GetFunction( pFunc->szName ) ) || pFTemp == functions.pFirst )
wExternals++;
pFunc = pFunc->pNext;
}
if( wExternals )
{
externNames = ( char * * ) OurMalloc( sizeof( char * ) * ( wExternals + 2 ) );
w = 1;
externNames[ 0 ] = "_VirtualMachine";
pFunc = funcalls.pFirst;
while( pFunc )
{
if( ! ( pFTemp = GetFunction( pFunc->szName ) ) || pFTemp == functions.pFirst )
externNames[ w++ ] = pFunc->szName;
pFunc = pFunc->pNext;
}
externNames[ w ] = 0;
ExternalNames( hObjFile, externNames );
}
}
static void putbyte( BYTE b, FILE * hObjFile )
{
fputc( b, hObjFile );
}
void putword( WORD w, FILE * hObjFile )
{
putbyte( LOBYTE( w ), hObjFile );
putbyte( HIBYTE( w ), hObjFile );
}
static void CompiledFileName( FILE * hObjFile, char * szFileName )
{
WORD wLen = strlen( szFileName );
BYTE bChk = 0; /* this is a checksum the linker will check to asure OBJ integrity */
BYTE bChar;
putbyte( 0x80, hObjFile ); /* this tells the linker the kind of OBJ record this is */
bChk += 0x80;
putbyte( 1 + 1 + wLen, hObjFile ); /* now it comes the total length of this OBJ record */
bChk += ( 1 + 1 + wLen );
putbyte( 0, hObjFile );
putbyte( wLen, hObjFile ); /* szFileName length */
bChk += wLen;
while( (bChar = * szFileName++) )
{
putbyte( bChar, hObjFile ); /* each of the szFileName characters */
bChk += bChar;
}
putbyte( 256 - bChk, hObjFile ); /* a checksum that will be recalculated by the linker */
}
static void CompilerVersion( FILE * hObjFile, char * szVersion )
{
WORD wLen = strlen( szVersion );
BYTE bChk = 0; /* this is a checksum the linker will check to asure OBJ integrity */
BYTE bChar;
putbyte( 0x88, hObjFile ); /* this tells the linker the kind of OBJ record this is */
bChk += 0x88;
putword( 3 + wLen, hObjFile ); /* now it comes the total length of this OBJ record */
bChk += LOBYTE( 3 + wLen );
bChk += HIBYTE( 3 + wLen );
putword( 0, hObjFile );
while( (bChar = * szVersion++) )
{
putbyte( bChar, hObjFile ); /* each of the szFileName characters */
bChk += bChar;
}
putbyte( 256 - bChk, hObjFile ); /* a checksum that will be recalculated by the linker */
}
static void LocalNames( FILE * hObjFile, char * szNames[] )
{
BYTE b = 0, c;
WORD wTotalLen = 0;
BYTE bChk = 0;
while( szNames[ b ] )
wTotalLen += strlen( szNames[ b++ ] );
wTotalLen += 2 + b;
putbyte( 0x96, hObjFile );
bChk += 0x96;
putbyte( LOBYTE( wTotalLen ), hObjFile );
bChk += LOBYTE( wTotalLen );
putbyte( HIBYTE( wTotalLen ), hObjFile );
bChk += HIBYTE( wTotalLen );
putbyte( 0, hObjFile );
b = 0;
while( szNames[ b ] )
{
putbyte( strlen( szNames[ b ] ), hObjFile );
bChk += strlen( szNames[ b ] );
c = 0;
while( szNames[ b ][ c ] )
{
putbyte( szNames[ b ][ c ], hObjFile );
bChk += szNames[ b ][ c++ ];
}
b++;
}
putbyte( 256 - bChk, hObjFile );
}
static void ExternalNames( FILE * hObjFile, char * szNames[] )
{
BYTE b = 0, c;
WORD wTotalLen = 0;
BYTE bChk = 0;
while( szNames[ b ] )
wTotalLen += strlen( szNames[ b++ ] ) + 1;
wTotalLen += 2 + b - 1;
putbyte( 0x8C, hObjFile );
bChk += 0x8C;
putword( wTotalLen, hObjFile );
bChk += LOBYTE( wTotalLen );
bChk += HIBYTE( wTotalLen );
b = 0;
while( szNames[ b ] )
{
putbyte( strlen( szNames[ b ] ), hObjFile );
bChk += strlen( szNames[ b ] );
c = 0;
while( szNames[ b ][ c ] )
{
putbyte( szNames[ b ][ c ], hObjFile );
bChk += szNames[ b ][ c++ ];
}
putbyte( 0, hObjFile );
b++;
}
putbyte( 256 - bChk, hObjFile );
}
static void CodeSegment( FILE * hObjFile, BYTE * prgCode, ULONG ulPrgLen, WORD wFunctions )
{
BYTE bCheckSum = 0;
WORD y;
WORD wTotalLen = ( ulPrgLen * wFunctions ) + 4;
ULONG ul;
PFUNCTION pFunction = functions.pFirst;
ULONG ulPCodeOffset = ( symbols.iCount - ( _iStartProc ? 0: 1 ) ) * sizeof( SYMBOL );
if( ! _iStartProc )
pFunction = pFunction->pNext;
putbyte( 0xA0, hObjFile );
bCheckSum += 0xA0;
putword( wTotalLen, hObjFile );
bCheckSum += LOBYTE( wTotalLen );
bCheckSum += HIBYTE( wTotalLen );
putbyte( 1, hObjFile ); /* 1 = _TEXT segment */
bCheckSum += 1;
putword( 0, hObjFile ); /* 0 = offset */
for( y = 0; y < wFunctions; y++ )
{
* ( ULONG * ) &prgCode[ 6 ] = ulPCodeOffset; /* function pcode offset */
for( ul = 0; ul < ulPrgLen; ul++ )
{
putbyte( * ( prgCode + ul ), hObjFile );
bCheckSum += * ( prgCode + ul );
}
ulPCodeOffset += pFunction->lPCodePos + 1; /* _ENDPROC !!! */
pFunction = pFunction->pNext;
}
putbyte( 256 - bCheckSum, hObjFile );
}
static void DataSegment( FILE * hObjFile, BYTE * symbol, WORD wSymLen, WORD wSymbols,
ULONG ulSize )
{
BYTE bCheckSum = 0;
WORD w, y;
WORD wTotalLen = 4 + ulSize;
PCOMSYMBOL pSymbol = GetFirstSymbol();
PFUNCTION pFunction = functions.pFirst;
ULONG ulSymbolNameOffset = GetSymbolsSize() + GetPCodesSize();
ULONG ulFunctionOffset;
if( ! _iStartProc )
pFunction = pFunction->pNext;
putbyte( 0xA0, hObjFile );
bCheckSum += 0xA0;
putword( wTotalLen, hObjFile );
bCheckSum += LOBYTE( wTotalLen );
bCheckSum += HIBYTE( wTotalLen );
putbyte( 2, hObjFile ); /* 2 = _DATA segment */
bCheckSum += 2;
putword( 0, hObjFile ); /* 0 = offset */
for( y = 0; y < wSymbols; y++ )
{
* ( ULONG * ) symbol = ulSymbolNameOffset;
if( ! IsExternal( y ) )
{
ulFunctionOffset = ( GetFunctionPos( pSymbol->szName ) - 1 ) *
sizeof( prgFunction );
* ( ( ULONG * ) &symbol[ 5 ] ) = ulFunctionOffset;
}
else
* ( ( ULONG * ) &symbol[ 5 ] ) = 0;
if( pSymbol->cScope == FS_MESSAGE )
symbol[ 4 ] = FS_PUBLIC;
else
symbol[ 4 ] = pSymbol->cScope;
for( w = 0; w < wSymLen; w++ )
{
putbyte( * ( symbol + w ), hObjFile );
bCheckSum += * ( symbol + w );
}
ulSymbolNameOffset += strlen( pSymbol->szName ) + 1;
pSymbol = pSymbol->pNext;
}
while( pFunction )
{
for( w = 0; w < pFunction->lPCodePos; w++ )
{
putbyte( pFunction->pCode[ w ], hObjFile );
bCheckSum += pFunction->pCode[ w ];
}
putbyte( _ENDPROC, hObjFile );
bCheckSum += _ENDPROC;
pFunction = pFunction->pNext;
}
pSymbol = GetFirstSymbol();
while( pSymbol )
{
for( w = 0; w < ( WORD ) strlen( pSymbol->szName ); w++ )
{
putbyte( pSymbol->szName[ w ], hObjFile );
bCheckSum += pSymbol->szName[ w ];
}
putbyte( 0, hObjFile );
pSymbol = pSymbol->pNext;
}
putbyte( 256 - bCheckSum, hObjFile );
}
static void DefineSegment( FILE * hObjFile, BYTE bName, BYTE bClass, WORD wLen )
{
BYTE bCheckSum = 0;
putbyte( 0x98, hObjFile );
bCheckSum += 0x98;
putbyte( 7, hObjFile ); /* SegDef records have always this length */
bCheckSum += 7;
putbyte( 0, hObjFile );
putbyte( 0xA9, hObjFile );
bCheckSum += 0xA9;
putword( wLen, hObjFile );
bCheckSum += LOBYTE( wLen );
bCheckSum += HIBYTE( wLen );
putbyte( bName, hObjFile );
bCheckSum += bName;
putbyte( bClass, hObjFile );
bCheckSum += bClass;
putbyte( 0, hObjFile );
putbyte( 256 - bCheckSum, hObjFile );
}
static void PubDef( FILE * hObjFile, char * szName, WORD wSegment, WORD wOffset )
{
BYTE bChk = 0;
BYTE bChar;
WORD wLen = 2 + 2 + strlen( szName ) + 2 + 1;
putbyte( 0x90, hObjFile );
bChk += 0x90;
putword( wLen, hObjFile );
bChk += LOBYTE( wLen );
bChk += HIBYTE( wLen );
putbyte( 0x00, hObjFile );
putbyte( wSegment, hObjFile );
bChk += wSegment;
putbyte( strlen( szName ), hObjFile );
bChk += strlen( szName );
while( (bChar = * szName++) )
{
putbyte( bChar, hObjFile );
bChk += bChar;
}
putword( wOffset, hObjFile);
bChk += LOBYTE( wOffset );
bChk += HIBYTE( wOffset );
putbyte( 0x00, hObjFile );
putbyte( 256 - bChk, hObjFile );
}
static void Fixup( FILE * hObjFile, BYTE bType, WORD wOffset, BYTE bFlags, BYTE bSymbol )
{
BYTE bCheckSum = 0;
putbyte( 0x9D, hObjFile ); bCheckSum += 0x9D;
putword( 5, hObjFile ); bCheckSum += 5;
putbyte( bType + HIBYTE( wOffset ), hObjFile );
bCheckSum += bType + HIBYTE( wOffset );
putbyte( LOBYTE( wOffset ), hObjFile );
bCheckSum += LOBYTE( wOffset );
putbyte( bFlags, hObjFile ); bCheckSum += bFlags;
putbyte( bSymbol, hObjFile ); bCheckSum += bSymbol;
putbyte( 256 - bCheckSum, hObjFile );
}
static void EnumeratedData( FILE * hObjFile, BYTE bSegment, BYTE * pData, WORD wLen, WORD wOffset )
{
BYTE bCheckSum = 0;
WORD w;
putbyte( 0xA0, hObjFile );
bCheckSum += 0xA0;
putword( ( WORD ) ( wLen + 4 ), hObjFile );
bCheckSum += LOBYTE( wLen + 4 );
bCheckSum += HIBYTE( wLen + 4 );
putbyte( bSegment, hObjFile );
bCheckSum += bSegment;
putword( wOffset, hObjFile );
bCheckSum += wOffset;
for( w = 0; w < wLen; w++ )
{
putbyte( * ( pData + w ), hObjFile );
bCheckSum += * ( pData + w );
}
putbyte( 256 - bCheckSum, hObjFile );
}
static void End( FILE * hObjFile )
{
BYTE bChk = 0;
putbyte( 0x8A, hObjFile ); bChk += 0x8A;
putbyte( 0x02, hObjFile ); bChk += 0x02;
putbyte( 0x00, hObjFile );
putbyte( 0x00, hObjFile ); bChk += 0x00;
putbyte( 256 - bChk, hObjFile );
}
static void GroupDef( FILE * hObjFile, BYTE bName, BYTE * aSegs )
{
BYTE bCheckSum = 0;
WORD wRecLen = 2;
WORD w = 0;
while( aSegs[ w++ ] )
wRecLen += 2;
putbyte( 0x9A, hObjFile );
bCheckSum += 0x9A;
putword( wRecLen, hObjFile );
bCheckSum += LOBYTE( wRecLen );
bCheckSum += HIBYTE( wRecLen );
putbyte( bName + 1, hObjFile );
bCheckSum += bName + 1;
w = 0;
while( aSegs[ w ] )
{
putbyte( 0xFF, hObjFile );
bCheckSum += 0xFF;
putbyte( aSegs[ w ], hObjFile );
bCheckSum += aSegs[ w ];
w++;
}
putbyte( 256 - bCheckSum, hObjFile );
}