Search code examples
assemblynasmx86-64calling-convention

How to use data stored in register when calling scanf in nasm assembly


In the following, I'm trying to get the user's choice and use it to call other functions. I'm pushing choice onto the stack, then pushing the format line, then calling scanf, but I can't seem to be able to use what was entered.

;nasm -f elf64 fib.asm -o fib.o
;gcc -S -masm=intel fib.c -o fib.s
;./fib

    bits 64
    global  main
    extern  puts
extern  printf
extern  scanf

section .data
errormsg:   db  'Invalid Input. Enter N,F, or X',0x0D,0x0a,0
numequalsmsg:   db  'Number equals: '
LC2:    db  "%d",0

menuprompt: db  0x0D,0x0a,'Enter N to enter an integer from 0 to 20',0x0D,0x0a,'Enter F to display the first N+1 numbers (beginning with zero) on the console',0x0D,0x0a,'Enter X to quit the program',0x0D,0x0a,0
choicemsg:  db  "Your Choice: ",0
LC5:    db  "%s",0
enterintmsg:    db  "Enter and integer 0-20: ",0
enternummsg:    db  'Enter a valid number between 0 and 20',0x0D,0x0a,0

LC8:    db  " , ",0
LC9:    db  'Success!',0x0D,0x0a,0
LC10:   db  'In L10!',0x0D,0x0a,0       
LC11:   db  'In L12!',0x0D,0x0a,0 
LC13:   db  'In compare to zero section',0x0D, 
value:  dw  0
choice: dw  0


section .text
main:

menu:
    push    rbp
    mov rbp, rsp
    sub rsp, 16

    mov edi, menuprompt
    call    puts            ;display menu
    mov edi,choicemsg
    mov eax, 0
    call    printf          ;display "Your choice: "    
    ;call   getn    

    push choice
    push LC5        ;string format
    call scanf      ;stores input in choice
    ;GetLInt     [choice]
    mov ebx, choice
    cmp ebx, 78
    je  correct

correct:
    mov edi, ebx
    mov eax,0
    call    printf

(editor's note: section.data is just a label declaration like foo.bar:, and so is .code. Probably you wanted section .data and section .text instead of having everything in the read-only .text section, since you want scanf to store a result there. I fixed this for you because this old question and the answer weren't about those errors.)


Solution

  • You are using the wrong convention. Obviously you know what you should do, since you had no problem calling printf. You should use the same convention for calling scanf too - the stack argument passing that you used is the 32 bit convention, 64 bit uses registers. Something like this:

    lea rdi, [LC5]    ; 1st arg = format
    lea rsi, [choice] ; 2nd arg = address of buffer
    xor eax, eax      ; no xmm registers
    call scanf        ; stores input in choice
    

    By the way, using an unconstrained %s with 2 bytes of space is a bad idea.

    Also, do what Frank said, ie. load a byte (mov bl, [choice]) when you want to process the input.