将scanf与x86 GAS组件一起使用

时间:2014-11-23 22:41:51

标签: assembly x86 scanf x86-64 gas

我一直有很多问题试图调用系统函数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气体组件中正确扫描的任何见解!

1 个答案:

答案 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

加载完整的64位地址
    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