/* * $Id$ */ /* * Harbour Project source code: * Harbour Portable Object (.HRB) file runner * * Copyright 1999 Matteo Baccan * Based on runlib.c of Eddie Runia * www - http://www.harbour-project.org * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this software; see the file COPYING. If not, write to * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, * Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/). * * As a special exception, the Harbour Project gives permission for * additional uses of the text contained in its release of Harbour. * * The exception is that, if you link the Harbour libraries with other * files to produce an executable, this does not by itself cause the * resulting executable to be covered by the GNU General Public License. * Your use of that executable is in no way restricted on account of * linking the Harbour library code into it. * * This exception does not however invalidate any other reasons why * the executable file might be covered by the GNU General Public License. * * This exception applies only to the code released by the Harbour * Project under the name Harbour. If you copy code from other * Harbour Project or Free Software Foundation releases into a copy of * Harbour, as the General Public License permits, the exception does * not apply to the code that you add in this way. To avoid misleading * anyone as to the status of such modified files, you must delete * this exception notice from them. * * If you write modifications of your own for Harbour, it is your choice * whether to permit this exception to apply to your modifications. * If you do not wish that, delete this exception notice. * */ #include "hbapi.h" #include "hbapiitm.h" #include "hbapierr.h" #include "hbapifs.h" #include "hbvm.h" #include "hbpcode.h" /* Specific define for java runner */ #include "hbrunj.h" /* TODO: Separate the loading/unloading and the caller functions, this way we could also call a specific function name from the .HRB file. This way we have basically reproduced the DLL functionality of Blinker. hnd := __hrbLoad( "MYHRB.HRB" ) IF hnd != 0 __hrbDo( hnd, "MYINITFUNC", par1, par2 ) funhnd := __hrbGetHnd( hnd, "MYINITFUNC" ) __hrbDoHnd( funhnd, par1, par2 ) __hrbUnLoad( hnd ) ENDIF */ /* TODO: Fill the error codes with valid ones (instead of 9999) */ /* TOFIX: Change this assembler hack to something standard and portable */ /* TODO: Change the fopen()/fread()/fclose() calls to hb_fs*() */ /* TOFIX: Fix the memory leak on error. */ /* NOTE: This is the assembler output from : hb_vmExecute( pcode, symbols ). */ /* #if INTEL32 */ static BYTE prgFunction[] = { 0x68, 0x00, 0x00, 0x00, 0x00, /* push offset pcode */ 0x68, 0x00, 0x00, 0x00, 0x00, /* push offset symbols */ 0xE8, 0x00, 0x00, 0x00, 0x00, /* call near relative hb_vmExecute */ 0x83, 0xC4, 0x08, /* add esp, 8 */ 0xC3 /* ret near */ }; /* #elseif INTEL16 */ /* #elseif MOTOROLA */ /* #elseif ... */ /* #endif */ typedef union { BYTE * pAsmData; /* The assembler bytes */ PHB_FUNC pFunPtr; /* The (dynamic) harbour function */ } ASM_CALL, * PASM_CALL; typedef struct { char * szName; /* Name of the function */ PASM_CALL pAsmCall; /* Assembler call */ BYTE * pCode; /* P-code */ } HB_DYNF, * PHB_DYNF; #define SYM_NOLINK 0 /* Symbol does not have to be linked */ #define SYM_FUNC 1 /* Defined function */ #define SYM_EXTERN 2 /* Prev. defined function */ #define SYM_NOT_FOUND 0xFFFFFFFF /* Symbol not found. FindSymbol */ static ULONG hb_hrbFindSymbol( char * szName, PHB_DYNF pDynFunc, ULONG ulLoaded ); static PASM_CALL hb_hrbAsmCreateFun( PHB_SYMB pSymbols, BYTE * pCode ); /* Create a dynamic function*/ static void hb_hrbAsmPatch( BYTE * pCode, ULONG ulOffset, void * Address ); static void hb_hrbAsmPatchRelative( BYTE * pCode, ULONG ulOffset, void * Address, ULONG ulNext ); static void hb_hrbFileRead( char * file, char * cBuffer, int iSize, int iCount ); static BYTE hb_hrbFileReadByte( char * file ); static char * hb_hrbFileReadId( char * file ); static long hb_hrbFileReadLong( char * file ); static ULONG s_ulSymEntry = 0; /* Link enhancement */ JNIEXPORT jlong JNICALL Java_Harbour_Run( JNIEnv *env, jclass obj, jintArray pCode ) { ULONG ulSymbols; /* Number of symbols */ ULONG ulFuncs; /* Number of functions */ ULONG ulSize; /* Size of function */ ULONG ul, ulPos; PHB_SYMB pSymRead; /* Symbols read */ PHB_DYNF pDynFunc; /* Functions read */ PHB_DYNS pDynSym; int i; jlong bError = FALSE; jint* dmm = env->GetIntArrayElements( pCode, 0 ); int nPos = env->GetArrayLength( pCode ); char * file = (char*)hb_xgrab( nPos ); while( nPos>0 ){ file[nPos-1] = (char)dmm[nPos-1]; nPos--; } env->ReleaseIntArrayElements( pCode, dmm, 0 ); /* initialize internal data structures */ hb_cmdargInit( __argc, __argv ); hb_vmInit( FALSE ); ulSymbols = hb_hrbFileReadLong( file ); pSymRead = ( PHB_SYMB ) hb_xgrab( ulSymbols * sizeof( HB_SYMB ) ); for( ul = 0; ul < ulSymbols; ul++ ) /* Read symbols in .HRB */ { pSymRead[ ul ].szName = hb_hrbFileReadId( file ); pSymRead[ ul ].cScope = hb_hrbFileReadByte( file ); pSymRead[ ul ].pFunPtr = ( PHB_FUNC ) ( ULONG ) hb_hrbFileReadByte( file ); pSymRead[ ul ].pDynSym = NULL; } ulFuncs = hb_hrbFileReadLong( file ); /* Read number of functions */ pDynFunc = ( PHB_DYNF ) hb_xgrab( ulFuncs * sizeof( HB_DYNF ) ); for( ul = 0; ul < ulFuncs; ul++ ) /* Read symbols in .HRB */ { pDynFunc[ ul ].szName = hb_hrbFileReadId( file ); ulSize = hb_hrbFileReadLong( file ); /* Read size of function */ pDynFunc[ ul ].pCode = ( BYTE * ) hb_xgrab( ulSize ); hb_hrbFileRead( file, ( char * ) pDynFunc[ ul ].pCode, 1, ulSize ); /* Read the block */ pDynFunc[ ul ].pAsmCall = hb_hrbAsmCreateFun( pSymRead, pDynFunc[ ul ].pCode ); /* Create matching dynamic */ /* function */ } s_ulSymEntry = 0; for( ul = 0; ul < ulSymbols; ul++ ) /* Linker */ { if( ( ( ULONG ) pSymRead[ ul ].pFunPtr ) == SYM_FUNC ) { ulPos = hb_hrbFindSymbol( pSymRead[ ul ].szName, pDynFunc, ulFuncs ); if( ulPos != SYM_NOT_FOUND ) { /* Exists and NOT static ? */ /* if( hb_dynsymFind( pSymRead[ ul ].szName ) && !( pSymRead[ ul ].cScope & FS_STATIC ) ) { hb_errRT_BASE( EG_ARG, 9999, "Duplicate symbol", pSymRead[ ul ].szName ); bError = TRUE; break; } */ pSymRead[ ul ].pFunPtr = pDynFunc[ ulPos ].pAsmCall->pFunPtr; } else pSymRead[ ul ].pFunPtr = ( PHB_FUNC ) SYM_EXTERN; } if( ( ( ULONG ) pSymRead[ ul ].pFunPtr ) == SYM_EXTERN ) { /* External function */ pDynSym = hb_dynsymFind( pSymRead[ ul ].szName ); if( !pDynSym ) { hb_errRT_BASE( EG_ARG, 9999, "Unknown or unregistered symbol", pSymRead[ ul ].szName, 0 ); bError = TRUE; break; } pSymRead[ ul ].pFunPtr = pDynSym->pFunPtr; } } if( ! bError ) { PHB_ITEM pRetVal; hb_vmProcessSymbols( pSymRead, ( USHORT ) ulSymbols ); /* Initialize static variables first */ for( ul = 0; ul < ulSymbols; ul++ ) /* Check INIT functions */ { if( ( pSymRead[ ul ].cScope & HB_FS_INITEXIT ) == HB_FS_INITEXIT ) { /* call (_INITSTATICS) function. This function assigns * literal values to static variables only. There is no need * to pass any parameters to this function because they * cannot be used to initialize static variable. */ pSymRead[ ul ].pFunPtr(); } } for( ul = 0; ul < ulSymbols; ul++ ) /* Check INIT functions */ { if( ( pSymRead[ ul ].cScope & HB_FS_INITEXIT ) == HB_FS_INIT ) { hb_vmPushSymbol( pSymRead + ul ); hb_vmPushNil(); for( i = 0; i < ( hb_pcount() - 1 ); i++ ) hb_vmPush( hb_param( i + 2, HB_IT_ANY ) ); /* Push other cmdline params*/ hb_vmDo( hb_pcount() - 1 ); /* Run init function */ } } hb_vmPushSymbol( pSymRead ); hb_vmPushNil(); for( i = 0; i < ( hb_pcount() - 1 ); i++ ) hb_vmPush( hb_param( i + 2, HB_IT_ANY ) ); /* Push other cmdline params*/ hb_vmDo( hb_pcount() - 1 ); /* Run the thing !!! */ pRetVal = hb_itemNew( NULL ); hb_itemCopy( pRetVal, &hb_stack.Return ); for( ul = 0; ul < ulSymbols; ul++ ) /* Check EXIT functions */ { if( ( pSymRead[ ul ].cScope & HB_FS_INITEXIT ) == HB_FS_EXIT ) { hb_vmPushSymbol( pSymRead + ul ); hb_vmPushNil(); hb_vmDo( 0 ); /* Run exit function */ pSymRead[ ul ].cScope = pSymRead[ ul ].cScope & ( ~HB_FS_EXIT ); /* Exit function cannot be handled by main in hvm.c */ } } hb_itemReturn( pRetVal ); hb_itemRelease( pRetVal ); } for( ul = 0; ul < ulFuncs; ul++ ) { hb_xfree( pDynFunc[ ul ].pAsmCall->pAsmData ); hb_xfree( pDynFunc[ ul ].pAsmCall ); hb_xfree( pDynFunc[ ul ].pCode ); hb_xfree( pDynFunc[ ul ].szName ); } for( ul = 0; ul < ulSymbols; ul++ ) hb_xfree( pSymRead[ ul ].szName ); hb_xfree( pDynFunc ); hb_xfree( pSymRead ); hb_xfree(file); hb_vmQuit(); return bError; } static ULONG hb_hrbFindSymbol( char * szName, PHB_DYNF pDynFunc, ULONG ulLoaded ) { ULONG ulRet; if( ( s_ulSymEntry < ulLoaded ) && /* Is it a normal list ? */ !strcmp( szName, pDynFunc[ s_ulSymEntry ].szName ) ) ulRet = s_ulSymEntry++; else { BOOL bFound = FALSE; ulRet = 0; while( !bFound && ulRet < ulLoaded ) { if( !strcmp( szName, pDynFunc[ ulRet ].szName ) ) bFound = TRUE; else ulRet++; } if( !bFound ) ulRet = SYM_NOT_FOUND; } return ulRet; } /* ReadId Read the next (zero terminated) identifier */ static char * hb_hrbFileReadId( char * file ) { char * szTemp; /* Temporary buffer */ char * szIdx; char * szRet; BOOL bCont = TRUE; szTemp = ( char * ) hb_xgrab( 256 ); szIdx = szTemp; do { hb_hrbFileRead( file, szIdx, 1, 1 ); if( *szIdx ) szIdx++; else bCont = FALSE; } while( bCont ); szRet = ( char * ) hb_xgrab( szIdx - szTemp + 1 ); strcpy( szRet, szTemp ); hb_xfree( szTemp ); return szRet; } static BYTE hb_hrbFileReadByte( char * file ) { BYTE bRet; hb_hrbFileRead( file, ( char * ) &bRet, 1, 1 ); return bRet; } static long hb_hrbFileReadLong( char * file ) { char cLong[ 4 ]; /* Temporary long */ hb_hrbFileRead( file, cLong, 4, 1 ); return ( ( BYTE ) cLong[ 0 ] ) + ( ( BYTE ) cLong[ 1 ] ) * 0x100 + ( ( BYTE ) cLong[ 2 ] ) * 0x10000 + ( ( BYTE ) cLong[ 3 ] ) * 0x1000000 ; } /* hb_hrbFileRead Controlled read from file. If errornous -> Break */ static void hb_hrbFileRead( char * file, char * cBuffer, int iSize, int iCount ) { static long nPos = 0; long nChar = iSize*iCount; while( nChar>0 ){ cBuffer[nChar-1] = ((char*)file+nPos)[nChar-1]; nChar--; } nPos += iSize*iCount; } /* Create dynamic function. This function is needed, since it will allow the existing strategy of function pointers to work properly. For each Harbour function a little program calling the virtual machine should be present (see : *.c) Since these programs no longer exists when using this system, they should be create dynamically at run-time. If a .PRG contains 10 functions, 10 dynamic functions are created which are all the same :-) except for 2 pointers. */ static PASM_CALL hb_hrbAsmCreateFun( PHB_SYMB pSymbols, BYTE * pCode ) { PASM_CALL asmRet; HB_TRACE(HB_TR_DEBUG, ("hb_hrbAsmCreateFun(%p, %p)", pSymbols, pCode)); asmRet = ( PASM_CALL ) hb_xgrab( sizeof( ASM_CALL ) ); asmRet->pAsmData = ( BYTE * ) hb_xgrab( sizeof( prgFunction ) ); memcpy( asmRet->pAsmData, prgFunction, sizeof( prgFunction ) ); /* Copy new assembler code in */ /* #if INTEL32 */ hb_hrbAsmPatch( asmRet->pAsmData, 1, pSymbols ); /* Insert pointer to testsym */ hb_hrbAsmPatch( asmRet->pAsmData, 6, pCode ); /* Insert pointer to testcode */ hb_hrbAsmPatchRelative( asmRet->pAsmData, 11, hb_vmExecute, 15 ); /* Insert pointer to hb_vmExecute() */ /* #elseif INTEL16 */ /* #elseif MOTOROLA */ /* #elseif ... */ /* #endif */ return asmRet; } /* Patch an address of the dynamic function */ static void hb_hrbAsmPatch( BYTE * pCode, ULONG ulOffset, void * Address ) { HB_TRACE(HB_TR_DEBUG, ("hb_hrbAsmPatch(%p, %lu, %p)", pCode, ulOffset, Address)); /* #if 32 bits and low byte first */ pCode[ ulOffset ] = ( BYTE ) ( ( ( ULONG ) Address ) & 0xFF ); pCode[ ulOffset + 1 ] = ( BYTE ) ( ( ( ULONG ) Address >> 8 ) & 0xFF ); pCode[ ulOffset + 2 ] = ( BYTE ) ( ( ( ULONG ) Address >> 16 ) & 0xFF ); pCode[ ulOffset + 3 ] = ( BYTE ) ( ( ( ULONG ) Address >> 24 ) & 0xFF ); /* #elseif 16 bits and low byte first */ /* #elseif 32 bits and high byte first */ /* #elseif ... */ /* #endif */ } /* Intel specific ?? Patch an address relative to the next instruction */ static void hb_hrbAsmPatchRelative( BYTE * pCode, ULONG ulOffset, void * Address, ULONG ulNext ) { ULONG ulBase; ULONG ulRelative; HB_TRACE(HB_TR_DEBUG, ("hb_hrbAsmPatchRelative(%p, %lu, %p, %lu)", pCode, ulOffset, Address, ulNext)); /* #if 32 bits and low byte first */ ulBase = ( ULONG ) pCode + ulNext; /* Relative to next instruction */ ulRelative = ( ULONG ) Address - ulBase; pCode[ ulOffset ] = ( BYTE ) ( ( ulRelative ) & 0xFF ); pCode[ ulOffset + 1 ] = ( BYTE ) ( ( ulRelative >> 8 ) & 0xFF ); pCode[ ulOffset + 2 ] = ( BYTE ) ( ( ulRelative >> 16 ) & 0xFF ); pCode[ ulOffset + 3 ] = ( BYTE ) ( ( ulRelative >> 24 ) & 0xFF ); /* #elseif 16 bits and low byte first */ /* #elseif 32 bits and high byte first */ /* #elseif ... */ /* #endif */ }