【问题标题】:GCC inline ASM guaranteesGCC 内联 ASM 保证
【发布时间】:2013-07-02 21:16:46
【问题描述】:

我认为这是一个简单的问题,但我找不到任何东西。 如果我写

void bar()
{
    {
        void *rax = 0/* ...*/, *rbx = 0/* ... */;
        asm volatile ("movq %0, %%rax; movq %1, %%rbx;" : : "m"(rax), "m"(rbx));
        goto foo;    
    }

    {
        foo:
        void* rax, *rbx;
        asm volatile ("movq %%rax, %0; movq %%rbx, %1;" : "=m"(rax), "=m"(rbx));

        // LOTS OF CODE
    }
}

是否保证我可以在第二个块中的任何其他代码运行之前获取 rax/rbx 的值?

【问题讨论】:

  • 似乎是一个 XY 问题 - 你到底想解决什么问题?
  • 我正在为 C++ 编写一个函数挂钩库。我想使用 ABI 未使用的寄存器将用户数据指针传输到钩子函数。
  • 那么为什么不编写一个调用实际函数的汇编包装器呢?这是解决这个问题的传统方法。
  • 顺便说一句,您的意思是从名为 rax 的变量读取到寄存器中,还是在第一个汇编程序部分中相反?以如此冗长的方式将 0 加载到寄存器中似乎很奇怪。
  • 1.) 我使用汇编程序包装器来调用函数 - 但我尝试将用户数据指针传输到被调用函数,以便调用函数对象而不是常规 C 函数。

标签: c++ c assembly inline-assembly


【解决方案1】:

否——编译器根据它在 asm 语句之前/之后分配的寄存器/内存位置的约束将输入/输出值挂钩,并假设其他寄存器不受影响。因此,在您的情况下,它可能在您正在破坏的 %%eax%%ebx 中添加了一些重要的内容(这可能会导致崩溃或其他不当行为)。

任何时候您在 asm 语句中使用固定寄存器时,都必须在 clobbers 列表中列出这些寄存器(除非您使用映射到特定寄存器的约束)。所以至少你需要:

asm volatile ("movq %0, %%rax; movq %1, %%rbx;" : : "m"(rax), "m"(rbx) : "rax", "rbx");

对于你的 asm 语句——但即使那样,编译器也不会保证 在您的第一个 asm 块之后和第二个之前(破坏您要保存的值),在 %%eax%%ebx 中添加其他内容。

【讨论】:

  • 感谢您的回复 - 我想我必须更具体一些。我只包含了第一个块来显示行为 - 第一个块 不是 由编译器创建,而是由我自己手动将指令字节写入缓冲区并执行缓冲区。对于那个很抱歉。我只需要知道我是否可以依赖第一个执行的第二个块中的内联 asm 语句,然后第二个块中的代码将它们用于其他用途。
  • @Ethon:那么听起来您可能希望将"a""b""c""d""S""D" 约束绑定到特定寄存器
【解决方案2】:

在 gcc 中使用 volatileasm 将保证编译器不会重新排序语句。但是,不能保证编译器不会在foo: 标签和内联asm 语句之间添加额外代码。当然,这意味着您不能依赖保留在该部分中的寄存器值 - 我还没有设法提出一个独特的例子,但我很确定编译器不能保证这可以不会发生。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-02-08
    • 2020-02-17
    • 1970-01-01
    • 2015-02-19
    • 2018-09-18
    • 2013-10-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多