在x86程序集中打印整数

时间:2018-03-09 13:58:00

标签: assembly x86 llvm-gcc

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

1 个答案:

答案 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上的解释非常有用!