非法指令 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 中,当您 call
ed 的函数返回时,堆栈不会改变 - 您之前 push
ed 的所有参数仍然存在。这就是您的代码中的问题,一个您不希望出现的单词。【参考方案2】:
将弹出指令替换为leave
。这将恢复堆栈指针和基指针。
【讨论】:
以上是关于非法指令 gcc 汇编程序的主要内容,如果未能解决你的问题,请参考以下文章