对于 64 位 nasm:
要将 scanf 与 nasm 一起使用,您首先需要在 .text 部分之前添加语句。
extern scanf
现在您需要首先使用
push rbp
如果您不想出现分段错误,这一点很重要。在进行调用之前,堆栈指针 rsp 必须与 16 字节边界对齐。进行调用的过程会将返回地址(8 字节)压入堆栈,因此当函数获得控制权时,rsp 未对齐。你必须自己创造额外的空间,通过推动一些东西或从 rsp 中减去 8。你可以在这里阅读更多关于它的信息。
现在,您的堆栈已准备就绪,您需要首先将输入格式化字符串移动到 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的有益和有见地的评论。