How To Use Scanf In NASM?

2019-01-25 07:16发布

问题:

I can't figure this out. I'm obviously really new to Assembly, and I'm trying to figure out how to use Scanf to get user input.

I know to use Printf all I have to do is push the data I want to write on the screen into the stack like this:

global _main
extern _printf
extern _scanf

section .data
msg db "Hi", 0

section .text
_main:
  push ebp
  mov ebp, esp  

  push msg
  call _printf

  mov esp, ebp
  pop ebp
ret

But I can't figure out how to use Scanf. Can someone please just give me the simplest possible source code you can for Scanf? I really just want to put what the user types in.

I'm not used to 32bit Assembly. I've only ever used 16bit, and I know in 16bit (DOS) you can just do this:

mov ah, 3fh
mov dx, input
int 21h

input rb 100d

And whatever you type in will the placed at the address of "input."

Please bear with me. I'm trying to figure this out.

回答1:

I found this 'Programming in NASM.PDF'

; add1.asm
SECTION .data
    message1: db "Enter the first number: ", 0
    message2: db "Enter the second number: ", 0
    formatin: db "%d", 0
    formatout: db "%d", 10, 0 ; newline, nul terminator
    integer1: times 4 db 0 ; 32-bits integer = 4 bytes
    integer2: times 4 db 0 ;
SECTION .text
   global _main 
   extern _scanf 
   extern _printf     

_main:

   push ebx ; save registers
   push ecx
   push message1
   call printf

   add esp, 4 ; remove parameters
   push integer1 ; address of integer1 (second parameter)
   push formatin ; arguments are right to left (first parameter)
   call scanf

   add esp, 8 ; remove parameters
   push message2
   call printf

   add esp, 4 ; remove parameters
   push integer2 ; address of integer2
   push formatin ; arguments are right to left
   call scanf

   add esp, 8 ; remove parameters

   mov ebx, dword [integer1]
   mov ecx, dword [integer2]
   add ebx, ecx ; add the values          ; the addition
   push ebx
   push formatout
   call printf                            ; call printf to display the sum
   add esp, 8                             ; remove parameters
   pop ecx
   pop ebx ; restore registers in reverse order
   mov eax, 0 ; no error
   ret

Which is the asm version of this C function:

#include <stdio.h>
int main(int argc, char *argv[])
{
    int integer1, integer2;
    printf("Enter the first number: ");
    scanf("%d", &integer1);
    printf("Enter the second number: ");
    scanf("%d", &integer2);
    printf("%d\n", integer1+integer2);
    return 0;
}


回答2:

Thanks Preet. I made a simple example based on your code to illustrate the use of scanf.

Program that requests an integer and prints it out to the screen:

section .text
  global main
  extern printf
  extern scanf

section .data
  message: db "The result is = %d", 10, 0
  request: db "Enter the number: ", 0
  integer1: times 4 db 0 ; 32-bits integer = 4 bytes
  formatin: db "%d", 0

main:
  ;  Ask for an integer
  push request
  call printf
  add esp, 4    ; remove the parameter

  push integer1 ; address of integer1, where the input is going to be stored (second parameter)
  push formatin ; arguments are right to left (first  parameter)
  call scanf
  add esp, 8    ; remove the parameters

  ; Move the value under the address integer1 to EAX
  mov eax, [integer1]

  ; Print out the content of eax register
  push eax
  push message
  call printf
  add esp, 8

  ;  Linux terminate the app
  MOV AL, 1
  MOV EBX, 0 
  INT 80h 


回答3:

This is the first post that shows up when you search for scanf in assembly, so, even if its a 4 years old post, I think it should be correct.

Oukei, so, to call scanf in NASM assembly you need to:

  1. Extern scanf
  2. Prepare a formatation for you scanf
  3. Prepare the variables or single variable to store the values expected
  4. Push the parameters in backward order
  5. Call scanf
  6. Restore stack

So, lets say you're traying to

scanf ("%d %d", &val1, &val2);

and following the list:
... 1.

section .text
extern scanf

... 2. This is the first parameter you pass to your C scanf, it says what will you get. One integer, two, a float, string, char... In this case, two integers separated by a space (also works with Enter)

section .data
fmt: db "%d %d",0

... 3.

section .bss
val1: resd 1
val2: resd 1

... 4 5 6. Note that you push the address of the variables, not its content (i.e. [var])

push val2
push val1
push fmt
call scanf
add esp, 12

Also note that you have to add 12 to the stack pointer because you pushed 3 double word parameters. So you add 12 bytes (3*4 bytes) to the stack to "jump" the parameters.

*I declared dword for the variables because %d uses dword, just as printf.
**The ,0 in the end of the formatation string is a sentinel character.



回答4:

Lets say you want to do something like

scanf("%d %d", &var1, &var2);

That takes two values and store them in the variables.

In assembly you would push the addres of the variables into the stack (in backward order) and then call scanf.

Something like you have two variables

var1 resd 1
var2 resd 1

... and then

push var2
push var1
call scanf

*Note that I pushed them in backward order, the first value will be stored in var1.

After execution the values you entered will be stored in the variables.

If you want only one value just push one variable.



标签: assembly nasm