0

我只是无法弄清楚如何在移动值时向目标添加偏移量,特别是在我拥有的英特尔语法中:

MOV   [gdtr + 2], EAX

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

movl %eax, gdtr(2,1)

编译时会出错,junk '(2,1)' after expression但使用gdtr(,1)效果很好。

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

4

2 回答 2

2

简单地写

movl %eax, gdtr+2

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

于 2020-04-07T22:35:01.703 回答
1

只是gdtr+2

gdtr(2,1)[给出错误]但使用gdtr(,1)效果很好。

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

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

+2 是寻址模式中位移的一部分,而不是基址或索引寄存器,无论语法如何。请参阅有关 [base + index*scale + disp]或 Intel 或 AMD 的有关寻址模式如何编码的手册的几个问题。(就如何将其编码为机器代码而言,您正在做的是[disp32]或寻址模式。)[disp16]

正如 Nate 指出的那样,链接器负责将汇编时文字常量 + 链接时常量符号地址转换为机器代码中的最终地址,编码为 a disp32(或disp1616 位地址大小)。或 x86-64 的相对 RIP rel32

有趣的事实:一些 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 在 Godbolt 编译器资源管理器上编译到这个 asm:

foo:
        movzbl  gdtr+2, %eax
        ret
gdtr:
        .zero   1024

有你的寻址模式,作为奖励,带有字节源的 movzx 的 AT&T 助记符。当然,您可以摆弄类型。

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

于 2020-04-08T01:56:54.277 回答