我一直有很多问题试图调用系统函数scanf在我的x86汇编程序中工作。目前我已经从标准中读取了它,但它只会读取没有段错误的字符(我不知道为什么,指定字符串是%d)。我在x86在线使用scanf看到的例子非常夸张或者是用NASM语法编写的,因此我尝试将它们用于我的程序。
f:
.string "%d"
_main:
movq $0, %rax #Clean rax
movq $f, %rdi #Load string format
movq %rcx, %rsi #Set storage to rcx (Not sure if this is valid)
call scanf
ret
在输入字符串或字符串后,分别使用printf返回1和0检查rcx和rax(只有这样程序不会出现段错误。)
非常感谢有关如何在x86气体组件中正确扫描的任何见解!
答案 0 :(得分:3)
正如您所担心的,movq %rcx, %rsi
不正确。您需要将指针传递给内存。寄存器不是存储器地址空间的一部分,因此您无法指向它们。您需要在全局或本地分配存储。顺便提一下,您不应将数据(特别是可写)放入默认的.text
部分,因为它是用于代码的,通常是只读的。此外,调用约定通常要求16字节堆栈指针对齐,所以你也应该处理它。
.globl main
main:
push %rbp # keep stack aligned
movq $0, %rax # clear rax
movq $f, %rdi # load format string
movq $x, %rsi # set storage to address of x
call scanf
pop %rbp
ret
.data
f: .string "%d"
x: .long 0
(如果您的环境需要符号的前导下划线,请使用_main
,可能使用_scanf
。)
只有当您的变量位于地址空间的较低4GiB时,上述操作才有效。或者,您可以使用rip-relative寻址来创建指针,如下所示:
leaq f(%rip), %rdi # load format string
leaq x(%rip), %rsi # set storage to address of x
您还可以使用助记符movabsq
movabsq $f, %rdi # load format string
movabsq $x, %rsi # set storage to address of x
根据要求:本地变量版本可能如下所示:
subq $8, %rsp # allocate 8 bytes from stack
movq $0, %rax # clear rax
movabsq $f, %rdi # load format string
movq %rsp, %rsi # set storage to local variable
call scanf
addq $8, %rsp # restore stack
ret