Function name decoration issue

Windows specific questions.
Post Reply
Vortex
Posts: 118
Joined: Sep 19, 2005 9:50

Function name decoration issue

Post by Vortex »

Compiling this code for testing :

Code: Select all

Function test naked stdcall alias "test"( Byval s As String ) As ZString Ptr
     Asm

        mov edx,DWORD PTR [esp+4]
        mov eax,DWORD PTR [edx]
        ret 4

    End Asm
        
End Function
Reading the assembly listing, the decoration of the function test looks incorrect :

Code: Select all

.globl _test@12
_test@12:
.Lt_0004:
mov edx,DWORD PTR [esp+4]
mov eax,DWORD PTR [edx]
ret 4
The expected symbol decoration is _test@4 as the function takes only one parameter. The listing shows _test@12
Source code compiled with FreeBASIC Version 1.07.1
fxm
Moderator
Posts: 12147
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Function name decoration issue

Post by fxm »

Extract of the Calling Conventions documentation page:
In DOS and Windows platforms, the procedure name is decorated with an "@N" suffix, where N is the total size, in bytes, of any parameters passed.
The value of 12 corresponds to the size of the string descriptor.
Vortex
Posts: 118
Joined: Sep 19, 2005 9:50

Re: Function name decoration issue

Post by Vortex »

Thanks for the info. Removing the ByVal statement from the function parameter helped here :

Code: Select all

.globl _test@4
_test@4:
.Lt_0004:
mov edx,DWORD PTR [esp+4]
mov eax,DWORD PTR [edx]
ret 4
jj2007
Posts: 2326
Joined: Oct 23, 2016 15:28
Location: Roma, Italia
Contact:

Re: Function name decoration issue

Post by jj2007 »

fxm wrote:The value of 12 corresponds to the size of the string descriptor.
IMHO the compiler should issue a warning like "are you sure you want to pass a string descriptor, i.e. by value?". ALL Windows APIs expect strings in form of a pointer, not a 12-byte FreeBasic string descriptor. Remember the "B" in "Basic" ;-)
fxm
Moderator
Posts: 12147
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Function name decoration issue

Post by fxm »

In fact, passing a string by value is a recent ability, but also a special case (compared to the passing of other variables by value), looking at the way it was implemented:
- When a string must be passed by value, in fact a copy of the original string is passed, but always by its descriptor (in the same way as for a string passed by reference), so that a pointer is always passed in both cases (Byref or Byval).

@admin: maybe this case of procedure name decoration (string passed by value) must be revised.
badidea
Posts: 2594
Joined: May 24, 2007 22:10
Location: The Netherlands

Re: Function name decoration issue

Post by badidea »

jj2007 wrote:Remember the "B" in "Basic" ;-)
jj2007 wrote:Function test naked stdcall alias "test"( Byval s As String ) As ZString Ptr
That does not look like "Beginners" stuff at all.

Edit: Sorry, 2nd quote was Vortex
Last edited by badidea on Feb 06, 2020 19:56, edited 1 time in total.
Vortex
Posts: 118
Joined: Sep 19, 2005 9:50

Re: Function name decoration issue

Post by Vortex »

I agree with jj2007. A warning message could be helpful.
fxm
Moderator
Posts: 12147
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Function name decoration issue

Post by fxm »

I would rather be in favor of changing the function name decoration (suffix @N) because in the 2 cases (Byref or Byval), a pointer (to the string descriptor) is always passed by value (for a 32-bit compilation: N should always be equal to 4).

Proof demonstrating that a string is always passed by the value of a pointer to its descriptor:

Code: Select all

Function test1 Naked Stdcall Alias "test1" ( Byref s As String ) As Zstring Ptr
    Asm
        mov edx,DWORD PTR [esp+4]
        mov eax,DWORD PTR [edx]
        ret 4
    End Asm
End Function

Function test2 Naked Stdcall Alias "test2" ( Byval s As String ) As Zstring Ptr
    Asm
        mov edx,DWORD PTR [esp+4]
        mov eax,DWORD PTR [edx]
        ret 4
    End Asm
End Function

Dim As String s = "A string is always passed by a pointer value (to its descriptor)"
Dim As Function (Byval p As Any Ptr) As Zstring Ptr p1 = Cptr(Any Ptr, @test1)
Dim As Function (Byval p As Any Ptr) As Zstring Ptr p2 = Cptr(Any Ptr, @test2)

Print "Print:"
Print "   s        :", s
Print "   *test1(s):", *test1(s)
Print "   *test2(s):", *test2(s)
Print "   *p1(@s)  :", *p1(@s)  '' in fact a pointer is passed by value
Print "   *p2(@s)  :", *p2(@s)  '' in fact a pointer is passed by value

Sleep

Code: Select all

Print:
   s        : A string is always passed by a pointer value (to its descriptor)
   *test1(s): A string is always passed by a pointer value (to its descriptor)
   *test2(s): A string is always passed by a pointer value (to its descriptor)
   *p1(@s)  : A string is always passed by a pointer value (to its descriptor)
   *p2(@s)  : A string is always passed by a pointer value (to its descriptor)
MrSwiss
Posts: 3910
Joined: Jun 02, 2013 9:27
Location: Switzerland

Re: Function name decoration issue

Post by MrSwiss »

fxm wrote:I would rather be in favor of changing the function name decoration (suffix @N) because in the 2 cases (Byref or Byval), a pointer (to the string descriptor) is always passed by value (for a 32-bit compilation: N should always be equal to 4).
I don't agree, because a FB_String is a Type (aka: UDT or struct) with it's size referenced in the decoration.
(needed for indexing a 'typed' Ptr as opposed to Any Ptr, which can't be indexed)
The preferred solution whould be: ByVal As ZString Ptr (conversion implicitly done by FBC).
Which will give @4 or @8, depending on the compiler's bitness.
fxm
Moderator
Posts: 12147
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Function name decoration issue

Post by fxm »

But presently (for 32-bit compilation):
- Passing a string by reference => @4 (see above)
- Passing a string by value => @12 (see above)
That is illogical because when a string is passed by value, in fact a copy of the original string is passed by reference!
In both cases, a string is always passed by reference, either the original string, or a copy of this string.
(In both cases under the hood, a pointer to the descriptor is passed by value, either to the descriptor of the original string, or to the descriptor of a copy of this string)
Vortex
Posts: 118
Joined: Sep 19, 2005 9:50

Re: Function name decoration issue

Post by Vortex »

Hi fmx,
when a string is passed by value, in fact a copy of the original string is passed by reference!
You are right. The code in my quick example demonstrates this fact :

Code: Select all

mov edx,DWORD PTR [esp+4]
mov eax,DWORD PTR [edx]
The function decoration should be consistent to avoid further issues.
dodicat
Posts: 7987
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: Function name decoration issue

Post by dodicat »

Passing a string byval is slower than using a static copy inside a function, and passing byref.

Code: Select all



sub dothis(byval s as string)
    s+=" zzz"
end sub

sub dothis2(byref s as string)
    static as string g:g=s
    g+=" zzz"
end sub

dim as long lim=1000000

dim as double t

dim as string x="HELLO"

'warmup

for n as long=1 to lim
    dothis(x)
    dothis2(x)
    next n

t=timer
for n as long=1 to lim
    dothis(x)
next
print timer-t,x

t=timer
for n as long=1 to lim
    dothis2(x)
next
print timer-t,x
sleep


 
Using the decorated names -gen gas

Code: Select all

Function test naked stdcall  alias "test"( Byval s As String ) As ZString Ptr
     Asm

        mov edx,DWORD PTR [esp+4]
        mov eax,DWORD PTR [edx]
        ret 4

    End Asm
       
End Function

Function test2 naked stdcall  alias "test2"( Byref s As String ) As ZString Ptr
     Asm

        mov edx,DWORD PTR [esp+4]
        mov eax,DWORD PTR [edx]
        ret 4

    End Asm
       
End Function




declare function decorated cdecl alias "test@12"( Byval As String ) As ZString Ptr
declare function decorated2 cdecl alias "test2@4"( Byref As String ) As ZString Ptr

print *decorated2(!"Hello\n")
print *decorated("Press any key to end . . .")
print
sleep

  
fxm
Moderator
Posts: 12147
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Function name decoration issue

Post by fxm »

If we emulate what FreeBASIC does under the hood to pass a string by value, we find a time equivalent to true passing by value:

Code: Select all

sub dothis(byval s as string)
    s+=" zzz"
end sub

sub dothis2(byref s as string)
    s+=" zzz"
end sub

dim as long lim=1000000

dim as double t

dim as string x="HELLO"

'warmup

for n as long=1 to lim
    dothis(x)
    dim as string x2 = x
    dothis2(x2)
    next n

t=timer
for n as long=1 to lim
    dothis(x)
next
print timer-t,x

t=timer
for n as long=1 to lim
    dim as string x2 = x
    dothis2(x2)
next
print timer-t,x
sleep
Vortex
Posts: 118
Joined: Sep 19, 2005 9:50

Re: Function name decoration issue

Post by Vortex »

Reading the assembly listings, one call that there is no any difference expect the name decoration. dothis1.asm :

Code: Select all

	.intel_syntax noprefix

.section .text
.balign 16

.globl _DOTHIS@12
_DOTHIS@12:
push ebp
mov ebp, esp
sub esp, 12
.Lt_0004:
push 0
push -1
push 5
push offset _Lt_0006
push -1
push dword ptr [ebp+8]
mov dword ptr [ebp-12], 0
mov dword ptr [ebp-8], 0
mov dword ptr [ebp-4], 0
lea eax, [ebp-12]
push eax
call _fb_StrConcat@20
push eax
push -1
push dword ptr [ebp+8]
call _fb_StrAssign@20
.Lt_0005:
mov esp, ebp
pop ebp
ret 4

.section .data
.balign 4
_Lt_0006:	.ascii	" zzz\0"
dothis2.asm :

Code: Select all

	.intel_syntax noprefix

.section .text
.balign 16

.globl _DOTHIS2@4
_DOTHIS2@4:
push ebp
mov ebp, esp
sub esp, 12
.Lt_0004:
push 0
push -1
push 5
push offset _Lt_0006
push -1
push dword ptr [ebp+8]
mov dword ptr [ebp-12], 0
mov dword ptr [ebp-8], 0
mov dword ptr [ebp-4], 0
lea eax, [ebp-12]
push eax
call _fb_StrConcat@20
push eax
push -1
push dword ptr [ebp+8]
call _fb_StrAssign@20
.Lt_0005:
mov esp, ebp
pop ebp
ret 4

.section .data
.balign 4
_Lt_0006:	.ascii	" zzz\0"
Post Reply