I am reading a tutorial of x86 assembly on AT&T syntax, and I encountered this instructions
movb $5, var(,1)
— store the value 5 into the byte at location var.
What does (,1)
after var
indicate? What is the general syntax for such suffix?
I am reading a tutorial of x86 assembly on AT&T syntax, and I encountered this instructions
movb $5, var(,1)
— store the value 5 into the byte at location var.
What does (,1)
after var
indicate? What is the general syntax for such suffix?
This is unconventional style to say the least; I've never seen anyone write that before, for addressing a static label with no registers.
It may be an attempt to indicate a SIB byte (with no base or index), instead of allowing the assembler to use a shorter encoding with just a ModRM byte.
(Yes, that's possible. 32-bit addressing modes have 2 redundant ways to encode [disp32]
absolute addresses. x86-64 redefines the shorter one as RIP-relative addressing. See also rbp not allowed as SIB base?)
But current GAS ignores it and encodes it the same as just var
.
So maybe it's an attempt to remind you that this is a memory operand, like always using [var]
in Intel-syntax instead of mov var, al
(which is valid in MASM-style flavours of Intel syntax such as GNU .intel_syntax
, but not NASM).
What is the general syntax for such suffix?
Or maybe they're just doing it for consistency of always using the disp(basereg, idxreg, scale)
syntax for memory operands, omitting unused parts.
Test source:
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
prints GNU assembler (GNU Binutils) 2.31.1
on my system.
$ 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's built-in assembler also accepts all 3 variants that GAS does, making an identical binary. (At least the .text
section that I'm disassembling; probably some difference somewhere in another section.)
So perhaps cmp $1, (var)
is a good way to make memory operands explicit? But it's not great, because unlike Intel syntax, you can't just add registers to that, you'd have to move var
outside the parens.