我正在尝试弄清楚如何使用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位装配。我只使用过16bit,而且我知道16bit(DOS)你可以这样做:
mov ah, 3fh
mov dx, input
int 21h
input rb 100d
无论你输入什么,都会放在“输入”地址。
答案 0 :(得分:16)
; 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;
}
答案 1 :(得分:3)
谢谢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
答案 2 :(得分:1)
这是您在装配中搜索scanf
时显示的第一个帖子,因此,即使它是一个4年的帖子,我认为它应该是正确的。
Oukei,所以,在NASM装配中call scanf
你需要:
所以,我们可以说你正在追踪到
scanf ("%d %d", &val1, &val2);
并在列表后面:
...... 1。
section .text
extern scanf
...
2.这是您传递给C scanf
的第一个参数,它表示您会得到什么。一个整数,两个,一个浮点数,一个字符串,一个char ...在这种情况下,两个整数用空格分隔(也适用于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
另请注意,您必须向堆栈指针添加12,因为您按下了3个双字参数。所以你将12个字节(3 * 4个字节)添加到堆栈中以跳转&#34;参数。
*我为变量声明了dword,因为%d
使用了dword,就像printf
一样
**格式化字符串末尾的,0
是一个标记字符。
答案 3 :(得分:1)
对于64位nasm:
要在nasm中使用scanf,首先需要在.text部分之前添加该语句。
extern scanf
现在您需要先使用
设置堆栈push rbp
如果您不希望出现分段错误,这一点很重要。进行调用之前,堆栈指针rsp必须对齐16字节边界。进行调用的过程将返回地址(8个字节)压入堆栈,因此当函数获得控制权时,rsp不会对齐。您必须自己推动额外的空间,方法是推入一些东西或从rsp中减去8。您可以详细了解here。
现在,您的堆栈已准备就绪,您需要首先将输入格式的字符串移动到rdi寄存器中,然后按严格的顺序移动rsi,rdx,rcx,r8,r9中的参数。
让我们以模仿c语句为例
scanf("%d %d", &a, &b);
等效的nasm代码为:
section .data
Input_format db "%d %d", 0
section .bss
var1: resd 1 ;reserves one double(4 bytes) for int variable
var2: resd 1
extern scanf
global main
default rel ; use this by default for efficiency. This is even mandatory if you run your code on macOS.
section .text
main:
push rbp
lea rdi, [Input_format] ;loading format
lea rsi, [var1]
lea rdx, [var2]
call scanf
pop rbp ;restores stack
;simulates return 0
mov rax, 0
ret
下面的代码是上面代码的更漂亮的版本。它提示用户输入,并打印输入的号码。
section .data
int_inMsg: db "Enter an integer value" , 10, 0 ;10 for new line, 0 for null
real_inMsg: db "Enter a real value", 10, 0
bool_inMsg: db "Enter a boolean value", 10, 0
arr_inMsg: db "Enter %d elements for array range %d to %d", 10, 0
intFormat db "%d", 0
section .bss
var1: resd 1
global main
extern printf
extern scanf
extern puts
extern exit
default rel
section .text
main:
push rbp ;setup stack
;printf("Enter blah blah\n");
lea rdi, [int_inMsg] ;first argument
xor rax, rax
call printf
;take input from the user
;scanf("%d", &var1);
lea rdi, [intFormat]
lea rsi, [var1]
xor rax, rax
call scanf
lea rdi, [intFormat]
mov esi, [var1] ;notice the [] for sending value of var1 instead of pointer to var1
xor rax, rax
call printf
; return
pop rbp ;restore stack
mov rax, 0 ;normal exit
ret
感谢@peter的有益和深刻见解。
答案 4 :(得分:0)
假设您想要做类似
的事情scanf("%d %d", &var1, &var2);
这需要两个值并将它们存储在变量中。
在装配中,您将push
变量的地址放入堆栈(按向后顺序),然后call scanf
。
像你这样的东西有两个变量
var1 resd 1
var2 resd 1
......然后
push var2
push var1
call scanf
*请注意,我按向后顺序推送它们,第一个值将存储在var1中。
执行后,您输入的值将存储在变量中。
如果你只需要一个值,只需按一个变量。