您的代码中有多个问题。
从我推断您正在尝试制作 64 位可执行文件64bit Ubuntu
。pushq %rax
如果是这样的话,那么...
这里:
pushq %rax
pushq $output
call printf
addl $8, %esp
函数调用后您没有正确平衡堆栈。你还记得这是 64 位代码吗?您需要添加到rsp
,而不是esp
。此外,如果您推送 2 个 8 字节参数,则必须准确删除 2 个 8 字节参数,这意味着您必须添加 16 个,而不是 8 个。
但它甚至比这更糟糕。在 64 位模式下,参数的传递方式不同。第一个参数位于寄存器rdi
、rsi
、rdx
、rcx
和r8
中r9
。所以,这给了我们:
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
之前始终是 16 字节对齐的。call
这里:
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
距离超过 2GB rip
(事实:在 64 位模式下的大多数指令中,位移仅限于内存操作数中的 32 位有符号整数,并且它们中的大多数没有仅位移的内存操作数也可以在 64 位模式下编码,它们在那里使用rip
-relative 寻址),您需要手动将 64 位地址values
和索引添加到数组中乘以 4。确保执行 64 位加法,没有任何截断一路上。
必读: