非法指令 gcc 汇编程序

Posted

技术标签:

【中文标题】非法指令 gcc 汇编程序【英文标题】:Illegal instruction gcc assembler 【发布时间】:2010-05-16 18:57:39 【问题描述】:

在汇编程序中:

.globl _test

_test:

pushl %ebp
movl %esp, %ebp
movl 8(%ebp), %eax

pushl %eax
call printf

popl %ebp
ret

从 c 调用

main()

  _test("Hello");

编译:

gcc -m32 -o test test.c test.s

这段代码有时给我非法指令,有时给我段错误。 在 gdc 中我总是收到非法指令,这只是一个简单的测试,我有一个更大的程序正在运行,但在没有明显原因后突然停止工作,现在即使我像上面一样从头开始,我总是会收到这个错误。

我已将范围缩小到 pushl %eax & call printf,如果我注释掉这些行代码运行良好。

有什么想法吗? (我在我的大学 linux 集群上运行程序,所以我没有更改任何设置..)

【问题讨论】:

您只是忘记在调用返回后从堆栈中删除printf() 的参数。您的 popl %ebp 删除了错误的内容,而您的 ret 尝试跳转到错误的位置 - 因为堆栈上的单词比您预期的要多。 【参考方案1】:

您的最后两条指令损坏了堆栈基指针。任何依赖 ebp(基指针)指向实际堆栈空间的代码都会失败。通常期望 ebp 指向堆栈空间是一个安全的假设,并且在与 C 代码交互时不应使该假设无效。

您正在执行pushl %eax(或任何其他寄存器),然后执行popl %ebp。这两个加起来效果和movl %eax, %ebp一样。

我假设您正在尝试返回存储在 eax 中的值。在 C 调用约定中,eax 用于返回值,因此无需推送它或对其执行任何操作,只需将值留在其中,其他代码将获取它。如果这不是你想要做的,那么我很难理解你为什么要在这个函数的末尾推送 %eax。

【讨论】:

感谢您指出这一点,我用更理智的示例更新了主帖,但我仍然收到错误。 printf 弹出堆栈的最后一项,因此 popl ebp 现在应该是正确的。 @Bernt:printf 为您从堆栈中弹出任何内容是错误的。在 Linux/x86 中,当您 called 的函数返回时,堆栈不会改变 - 您之前 pushed 的所有参数仍然存在。这就是您的代码中的问题,一个您不希望出现的单词。【参考方案2】:

将弹出指令替换为leave。这将恢复堆栈指针和基指针。

【讨论】:

以上是关于非法指令 gcc 汇编程序的主要内容,如果未能解决你的问题,请参考以下文章

由于用于构建 GCC 的 CPU 的体系结构,这是 g++ 的“非法指令错误”吗?

程序接收信号 SIGILL 非法指令

工作程序在“清洁机器”上出现非法指令错误?

运行DPDK程序报错:非法指令 核心已转储

使用 -mfma 编译时的非法指令

Vortex86DX C++ 代码/工具链构建的非法指令