flat assembler
Message board for the users of flat assembler.
 Home   FAQ   Search   Register 
 Profile   Log in to check your private messages   Log in 
flat assembler > Linux > Reading int or float from the command line

Goto page 1, 2  Next
Author
Thread Post new topic Reply to topic
dstyl



Joined: 23 Jul 2015
Posts: 48
Reading int or float from the command line
Hello i have the following problem.
Ive wrote a programm to calculate the average of x amount of numbers.
I used xmm registers and im getting wrong results.
3 3 3 averages to 2.2518e+15 which cant be right.
Thanks in advance Smile

Code:

; -----------------------------------------------------------------------------
; 64-bit program that treats all its command line arguments as floating point 
; number and displays their average as a floating point number.  This program 
; uses a data section to store intermediate results, not that it has to, but 
; only to illustrate how data sections are used.
; -----------------------------------------------------------------------------
        global  main

        extern  atof

        extern  printf

        default rel


                section .text
main:
                dec                     rdi                                     ;argc-1, da wir den programm namen ignorieren
                jz                      nothingToAverage        ;wenn rdi == 0
                mov                     [count], rdi            ;speichere args in [count]
accumulate:
                push            rdi                                     ;sichere reg vor atoi aufruf
                push            rsi
                mov                     rdi, [rsi+rdi*8]        ;argv[rdi] c alignment beachten!
                call            atof                            ;rax enthält den wert von arg
                pop                     rsi                                     ;wiederherstellen der reg nach
                pop                     rdi                                     ;aufruf von atoi
                add                     [sum], rax                      ;summieren der werte
                dec                     rdi                                     ;argc runterzählen
                jnz                     accumulate                      ;wiederhole wen argc != 0
average:
                movsd           xmm0, [sum]                     ;verschiebe signed double
                movsd           xmm1, [count]           ;in xmm register
                divsd           xmm0xmm1                      ;xmm0 ist sum/count
                mov                     rdiformat                     ;erste arg für printf
                mov                     rax1                          ;printf hat var args es gibt 1 nicht
                sub                     rsp8                          ;align des stackpointers
                call            printf                          ;printf(format, sum/count)
                add                     rsp8                          ;wiederherstellen des stackpointers

                ret
nothingToAverage:
                mov                     rdierror
                xor                     raxrax
                call            printf
                ret
                section .data
count:  dq              0
sum:    dq              0
formatdb              "%g"100
error:  db              "There are no cmdcmnds to average"100




Last edited by dstyl on 20 Apr 2017, 10:08; edited 1 time in total
Post 19 Apr 2017, 17:28
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 14794
Location: Lost in translation
You are using an integer instruction (add) on floating point values. Instead you will need to use a floating point instruction (addsd or equivalent) to do the addition.
Post 19 Apr 2017, 17:36
View user's profile Send private message Visit poster's website Reply with quote
dstyl



Joined: 23 Jul 2015
Posts: 48
thanks a lot i tried it out and replaced add with addsd [sum],rax but im getting an opcode error now.
Post 19 Apr 2017, 17:42
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 14794
Location: Lost in translation
Using XMM is not quite the same as the integer instructions. You'll need to load the value from RAX into one of the XMM registers first, and then do the addsd. But AFICT there is no direct instruction to transfer RAX into XMM, so you'll need to place RAX in memory first, and then load into XMM from memory.
Post 19 Apr 2017, 17:53
View user's profile Send private message Visit poster's website Reply with quote
dstyl



Joined: 23 Jul 2015
Posts: 48
I ve commented out some lines just to check if the movsd works and there is the error. is there
another opcode to move a float from mem to reg?

Code:

; -----------------------------------------------------------------------------
; 64-bit program that treats all its command line arguments as floating point 
; number and displays their average as a floating point number.  This program 
; uses a data section to store intermediate results, not that it has to, but 
; only to illustrate how data sections are used.
; -----------------------------------------------------------------------------
        global  main

        extern  atof

        extern  printf

        default rel


                section .text
main:
                dec                     rdi                                     ;argc-1, da wir den programm namen ignorieren
                jz                      nothingToAverage        ;wenn rdi == 0
                mov                     [count], rdi            ;speichere args in [count]
accumulate:
                push            rdi                                     ;sichere reg vor atof aufruf
                push            rsi
                mov                     rdi, [rsi+rdi*8]        ;argv[rdi] c alignment beachten!
                call            atof                            ;rax enthält den wert von arg
                pop                     rsi                                     ;wiederherstellen der reg nach
                pop                     rdi                                     ;aufruf von atof
                add                     [sum], rax                      ;summieren der werte
                dec                     rdi                                     ;argc runterzählen
                jnz                     accumulate                      ;wiederhole wen argc != 0
average:
                movsd           xmm0, [sum]                     ;verschiebe signed double
;               movsd           xmm1, [count]           ;in xmm register
;               divsd           xmm0, xmm1                      ;xmm0 ist sum/count
                mov                     rdiformat                     ;erste arg für printf
                mov                     rax1                          ;printf hat var args es gibt 1 nicht
                sub                     rsp8                          ;align des stackpointers
                call            printf                          ;printf(format, sum/count)
                add                     rsp8                          ;wiederherstellen des stackpointers

                ret
nothingToAverage:
                mov                     rdierror
                xor                     raxrax
                call            printf
                ret
                section .data
count:  dq              0
sum:    dq              0
formatdb              "%g"100
error:  db              "There are no cmdcmnds to average"100


Post 19 Apr 2017, 18:02
View user's profile Send private message Reply with quote
cod3b453



Joined: 25 Aug 2004
Posts: 614
There is a movd xmm,reg64 (66 0F 6E /r) but seems FASM doesn't support it syntactically and instead (re)uses movq xmm,reg64 which seems to assemble to the expected opcode [and kinda makes more sense really].
Post 19 Apr 2017, 18:06
View user's profile Send private message Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 14794
Location: Lost in translation
Okay, movq is the one.

Code:
movq xmm0,rax
addsd [sum],xmm0

Post 19 Apr 2017, 18:15
View user's profile Send private message Visit poster's website Reply with quote
dstyl



Joined: 23 Jul 2015
Posts: 48
Thanks for your time but it still doesnt work now i replaced addsd because it says invalid opcode so now i have

Code:

; -----------------------------------------------------------------------------
; 64-bit program that treats all its command line arguments as floating point 
; number and displays their average as a floating point number.  This program 
; uses a data section to store intermediate results, not that it has to, but 
; only to illustrate how data sections are used.
; -----------------------------------------------------------------------------
        global  main

        extern  atof

        extern  printf

        default rel


                section .text
main:
                dec                     rdi                                     ;argc-1, da wir den programm namen ignorieren
                jz                      nothingToAverage        ;wenn rdi == 0
                mov                     [count], rdi            ;speichere args in [count]
accumulate:
                push            rdi                                     ;sichere reg vor atof aufruf
                push            rsi
                mov                     rdi, [rsi+rdi*8]        ;argv[rdi] c alignment beachten!
                call            atof                            ;rax enthält den wert von arg
                pop                     rsi                                     ;wiederherstellen der reg nach
                pop                     rdi                                     ;aufruf von atof
;
                movq            xmm0,rax
                movq            [sum],xmm0 
;
;               add                     [sum], rax                      ;summieren der werte
                dec                     rdi                                     ;argc runterzählen
                jnz                     accumulate                      ;wiederhole wen argc != 0
average:
;               movsd           xmm0, [sum]                     ;verschiebe signed double
;               movsd           xmm1, [count]           ;in xmm register
;               divsd           xmm0, xmm1                      ;xmm0 ist sum/count
                mov                     rdiformat                     ;erste arg für printf
                mov                     rax1                          ;printf hat var args es gibt 1 nicht
                sub                     rsp8                          ;align des stackpointers
                call            printf                          ;printf(format, sum/count)
                add                     rsp8                          ;wiederherstellen des stackpointers

                ret
nothingToAverage:
                mov                     rdierror
                xor                     raxrax
                call            printf
                ret
                section .data
count:  dq              0
sum:    dq              0
formatdb              "%g"100
error:  db              "There are no cmdcmnds to average"100


Post 19 Apr 2017, 18:39
View user's profile Send private message Reply with quote
redsock



Joined: 09 Oct 2009
Posts: 251
Location: Australia
Rather than fixup your code, I wrote an equivalent with my own x86_64 linux library.

Of note in yours however, atof returns its result in xmm0, not rax. Anyway, my morning coffee writeup works and should help Smile cheers.

Code:
include 'HeavyThing-1.19/ht_defaults.inc'
include 'HeavyThing-1.19/ht.inc'

public _start
falign
_start:
        call    ht$init

        sub     dword [argc], 1
        jz      .nothingtodo
        ; store our double accumulator and counter in callee-saves
        ; (xmm regs are not callee-save)
        xor     r15dr15d
        xor     ebxebx
.accumulate:
        ; accumulate arguments in reverse order
        mov     rdi, [argv]
        call    list$pop_back
        ; HeavyThing turns argv into strings, save it
        mov     r12rax
        
        ; convert it to double
        mov     rdirax
        call    string$to_double
        ; accumulate and increase counter
        movq    xmm1r15
        addsd   xmm1xmm0
        movq    r15xmm1
        add     ebx1
        ; free the string
        mov     rdir12
        call    heap$free
        ; keep going
        sub     dword [argc], 1
        jnz     .accumulate
        
        ; prepare our argument for double to string
        movq    xmm0r15
        ; convert our counter to a double
        cvtsi2sd        xmm1ebx
        ; divide them
        divsd   xmm0xmm1
        ; display the result
        ; string$from_double needs mode and precision
        mov     edidouble_string_normal
        mov     esi15
        call    string$from_double
        mov     r12rax
        mov     rdirax
        call    string$to_stdoutln
        mov     rdir12
        call    heap$free
        ; exit cleanly
        mov     eaxsyscall_exit
        xor     ediedi
        syscall
.nothingtodo:
        mov     rdi.nothingmsg
        call    string$to_stderrln
        mov     eaxsyscall_exit
        mov     edi1
        syscall
cleartext .nothingmsg'Nothing to average.'

include 'HeavyThing-1.19/ht_data.inc'


Output examples:

Code:
./average 3 3 3 3
3
./average 3 3 3 3 5
3.4
./average 3 3 3 3 9 11
5.333333333333333



_________________
2 Ton Digital - https://2ton.com.au/
Post 19 Apr 2017, 22:00
View user's profile Send private message Reply with quote
fasmnewbie



Joined: 01 Mar 2011
Posts: 396
You don't need atof in there. Just use atoi then convert it to double using CVTxxx

sub rsp,8
sub rdi
mov [count],rdi
... loop
call atoi
cvtsi2sd... convert integer in rax to float (double)
addsd some_accumulator

after the loop
cvtsi2sd [count]
divsd some_accumulator, [count]
printf
add rsp,8
ret
Post 20 Apr 2017, 04:38
View user's profile Send private message Visit poster's website Reply with quote
revolution
When all else fails, read the source


Joined: 24 Aug 2004
Posts: 14794
Location: Lost in translation

fasmnewbie wrote:
You don't need atof in there.

How do you know that? Maybe the user wants to enter numbers like 3.1415926535
Post 20 Apr 2017, 04:45
View user's profile Send private message Visit poster's website Reply with quote
fasmnewbie



Joined: 01 Mar 2011
Posts: 396
@revolution.

Look at his comment lines. It is clear he's trying to solve an ATOI problem but thought he could use ATOF as the solution. Also look at his input attempt. This type of question is a familiar question among beginners so we should be able to anticipate beginner's confusions and intentions. Which is something like so;

Code:
global main
extern atoi
extern printf

section .data
formt db 'Average = %f',0ah,0

section .code
main:   sub     rsp,8
        mov     r14,rdi
        sub     r14,1
        mov     r13,r14         ;count
        mov     r15,rsi
        pxor    xmm8,xmm8       ;accumulator
.next:  mov     rdi,[r15+r14*8]
        call    atoi
        cvtsi2sd xmm0,rax       ;convert int to double
        addsd   xmm8,xmm0       ;add to accumulator
        sub     r14,1
        jnz     .next
        cvtsi2sd xmm0,r13       ;convert count to double
        divsd   xmm8,xmm0       ;average is here
        movq    xmm0,xmm8       ;prepare for printf
        mov     rdi,formt
        mov     rax,1
        call    printf
        add     rsp,8
        ret

Post 20 Apr 2017, 05:30
View user's profile Send private message Visit poster's website Reply with quote
redsock



Joined: 09 Oct 2009
Posts: 251
Location: Australia
While I appreciate what you're saying @fasmnewbie, the OP actually used xmm regs AND atof, which together suggest the need for floating point math. My example (though I didn't bother to include example output) does exactly that with arbitrary floating point input. Your example is much cleaner though for whole integers. Maybe there is some middle ground for people who struggle with things.

Code:
./average 3.1415 1.0003e-1 6.283
3.1748433333333335



_________________
2 Ton Digital - https://2ton.com.au/
Post 20 Apr 2017, 05:53
View user's profile Send private message Reply with quote
fasmnewbie



Joined: 01 Mar 2011
Posts: 396
@redsock

My suspicion is not baseless though. I see traces of previous ATOI attempts in both his side comments and his implied input (3 3 3 3...). But when the result was not that satisfying, he resorted to ATOF. Mixing both FP and integer is not a beginner's material IMO. He probably needs more than one externs from the C library if such was the case.
Post 20 Apr 2017, 06:24
View user's profile Send private message Visit poster's website Reply with quote
fasmnewbie



Joined: 01 Mar 2011
Posts: 396
This is a quick fix to my original progam above, just in case the user can key in both FP and integer values at the command-line;


Code:
global main

extern atoi
extern atof
extern strchr
extern printf

section .data
formt db 'Average = %f',0ah,0

section .code
main:
        sub     rsp,8           ;align the stack
        mov     r14,rdi
        sub     r14,1
        mov     r13,r14         ;count
        mov     r15,rsi         ;command string pointer
        pxor    xmm8,xmm8       ;accumulator
.next:  mov     rdi,[r15+r14*8]
        mov     rsi,'.'
        call    strchr
        test    rax,rax
        jnz     .float
        mov     rdi,[r15+r14*8]
        call    atoi
        cvtsi2sd xmm0,rax       ;convert int to double
        jmp     .ints
.floatmov     rdi,[r15+r14*8]
        call    atof
.ints:  addsd   xmm8,xmm0       ;add to accumulator
        sub     r14,1
        jnz     .next
        cvtsi2sd xmm0,r13       ;convert count to double
        divsd   xmm8,xmm0       ;average is here
        movq    xmm0,xmm8       ;prepare for printf
        mov     rdi,formt
        mov     rax,1
        call    printf
        add     rsp,8
        ret



Haven't given it a thorough test. The output:


Code:
~/fasm $ ./prog 3 .5 1.6 7 9 10.12 11.654 0.1 -.7
Average = 4.697111

Post 20 Apr 2017, 06:59
View user's profile Send private message Visit poster's website Reply with quote
fasmnewbie



Joined: 01 Mar 2011
Posts: 396
What am I doing. This is a FASM forum ;D


Code:
format ELF64
public main

extrn atoi
extrn atof
extrn strchr
extrn printf

section '.data' writeable
formt db 'Average = %f',0ah,0

section '.code' executable
main:
        sub     rsp,8           ;align the stack
        mov     r14,rdi
        sub     r14,1
        mov     r13,r14         ;count
        mov     r15,rsi         ;command string pointer
        pxor    xmm8,xmm8       ;accumulator
.next:  mov     rdi,[r15+r14*8]
        mov     rsi,'.'
        call    strchr
        test    rax,rax
        jnz     .float
        mov     rdi,[r15+r14*8]
        call    atoi
        cvtsi2sd xmm0,rax       ;convert int to double
        jmp     .ints
.floatmov     rdi,[r15+r14*8]
        call    atof
.ints:  addsd   xmm8,xmm0       ;add to accumulator
        sub     r14,1
        jnz     .next
        cvtsi2sd xmm0,r13       ;convert count to double
        divsd   xmm8,xmm0       ;average is here
        movq    xmm0,xmm8       ;prepare for printf
        mov     rdi,formt
        mov     rax,1
        call    printf
        add     rsp,8
        ret



;gcc -m64 prog.o -o prog
Post 20 Apr 2017, 07:04
View user's profile Send private message Visit poster's website Reply with quote
dstyl



Joined: 23 Jul 2015
Posts: 48
Thanks for your help to all i learned alot , but i have already an atoi solution i would like redsock said to use atof so the user could enter doubles. You all have way better solutions than mine. Sorry for the misleading comments.
Post 20 Apr 2017, 07:51
View user's profile Send private message Reply with quote
fasmnewbie



Joined: 01 Mar 2011
Posts: 396
@dstyl

good to know you managed to find the solution. Don't forget to share it with us here so future visitors of this thread can learn many things from the discussions here. Help this board grows. Don't be shy to share your solution. We can give you small fixes if there's a problem.

If it's not a problem, you can change the thread's title to something more accurate to the problems discussed here to make it more search-friendly. Like "Reading int or float from the command line" or similar.

Regards.
Post 20 Apr 2017, 09:56
View user's profile Send private message Visit poster's website Reply with quote
dstyl



Joined: 23 Jul 2015
Posts: 48
Thanks for the advice ive changed the thread title, i only have the error when i try to place a float value from mem into the xmm registers, here is my atoi solution but i checked and atof also works just using xmm regs doesnt work. My solution is not as short as yours

Code:

; -----------------------------------------------------------------------------
; 64-bit program that treats all its command line arguments as integers and
; displays their average as a floating point number.  This program uses a data
; section to store intermediate results, not that it has to, but only to
; illustrate how data sections are used.
; -----------------------------------------------------------------------------
        global  main

        extern  atoi

        extern  printf

        default rel


                section .text
main:
                dec                     rdi                                     ;argc-1, da wir den programm namen ignorieren
                jz                      nothingToAverage        ;wenn rdi == 0
                mov                     [count], rdi            ;speichere args in [count]
accumulate:
                push            rdi                                     ;sichere reg vor atoi aufruf
                push            rsi
                mov                     rdi, [rsi+rdi*8]        ;argv[rdi] c alignment beachten!
                call            atoi                            ;rax enthält den wert von arg
                pop                     rsi                                     ;wiederherstellen der reg nach
                pop                     rdi                                     ;aufruf von atoi
                add                     [sum], rax                      ;summieren der werte
                dec                     rdi                                     ;argc runterzählen
                jnz                     accumulate                      ;wiederhole wen argc != 0
average:
                cvtsi2sd        xmm0, [sum]                     ;konvertiere signed dw int zu signed
                cvtsi2sd        xmm1, [count]           ;double precision float
                divsd           xmm0xmm1                      ;xmm0 ist sum/count
                mov                     rdiformat                     ;erste arg für printf
                mov                     rax1                          ;printf hat var args es gibt 1 nicht
                sub                     rsp8                          ;align des stackpointers
                call            printf                          ;printf(format, sum/count)
                add                     rsp8                          ;wiederherstellen des stackpointers

                ret
nothingToAverage:
                mov                     rdierror
                xor                     raxrax
                call            printf
                ret
                section .data
count:  dq              0
sum:    dq              0
formatdb              "%g"100
error:  db              "There are no cmdcmnds to average"100



but it works ^^ do you know a solution to the xmm reg problem?
Post 20 Apr 2017, 10:12
View user's profile Send private message Reply with quote
fasmnewbie



Joined: 01 Mar 2011
Posts: 396
@dystl

It doesn't work that way with ATOI.

ATOI takes only the integer part of the string input and ignores the fraction

./average 3.4 3 3 5.6

Is actually interpreted by ATOI as

./average 3 3 3 5

And not even rounding it. In this case, you have to set your own input control / policy for the input values. It's either integer only or floating point only (using ATOF). You're confusing the input values with the output values (which are floats in both cases anyway). My last example however takes both types of input.

I hope I understood what your real questions are because you're sending mixed messages.
Post 20 Apr 2017, 12:28
View user's profile Send private message Visit poster's website Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  
Goto page 1, 2  Next

< Last Thread | Next Thread >

Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum


Powered by phpBB © 2001-2005 phpBB Group.

Main index   Download   Documentation   Examples   Message board
Copyright © 2004-2016, Tomasz Grysztar.