Qbasicnews.com

Full Version: Initialised Array In Function ??? Problem ???
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
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
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, ...).
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
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 ;)
The following code proves that you must be right Smile 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
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 Wink

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 ;-).
I get it now ! Pretty simple Smile
-----------------------------------
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 Smile.

Thanks for repliez and for writing FreeBasic ... a long awaited pearl.

Your reward Wink :
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 Smile like in the sweet old days !

Erdemal
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.
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 'commonSmile' Windows versions : it works !

I modestly named these libraries .nll 'not linked libraries' or .all 'auto linked libraries' Smile

I'll look for more informations about what you stated on XP ??? being protected ???

Erdemal