CallFunction topic [ fastpointer.dll ]

Blitz3D Forums/Blitz3D Programming/CallFunction topic [ fastpointer.dll ]

virtlands(Posted 2013) [#1]
Hey folks,
I've been studying some of the FastPointer [dll] functions, and some of them are misbehaving.

Why won't any of the CallFunction routines return a value ?

See in this example, (my short masterpiece), the sample function simply returns v*v, but all I get is zero.

 func1_ptr = FunctionPointer()
    Goto skipit1
    sampleF(0)
    .skipit1

 w = CallFunctionVarInt (func1_ptr, 3) 
 Print" w = "+w    ;; should return a 9,  BUT IT DOESN'T /  aaaaaaaaaarrrrrrrrrghhhhhhh!

 weee()  ;; wheeeeeeeeeeee!


 Function weee()    
      WaitKey():End 
 End Function 

 Function sampleF(v)   
      Print" We are in the Sample Function "
      Print" Have a nice day :) "
      Print 

      Return v*v 
 End Function 


The DECLS file specifically says the the return type is INT:
;;----- a sampling follows of the FastPointer.decls -----

.lib "FastPointer.dll"

FunctionPointer% () : "FunctionPointer_"
DataPointer% () : "DataPointer_"
LabelPointer% () : "LabelPointer_"
ArrayPointer% () : "ArrayPointer_"
VarPointer% () : "VarPointer_"
TypePointer% (type*) : "TypePointer_"

CallFunction% (FunctionPointer%) : "CallFunction_"
CallFunctionVarInt% (FunctionPointer%, value%) : "CallFunctionVar_"
CallFunctionVarFloat% (FunctionPointer%, value#) : "CallFunctionVar_"
CallFunctionVarType% (FunctionPointer%, value*) : "CallFunctionVar_"
......


Yasha(Posted 2013) [#2]
I think it's just a bug in the library.

Workarounds:

-- pass the result out using the argument (if it was a bank or object)
-- write a new CallFunction function in C (because it's trivially easy - it's not the thing you got this DLL for)


Want to see a really naughty trick?

Local arr[0]

Local fptr = FunctionPointer() : Goto skip : ArrFunc(arr)
.skip

Local bk = CreateBank(11 * 4), i
PokeInt bk, 0, 10

For i = 1 To 10
	PokeInt bk, i * 4, i * 3
Next


CallFunctionVarType fptr, bk

WaitKey
End


Function ArrFunc(a[0])
	Local x : For x = 1 To a[0]
		Write a[x] + " "
	Next
	Print ""
End Function


Heh heh. For very fast access to bank data. Pass the bank with "..VarType" so that it passes the raw pointer to the bank data, and it will match the shape of the array Blitz is expecting!


Note: in Release mode array sizes are unchecked and this works fine. In Debug mode, the size of the array is checked based on the type of the array variable, not the size of the actual array or bank object. So this example won't work in Debug mode. It actually will if you change the size of the array parameter to be greater than or equal to the size of the bank, but doing that isn't always practical since half the point of banks is that they are resizeable (e.g. you'd have to have a dummy array of size 999999999 to take the function pointer initially if you wanted it to handle banks of that size).

I can think of ways to work around this restriction but they're clunky and anyway it's only needed for Debug mode (heck, easier to just waste memory and change a constant with the size of the array for Debug mode).


virtlands(Posted 2013) [#3]
Thanks Yasha, you're a wiz with this stuff.
Noted, there is a bug there with the aging CallFunction() fleet.

I see what you did there.
You let the first array position (1st INT=offset 0) act as information for the accessing the rest of the array,
(and if you wanted to, you could have overwritten the 1st index as well).

{ These arrays can represent BYTES, SHORTS, INTS,... too. }

You said the debug-mode complains about the code. In that case, I'll just not use debug-mode

I've been trying to study assembly language a little bit too, and
thought it would be brilliant to find ways to use it with Blitz-3D

I found this old code, which I plan to study later: Blitz3D Function Pointers (Hack)_1639 by Author MCP
https://www.dropbox.com/sh/g0l4macua5y48t9/cJT1ZY9-Wg/Blitz3d%20Function%20Pointers%20%28Hack%29_1639.bb

Shown below is an evil experiment I did to see if I could put assembly language code directly in the DATA statements,
to try to get Blitz3D to run it.

Needless to say the experiment failed.
Is it because the DATA statements are not in the CODE segment (CS)?
Would it require some unusual far call to do it?

Do functions like LabelPointer() and FunctionPointer()
retrieve only offsets instead of absolute addresses?
I was thinking that each Label or Function lives in a different SEGMENT, which would make them hard to inter-relate.

Therefore to maybe call data in a program and treat it as code, you'll need to call it with a FAR CALL, ( because CS<>DS ),
(but I don't how to do anything that exotic yet).

For reference, read about the SEGMENT:OFFSET addressing scheme:
http://thestarman.pcministry.com/asm/debug/Segments.html
http://en.wikipedia.org/wiki/X86_memory_segmentation
{__ Absolute memory location = (Segment*16) + Offset __}

Here's that experiment that failed.


The strange thing is that the PRINT statement near the end does get executed, but my embedded machine code gets ignored.
There is also within Blitz3D an invisible ret code at the end,,,, which is apparent because it jumps back to PRINT" We have returned..."

___ My next goal then would be to take a Function() that already exists, and (during run-time) change its byte-codes, (=machine code), using something like pokebyte if possible.
The Function() would have to be previously well-fed with "temporary code", so that we don't overwrite its RET.

This would also be known as self-modifying code.
http://en.wikipedia.org/wiki/Self-modifying_code

Is it possible to do that with Blitz3D?


Yasha(Posted 2013) [#4]
You'll need some Windows kernel functions in order to do what you are asking.

You need to use VirtualProtect to set the permissions of the pages containing your code to PAGE_EXECUTE_READWRITE: http://msdn.microsoft.com/en-us/library/aa366898%28v=VS.85%29.aspx

The pages themselves need to be allocated with VirtualAlloc (details are linked from the VirtualProtect page), so you can't put the code into simple B3D data structures because those are created using simple allocation functions, or in the case of Data statements placed elsewhere statically. (You can always build the code in a bank and then copy it with RtlMoveMemory if that's easier.)


PS to use the previous hack in debug mode, try this:



Set DEBUGMODE to false when you're done developing and it will stop wasting memory on any unused arrays. Don't feel compelled to limit yourself to what you see in examples, e.g. you could easily pass information in and out of the function (array size, return values, etc.) using globals.


Anyway a much easier way to embed assembly in a B3D program would be to use TCC.


virtlands(Posted 2013) [#5]
Yasha wrote "PS to use the previous hack in debug mode, try this:"

Wow, that's awesome, just tried it and it works fine with debug mode.

I don't think I'll use the VirtualProtect stuff for now, it's quite complex for me to get into.

Yasha wrote "Heh heh. For very fast access to bank data. Pass the bank with
"..VarType" so that it passes the raw pointer to the bank data, and it will match the shape of the array Blitz is expecting!"

I'll remember that, thanks...