-1

我正在 Xcode 4 上使用 gcc 编译器构建一些 intel 风格的内联汇编代码。下面列出了部分内联汇编代码:

_asm
{   
    mov eax, esp
    sub esp, 116
    and esp, ~15
    mov [esp+112], eax       
}

在 ship 模式下,GCC 将上述 4 行 asm 代码编译为:

mov    %esp,%eax
sub    $0x74,%esp
and    $0xfffffff0,%esp
mov    %eax,0x70(%esp)

这正是我想要的。但是,在调试模式下,GCC 会将该代码编译为

mov    %esp,%eax
mov    %eax,%esp
mov    %esp,%eax
mov    %eax,-0x28(%ebp)
mov    %esp,%eax
mov    %eax,%esp
sub    $0x74,%esp
mov    %esp,%eax
mov    %eax,-0x24(%ebp)
mov    %esp,%eax
mov    %eax,%esp
**and    $0xfffffff0,%esp**         
**mov    %esp,%eax**        **//changing the value of “eax”**
mov    %eax,-0x24(%ebp)
mov    %esp,%ecx
mov    %ecx,%esp
**mov    %eax,0x70(%esp)**  **//store a “dirty” value to address 0x70(%esp), which is not we want**

解决上述问题的一种方法是使用 AT&T 样式指令重写内联 asm 代码,并将寄存器添加到破坏列表中。但这种方式将是一项非常耗时的工作,因为要重写的代码太……太长了。

有没有其他有效的方法来解决这个问题?让 gcc 编译器知道应该保留寄存器“eax”?

4

2 回答 2

2

有2种方式:

  1. 解决它的最佳方法是使用 gcc 程序集模板功能。然后你可以告诉编译器你在做什么,寄存器分配器不会将你的寄存器用于其他任何事情。

  2. 一个快速破解方法是只使用“asm volatile”而不是“asm”,这样 gcc 就不会重新安排该块内的任何指令。您仍然必须告诉 GCC 您正在使用该寄存器,因此它不会在其中存储任何内容。您还应该在 clobber 列表中列出“内存”,以便 gcc 知道它不能信任它可能在您的代码块之前加载的值。

    asm volatile("代码在这里":::"eax", "esp", "memory");

顺便说一句:您的代码正在做一些“坏事”,例如移动 esp,这可能会导致麻烦,除非您确切知道自己在做什么。

于 2012-04-24T11:12:22.760 回答
-1

英特尔风格的块之后的空asm块解决了问题,如下所示:

__asm volatile {   
    mov eax, esp
    sub esp, 116
    and esp, ~15
    mov [esp+112], eax       
};
__asm__ __volatile__ ("":::"eax", "memory");

但是,如果您不恢复%esp,它将造成严重破坏。

于 2016-09-27T14:45:00.073 回答