AT& T汇编代码中的分段错误(核心转储)错误

时间:2012-07-14 03:30:35

标签: assembly

我用汇编语言编写了一个简单的程序,尝试在我的64位Ubuntu操作系统上运行它。但是,它因“分段故障(核心转储)错误”而失败。

这是我的代码:

    .section .data
    values :
        .int 10, 15, 20, 25, 30 ,35, 40, 45, 50, 55, 60
    output :
        .asciz "The value is %d\n"
   .section .text
   .globl main
   main :
        nop
        movl $0, %edi
   loop :
        movl values( , %edi, 4), %eax
        pushq %rax
        pushq $output
        call printf
        addl $8, %esp
        inc %edi
        cmpl $11, %edi
        jne loop
        movl $0, %ebx
        movl $1, %eax
        int $0x80

1 个答案:

答案 0 :(得分:3)

您的代码中存在多个问题。

64bit Ubuntupushq %rax我推断您正在尝试制作64位可执行文件。

如果是这样,那么......

下面:

pushq %rax
pushq $output
call printf
addl $8, %esp

您在函数调用后没有正确平衡堆栈。你还记得这是64位代码吗?您需要添加到rsp,而不是esp。此外,如果您按下2个8字节参数,则必须准确删除2个8字节参数,这意味着您必须添加16个而不是8个。

但情况甚至更糟。在64位模式下,参数的传递方式不同。第一个参数位于寄存器rdirsirdxrcxr8r9中。所以,这给了我们:

movq %rax, %rsi
movq $output, %rdi
movq $0, %rax ; number of vector registers used for var-arg-function printf()
call printf

下面:

inc %edi

您刚刚通过调用销毁了rdi的值,并使用此寄存器进行参数传递。您需要在通话前手动推送rdi,然后将其弹出。或者您可以将其保存在全局变量中。如果您选择推送和弹出,请确保在任何rsp指令之前,堆栈指针call始终是16字节对齐。

下面:

movl $0, %ebx
movl $1, %eax
int $0x80

您正在使用32位系统调用接口。在64位程序中,您必须使用64位系统调用接口:

movq $60, %rax ; sys_exit
movq $0, rdi ; return 0 (success)
syscall

现在,我认为这个也可能有问题:

movl $0, %edi
loop :
movl values( , %edi, 4), %eax

通常,在64位代码中进行地址计算时,不应该使用32位寄存器和32位指令。我将其更改为:

movl $0, %rdi
loop :
movl values( , %rdi, 4), %eax

如果两者都不起作用,因为values的地址距rip的距离超过2GB(事实:在64-的大多数指令中,位移仅限于内存操作数中的32位有符号整数位模式,其中大部分都没有64位模式的仅位移内存操作数编码,它们使用rip - 相对寻址,你需要手动添加{{1}的64位地址并将数组中的索引乘以4.确保在此过程中进行64位加法而没有任何截断。

必备读取:

  • System V应用程序二进制接口AMD64架构处理器补充草案版本0.99.6

  • 调用不同C ++编译器和操作系统的约定作者:Agner Fog