在gcc中使用“-masm=intel”时,名为“offset”的变量会导致出现“Error:invalid use of register”,但在AT&T模式下不会出现错误

vuv7lop3  于 9个月前  发布在  其他
关注(0)|答案(1)|浏览(107)

我试着用gcc和-masm=intel选项编译一个非常简单的程序。但是出现了“错误:无效使用寄存器”。

// test.c
#include <stdio.h>
size_t offset;

int main(int argc, char **argv, char **envp)
{
        offset = 20;
        return 0;
}

字符串
结果:

$ gcc test.c -masm=intel
/tmp/ccPnqEmz.s: Assembler messages:
/tmp/ccPnqEmz.s:19: Error: invalid use of register


但是当我删除赋值语句时,它可以正常编译:

// test.c
#include <stdio.h>
size_t offset;

int main(int argc, char **argv, char **envp)
{
        //offset = 20;
        return 0;
}


结果:

$ gcc test.c -masm=intel
$


当我查看两者的汇编代码时,我只发现前者比后者多了一条存储指令,实现了offset = 20赋值:

mov     QWORD PTR offset[rip], 20


为什么GNU汇编程序会在GCC发出的这条指令上阻塞?

ui7jx7zq

ui7jx7zq1#

这是因为offset是Intel语法汇编中的关键字。
Intel语法模式下的GNU汇编程序遵循微软汇编程序惯例,在汇编指令中提及空符号名会产生一个带有该符号地址的内存操作数,而不是立即操作数。要选择立即操作数解释,需要在符号前放置offset关键字。

mov     esi, var         # loads the value from memory at var
        mov     esi, offset var  # loads the address of var

字符串
NASM有相反的约定,在那里人们会写:

mov     esi, [var]       ; loads the value from memory at var
        mov     esi, var         ; loads the address of var


在GNU汇编程序的AT&T语法中,这些将是:

movl    var, %esi        # loads the value from memory at var
        movl    $var, %esi       # loads the address of var


当GNU汇编器解析编译器产生的代码时,单词offset被解释为关键字而不是符号名,这会混淆汇编器的解析器。为了在手工编写汇编代码时消除含义的歧义,您可以将符号名放在引号中:

mov     QWORD PTR "offset"[rip], 20


这将由汇编程序正确解析和解释。(NASM使用$用于此目的。)
如果您将变量命名为与寄存器相同的变量,则会出现相同的问题,并进行相同的修复。Intel语法很少用于GNU汇编程序,特别是当GCC通常用于编译代码时,这意味着此错误很容易被忽略。

相关问题