GCC INLINE ASSEMBLY不会让我覆盖$ esp

Cha*_*had 5 c x86 assembly gcc inline-assembly

我正在编写代码来临时使用我自己的堆栈进行实验.这在我使用文字内联汇编时起作用.我将变量位置硬编码为ebp的偏移量.但是,我希望我的代码可以不用硬编码内存地址,所以我一直在研究GCC的扩展内联汇编.我所拥有的是以下内容:

volatile intptr_t new_stack_ptr = (intptr_t) MY_STACK_POINTER;
volatile intptr_t old_stack_ptr = 0;
asm __volatile__("movl %%esp, %0\n\t"
        "movl %1, %%esp"
        : "=r"(old_stack_ptr) /* output */
        : "r"(new_stack_ptr) /* input */
        );
Run Code Online (Sandbox Code Playgroud)

这一点是首先将堆栈指针保存到变量old_stack_ptr中.接下来,堆栈指针(%esp)将被我在new_stack_ptr中保存的地址覆盖.

尽管如此,我发现GCC将%esp保存到old_stack_ptr中,但是没有用new_stack_ptr替换%esp.经过深入检查,我发现它实际上扩展了我的程序集并添加了它自己的指令,如下所示:

mov    -0x14(%ebp),%eax
mov    %esp,%eax
mov    %eax,%esp
mov    %eax,-0x18(%ebp)
Run Code Online (Sandbox Code Playgroud)

我认为GCC正试图保留%esp,因为我没有将它明确声明为"输出"操作数......我可能完全错了...

我真的很想使用扩展的内联汇编来实现这一点,因为如果没有,似乎我必须将%ebp的位置偏移"硬编码"到程序集中,我宁愿使用像这样的变量名.特别是因为这个代码需要在几个不同的系统上工作,这些系统似乎都以不同的方式抵消了我的变量,所以使用扩展的内联汇编允许我明确地说出变量位置......但是我不明白为什么它会这样做额外的东西,不要让我像以前一样覆盖堆栈指针,自从我开始使用扩展程序集以来,它一直在这样做.

我感谢任何帮助!

Jes*_*ter 8

好的,问题是gcc正在将输入和输出分配给同一个寄存器eax.你想告诉gcc你在使用输入之前破坏输出,也就是说."earlyclobber".

asm __volatile__("movl %%esp, %0\n\t"
        "movl %1, %%esp"
        : "=&r"(old_stack_ptr) /* output */
        : "r"(new_stack_ptr) /* input */
        );
Run Code Online (Sandbox Code Playgroud)

注意&输出的符号.这应该修复你的代码.

更新:或者,您可以强制输入和输出为相同的寄存器并使用xchg,如下所示:

asm __volatile__("xchg %%esp, %0\n\t"
        : "=r"(old_stack_ptr) /* output */
        : "0"(new_stack_ptr) /* input */
        );
Run Code Online (Sandbox Code Playgroud)

注意"0"那说" 将它放入与参数0相同的寄存器 ".