Illegal mov in Assembler to UDT

General FreeBASIC programming questions.
Post Reply
stephanbrunker
Posts: 62
Joined: Nov 02, 2013 14:57

Illegal mov in Assembler to UDT

Post by stephanbrunker »

Hello,

there's an tutorial at freebasic-portal.de about Inline-Assembler. Okay, last update was 2009 ...

But this code doesn't compiles anymore (but surely it did anno 2009):

Code: Select all

Type pnt
   x As Integer
   y As Integer
End Type
Dim Punkt As pnt

 Punkt.x = 17
 Punkt.y = 55
Print Punkt.x, Punkt.y

Asm
   mov eax, [Punkt]    'eax = Punkt.x
   add eax, [Punkt+4]  'eax + Punkt.y
   Inc eax             'eax + 1
   Shr eax, 1          'eax=(Punkt.x + Punkt.y +1)/2
   mov [Punkt], eax    'Punkt.x = eax
   mov [Punkt+4], eax  'Punkt.y = eax
End Asm

Print Punkt.x,Punkt.y
The message is, that the return move from eax to the UDT member is "unsupported".

Any Ideas? Because I'm going to write an 128-Bit datatype for x64 freebasic and I for that I have to do some operations in Assembler, like the 64bit * 64bit = 128 bit multiply, which is supported by the platform. My datatype is an UDT with a high and a low Ulongint, and I'd like to write to these UDT members, of course ...
fxm
Moderator
Posts: 12106
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Illegal mov in Assembler to UDT

Post by fxm »

It compiles with 'gas' but not with 'gcc'!
caseih
Posts: 2157
Joined: Feb 26, 2007 5:32

Re: Illegal mov in Assembler to UDT

Post by caseih »

Just curious, but what operations will require assembler to implement?
fxm
Moderator
Posts: 12106
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Illegal mov in Assembler to UDT

Post by fxm »

But for the asm block syntax (with gas) accessing UDT fields, I prefer this more safe syntax:

Code: Select all

Type pnt
   x As Integer
   y As Integer
End Type
Dim Punkt As pnt

 Punkt.x = 17
 Punkt.y = 55
Print Punkt.x, Punkt.y

Asm
   mov eax, [Punkt+offsetof(pnt, x)]  'eax = Punkt.x
   add eax, [Punkt+offsetof(pnt, y)]  'eax + Punkt.y
   Inc eax                            'eax + 1
   Shr eax, 1                         'eax=(Punkt.x + Punkt.y +1)/2
   mov [Punkt+offsetof(pnt, x)], eax  'Punkt.x = eax
   mov [Punkt+offsetof(pnt, y)], eax  'Punkt.y = eax
End Asm

Print Punkt.x,Punkt.y
St_W
Posts: 1626
Joined: Feb 11, 2009 14:24
Location: Austria
Contact:

Re: Illegal mov in Assembler to UDT

Post by St_W »

Using inline assembly:

Code: Select all

Type pnt
   x As Integer
   y As Integer
End Type
Dim Punkt As pnt

Punkt.x = 17
Punkt.y = 55
Print Punkt.x, Punkt.y

#If (Not Defined(__FB_64BIT__))
	#Error "only x86_64 architecture supported"
#EndIf
Asm
	lea rcx, Punkt
	mov rax, [rcx+offsetof(pnt, x)]
	Add rax, [rcx+OffsetOf(pnt, y)]
	inc rax
	Shr rax, 1
	mov [rcx+offsetof(pnt, x)], rax
	mov [rcx+offsetof(pnt, y)], rax
End Asm


Print Punkt.x,Punkt.y
Sleep
or alternatively implementing it using a (naked) function:

Code: Select all

Type pnt
   x As Integer
   y As Integer
End Type
Dim Punkt As pnt

Punkt.x = 17
Punkt.y = 55
Print Punkt.x, Punkt.y


Sub doCalc Naked (p As pnt Ptr)
#If (Not Defined(__FB_WIN32__)) Or (Not Defined(__FB_64BIT__))
	#Error "only x86_64 architecture on windows supported"
#EndIf
	Asm
		mov rax, [rcx+offsetof(pnt, x)]
		Add rax, [rcx+offsetof(pnt, y)]
		inc rax
		Shr rax, 1
		mov [rcx+offsetof(pnt, x)], rax
		mov [rcx+offsetof(pnt, y)], rax
		ret
	End Asm
End Sub

doCalc(@Punkt)

Print Punkt.x,Punkt.y
Sleep
Of course using assembly does not make sense in this example.


See also
https://msdn.microsoft.com/en-us/library/ms235286.aspx
https://msdn.microsoft.com/en-us/library/6t169e9c.aspx
(or the corresponding docs of the platform you use)

The calling conventions used by Windows / Unix differ and are not compatible, so you probably have to adapt the code to the corresponding platform.

//edit: integrated fxm's suggestion using "offsetof" instead of hardcoded offsets; I didn't know that FB's inline assembly supports that
//edit2: I've updated the wiki/tutorial pages accordingly with portability warnings (text in german):
http://www.freebasic-portal.de/tutorial ... ic-50.html
http://www.freebasic-portal.de/befehlsr ... sm-47.html
http://www.freebasic-portal.de/befehlsr ... r-434.html
//edit3: corrected too many brackets error introduced with first edit (thanks again, fxm)
Last edited by St_W on Jul 08, 2015 14:05, edited 1 time in total.
fxm
Moderator
Posts: 12106
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: Illegal mov in Assembler to UDT

Post by fxm »

In the naked version, there would not have too of square brackets right (see 4 lines)?

[edit]
OK now.
Last edited by fxm on Jul 08, 2015 16:28, edited 2 times in total.
stephanbrunker
Posts: 62
Joined: Nov 02, 2013 14:57

Re: Illegal mov in Assembler to UDT

Post by stephanbrunker »

Thank you for the help.

I know that with assembler code I'm bound to a specific platform. But in this case, the x86 version of the code is already running, and I want to add a 64-bit version, which is (hopefully) many times faster because of the wider blocksize. Crypto applications running very slow if designed for quadwords and executed on 32-bit. Of course, I'd prefer if somebody else extend the 64-bit fbc with this 128-bit datatype like it was done with longint on 32-bit, but somebody has to start working on that.

So, first application is the RFC-4418 UMAC, which needs some 64x64bit = 128 bit operations, and second is the implementation of the ElGamal assymmetric cryptosystem, which needs calculations for 2048-bit numbers, for which I've evolved the Big_Integer code originally from Richard. This one is at the moment based on a 32/16-bit wordsize, and would also greatly improve with 64-bit wordsize. The slowest operation is the division - at the moment I need a testdivison for the highest 48bit (blocksize 16bit + previous remainder 16bit + 16bit overflow from the next lowest block), and a greater blocksize with the same processor cycles increases the speed, of course ...
stephanbrunker
Posts: 62
Joined: Nov 02, 2013 14:57

Re: Illegal mov in Assembler to UDT

Post by stephanbrunker »

Oh, I tried -gen gas and there is a new error:
error 82: Selected -gen gas ASM backend for non-x86 CPU, x86-64

???

Okay, here is the very first beginning of the project. Without -gen gas, it compiles now, but it returns zero for the addition. If I DIM two Ulongints in the Operator, move the result there and then again copy the Uintegers in the return Ulonglongint, it works. But thats two steps more than neccessary.

Code: Select all

#If (Not Defined(__FB_64BIT__))
    #Error "only x86_64 architecture supported"
#EndIf

Type Ulonglongint
    lo as ULongint
    hi as Ulongint
    Declare Constructor ()
    Declare Constructor (Byref a as Ulongint)
    Declare Operator Let (Byref a as Ulonglongint)
End Type

Declare Operator + (ByRef x As Ulonglongint) As Ulonglongint
Declare Operator + (ByRef aa As Ulonglongint, ByRef bb As Ulonglongint) As Ulonglongint
Declare Function CUlnglng Overload(a as ULongInt) as Ulonglongint

Constructor Ulonglongint ()
    this.hi = 0
    this.lo = 0
End Constructor
    
Constructor Ulonglongint (Byref a as Ulongint)
    this.hi = 0
    this.lo = a
End Constructor

Operator Ulonglongint.Let (Byref a as Ulonglongint)
    this.hi = a.hi
    this.lo = a.lo
End Operator

Function CUlnglng Overload(a as ULongInt) as Ulonglongint
    Dim as Ulonglongint b = a
    Return b
End Function

Operator + (ByRef x As Ulonglongint) As Ulonglongint
	Return x
End Operator

Operator + (ByRef aa As Ulonglongint, ByRef bb As Ulonglongint) As Ulonglongint
    Dim as Ulonglongint cc = 0
    asm
        mov rsi,[aa]
        mov rdi,[bb]
        mov rax,[rsi+offsetof(Ulonglongint,lo)]
        mov rbx,[rsi+offsetof(Ulonglongint,hi)]
        add rax,[rdi+offsetof(Ulonglongint,lo)]
        adc rbx,[rdi+offsetof(Ulonglongint,hi)]
        mov rsp,[cc]
        mov [rsp+offsetof(Ulonglongint,lo)],rax
        mov [rsp+offsetof(Ulonglongint,hi)],rbx
    end asm
    Return cc
End Operator

'=====================================================
        
dim a as Ulongint = &h8000800080008000
dim b as Ulongint = &h8000800080008000
dim as Ulonglongint c
c = Culnglng(a) + Culnglng(b)
print hex(c.hi,16),hex(c.lo,16)
Last edited by stephanbrunker on Jul 08, 2015 17:52, edited 1 time in total.
St_W
Posts: 1626
Joined: Feb 11, 2009 14:24
Location: Austria
Contact:

Re: Illegal mov in Assembler to UDT

Post by St_W »

Gen gas is only supported on x86. My x86_64 code example was intended to be compiled with gen gcc as usual for x86_64 (just leave it out).
stephanbrunker
Posts: 62
Joined: Nov 02, 2013 14:57

Re: Illegal mov in Assembler to UDT

Post by stephanbrunker »

Now, I've running addition, subtraction and multiply, even if I cannot access the UDT directly from the asm inside the operators.

But then, the DIV command doesn't work, while at the same place IDIV works (replace IDIV with DIV and an error occurs):
(and it's the same with DWORD or QWORD operation)

Code: Select all

dim as uinteger b = 738
dim as ulongint a = 345987
dim as uinteger r,q
sub div(byref a as ulongint,byref b as uinteger, byref q as uinteger,byref r as uinteger)
    dim as uinteger a1 = a
    dim as uinteger a2 = a shr 32
    asm
        mov rsi,[b]
        mov eax,dword ptr[a1]
        mov edx,dword ptr[a2]
        idiv dword ptr[rsi]
        mov rsi,[q]
        mov rbp,[r]
        mov [rsi],eax
        mov [rbp],edx
    end asm
end sub
div(a,b,r,q)
print "a : ";a;" / b : ";b
print "= ";q; "rest ";r
St_W
Posts: 1626
Joined: Feb 11, 2009 14:24
Location: Austria
Contact:

Re: Illegal mov in Assembler to UDT

Post by St_W »

stephanbrunker wrote:Now, I've running addition, subtraction and multiply, even if I cannot access the UDT directly from the asm inside the operators.

But then, the DIV command doesn't work, while at the same place IDIV works (replace IDIV with DIV and an error occurs):
(and it's the same with DWORD or QWORD operation) [..]
The DIV does not work because of a name clash. Rename the function e.g. to "doDiv" to make it work. I'd regard that a bug in the compiler...
St_W
Posts: 1626
Joined: Feb 11, 2009 14:24
Location: Austria
Contact:

Re: Illegal mov in Assembler to UDT

Post by St_W »

St_W wrote:The DIV does not work because of a name clash. Rename the function e.g. to "doDiv" to make it work. I'd regard that a bug in the compiler...
dkl (thank you!) has fixed that in his latest commit, see related ticket: http://sourceforge.net/p/fbc/bugs/782/
the fix, however, prevents usage of asm keywords as references to fb symbols at all - e.g. "MOV eax, [div]" isn't possible anymore after that fix.
You can try a nightly FreeBasic build or compile the newest fbc sources yourself for testing this fix.
nightly builds: http://users.freebasic-portal.de/stw/builds/ (see the changelog to be sure that the build contains the fix)

@dkl: this seems to have introduced a build error of the inline-asm test (x64):

Code: Select all

fbc.exe -c -w 3 -i fbcu/include  -mt quirk/inline-asm-syntax.bas
quirk/inline-asm-syntax.c: In function 'TEST':
quirk/inline-asm-syntax.c:29:28: error: expected ':' or ')' before 'incl'
  __asm__ __volatile__( "\t"incl %0\n" : "+m" (%0) : :\n" : "=m" (A$1) : "m" (A$1) : "cc", "memory", "eax", "ebx", "ecx", "edx", "esp", "edi", "esi" );
                            ^
quirk/inline-asm-syntax.c:29:28: error: stray '\' in program
dkl
Site Admin
Posts: 3235
Joined: Jul 28, 2005 14:45
Location: Germany

Re: Illegal mov in Assembler to UDT

Post by dkl »

St_W wrote:[...] prevents usage of asm keywords as references to fb symbols at all - e.g. "MOV eax, [div]" isn't possible anymore after that fix.
Well, as far as -gen gas is concerned, nothing changed, and as for -gen gcc, it now behaves the same as -gen gas in this aspect.

Thanks for reporting the issue with the test case, it should be fixed in Git now. Turns out __FB_ASM__ wasn't being defined on x86_64.
Post Reply