flat assembler
Message board for the users of flat assembler.

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: 58
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: 15859
Location: 162173 Ryugu
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: 58
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: 15859
Location: 162173 Ryugu
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: 58
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: 617
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: 15859
Location: 162173 Ryugu
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: 58
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: 283
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 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: 514
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: 15859
Location: 162173 Ryugu
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: 514
@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: 283
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: 514
@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: 514
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: 514
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: 58
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: 514
@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: 58
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: 514
@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 © 2004-2018, Tomasz Grysztar.

Powered by rwasa.