在 x86 程序集中打印整数



我正在尝试使用以下代码在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)。

好的,我发现了问题所在。它是双重的:

首先,我发现我缺少一个 .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

编辑:如果有人对堆栈对齐感兴趣,我发现这个网站上的解释非常有用!

最新更新