2

I am having some trouble getting the c function atof() to work in my asm program. I'm trying to read in 4 numbers from the keyboard, and ultimately print their average. Before i can do that, however, i need to convert the numbers to floats. I'm stuck on successfully getting my 'total' variable to work. I have tried calling atof in multiple spots to no avail.

This is a x86 NASM program

;   nasm -f elf -l prg2.lst prg2.asm
;   gcc -o prg2 prg2.o
;   ./prg2

SECTION .DATA

prompt  DB  'enter a test score.', 13,10
fmt DB  "%s",0
fmtf    DB  "%f",0      


SECTION .bss
test1   resb    1000        ;reserves variable names to
test2   resb    1000        ;put stuff in
test3   resb    1000
test4   resb    1000
total   resb    1000


SECTION .code
extern printf
extern scanf
extern atof
global main
main:

push    ebp
mov     ebp, esp

push    prompt
call    printf
add     esp, 4  ;prompt user

push    test1   ;push test1 variable
push    fmt
call    scanf
add esp, 8  ;store test1 variable

push    prompt
call    printf
add     esp, 4  ;prompt user

push    test2   ;push test2 variable
push    fmt
call    scanf
add esp, 8  ;store test2 variable

push    prompt
call    printf
add     esp, 4  ;prompt user

push    test3   ;push test3 variable
push    fmt
call    scanf
add esp, 8  ;store test3 variable

push    prompt
call    printf
add     esp, 4  ;prompt user

push    test4   ;push test4 variable
push    fmt
call    scanf
add esp, 8  ;store test4 variable

mov     eax,[test1]
add     eax,[test2] 
add     eax,[test3] 
add     eax,[test4] 

call    atof
mov     [total], eax

push total
call printf ;not printing what i want, 
add esp,4   ;or printing anything at all

push    test1   ;printing scores for verification
call    printf
add esp, 4  

push    test2
call    printf
add esp, 4

push    test3
call    printf
add esp, 4

push    test4
call    printf
add esp, 4

mov     esp, ebp
pop     ebp

ret

EDIT: upon revision, i was able to turn the inputted values in their respective numeric values using these code blocks

mov eax, 0          ;
add eax,[test1]     ;put test1 value in eax
mov [total], eax    
sub eax, '0'        

add eax,[test2]     
mov [total], eax        
sub eax,'0'

add eax,[test3]     
mov [total], eax        
sub eax,'0'

add eax,[test4]     ;
mov [total], eax        
sub eax,'0'

push    total   
call    printf  
add esp, 4  

Sample run through:

./prg2b
enter a test score.
1
enter a test score.
1
enter a test score.
1
enter a test score.
1
41111

this addition to my code gets rid of my problem with the atof() call, but it is only successful if the numbers are one digit and if total is <10

If anyone could give a hint as to how to properly using atof, or how to properly convert to floating point numbers in a program that uses scanf, it would be greatly appreciated. I'm very new (read: 2 weeks of learning) to x86 asm. This is compiled in the terminal on a UNIX system

Michael Petch
  • 46,082
  • 8
  • 107
  • 198
pfNbigblue
  • 25
  • 5
  • `add` is integer add. It doesn't add floating point numbers. I don't know anything about your course material but maybe your professor intended to have you use x87 floating point instructions (or SSE)? For example information on adding floats in NASM using x87 can be found in the example near the bottom of these [examples](http://www.csee.umbc.edu/portal/help/nasm/sample.shtml) – Michael Petch Nov 22 '15 at 02:38
  • Well, i think i'm to just add them using integer addition, but when i divide for the average i'm to produce a floating point number. So i was concerned about storing the values as floats – pfNbigblue Nov 22 '15 at 02:49
  • So you need to be reading the "%d" format specifier to read in integers. You can use `add` to add the integers together. I recommend reading your course material which likely includes information on instructions like fild to load an integer onto the FPU stack (converting it to a float in the process). You can use fdiv (fidiv might be more appropriate) to divide by the the number of elements. Many ways to skin this cat. Understanding floating point operations is needed. – Michael Petch Nov 22 '15 at 03:18

1 Answers1

1

You can define a C literal with escape sequences in NASM by using backticks. E.g.

prompt  DB  `enter a test score.\n`, 0    ; Don't forget the last 0

atof needs a memory address on the stack and returns the result in register ST(0) of the FPU. You have to convert every single string to a number before you can calculate with it.

SECTION .data
    prompt  DB `Enter a test score\n`, 0
    fmt     DB  " %s", 0
    fmtf    DB  `Sum: %f\n`, 0

SECTION .bss
    test1   resb 1000
    test2   resb 1000
    test3   resb 1000
    test4   resb 1000
    double1 resq 1          ; Reserve Quadword = Double
    double2 resq 1
    double3 resq 1
    double4 resq 1
    sum     resq 1

SECTION .code
extern printf, scanf, atof
global main
main:

    push ebp                ; Prolog
    mov ebp, esp

    push prompt             ; `enter a test score\n`
    call printf
    add esp, (1*4)          ; Pop 1 dword
    push test1
    push fmt                ; " %s"
    call scanf
    add esp, (2*4)          ; Pop 2 dwords
    push test1
    call atof
    fstp qword [double1]
    add esp, (1*4)          ; Pop 1 dword

    push prompt             ; `enter a test score\n`
    call printf
    add esp, (1*4)          ; Pop 1 dword
    push test2
    push fmt                ; " %s"
    call scanf
    add esp, (2*4)          ; Pop 2 dwords
    push test2
    call atof
    fstp qword [double2]
    add esp, (1*4)          ; Pop 1 dword

    push prompt             ; `enter a test score\n`
    call printf
    add esp, (1*4)          ; Pop 1 dword
    push test3
    push fmt                ; " %s"
    call scanf
    add esp, (2*4)          ; Pop 2 dwords
    push test3
    call atof
    fstp qword [double3]
    add esp, (1*4)          ; Pop 1 dword

    push prompt             ; `enter a test score\n`
    call printf
    add esp, (1*4)          ; Pop 1 dword
    push test4
    push fmt                ; " %s"
    call scanf
    add esp, (2*4)          ; Pop 2 dwords
    push test4
    call atof
    fstp qword [double4]
    add esp, (1*4)          ; Pop 1 dword

    fld qword [double1]
    fadd qword [double2]
    fadd qword [double3]
    fadd qword [double4]
    fstp qword [sum]

    push dword [sum + 4]    ; Push a double in two steps
    push dword [sum + 0]
    push fmtf               ; `result: %f\n`, 0
    call printf
    add esp, (3*4)          ; Pop 3 dwords

    mov esp, ebp            ; Epilog
    pop ebp
    ret

You don't need atof. You can let scanf convert the inputted string with the format string " %lf".

SECTION .data
    prompt  DB `Enter a test score\n`, 0
    fmt     DB  " %lf", 0                   ; scanf needs 'lf' to store a double
    fmtf    DB  `Sum: %f\n`, 0              ; printf needs only 'f' to print a double

SECTION .bss
    double1 resq 1          ; Reserve Quadword = Double
    double2 resq 1
    double3 resq 1
    double4 resq 1
    sum     resq 1

SECTION .code
extern printf, scanf, atof
global main
main:

    push ebp                ; Prolog
    mov ebp, esp

    push prompt             ; `enter a test score\n`
    call printf
    add esp, (1*4)          ; Pop 1 dword
    push double1
    push fmt                ; " %lf"
    call scanf
    add esp, (2*4)          ; Pop 2 dwords

    push prompt             ; `enter a test score\n`
    call printf
    add esp, (1*4)          ; Pop 1 dword
    push double2
    push fmt                ; " %lf"
    call scanf
    add esp, (2*4)          ; Pop 2 dwords

    push prompt             ; `enter a test score\n`
    call printf
    add esp, (1*4)          ; Pop 1 dword
    push double3
    push fmt                ; " %lf"
    call scanf
    add esp, (2*4)          ; Pop 2 dwords

    push prompt             ; `enter a test score\n`
    call printf
    add esp, (1*4)          ; Pop 1 dword
    push double4
    push fmt                ; " %lf"
    call scanf
    add esp, (2*4)          ; Pop 2 dwords

    fld qword [double1]
    fadd qword [double2]
    fadd qword [double3]
    fadd qword [double4]
    fstp qword [sum]

    push dword [sum + 4]    ; Push a double in two steps
    push dword [sum + 0]
    push fmtf               ; `result: %f\n`, 0
    call printf
    add esp, (3*4)          ; Pop 3 dwords

    mov esp, ebp            ; Epilog
    pop ebp
    ret
rkhb
  • 14,159
  • 7
  • 32
  • 60
  • that most certainly works, thank you very much! I was hoping i could just store the input as floats using scanf, I just didn't know the correct format. – pfNbigblue Nov 22 '15 at 23:06