将 [symbol + constant] Intel 语法寻址模式转换为 AT&T 语法?

Converting [symbol + constant] Intel syntax addressing mode to AT&T syntax?

我只是不知道如何在移动值时向我的目的地添加偏移量,特别是在英特尔语法中我有:

MOV   [gdtr + 2], EAX

对于 AT&T 语法,我尝试将其转换为:

movl %eax, gdtr(2,1)

编译 junk '(2,1)' after expression 时出错,但仅使用 gdtr(,1) 就可以正常工作。

我不明白为什么我不能使用基本偏移,只能使用比例因子。

随便写

movl %eax, gdtr+2

基址偏移寻址仅在偏移为寄存器时有效。将两个常量相加的寻址模式毫无意义;它的工作方式(无论语法如何)是汇编器/链接器将 symbol+constant 解析为指令编码的位移字段的单个数字。

只是gdtr+2

gdtr(2,1) [gives an error] but using just gdtr(,1) works fine.

AT&T寻址方式()括号内的内容只能是寄存器(和比例因子):disp(base, index, scale)。基数和索引是可选的,所以空是可以的,但无效(非注册)不是。

并且当您指定没有底数或索引的比例时,显然您只能使用一个逗号:(,,1) 是关于空比例因子的错误。
您可以将其写为 gdtr+2(,1) 以明确不使用寄存器。

无论语法如何,+2 都是寻址模式中位移的一部分,而不是基址或变址寄存器。请参阅 或 Intel 或 AMD 的手册,了解如何对寻址模式进行编码。 (你正在做的是 [disp32][disp16] 寻址模式,就如何将其编码为机器代码而言。)

正如 Nate 指出的那样,linker 负责将 assemble-time 文字常量 + link-time-constant 符号地址转换为机器代码中的最终地址,编码为 disp32(或 disp16 用于 16 位地址大小)。或 RIP-relative rel32 for x86-64.

有趣的事实:一些 AT&T assemblers 接受 (gdtr) 作为 gdtr 的替代品,但不接受 2(gdtr).


自己解决这个问题的方法:

通常,如果您卡在 NASM -> AT&T,您可以 assemble NASM 来源(例如 nasm -felf)和 disassemble AT&T disassembler 喜欢 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

这是您的寻址​​模式,作为奖励,AT&T 助记符用于带有字节源的 movzx。当然你可以 fiddle 类型。

编译器是有用的资源;他们知道如何在编译简单的 C 函数时做很多事情 "the normal way",并且他们知道调用约定和类型宽度。以及包括函数指针在内的所有内容的 AT&T 语法。 如果您遇到困难,请咨询编译器。基本上,您唯一无法让编译器向您展示的是 jmp far (AT&T ljmp)

的语法