Linux 非法指令gcc汇编程序

Linux 非法指令gcc汇编程序,linux,gcc,assembly,Linux,Gcc,Assembly,在汇编程序中: .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测试c测试s 这段代码有时给我非法指令,有时给我段错误。 在gdc中,我总是得到非法指令,这只是一个简单的测试,我有一个更大的程序正在工作,在没有明显原因后突然停止工作,现

在汇编程序中:

.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测试c测试s

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

我已经把它缩小到pushl%eax&调用printf,如果我注释掉这些行,代码运行良好

有什么想法吗?
(我正在我的大学linux群集上运行该程序,因此我没有更改任何设置。)

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

您正在执行
pushl%eax
(或任何其他寄存器),然后执行
popl%ebp
。这两种方法的效果与执行
movl%eax,%ebp
的效果相同


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

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

您正在执行
pushl%eax
(或任何其他寄存器),然后执行
popl%ebp
。这两种方法的效果与执行
movl%eax,%ebp
的效果相同


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

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

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

感谢您指出这一点,我用一个更合理的示例更新了主帖,但仍然会出现错误。printf弹出堆栈的最后一项,因此popl ebp现在应该是正确的了。@Bernt:printf弹出堆栈中的任何内容都是错误的。在Linux/x86中,当
调用的函数返回时,堆栈保持不变-之前推送的所有参数仍然在那里。这就是你的代码中的问题,一个你不期望的词。感谢你指出这一点,我用一个更理智的示例更新了主要帖子,但我仍然得到了错误。printf弹出堆栈的最后一项,因此popl ebp现在应该是正确的了。@Bernt:printf弹出堆栈中的任何内容都是错误的。在Linux/x86中,当
调用的函数返回时,堆栈保持不变-之前推送的所有参数仍然在那里。这就是代码中的问题所在,一个你不希望出现的单词。你只是忘记了在调用返回后从堆栈中删除
printf()
的参数。您的
popl%ebp
取下了错误的内容,而您的
ret
尝试跳转到错误的位置-因为堆栈上的字比您预期的多。您只是在从调用返回后忘记从堆栈中删除
printf()
的参数。你的
popl%ebp
取下了错误的东西,而你的
ret
试图跳转到错误的位置-因为堆栈上比你预期的多了一个单词。