只是gdtr+2
gdtr(2,1) [给出错误] 但仅使用 gdtr(,1) 工作正常。
AT&T 寻址模式中() 括号内的内容只能是寄存器(和比例因子):disp(base, index, scale)。基数和索引是可选的,所以空是可以的,但无效(非注册)不是。
当您指定一个没有基数或索引的比例时,显然您只能使用一个逗号:(,,1) 是关于空比例因子的错误。
您可以将其写为 gdtr+2(,1) 以明确不使用任何寄存器。
+2 是寻址模式中位移的一部分,而不是基址或索引寄存器,无论语法如何。请参阅A couple of questions about [base + index*scale + disp] 或 Intel 或 AMD 的手册了解寻址模式的编码方式。 (您正在做的是[disp32] 或[disp16] 寻址模式,就如何将其编码为机器代码而言。)
正如 Nate 所指出的,链接器负责将汇编时文字常量 + 链接时常量符号地址转换为机器代码中的最终地址,编码为 disp32(或 disp16 用于 16-位地址大小)。或 RIP 相关的 rel32 用于 x86-64。
有趣的事实:一些 AT&T 汇编器接受 (gdtr) 作为 gdtr 的替代品,但不接受 2(gdtr)。
自己解决这个问题的方法:
通常,如果您卡在 NASM -> AT&T,您可以组装 NASM 源代码(例如nasm -felf)并使用 AT&T 反汇编程序(如objdump -drwC)进行反汇编。但这对符号寻址模式语法没有帮助,因为充其量 objdump -dr 只是用符号名称信息注释数字寻址模式。
所以在这种情况下,最好的办法是让 GCC 或 clang 发出一条使用符号名称和数字常量的指令,像这样
char gdtr[1024]; // global var so it has a symbol
char foo() { return gdtr[2]; } // load from global symbol + constant.
用gcc9.3 -O2 -m32 on the Godbolt compiler explorer 编译到这个asm:
foo:
movzbl gdtr+2, %eax
ret
gdtr:
.zero 1024
这是您的寻址模式,作为奖励,还有带有字节源的 movzx 的 AT&T 助记符。当然,你可以摆弄类型。
编译器是有用的资源;在编译简单的 C 函数时,他们知道如何以“正常方式”做很多事情,并且他们知道调用约定和类型宽度。以及包括函数指针在内的所有内容的 AT&T 语法。 如果遇到困难,请询问编译器。基本上,您唯一无法让编译器向您展示的是jmp far (AT&T ljmp) 的语法