Miscalleneous bugs in the 32bit compiler

General discussion for topics related to the FreeBASIC project or its community.
stephanbrunker
Posts: 62
Joined: Nov 02, 2013 14:57

Miscalleneous bugs in the 32bit compiler

Post by stephanbrunker »

Hello,

I hope this is the right place for reporting the bugs I've found in the 32-bit Version of the Compiler.

1. not()
does'nt work properly if used in some conditions, try this:

Code: Select all

dim as ulongint a, nota
dim as ulong b, notb
dim as ushort c, notc

a=1
nota=not(a)

print hex(a), hex(nota)

b=1
notb=not(b)
nota=not(b)

print hex(b), hex(notb), hex(nota)
'nota should be 64bit, but is only 32bit and thus false

c=1
notc=not(c)
notb=not(c)
nota=not(c)

print hex(c), hex(notc), hex(notb), hex(nota)
2. &
& works not properly if zerobytes are involved:

Code: Select all

dim as string a,b
dim as ulong c,d
dim as string*4 e
dim as string f,g,h

a="&h00123456"
print a

b="&h12345600"
print b

c=valuint(a)
d=valuint(b)

print c
print d

e=mki<32>(c)
f=mki<32>(d)

print len(e)
print len(f)

g="xxxx" & e   'the zerobyte goes missing
h="xxxx" & f

print len(g)
print len(h)
3. hex()
hex () is not overloaded for all datatypes, you'll get the error "Ambigious call to overloaded function". This fix is to actually overload hex for the missing types, including one for binary strings:

Code: Select all

Declare Function hex Overload (a as long,b as integer) as string
Declare Function hex Overload (a as ulong,b as integer) as string
Declare Function hex Overload (a as longint,b as integer) as string
Declare Function hex Overload (byref a as string) as string

Function hex Overload (a as long,b as integer) as string
    dim as integer c = cint(a)
    return hex(c,b)
End Function

Function hex Overload (a as ulong,b as integer) as string
    dim as integer c = cint(a)
    return hex(c,b)
End Function

Function hex Overload (byval a as longint,b as integer) as string
    dim as integer lo = cint(a)
    dim as integer hi = cint(a shr 32)
    dim as string result
    if b > 16 then
        result = string(b-16,"0") & hex(hi) & hex(lo)
    else
        result = right(hex(hi,8) & hex(lo,8),b)
    end if
    return result
End Function

Function hex Overload (byref aa as string) as string
    'Achtung auf Endian-switch!
    dim a as string = aa
    dim ablocks as ulong
    dim pad as ubyte
    pad=4-(len(a) mod 4)
    if pad <> 4 then a &= string(pad,chr(0))
    ablocks=len(a)\4 - 1
    dim pa as ulong ptr = cast(ulong ptr,strptr(a))
    dim result as string = space(len(a)*2)
    dim presult as ulongint ptr = cast(ulongint ptr,strptr(result))
    dim i as integer
    for i = 0 to ablocks
        *(presult+ablocks-i)=cvlongint(hex(*(pa+i),8))
    next i
    return result
End Function

Function hex Overload (byref aa as string,b as integer) as string
    'Achtung auf Endian-switch!
    dim a as string = aa
    dim ablocks as ulong
    dim pad as ubyte
    pad=4-(len(a) mod 4)
    if pad <> 4 then a &= string(pad,chr(0))
    ablocks=len(a)\4 - 1
    dim pa as ulong ptr = cast(ulong ptr,strptr(a))
    dim result as string = space(len(a)*2)
    dim presult as ulongint ptr = cast(ulongint ptr,strptr(result))
    dim i as integer
    for i = 0 to ablocks
        *(presult+ablocks-i)=cvlongint(hex(*(pa+i),8))
    next i
    '----    
    dim lena as integer = len(result)
    dim result2 as string
    if b < lena then 
        result2 = right(result,b)
    elseif b = lena then 
        result2 = result
    elseif b > lena then 
        if a[lena-1] = 70 or a[lena-1] = 102 then
            result2 = string(b-lena,"f") & result
        else
            result2 = string(b-lena,"0") & result
        end if
    end if
    return result2
End Function
4. rol and ror
(bit rotate right and left) are not supported, but used often in crypto. For 32bit rotate left, it looks like:

Code: Select all

Function rotateleft(ByVal x As ulong, byval y as ubyte) as ulong
    Asm
        mov   eax,[x]
        mov   cl,[y]
        rol   eax,cl
        mov [Function],eax
    End Asm
End Function
Last edited by stephanbrunker on Dec 19, 2013 21:51, edited 1 time in total.
TJF
Posts: 3809
Joined: Dec 06, 2009 22:27
Location: N47°, E15°
Contact:

Re: Miscalleneous bugs in the 32bit compiler

Post by TJF »

#1:
stephanbrunker wrote:'nota should be 64bit, but is only 32bit and thus false
The result of
  • not(b)
is of type ULONG (the result is of the same type as the argument). Finally this result gets converted to the type of nota (ULONG -> ULONGINT).

==> No problem here

When you need a LONGINT NOT operation you've to pass a LONGINT argument like
  • nota = NOT(CAST(ULONGINT, b))
TJF
Posts: 3809
Joined: Dec 06, 2009 22:27
Location: N47°, E15°
Contact:

Re: Miscalleneous bugs in the 32bit compiler

Post by TJF »

#2:
stephanbrunke wrote:'the zerobyte goes missing
Check STRING (Wiki). Fixed length STRINGs gets interpreted like C strings. The 8th byte is present but the LEN function stops to count at the zero byte. ==> Be careful when using MKI and STRING*. Either store binary data or text data only, mind the appended zero byte. Don't mix MKI, MKL, ... and INSTR, MID, LEN. This only works with variable length STRINGs (but doesn't make any sense).
TJF
Posts: 3809
Joined: Dec 06, 2009 22:27
Location: N47°, E15°
Contact:

Re: Miscalleneous bugs in the 32bit compiler

Post by TJF »

#3:

The ULONG and ULONGINT versions are implemented here (fbc-0.24 on Ubuntu-12.04).

Regarding the STRING versions: please check your code. (And do we really need that?)

Regarding the signed versions: what result do you expect from HEX(-&h12345L). Should it get
  • -12345
or
  • FFFEDCBB
The later is standard (and the output of the unsigned version). Since hex-numbers usually show pointer values or the contents of memory cells and are used in a binary matter, there's no need for negative output. No 'normal' users will deal with them, instead only programmers use this number format. The experienced programmer notices the leading "F" as an indicator for the negative sign.


#4:

ROL and ROR are usually not used in a high-level programming language. These are binary operations on processor level. IMHO this shouldn't get included in FB (we have allready more than 400 keyword). Anyway, your code is helpful for somebody needing it.

Thank you for trying to improve the FB project.
dkl
Site Admin
Posts: 3235
Joined: Jul 28, 2005 14:45
Location: Germany

Re: Miscalleneous bugs in the 32bit compiler

Post by dkl »

1. In FB generally the results of math/bit operations depend on the operands, not at all on where or how the expression is used afterwards. And the operands are promoted to Integer if they're smaller. You can use #print typeof() to check:

Code: Select all

#print "--- short ---"
dim sh as short
#print typeof(sh)
#print typeof(not sh)

#print "--- ushort ---"
dim ush as ushort
#print typeof(ush)
#print typeof(not ush)

#print "--- long ---"
dim l as long
#print typeof(l)
#print typeof(not l)

#print "--- ulong ---"
dim ul as ulong
#print typeof(ul)
#print typeof(not ul)

#print "--- longint ---"
dim ll as longint
#print typeof(ll)
#print typeof(not ll)

#print "--- ulongint ---"
dim ull as ulongint
#print typeof(ull)
#print typeof(not ull)
In case of the (not c) example, where c is a UShort, it will be promoted to Integer too. The result of (not c) there is &hFFFFFFFE, but note that it's a signed Integer, not UInteger. So then, when assigning to nota (64bit ULongInt) there is a sign extension to 64bit which produces the &hFFFFFFFFFFFFFFFE value. The sign extension is only done for signed types, but not for unsigned. I agree that UShort becoming Integer seems a little weird, while ULong becomes UInteger... but I checked GCC and the behaviour is the same.

Note: Not is a unary operator, not a function, so it's necessary to use (not x) instead of not(x) in order to group the Not to the operand. (FB's Not does have some pretty unusual operator precedence...)

2. Indeed FB uses null terminators in all strings currently, so it's risky to have null bytes in them too. I think it only works properly with String's (the variable-length, dynamically allocated String objects). But for fixed-length strings, in many places a null byte signals the end. Commands like Print and Len sometimes stop at the 1st null byte, sometimes use the length stored in var-len string descriptors, and sometimes use the length that fix-len strings were declared with.

Code: Select all

dim fs as string * 3

'' Print and len() return 3 chars for the String*3 here instead of stopping at
'' the 1st null byte. (QB compatibility; I think in QB, unused parts of
'' fixed-length strings were filled with spaces, or something like that)
print "<";fs;">", len(fs)

fs[0] = asc("a")
fs[1] = 0
fs[2] = asc("b")
'fs[3] = 0  '' already there, implicit null terminator

'' Similar: prints "a b" because it takes into account the declared length (*3),
'' instead of stopping at 1st null byte.
print "<";fs;">", len(fs)

'' But when assigning to a var-len string, only the part up to the 1st null byte
'' is copied. (QB compatibility too, right? I think QB didn't preserve the
'' unused part of fix-len strings when copying to var-len strings, not sure)
dim s as string = fs
print "<";s;">", len(s)

'' But we can recreate it manually:
s = space(3)
s[0] = asc("a")
s[1] = 0
s[2] = asc("b")
print "<";s;">", len(s)

'' Or like this, thanks to special support for chr(0) (QB compatibility):
s = "a" + chr(0) + "b"
print "<";s;">", len(s)

'' Interestingly enough, copying in this direction works, and doesn't stop at
'' 1st null byte. That's because the var-len string stores its length.
fs = ""
fs = s
print "<";fs;">", len(fs)
As for the & operator specifically, yea, the null byte at the end goes missing, but that's by design. The string returned from mki() is a var-len one, so we can expect the proper data to be stored into the fix-len string. But then the conversion back to var-len string causes the problem, because it stops at the 1st null byte. (the +/& string concatenation operators work with var-len strings, but to show the issue we don't need them; and assignment/conversion to var-len string apparently has the same issue)

Code: Select all

dim fs as string * 4
dim s as string

fs = mki<32>(valuint("&h61626300"))
print "<";fs;">", len(fs)

s = fs
print "<";s;">", len(s)
I'd like to know what QB does in such cases. Anyways, the way fix-len strings are implemented in FB at the moment, it's really not possible to fix the issue. How to tell the difference between a fresh fix-len string (which are initialized to all zeroes, just like any other variable in FB) and a fix-len string containing null chars? The memory is the same in both cases, and there is no length information stored separately, as done for var-len strings. (if we started doing that, then we may aswell have used var-len strings to begin with)

3. The issues with overload resolution, including such problems with the Bin/Oct/Hex functions will be fixed in the next release, see also: #655

4. I'd like it to have more operations built-in. For example bswap, min, max; might aswell add rol/ror to that wishlist.
gothon
Posts: 225
Joined: Apr 11, 2011 22:22

Re: Miscalleneous bugs in the 32bit compiler

Post by gothon »

stephanbrunker wrote: 4. rol and ror
(bit rotate right and left) are not supported, but used often in crypto.
Its true that bit rotations are not widely supported in high level languages. Outside of cryptography they are not used much. However you can use code such as:

Code: Select all

#Define Rol(X, Y) (((X) Shl (Y)) Or ((X) Shr (8*SizeOf(X)-(Y))))
#Define Ror(X, Y) (((X) Shr (Y)) Or ((X) Shl (8*SizeOf(X)-(Y))))

Dim L As ULongInt, I As UInteger, S As UShort, B As UByte
L = 1
I = 3
S = 1
B = 3
Print Bin(Rol(L, 2), 64), Bin(Ror(L, 2), 64)
Print Bin(Rol(I, 2), 32), Bin(Ror(I, 2), 32)
Print Bin(Rol(S, 2), 16), Bin(Ror(S, 2), 16)
Print Bin(Rol(B, 2),  8), Bin(Ror(B, 2),  8)

Sleep
because this formula is widely recognized by C compilers and optimized to rotation instructions, and you can compile your program using the C emitter with the '-gen gcc' option to ensure this optimization happens. See the Wikipedia article: http://en.wikipedia.org/wiki/Circular_s ... lar_shifts

I also recomend using '-gen gcc' when doing intense bit operations on 64 bit numbers because there are some bugs I found in the default 'gas' back end. See this thread: http://www.freebasic.net/forum/viewtopi ... =3&t=21215
Last edited by gothon on Dec 19, 2013 0:27, edited 1 time in total.
Zippy
Posts: 1295
Joined: Feb 10, 2006 18:05

Re: Miscalleneous bugs in the 32bit compiler

Post by Zippy »

dkl wrote: <snip>
As for the & operator specifically, yea, the null byte at the end goes missing, but that's by design. The string returned from mki() is a var-len one, so we can expect the proper data to be stored into the fix-len string. But then the conversion back to var-len string causes the problem, because it stops at the 1st null byte. (the +/& string concatenation operators work with var-len strings, but to show the issue we don't need them; and assignment/conversion to var-len string apparently has the same issue)

Code: Select all

dim fs as string * 4
dim s as string

fs = mki<32>(valuint("&h61626300"))
print "<";fs;">", len(fs)

s = fs
print "<";s;">", len(s)
I'd like to know what QB does in such cases. Anyways, the way fix-len strings are implemented in FB at the moment, it's really not possible to fix the issue. How to tell the difference between a fresh fix-len string (which are initialized to all zeroes, just like any other variable in FB) and a fix-len string containing null chars? The memory is the same in both cases, and there is no length information stored separately, as done for var-len strings. (if we started doing that, then we may aswell have used var-len strings to begin with)
<snip>
I hope I'm not wasting your time with this; I don't have QB per se, only PDS 7.1. Wherein fixed length strings are initialized with/to chr(0). And assignment of a fixed len string to a variable length is 1:1 (transparent).

This isn't an exact translation of your fb code (can't):

Code: Select all

'PDS 7.1
'
CLS
DIM i AS INTEGER
DIM fs AS STRING * 4
DIM s AS STRING
'
PRINT "fs contents before assignment:"
FOR i = 1 TO 4
PRINT i; TAB(4); "fs: "; ASC(MID$(fs, i, 1))
NEXT i
'
PRINT
PRINT "assignment: string contents and len()"
fs = MKL$(CLNG(&H61626300))
PRINT "fs = <"; fs; ">", LEN(fs)
s = fs
PRINT " s = <"; s; ">", LEN(s)
'
PRINT
'
PRINT "fs and s contents after assignment:"
FOR i = 1 TO 4
PRINT i; TAB(4); "fs: "; ASC(MID$(fs, i, 1)), "s: "; ASC(MID$(s, i, 1))
NEXT i
'
'Output:
'
fs contents before assignment:
 1 fs:  0
 2 fs:  0
 3 fs:  0
 4 fs:  0

assignment: string contents and len()
fs = < cba>    4
 s = < cba>    4

fs and s contents after assignment:
 1 fs:  0     s:  0
 2 fs:  99    s:  99
 3 fs:  98    s:  98
 4 fs:  97    s:  97
It appears that QB[X] operates, always, with the dimmed-len of the fixed len string. I'll test with terminating nulls...

I cannot offer solutions, only add to the problem.
Zippy
Posts: 1295
Joined: Feb 10, 2006 18:05

Re: Miscalleneous bugs in the 32bit compiler

Post by Zippy »

QB[X] fixed-to-variable string test with initial null byte, embedded nulls, and trailing nulls:

Code: Select all

'PDS 7.1
'
CLS
DIM fs AS STRING * 18
DIM s  AS STRING
'
'deliberately not assigning last 2 bytes
fs = CHR$(0) + "December" + CHR$(0) + CHR$(0) + "2013" + CHR$(0)
PRINT "               11111111112"
PRINT "      12345678901234567890"
PRINT "fs = <"; fs; ">", LEN(fs); "bytes"
'
s = fs
PRINT " s = <"; s; ">", LEN(s); "bytes"
'
'Output:
'
               11111111112
      12345678901234567890
fs = < December  2013   >    18 bytes
 s = < December  2013   >    18 bytes

'Output from fb:
'
               11111111112
      12345678901234567890
fs = <December2013      >    18bytes
 s = <December2013>          12bytes
In this case fb copies the non-null chars from the fixed string to the variable string. Peculiar...
TJF
Posts: 3809
Joined: Dec 06, 2009 22:27
Location: N47°, E15°
Contact:

Re: Miscalleneous bugs in the 32bit compiler

Post by TJF »

@Zippy

can you please send the results of a second test with swapped order of the initialisations

Code: Select all

'PDS 7.1
'
CLS
DIM fs AS STRING * 18
DIM s  AS STRING
'
'deliberately not assigning last 2 bytes
s = CHR$(0) + "December" + CHR$(0) + CHR$(0) + "2013" + CHR$(0)
fs = s
PRINT "               11111111112"
PRINT "      12345678901234567890"
PRINT "fs = <"; fs; ">", LEN(fs); "bytes"
'
PRINT " s = <"; s; ">", LEN(s); "bytes"
Zippy
Posts: 1295
Joined: Feb 10, 2006 18:05

Re: Miscalleneous bugs in the 32bit compiler

Post by Zippy »

TJF wrote:@Zippy

can you please send the results of a second test with swapped order of the initialisations
<snip>
Variable-length string to fixed-length:

Code: Select all

'PDS Output:
'
               11111111112
      12345678901234567890
 s = < December  2013 >      16 bytes
fs = < December  2013   >    18 bytes
'
'fb Output:
'
               11111111112
      12345678901234567890
 s = < December  2013 >      16 bytes
fs = < December  2013   >    18 bytes
This is correct/expected behavior, me thinks.
stephanbrunker
Posts: 62
Joined: Nov 02, 2013 14:57

Re: Miscalleneous bugs in the 32bit compiler

Post by stephanbrunker »

I have to admit that my intepretation of the definition of "bug" was probably not the right one. But for me, the behaviour was not like I expected. Sometimes, the result for not is expanded to the bitlength of the result, and sometimes not. My current project is a just-for-fun implementation of some crypto ( I know: Never implement crypto yourself!), including finding and optimizing a bigint-implementation. And following that, i had a nice time to localize why my code doesn't work as expected, and every second time I get that nasty "Ambigious call for overloaded function" when I try to check my values with hex because they are mostly stored in binary strings or 32bit datatypes like ulong. (Okay, the code for the string to hex was quickly copied together and false ...). Or if i want to store the keys in a ascII-coded Hex textfile for later reading and re-converting them in a string. And, because the pseudorandom strings are like random, every 256th byte is a nullbyte and of course, I'd miss it in a concatenation situation.

My precedessor used not in the bigint as solution for subtraction with unsigned 32-bit-blocks, but this got south as I used 16 and 64 bit-blocks in the optimization of the division. It took me days to figure something out what was as fast as possible and actually worked.

Salsa20 and the SHA-3 are using both bitrotation and rol and ror are actually Assembler commands, so why not implement them?

And why is:

Code: Select all

dim shared a as string   
a = string(32,0)
' compiles fine

dim shared a as string = string(32,0)
'error
?
dodicat
Posts: 7983
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: Miscalleneous bugs in the 32bit compiler

Post by dodicat »

I think because Freebasic is tending towards Gcc.
With -gen gcc assembler code doesn't work at the moment.

But the developers hopefully will keep -gen gas alive and running.

Here's some more rots compared to your assembler:

Code: Select all

Function roL(N As Uinteger,S As Integer) As Uinteger
    Return N Shl S Or N Shr  (Sizeof(N)*8-S)
End Function

Function roR(N As Uinteger,S As Integer) As Uinteger
    Return N Shr S Or N Shl (Sizeof(N)*8-S)
End Function

Function rotateleft(Byval x As Ulong, Byval y As Ubyte) As Ulong
    Asm
        mov   eax,[x]
        mov   cl,[y]
        rol   eax,cl
        mov [Function],eax
    End Asm
End Function

Function rotateright(Byval x As Ulong, Byval y As Ubyte) As Ulong
    Asm
        mov   eax,[x]
        mov   cl,[y]
        ror   eax,cl
        mov [Function],eax
    End Asm
End Function

#define Intrange(f,l) int(Rnd*((l+1)-(f))+(f))
Dim As Integer i,rot
Dim As String ikey
Do
    ikey=Inkey
    i=IntRange(0,1000)
    rot=IntRange(-5,5)
    Print "-----------------"
    Print rotateleft(i,rot),roL(i,rot),"rotleft (";i;",";rot;")"
    Print
    Print rotateright(i,rot),roR(i,rot),"rotright (";i;",";rot;")"
    Print "-----------------"
    Print
    Sleep
Loop Until ikey=Chr(27)
Sleep
  
dodicat
Posts: 7983
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: Miscalleneous bugs in the 32bit compiler

Post by dodicat »

stephanbrunker.
Since you quite like Richard's bigint stuff, heres a little treat for you.
Bigroller to the left:

Code: Select all

'==================  PLUS FUNCTION ==============================
Dim Shared ADDQmod(0 To 19) As Ubyte
Dim Shared ADDbool(0 To 19) As Ubyte
For z As Integer=0 To 19
    ADDQmod(z)=(z Mod 10+48)
    ADDbool(z)=(-(10<=z))
Next z 
Function plus(_num1 As String,_num2 As String) As String
    Var _flag=0,n_=0
    Dim As Ubyte addup=Any,addcarry=Any
    #macro finish()
    answer=Ltrim(answer,"0")
    If _flag=1 Then Swap _num2,_num1
    Return answer
    #endmacro
    If Len(_num2)>Len(_num1) Then 
        Swap _num2,_num1
        _flag=1
        Endif
        Var diff=Len(_num1)-Len(_num2)
        Var answer="0"+_num1
        addcarry=0
        For n_=Len(_num1)-1 To diff Step -1 
            addup=_num2[n_-diff]+_num1[n_]-96
            answer[n_+1]=ADDQmod(addup+addcarry)
            addcarry=ADDbool(addup+addcarry)
        Next n_ 
        If addcarry=0 Then 
            finish()
        End If
        If n_=-1 Then 
            answer[0]=addcarry+48
            finish()
            Endif
            For n_=n_ To 0 Step -1 
                addup=_num1[n_]-48
                answer[n_+1]=ADDQmod(addup+addcarry)
                addcarry=ADDbool(addup+addcarry)
                If addcarry=0 Then Exit For
            Next n_
            answer[0]=addcarry+48
            finish()
        End Function
        
        ' ============== BINARY TO DECIMAL =================================     
        Function Base10(BinaryNumber As String) As String
            Dim As String sum
            sum=Left(BinaryNumber,1)
            For n As Integer=2 To Len(BinaryNumber)
                sum=plus(plus(sum,sum),Chr(BinaryNumber[n-1])) 
            Next n
            Return sum
        End Function
        
        ' ==================== DECIMAL TO BINARY ==================================  
        
        Function base2(DecimalNumber As String) As String
            Dim As String starter=DecimalNumber,ans,m,b
            Dim As Ubyte main,carry,temp',c
            Dim As Integer c
            #macro reverse(s)
            Scope
                Var lens=Len(s)
                For n As Integer=0 To Int((lens-1)/2):Swap s[n],s[lens-1-n]:Next
                End Scope
                #endmacro
                #macro div2(s,m,c)
                carry=0:ans=s
                For z As Integer=0 To Len(s)-1
                    temp=(s[z]-48+carry)
                    main=temp Shr 1
                    carry=(temp And 1) Shl 3 +(temp And 1) Shl 1
                    ans[z]=main+48
                Next z
                c= carry\10
                m= Ltrim(ans,"0")
                #endmacro
                Do
                    c=0
                    div2(starter,m,c)
                    b=b+Str(c)
                    starter=m
                Loop Until m="1"
                reverse(b)
                b=Str(m)+b
                Var Ln=Len(b) Mod 32
                Var s=String(32-Ln,"0")
                Return s+b
            End Function
            
            #macro reverse(s)
            Scope
                Var lens=Len(s)
                For n As Integer=0 To Int((lens-1)/2):Swap s[n],s[lens-1-n]:Next
                End Scope
                #endmacro
                
                Function Rol(in As String,c As Integer) As String
                    Var s=in
                    s=base2(s)
                    reverse(s)
                    If c=0 Then Return in
                    c=c Mod Len(s)
                    For z As Integer=1 To c
                        For n As Integer=Len(s)-1 To 1 Step -1
                            Swap s[n],s[n-1]
                        Next n
                    Next z
                    reverse(s)
                    s=base10(s)
                    Return s
                End Function
                
                Function rotateleft(Byval x As Ulong, Byval y As Ubyte) As Ulong
                    Asm
                        mov   eax,[x]
                        mov   cl,[y]
                        rol   eax,cl
                        mov [Function],eax
                    End Asm
                End Function
                
                '=========  SMALL TEST =================      
                #define Intrange(f,l) Int(Rnd*((l+1)-(f))+(f))
                Dim As Integer i,rot
                Dim As String ikey
                Do
                    ikey=Inkey
                    i=IntRange(0,1000)
                    rot=IntRange(0,5)
                    Print "-----------------"
                    Print rotateleft(i,rot),roL(Str(i),rot),"rotleft (";i;",";rot;")"
                    Print "-----------------"
                    Print
                    Sleep
                Loop Until Inkey=Chr(27)
                
                '===========  BIG ONE ===============        
                Print "big one"
                Dim As String s
                s=String(500,"9")+String(500,"7")
                Print "Rol(";s;" ,50)"
                Print
                Print Rol(s,50)
                
                Sleep
                
                
                 
MichaelW
Posts: 3500
Joined: May 16, 2006 22:34
Location: USA

Re: Miscalleneous bugs in the 32bit compiler

Post by MichaelW »

stephanbrunker wrote: 4. rol and ror
(bit rotate right and left) are not supported, but used often in crypto. For 32bit rotate left, it looks like:

Code: Select all

Function rotateleft(ByVal x As ulong, byval y as ubyte) as ulong
    Asm
        mov   eax,[x]
        mov   cl,[y]
        rol   eax,cl
        mov [Function],eax
    End Asm
End Function
Coded that way the compiler (-gen gas) is adding a bunch of overhead to the function:

Code: Select all

_ROTATELEFT@8:
push ebp
mov ebp, esp
sub esp, 4
push ebx
push esi
push edi
mov dword ptr [ebp-4], 0
.Lt_0004:
mov eax,[ebp+8]
mov cl,[ebp+12]
rol eax,cl
mov [ebp-4],eax
.Lt_0005:
mov eax, dword ptr [ebp-4]
pop edi
pop esi
pop ebx
mov esp, ebp
pop ebp
ret 8
Where for a naked function, the code can be reduced to the minimum:

Code: Select all

_ROL@8:
.Lt_0006:
mov eax, [esp+4]
mov ecx, [esp+8]
rol eax, cl
ret 8

Code: Select all

function rotateleft(x As uinteger, y as uinteger) as uinteger
    asm
        mov eax,[x]
        mov cl,[y]
        rol eax,cl
        mov [function],eax
    end asm
end function

function rol naked( x as uinteger, y as uinteger ) as uinteger
    asm
        mov eax, [esp+4]
        mov ecx, [esp+8]
        rol eax, cl
        ret 8
    end asm
end function

dim as integer x
dim as double t

x = 1
for y as integer = 0 to 32
    print bin(rotateleft(x,y),32)
    print bin(rol(x,y),32)
next
print

sleep 5000

t = timer
for i as integer = 1 to 1000000
    x = rotateleft(1,16)
next
print timer-t

t = timer
for i as integer = 1 to 1000000
    x = rol(1,16)
next
print timer-t

sleep
The timing running on a P3:

Code: Select all

 0.04763203144987926
 0.02204609803906266
fxm
Moderator
Posts: 12107
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Miscalleneous bugs in the 32bit compiler

Post by fxm »

stephanbrunker wrote:And why is:

Code: Select all

dim shared a as string   
a = string(32,0)
' compiles fine

dim shared a as string = string(32,0)
'error
?
See documentation at SHARED and specially the following note:
KeyPgShared wrote:.....
Note: A shared variable may only be initialized with a constant value: its starting value is set at the start of the program before any code is run, and so it cannot depend on any variables or functions in it. The exception is a shared variable of var-len string type, which never can be initialized, even with a constant string, because of its structure with a descriptor pointing to dynamic memory block.
.....
Post Reply