Assembly 为什么这会给我一个错误
我正试图写一个hello world程序,但它不起作用-为什么Assembly 为什么这会给我一个错误,assembly,x86-64,gnu-assembler,x86,Assembly,X86 64,Gnu Assembler,X86,我正试图写一个hello world程序,但它不起作用-为什么 .data str: .ascii "Hello World\12\0" .text .globl main .extern printf main: pushq %rbp movq %rsp,%rbp movq str,%rdi callq printf movq %rbp,%rsp po
.data
str:
.ascii "Hello World\12\0"
.text
.globl main
.extern printf
main:
pushq %rbp
movq %rsp,%rbp
movq str,%rdi
callq printf
movq %rbp,%rsp
popq %rbp
ret
您违反了呼叫约定。由于这是在Linux上运行的64位代码,因此适用的调用约定是。(更多详细信息请参见标记wiki。) 请注意,对于变量函数,如
printf
,此调用约定要求调用方设置RAX
寄存器,以指示在向量寄存器中传递的浮点参数的数量。您没有初始化RAX
寄存器,因此它实际上包含垃圾数据。然后,printf
函数尝试从向量寄存器读取未定义数量的浮点值,从而导致分段错误
您只需在拨打电话之前将RAX归零即可修复代码。有几种方法可以做到这一点。显而易见的是movq$0,%rax
,然而,寄存器归零的一种更为理想的方法是使用XOR
指令,例如:xorq%rax,%rax
。但你可以做得更好。由于在x86-64上,所有指令都隐式清除目标寄存器的上32位,因此只需执行xorl%eax,%eax
。这将缩短一个字节,执行速度将略快
从技术上讲,您的main
函数也应该返回0。调用约定指定函数使用RAX
寄存器返回一个整数结果,因此在返回之前只需再次将RAX
归零。现在,printf
正在RAX
中返回其结果,并且由于您没有设置RAX
,因此实际上是从main
返回printf
的结果。这是合法的,但可能不是你想要的
因此,您的main
函数应该如下所示:
pushq %rbp
movq %rsp, %rbp
movq str, %rdi
xorl %eax, %eax
callq printf
xorl %eax, %eax
movq %rbp, %rsp
popq %rbp
ret
但是您可以通过删除movq%rsp,%rbp
指令来缩短代码。你没有做相对寻址,所以这里不需要。而且,您可以将movq str、%rdi
优化为movl str、%edi
。最后的代码就是:
pushq %rbp # reserve 8 bytes of space on the stack
movl str, %edi # get address of string constant
xorl %eax, %eax # clear RAX register in preparation for calling printf
callq printf
xorl %eax, %eax # clear RAX register so we return 0
popq %rbp # clean up the stack
ret
您应该使用
movabsq$str,%rdi
加载地址。您所做的是加载字符串的前8个字节,然后poorprintf
尝试将其用作地址并出现故障。另外,在调用@Jestermov$str之前,您需要将%al
归零,因为ABI将数据和代码放在地址空间的前2G字节内,所以%rdi
就足够了。@fuz:mov$str,%edi
当然更好,由于GNUas
不会将7字节符号扩展mov立即数优化为5字节零扩展mov立即数。要格式化代码,请不要使用
,选择代码并按编辑器中的{}
按钮。请确保最初遵循目标平台+汇编程序语法的课程信息/教程(即在这种情况下,气体+64b clib)。对于人类来说,gas语法比Intel语法更难读/写,因此您必须特别注意所有这些奇怪的符号,例如,$
是否在数字之前,使其成为完全不同的指令。一旦您稍微熟悉了基础知识并完全了解了指令在CPU,您可以很容易地选择不同的语法/平台示例以获取灵感,但一开始它们会让您感到困惑。movq str,%rdi
从字符串中加载8个字节,这是导致printf segfaulting的主要原因(除非OP有一个旧的libc,它使用AL进行计算跳转,而不是仅使用0/non-0检查来保存所有XMM regs)。您希望mov$str,%edi
或lea str(%rip),%rdi
传递指向标签的指针。