flat assembler
Message board for the users of flat assembler.

Index > 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: 67
dstyl 19 Apr 2017, 17:28
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           xmm0, xmm1                      ;xmm0 ist sum/count
                mov                     rdi, format                     ;erste arg für printf
                mov                     rax, 1                          ;printf hat var args es gibt 1 nicht
                sub                     rsp, 8                          ;align des stackpointers
                call            printf                          ;printf(format, sum/count)
                add                     rsp, 8                          ;wiederherstellen des stackpointers

                ret
nothingToAverage:
                mov                     rdi, error
                xor                     rax, rax
                call            printf
                ret
                section .data
count:  dq              0
sum:    dq              0
format: db              "%g", 10, 0
error:  db              "There are no cmdcmnds to average", 10, 0
    


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: 20344
Location: In your JS exploiting you and your system
revolution 19 Apr 2017, 17:36
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: 67
dstyl 19 Apr 2017, 17:42
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: 20344
Location: In your JS exploiting you and your system
revolution 19 Apr 2017, 17:53
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: 67
dstyl 19 Apr 2017, 18:02
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                     rdi, format                     ;erste arg für printf
                mov                     rax, 1                          ;printf hat var args es gibt 1 nicht
                sub                     rsp, 8                          ;align des stackpointers
                call            printf                          ;printf(format, sum/count)
                add                     rsp, 8                          ;wiederherstellen des stackpointers

                ret
nothingToAverage:
                mov                     rdi, error
                xor                     rax, rax
                call            printf
                ret
                section .data
count:  dq              0
sum:    dq              0
format: db              "%g", 10, 0
error:  db              "There are no cmdcmnds to average", 10, 0
    
Post 19 Apr 2017, 18:02
View user's profile Send private message Reply with quote
cod3b453



Joined: 25 Aug 2004
Posts: 618
cod3b453 19 Apr 2017, 18:06
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: 20344
Location: In your JS exploiting you and your system
revolution 19 Apr 2017, 18:15
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: 67
dstyl 19 Apr 2017, 18:39
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                     rdi, format                     ;erste arg für printf
                mov                     rax, 1                          ;printf hat var args es gibt 1 nicht
                sub                     rsp, 8                          ;align des stackpointers
                call            printf                          ;printf(format, sum/count)
                add                     rsp, 8                          ;wiederherstellen des stackpointers

                ret
nothingToAverage:
                mov                     rdi, error
                xor                     rax, rax
                call            printf
                ret
                section .data
count:  dq              0
sum:    dq              0
format: db              "%g", 10, 0
error:  db              "There are no cmdcmnds to average", 10, 0
    
Post 19 Apr 2017, 18:39
View user's profile Send private message Reply with quote
redsock



Joined: 09 Oct 2009
Posts: 430
Location: Australia
redsock 19 Apr 2017, 22:00
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     r15d, r15d
        xor     ebx, ebx
.accumulate:
        ; accumulate arguments in reverse order
        mov     rdi, [argv]
        call    list$pop_back
        ; HeavyThing turns argv into strings, save it
        mov     r12, rax
        
        ; convert it to double
        mov     rdi, rax
        call    string$to_double
        ; accumulate and increase counter
        movq    xmm1, r15
        addsd   xmm1, xmm0
        movq    r15, xmm1
        add     ebx, 1
        ; free the string
        mov     rdi, r12
        call    heap$free
        ; keep going
        sub     dword [argc], 1
        jnz     .accumulate
        
        ; prepare our argument for double to string
        movq    xmm0, r15
        ; convert our counter to a double
        cvtsi2sd        xmm1, ebx
        ; divide them
        divsd   xmm0, xmm1
        ; display the result
        ; string$from_double needs mode and precision
        mov     edi, double_string_normal
        mov     esi, 15
        call    string$from_double
        mov     r12, rax
        mov     rdi, rax
        call    string$to_stdoutln
        mov     rdi, r12
        call    heap$free
        ; exit cleanly
        mov     eax, syscall_exit
        xor     edi, edi
        syscall
.nothingtodo:
        mov     rdi, .nothingmsg
        call    string$to_stderrln
        mov     eax, syscall_exit
        mov     edi, 1
        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: 555
fasmnewbie 20 Apr 2017, 04:38
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: 20344
Location: In your JS exploiting you and your system
revolution 20 Apr 2017, 04:45
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: 555
fasmnewbie 20 Apr 2017, 05:30
@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: 430
Location: Australia
redsock 20 Apr 2017, 05:53
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: 555
fasmnewbie 20 Apr 2017, 06:24
@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: 555
fasmnewbie 20 Apr 2017, 06:59
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
.float: mov     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: 555
fasmnewbie 20 Apr 2017, 07:04
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
.float: mov     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: 67
dstyl 20 Apr 2017, 07:51
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: 555
fasmnewbie 20 Apr 2017, 09:56
@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: 67
dstyl 20 Apr 2017, 10:12
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           xmm0, xmm1                      ;xmm0 ist sum/count
                mov                     rdi, format                     ;erste arg für printf
                mov                     rax, 1                          ;printf hat var args es gibt 1 nicht
                sub                     rsp, 8                          ;align des stackpointers
                call            printf                          ;printf(format, sum/count)
                add                     rsp, 8                          ;wiederherstellen des stackpointers

                ret
nothingToAverage:
                mov                     rdi, error
                xor                     rax, rax
                call            printf
                ret
                section .data
count:  dq              0
sum:    dq              0
format: db              "%g", 10, 0
error:  db              "There are no cmdcmnds to average", 10, 0
    

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: 555
fasmnewbie 20 Apr 2017, 12:28
@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


Copyright © 1999-2024, Tomasz Grysztar. Also on GitHub, YouTube.

Website powered by rwasa.