首页 > 解决方案 > x86 指令“movb $5, var(,1)”

问题描述

我正在阅读关于 AT&T 语法的 x86 汇编教程,我遇到了这个说明

movb $5, var(,1)— 将值 5 存储到位置 var 的字节中。

(,1)aftervar表示什么?这种后缀的一般语法是什么?

标签: assemblyx86att

解决方案


至少可以说这是非常规的风格。我以前从未见过有人写过这样的东西,用于解决没有寄存器的静态标签。


这可能是试图指示一个 SIB 字节(没有基址或索引),而不是允许汇编器使用只有 ModRM 字节的较短编码。

(是的,这是可能的。32 位寻址模式有 2 种冗余方式来编码[disp32]绝对地址。x86-64 将较短的一种重新定义为 RIP 相对寻址。另请参阅rbp not allowed as SIB base?

但是当前的 GAS 会忽略它并将其编码为与 just 相同var

因此,也许它试图提醒您这是一个内存操作数,就像总是[var]在 Intel 语法中使用而不是mov var, al(这在 MASM 风格的 Intel 语法风格中有效,例如 GNU .intel_syntax,但不是 NASM)。

这种后缀的一般语法是什么?

或者,也许他们只是为了始终使用disp(basereg, idxreg, scale)内存操作数的语法保持一致性,省略未使用的部分。


测试来源:

var:                  # this won't be in writeable memory, it will assemble but not run
movb  $5, var
movb  $5, var(,1)
movb  $5, (var)      # turns out this is valid, too!

#movb $5, var(%rip)  # RIP-relative is x86-64 only, but it's recommended when available.

# movb  $5, var()     # Error: junk `()' after expression
# movb  $5, (var,,1)  # also invalid
# movb  $5, (var,%ecx,1)       # also invalid.
# movb  $5, (var+%eax,%ecx,1)  # also invalid.

as --versionGNU assembler (GNU Binutils) 2.31.1在我的系统上打印。

$ gcc -m32 -no-pie -nostdlib foo.s
/usr/bin/ld: warning: cannot find entry symbol _start; defaulting to 0000000008049000
 # I just wanted a linked binary with real addresses filled in, not to run it.
 # entry = start of the .text section is fine.

$ objdump -drwC -Mintel a.out

08049000 <var>:
 8049000:       c6 05 00 90 04 08 05    mov    BYTE PTR ds:0x8049000,0x5
 8049007:       c6 05 00 90 04 08 05    mov    BYTE PTR ds:0x8049000,0x5
 804900e:       c6 05 00 90 04 08 05    mov    BYTE PTR ds:0x8049000,0x5

Clang 7.0 的内置汇编器也接受 GAS 所做的所有 3 个变体,生成相同的二进制文件。(至少.text我正在拆卸的部分;可能在另一部分的某个地方有所不同。)


那么也许cmp $1, (var)是使内存操作数显式的好方法? 但这并不是很好,因为与 Intel 语法不同,您不能只向其中添加寄存器,您必须移出var括号。


推荐阅读