So, since I'm currently messing around with Lua, I got interested, if it's possible to find out the pointer that points to a user-defined Blitzbasic function.
It should be possible, since every time, when Blitz calls a function, it pushes the current instruction pointer onto the stack, so that the called function is able to return to this point.
So, imagine, you wrote a function in C in combination with inline assembler, that is called by your Blitz function right after the function itself is called.
The C function then reads the instruction pointer, which was pushed by Blitz onto the stack, and gets a value that points to the instruction right after the Blitz function calls the C function.
Everything you have to do now is to subtract a small value from this instruction pointer and you get... the pointer to the Blitz function!
I tried it out and it actually works - but there're still problems.
It seems that Blitz uses a different calling convention when calling Blitz functions than the _stdcall convention.
That leads to a memory access violation, when the Blitz function tries to return to its caller.
I found a way to avoid this, but it's not as clean as I want it to be.
I rewrote 'CallFunction' so it remembers from where it was called (using the instruction pointer on the stack).
The Blitz function then calls a C function 'ReturnInt' instead of 'Return', when it's called by the DLL.
'ReturnInt' then jumps back to the instruction pointer saved by 'CallFunction'.
This actually works, but it leaves a really messy stack behind, which leads to a stack overflow, if you let the DLL call the Blitz function too often.
So, is there anyone out there who knows, how a Blitz function has to be called or which convention it uses?
It would be very nice to get the function pointers to work, especially for DLLs that require Callback functions or for example Lua, which would call user-defined Blitz functions, when used in the script.
My current test code in Blitz:
C++ - Code:
It should be possible, since every time, when Blitz calls a function, it pushes the current instruction pointer onto the stack, so that the called function is able to return to this point.
So, imagine, you wrote a function in C in combination with inline assembler, that is called by your Blitz function right after the function itself is called.
The C function then reads the instruction pointer, which was pushed by Blitz onto the stack, and gets a value that points to the instruction right after the Blitz function calls the C function.
Everything you have to do now is to subtract a small value from this instruction pointer and you get... the pointer to the Blitz function!
I tried it out and it actually works - but there're still problems.
It seems that Blitz uses a different calling convention when calling Blitz functions than the _stdcall convention.
That leads to a memory access violation, when the Blitz function tries to return to its caller.
Global Pointer Test() CallFunction( Pointer ) ;<--- This is the C function that calls the Blitz function by it's pointer WaitKey() End Function Test() Pointer = FunctionPointer() ;<--- This is the C function that returns the function pointer Print "This works! Function pointer: " + Pointer Return ;<--- This works fine when the function is called by Blitz ;however, when the DLL calls this function, 'Return' leads to a MAV End Function
I found a way to avoid this, but it's not as clean as I want it to be.
I rewrote 'CallFunction' so it remembers from where it was called (using the instruction pointer on the stack).
The Blitz function then calls a C function 'ReturnInt' instead of 'Return', when it's called by the DLL.
'ReturnInt' then jumps back to the instruction pointer saved by 'CallFunction'.
This actually works, but it leaves a really messy stack behind, which leads to a stack overflow, if you let the DLL call the Blitz function too often.
So, is there anyone out there who knows, how a Blitz function has to be called or which convention it uses?
It would be very nice to get the function pointers to work, especially for DLLs that require Callback functions or for example Lua, which would call user-defined Blitz functions, when used in the script.
My current test code in Blitz:
Global Pointer, Call Print Test() CallFunction( Pointer ) WaitKey() End Function Test() Pointer = FunctionPointer() Print "Works! Call no. " + Call Call = Call + 1 If Call = 1 Then Return 5 Else ReturnInt( 5 ) EndIf End Function
C++ - Code:
#define BBEXPORT extern "C" _declspec(dllexport) void (__stdcall *JumpFunction)(void); BBEXPORT int __stdcall FunctionPointer() { unsigned int StackPosition, Adress; __asm { mov StackPosition,esp mov esp,ebp add esp,4 pop Adress mov esp,StackPosition } return Adress - 8; } BBEXPORT int __stdcall CallFunction( int (__stdcall *B3DFunction)(void) ) { unsigned int StackPosition; __asm { mov StackPosition,esp mov esp,ebp add esp,4 pop JumpFunction mov esp,StackPosition } return B3DFunction(); } BBEXPORT void __stdcall ReturnInt( int Value ) { __asm { mov eax,[Value] } JumpFunction(); }