我正在尝试使用以下代码在macOS High Sierra上打印32位x86程序集中的整数:
.cstring
STR_D:
.asciz "%d"
.globl _main
_main:
movl $53110, %edi #moves constant int into register
sub $8, %esp #make space on stack
movl %edi, 4(%esp) #move int to stack
movl $STR_D, 0(%esp) #move "%d" to stack
call _printf
add $8, %esp #restore stack pointer
ret
我正在使用命令
进行编译 gcc -m32 -Wl,-no_pie -o foo foo.s
然后执行可执行文件 foo 。然后我得到一个错误说"非法指令:4"。我很确定错误在于将字符串常量移动到堆栈的指令。如果我删除该行和以下函数调用,一切正常。 我做错了什么?
更多信息/问题:我这样做是编写编译器的项目的一部分。当我在Linux上执行这些指令时(当然更改特定于平台的东西,例如main而不是_main,.data而不是.cstring等),它可以工作。为什么macOS不起作用?这与堆栈对齐有关吗?
我的编译器版本(由gcc -version获得)是Apple LLVM 9.0.0(clang-900.0.39.2)。
答案 0 :(得分:1)
好的,我发现了问题所在。这有两个方面:
首先,我发现我错过了.text段。这显然是必要的,即使它是空的。这就是"非法指令的原因:4"错误。但是,如果你纠正了这个问题,你会得到一个SEGFAULT。
正如我在问题中所怀疑的那样,它与堆栈对齐有关。 macOS与Linux有不同的要求:堆栈需要在macOS上进行16位对齐。这意味着在执行函数调用(将返回地址压入堆栈)之前,堆栈需要进行12对齐(意味着堆栈指针需要如下所示:0xnnnnnnnC)。为了确保这一点,需要确保
1)按n次,其中n是3的倍数(按3次,6次,9次等)
2)如果您自己修改堆栈指针(就像我一样),请确保符合12位要求
总而言之,适用于我的代码如下所示:
.cstring
STR_D:
.asciz "%d"
.text #need this, even if it's empty
.globl _main
_main:
movl $53110, %edi #moves constant int into register
sub $12, %esp #make space on stack, respecting alignment
movl %edi, 4(%esp) #move int to stack
movl $STR_D, 0(%esp) #move "%d" to stack
call _printf
add $12, %esp #restore stack pointer
ret
编辑:如果有人对堆栈对齐感兴趣,我发现this website上的解释非常有用!