如何在更改sp时访问GCC内联程序集中的局部变量?

如何在更改sp时访问GCC内联程序集中的局部变量?,gcc,inline-assembly,gcc4,Gcc,Inline Assembly,Gcc4,考虑以下简化的示例函数: void foo(void) { int t; asm("push %0\n\t" "push %0\n\t" "call bar" : : "m" (t) : ); } 如果我使用Cygwin x86 gcc 4.8.3编译它而不进行优化,推送指令将变成: push -4(%ebp) push -4(%ebp) 这很好。问题发生在-O上: push 12

考虑以下简化的示例函数:

void foo(void) {
    int t;
    asm("push %0\n\t"
        "push %0\n\t"
        "call bar"
        :
        : "m" (t)
        :
        );
}
如果我使用Cygwin x86 gcc 4.8.3编译它而不进行优化,推送指令将变成:

push -4(%ebp)
push -4(%ebp)
这很好。问题发生在-O上:

push 12(%esp)
push 12(%esp)
这显然是错误的。第一次推送更改esp,第二次推送访问错误的位置。我有,但没有用。如何使GCC使用帧指针或适当地考虑ESP更改?< /P>
假设从bar函数返回将esp设置为asm语句之前的值。我只需要调用一个thiscall函数,并使用内联程序集即可。

我可以简单地使用_属性_optimize-fno-omit-frame-pointer来防止这个函数出现导致优化的问题。这可能是最好的解决方案dreamlayers

研发怎么样?这让我推%rax\n推%rax。这是“错误的”,因为gcc不对asm主体执行任何类型的语义分析。gcc asm不接受%ebp或%esp作为约束IIRC,也不接受ELF PIC平台上的%ebx。我认为@DavidWohlferd应该提交一个答案-这是一个不错的选择,因为%eax通常被当作返回值。但是a&t相反。如果我们想假设%eax被返回,那么我们可能应该做一些更像=a retval:0&t的事情。毕竟,我们必须让gcc知道eax的内容正在改变。我会说调用C++代码会很棘手。你是否在打电话之前按了被叫人可能更改的每个寄存器,并在返回时弹出它们?您确定在执行调用之前,gcc存储在寄存器中的所有bar可能需要的内容都已刷新回内存吗?这里可能没有选项,但使用内联asm并不是我的第一选择。使用r可以工作,但它有点混乱并导致其他问题。这只是一个简单的例子。我实际调用的函数有更多的参数,并且会删除一些寄存器。GCC不允许用于输入的寄存器位于clobber列表中。我必须为一些被破坏的寄存器引入虚拟输出变量,这样我就不会耗尽寄存器。我认为在这里使用r并没有什么内在的混乱,尽管它可能会限制其他地方可用的寄存器数量,这可能会导致混乱。虽然使用虚拟输出在美学上是不纯洁的,但我不知道使用它们会对性能产生任何实际影响。因此,虽然这可能确实是最好的解决方案,但很难说没有看到实际的代码、了解调用约定等等。