web-dev-qa-db-ja.com

NASMでscanfを使用する方法は?

scanfを使用してユーザー入力を取得する方法を理解しようとしています。私はprintfを使用することを知っています。次のように、画面に書き込むデータをスタックにプッシュするだけです。

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

しかし、scanfの使い方がわかりません。誰かがscanfにできる最も簡単なソースコードを教えてくれませんか?私は本当にユーザーが入力したものを入れたいだけです。

私は32ビットアセンブリに慣れていません。私はこれまで16ビットしか使用していませんが、16ビット(DOS)では次のことができます。

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

input rb 100d

そして、入力したものは何でも「入力」のアドレスに配置されます。

15
user1432532

私はこれを見つけました '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

このC関数のasmバージョンはどれですか。

#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;
}
16
Preet Sangha

Preetに感謝します。 scanfの使用法を説明するために、コードに基づいて簡単な例を作成しました。

整数を要求して画面に出力するプログラム:

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
mateuszb

これは、Assemblyでscanfを検索したときに表示される最初の投稿なので、4年前の投稿であっても、正しいはずだと思います。

Oukei、つまり、NASMアセンブリの_call scanf_には、次のことを行う必要があります。

  1. Extern scanf
  2. Scanfのフォーマットを準備します
  3. 期待される値を格納するための変数または単一の変数を準備します
  4. パラメータを逆順にプッシュします
  5. Scanfを呼び出す
  6. スタックを復元する

だから、あなたがトレーにいるとしましょう

_scanf ("%d %d", &val1, &val2);
_

そして次のリスト:
... 1。

_section .text
extern scanf
_

... 2。これはCscanfに渡す最初のパラメーターであり、何を取得するかを示します。 1つの整数、2つ、float、string、char ...この場合、スペースで区切られた2つの整数(Enterでも機能します)

_section .data
fmt: db "%d %d",0
_

... 3。

_section .bss
val1: resd 1
val2: resd 1
_

... 4 5 6.内容ではなく変数のアドレスをプッシュすることに注意してください(つまり、[var])

_Push val2
Push val1
Push fmt
call scanf
add esp, 12
_

また、3つのダブルWordパラメーターをプッシュしたため、スタックポインターに12を追加する必要があることに注意してください。したがって、12バイト(3 * 4バイト)をスタックに追加して、パラメーターを「ジャンプ」します。

* _%d_はprintfと同じようにdwordを使用するため、変数のdwordを宣言しました。
**フォーマット文字列の最後の_,0_は、歩哨文字です。

1
user6829088

あなたが次のようなことをしたいとしましょう

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

これは2つの値を取り、それらを変数に格納します。

アセンブリでは、変数のアドレスをスタックにPush(逆順で)してからcall scanf

2つの変数があるようなもの

var1 resd 1
var2 resd 1

... その後

Push var2
Push var1
call scanf

*逆の順序でプッシュしたことに注意してください。最初の値はvar1に格納されます。

実行後、入力した値は変数に保存されます。

1つの値のみが必要な場合は、1つの変数をプッシュします。

0
PunditPoe