为什么 %rbp 和 %rax 是 movl 的无效操作数?

问题描述 投票:0回答:1

我正在尝试使用

%rbp
%rax
的值放入
__asm__
寄存器中,这样我就可以获得对堆栈帧的引用,当我创建外部变量时它不会被更改。

我正在使用以下代码来执行此操作:

int some_variadic_function(int n, ...)
{
    __asm__("movl %rax, %rbp");
    return 0;   
}


int main() {
    some_variadic_function(3, 1, 2, 3);
    return 0;
}

但是,当我尝试用 clang 编译它时,出现以下错误:

using_rbp.c:4:13: error: invalid operand for instruction
    __asm__("movl %rax, %rbp");
            ^
<inline asm>:1:7: note: instantiated into assembly here
        movl %rax, %rbp
             ^~~~~
1 error generated.

这似乎在暗示我不能把

%rbp
直接变成
%rax
。这是发生了什么,还是这段代码还有其他问题?

作为参考,我在 Mac 上使用

x86-64
硬件。

c x86-64 inline-assembly att mov
1个回答
3
投票

你犯了一大堆错误。让我们一一道来:

  1. 在 x86 的 AT&T 汇编语法中,如果您在指令上提供大小后缀,它必须与从操作数推断的大小相匹配。对于 x86,大小后缀几乎总是不必要的(我能想到的唯一情况是,当源操作数是一个立即值并且目标是内存时需要它们):我建议将它们排除在外,除非汇编程序抱怨他们缺席。

  2. 在 AT&T 汇编语法中,目标位于 second

    mov %rax, %rbp
    将 RAX 复制到 RBP,而不是相反。

  3. 在 GNU 风格的内联汇编中,

    %
    开始转义序列(如
    printf
    );要写一个文字寄存器名称,您必须将百分号加倍。这就是为什么您从 clang 而不是汇编程序中收到错误的原因。

  4. GNU 风格的内联汇编必须用“操作数约束”进行注释,以便编译器理解您在做什么。您不能简单地将一个值移入 RAX 并期望它成为返回值。请参阅https://gcc.gnu.org/onlinedocs/gcc-11.3.0/gcc/Using-Assembly-Language-with-C.html——阅读本手册部分的all,而不仅仅是摘要页面我链接到。

  5. 在 x86 的 64 位 System V ABI 中,

    %rbp
    是一个普通的通用寄存器,而不是“帧指针”。

做你想做的事情的正确方法是

long some_variadic_function(int n, ...)
{
    long rv;
    __asm__("mov %%rbp, %0" : "=r" (rv));
    return rv;
}

但是,这个必须用

-fno-omit-frame-pointer
编译,否则返回值是垃圾。

您可能正在遭受臭名昭著的XY问题。提出一个关于您 最初 尝试做的事情的新问题,而不是关于您尝试解决问题的细节,我们可能会更有帮助。

© www.soinside.com 2019 - 2024. All rights reserved.