Posts: 7
Threads: 2
Joined: Feb 2005
It seem that this is a bug ?
Code: Dim myLong As Long
myLong = &HAABBCCDD
''
Function myFunc (Arg1 As Long) As Long
Dim myArray (0 To 3) As Long => {1, 2, 3, 4}
Dim myData As Long
myData = 33
Function = myData
End Function
''
Print Hex$(myFunc (myLong))
Print " *** FINISHED OK *** "
Translates in ASM (for the function part)
Code: .globl _MYFUNC@4
_MYFUNC@4:
push ebp
mov ebp, esp
sub esp,52 ; (1) ??????????????
push ebx
push esi
push edi
lea edi, [ebp-52]
mov ecx,13
xor eax, eax
rep stosd
_t0004:
push 3
push 0
push 1
push 4
lea eax, [ebp-20]
push eax
lea eax, [ebp-48]
push eax
call _fb_ArraySetDesc
add esp, 24 ; (2) ?????????????
mov dword ptr [ebp-20], 1
mov dword ptr [ebp-16], 2
mov dword ptr [ebp-12], 3
mov dword ptr [ebp-8], 4
mov dword ptr [ebp-52], 33 ; (3) ?????????????
mov eax, dword ptr [ebp-52] ; (4) ?????????????
mov dword ptr [ebp-4], eax
_t0003:
mov eax, dword ptr [ebp-4]
pop edi
pop esi
pop ebx
mov esp, ebp
pop ebp
ret 4
First 52 bytes of local datas are reserved on the stack (sub esp, 52)(1)
...
Then 24 bytes of these 52 bytes are "Freed "
(add esp, 24)(2)
...
Then the "freed space" is read/Write ! (3) & (4)
mov dword ptr [ebp-52], 33
mov eax, dword ptr [ebp-52]
That [ebp+52] is a space below esp, thus in free stack space and may be overwriten by any push, call ...
erdemal
Posts: 922
Threads: 15
Joined: Jun 2003
Nothing seems wrong, 52 bytes are needed because every array has a descriptor.
ArraySetDesc() is called so you can pass the local arrays by descriptor to other functions (that's it, the descriptor is created on-the-fly). QB would allocate the array as dynamic, but that would be much slower than simply filling a descriptor. ArraySetDesc() is a var-args function, so the stack is cleared by the caller (thus the add esp, ...).
Posts: 7
Threads: 2
Joined: Feb 2005
Yes, ??? But it seems that a variable is initialised 'under' the ?descriptor then 'freed' with it ! A read and write is done at [ebp-52] when esp is [ebp-28]
(btw if the last declared variable is the array the ???problem is solved)
Erdemal
Posts: 922
Threads: 15
Joined: Jun 2003
No, the array descriptor is at ebp-48, the array at ebp-20, mydata at ebp-52 and the function result at ebp-4, nothing is being overwritten.
Btw, i wrote the compiler, i know what i'm talking about, a bit ;)
Posts: 7
Threads: 2
Joined: Feb 2005
The following code proves that you must be right and that I miss something !
Your code is a great code BTW.
Code: Dim myLong As Long
myLong = &HAABBCCDD
''
Function myFunc (Arg1 As Long) As Long
Dim myArray (0 To 3) As Long => {1, 2, 3, 4}
Dim myData, N As Long
myData = &H33443344
asm
push dword ptr &H11223344
push dword ptr &H11223344
push dword ptr &H11223344
push dword ptr &H11223344
push dword ptr &H11223344
push dword ptr &H11223344
push dword ptr &H11223344
push dword ptr &H11223344
push dword ptr &H11223344
push dword ptr &H11223344
'
pop eax
pop eax
pop eax
pop eax
pop eax
pop eax
pop eax
pop eax
pop eax
pop eax
end asm
Function = myData
End Function
''
Print Hex$(myFunc (myLong))
Print " *** FINISHED OK *** "
It returns &H33443344
Apology,
Erdemal
Posts: 525
Threads: 23
Joined: Oct 2004
Quote:No, the array descriptor is at ebp-48, the array at ebp-20, mydata at ebp-52 and the function result at ebp-4, nothing is being overwritten.
Btw, i wrote the compiler, i know what i'm talking about, a bit
At least, we all hope you do ;-)...LOL sorry couldn't help myself LOL
you've proven, in the last 13 releases that you DO know what you're talking about ;-).
Posts: 7
Threads: 2
Joined: Feb 2005
I get it now ! Pretty simple
-----------------------------------
push 3
push 0
push 1
push 4
lea eax, [ebp-20]
push eax
lea eax, [ebp-48]
push eax
call _fb_ArraySetDesc
add esp, 24
-----------------------------------
That 'add esp, 24' simply frees the six passed args to _fb_ArraySetDisc ! Me used to see that as 'ret 24' in the function .
Thanks for repliez and for writing FreeBasic ... a long awaited pearl.
Your reward :
Did you ever see a FreeBasic Array being executed ?
Here it is :
Code: Dim myLong, myLong2 As Long
myLong = &HAABBCCDD
myLong2 = &H11223344
'' ARGUMENTS ARE PASSED BYREF BY DEFAULT !!!!
Function ReadDwordAt (ByVal Address As Long) As Long
Dim NasmBin (0 To 13) As Byte = {&H55,&H89,&HE5,&H8B,&H45,&H08,&H8B,&H00,&H89,_
&HEC,&H5D,&HC2,&H04,&H00}
'' ---- NASM code in the NasmBin Array ----
'' bits 32
'' %define address [ebp+8]
'' segment .text
'' start:
'' push ebp
'' mov ebp, esp
'' mov eax, address
'' mov eax, [eax]
'' mov esp, ebp
'' pop ebp
'' ret 4
'' ----------------------------------------
asm
push [ebp+8] ' Arg1
lea eax, [ebp-20] ' (20 array size) + 4) align 32
call eax
mov [ebp-4], eax ' always -4 (FreeBasic returned value)
end asm
End Function
'' Read myLong, change 0 to 1 to 4 and you'll see myLong2
Print "Function Result : ";Hex$(ReadDwordAt (0 + @MyLong))
Print " *** FINISHED *** "
Data sections are read,write and executable ! So the code can modify itself like in the sweet old days !
Erdemal
Posts: 922
Threads: 15
Joined: Jun 2003
Yeah, the inline asm block could be also written as:
Code: asm
push dword ptr [address]
lea eax, [nasmbin]
call eax
mov [ebp-4], eax ' always -4 (FreeBasic returned value)
end asm
I will add FUNCTION to the inline asm evaluation so guessing the return var won't be needed, nor a temp variable.
It could be also done as:
Code: Function ReadDwordAt (ByVal Address As Long) As Long
Dim NasmBin (0 To 13) As Byte = {&H55,&H89,&HE5,&H8B,&H45,&H08,&H8B,&H00,&H89,_
&HEC,&H5D,&HC2,&H04,&H00}
dim asmproc as function( byval addr as long ) as long
asmproc = @nasmbin(0)
function = asmproc( address )
End Function
Or just:
Code: Function ReadDwordAt (ByVal Address As Long ptr) As Long
function = *address
End Function
But i guess that wasn't what you were trying to show ;). Btw, XP SP2 has a security "feature" enabled by default that prevents code to be executed from data segments on new CPU's.
Posts: 7
Threads: 2
Joined: Feb 2005
The "Function = *Address" feature will make it much easier !
As you sound interested : it would be nice and faster if the Asm.bin file would be loaded at compile time as a resource (or whatever). It would avoid the loadind of the array that may be long to load if the 'procedure' size is long ... and more.
With the "resource" type, you loose some "portability" of the "text-array" type.
So the Array and the Resource type are of some use.
Well for resource type, this RapidQ example will be more clear :
Code: ' ============================================================
$IFNDEF CALL_ASM_PROC_X
$DEFINE CALL_ASM_PROC_X
DECLARE FUNCTION CallAsmProc LIB "user32" ALIAS "CallWindowProcA" (ptrProc AS LONG, _
A1 AS LONG, A2 AS LONG, A3 AS LONG, A4 AS LONG) AS LONG
$ENDIF
' CallWindowProcA API is nothing else than a CallAddress_Arg1 (Arg2, Arg3, Arg4, Arg5)
' No other way found in RapidQ.
' ============================================================
$RESOURCE LIB_COUNTCYCLE AS "CountCycle.Bin" ' The merged .Bin output of Nasm compiler (one .bin for each function).
Dim MS_CountCycle As QMemoryStream
MS_CountCycle.ExtractRes(Resource(0))
' ============================================================
DefInt ptrStartCycleCounter = MS_CountCycle.Pointer + 0 ' 0 : Offset in the Bin
Function StartCycleCounter (RQ_Struct As Long) As Long
Result = CallAsmProc (ptrStartCycleCounter, RQ_Struct, 0, 0, 0)
End Function
' ------------------------------------------------------------
DefInt ptrStopCycleCounter = MS_CountCycle.Pointer + 19 ' 19 : Offset in the bin of this function
Function StopCycleCounter (RQ_Struct As Long) As Long
Result = CallAsmProc (ptrStopCycleCounter, RQ_Struct, 0, 0, 0)
End Function
' ------------------------------------------------------------
DefInt ptrStartStopCycleCounter = MS_CountCycle.Pointer + 43
Function StartStopCycleCounter (RQ_Struct As Long) As Long
Result = CallAsmProc (ptrStartStopCycleCounter, RQ_Struct, 0, 0, 0)
End Function
' ============================================================
'(It's very easy to generate such code as well as the Array type ... you know that better than me:))
Here the code is loaded as a resource at compile time and the resource as a "MemoryStream" (?allocated on the heap) at Runtime.
This example was chosen to show that one 'bin' may include multiple functions. It's just like a Libraray that would not have to be recompiled and would be portable even on compilers that have no linker. The only problem is that the code is PIC (position independent code) but it's
easy -and cheap in overhead- to turn around that.
This kind of code has been succesfully tested on all 'common ' Windows versions : it works !
I modestly named these libraries .nll 'not linked libraries' or .all 'auto linked libraries'
I'll look for more informations about what you stated on XP ??? being protected ???
Erdemal
|