x86 指令"movb $5, var(,1)"



我正在阅读AT&T语法,我遇到了这个指令

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

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

至少可以说,这是一种非传统的风格;我以前从未见过有人写过这样的东西,用于寻址没有寄存器的静态标签


这可能是一种指示SIB字节(没有基或索引)的尝试,而不是允许汇编程序仅使用ModRM字节使用较短的编码。

(是的,这是可能的。32位寻址模式有两种冗余方式来编码[disp32]绝对地址。x86-64将较短的一种重新定义为RIP相对寻址。另请参阅rbp不允许作为SIB基础?)

但当前GAS忽略它,并将其编码为仅var

因此,这可能是为了提醒您这是一个内存操作数,就像在英特尔语法中总是使用[var]而不是mov var, al一样(这在MASM风格的英特尔语法中有效,如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 --version在我的系统上打印GNU 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移到parens之外。

最新更新