Steve Woods' post gave me the impression he thinks & is a dereference operator. & is C's reference operator. * is C's dereference operator. The OP has a valid concern. [] can seem to function as both depending on the context. It is neither a dereference or reference operator. It is the "This is a memory address!!!" operator.
https://nasm.us/doc/nasmdoc3.html#section-3.3
An effective address is any operand to an instruction which references memory. Effective addresses, in NASM, have a very simple syntax: they consist of an expression evaluating to the desired address, enclosed in square brackets.
; assume wordvar was used as a label, and the linker gave it address 6291668
; or mostly equivalently, you used wordvar equ 6291668
mov eax,wordvar ; eax = 6291668. Move value 6291668 to eax.
mov eax,[wordvar] ; eax = 12. Move contents of address 6291668 to eax.
mov eax,13
; mov wordvar,eax ; Move eax to value 6291668. syntax error.
mov [wordvar],eax ; mem(6291668) = 13. Move eax to address 6291668.
When an operand is a memory address, it has to be enclosed in square brackets to tell nasm that is the case. It's not dereferencing it, it's just letting nasm know what's up. If it was equivalent to the dereference operator,
mov [wordvar], eax
would set memory location 12 to 13.
It's not the dereference operator. It's the "this is a memory address" operator. This appears to be both dereferencing and referencing in different cases because x86 and x86_64 instructions behave differently based on whether its operands are memory locations or values. I am teaching myself assembly and I had to explain this to figure it out myself.
mov test, 0x01
would mean0x00000052 = 0x01
, i.e. number = other_number, which doesn't make sense. Your comment ";address 0x00000052 = 0x01" somehow assumes the value 0x52 is memory address, but there's no reason to assume that. BTWtest
is not variable, it is symbolic label for certain memory address0x52
, you can create label just bytest:
, you don't need to follow it withdb
directive to reserve any space (although you should, if you want to overwrite the bytes following that label). My quarrel is about how you think about it, there are no variables in asm. – Cottonmouthmov [test], 0x01 ;address 0x01 = 0x01
has weird comment too... it'smov [0x52],1
= store value1
into memory at address0x52
, and it's ambiguous, as the assembler can't tell from that source if you want to store 8/16/32/64 bit value1
, NASM should either fail or at least emit warning on that line. In ambiguous case you should specify size explicitly, likemov byte [test],1
-> to write only single byte into memory. (BTW "why" - because Intel syntax marks memory access with square brackets and NASM creators decided to follow that rigorously). – Cottonmouthmov rax, test ;rax = 0x00000052
shows you're probably looking at disassembly of a.o
you haven't linked. It's 0x52 bytes from the start of the file or something.mov rax, test
is amov r64, sign_extended_imm32
of the address. – Mottlemov rax, [test]
is a load, the other order is a store (different opcode but same mnemonic). On load/store architectures with separate mnemonics likelw
andsw
, it's typical for them not to follow the pattern of which operand is the destination for ALU instructions. e.g. MIPSlw $t0, ($a0)
andsw $t0, ($a0)
, notsw ($a0), $t0
. But on x86, almost all instructions can have a memory source or a memory destination, so they always respect the operand ordering. – Mottlemov eax,0x52
andmov eax,[0x52]
, first one will load the value 0x52 itself intoeax
, the second will use0x52
as memory address, and load 32 bit value (size is deducted from target register = eax = 32 bits) from memory. When you flip the arguments, the source vs destination is flipped, which makes sense withmov [0x52],eax
(storing 32 bit value ofeax
into memory), but notmov 0x52,eax
(immediate constant is not something desirable for writing into). NASM is consistent in style "[] = memory access". – Cottonmouth