【问题标题】:How to make gcc compiler reserve registers when building intel-style inline assembly code?构建intel风格的内联汇编代码时如何使gcc编译器保留寄存器?
【发布时间】:2012-04-24 10:22:29
【问题描述】:

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

_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”?

【问题讨论】:

  • 倾斜代码使用寄存器 eax 来存储重要值,但 GCC 使用“eax”作为临时寄存器并“污染”寄存器“eax”。如何避免这种情况?
  • 保存是什么意思?在 inline-asm 语句结束之后?这是没有意义的;一旦您的 asm 语句完成,编译器将再次拥有这些寄存器。如果您希望函数返回您在eax 中留下的内容,您需要使用 C 变量来实现。包含 asm 块的函数可以内联到另一个函数中...

标签: debugging gcc assembly xcode4 inline-assembly


【解决方案1】:

有两种方式:

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

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

    asm 易失性( “代码在这里” : : : “eax”、“esp”、“内存” );

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

【讨论】:

  • 正如我所说,代码很长很复杂,我这里贴的只是原始代码的一小部分。使用您建议的第二种方式重写整个代码将非常耗时。有没有其他方法可以声明寄存器 eax 已被保留?
  • 其实mov eax, esp sub esp, 116 and esp, ~15 mov [esp+112], eax 后面还有很多其他指令,这里不方便贴出来。
  • 您只需将: : : "eax", "esp", "memory" 部分添加到汇编代码的末尾并将该块声明为易失性。您还需要将您正在破坏的所有寄存器添加到列表中。然后 gcc 会做“正确的事”。
  • 是的,我明白你的建议。但是上面的代码是使用 Intel 风格的指令编写的,其中 asm{} 块内部有很多宏定义、内存访问等。
  • @behe:您可以使用 -masm=intel 进行编译,因此您可以在 GNU C 扩展 asm 语句中使用 GNU as 的 Intel 语法版本,并具有适当的输入和输出约束。您可能只需要更改一些处理将数据输入/输出 asm 块的指令,而不是将所有内容大量转换为 AT&T 语法。
【解决方案2】:

intel 风格块解决问题后的空asm 块,如下所示:

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

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

【讨论】:

    猜你喜欢
    • 2012-02-12
    • 2021-05-20
    • 2013-06-14
    • 1970-01-01
    • 1970-01-01
    • 2019-03-24
    • 1970-01-01
    • 2019-05-11
    • 1970-01-01
    相关资源
    最近更新 更多