x86 doesn't have memory-indirect data addressing. It's the difference between 0 and 1 levels of indirection vs. the symbol address as an immediate, not 1 vs. 2.
Unlike C, in FASM (and NASM) syntax, mentioning a bare symbol name is the address as a value.
e.g. mov eax, symbol
sets EAX = the address where you put that label, with a mov eax, imm32
instruction, not a load from memory.
Of course mov symbol, eax
can't work because an immediate constant can't be a destination, only a [disp32]
addressing mode.
if I think of mov as write it makes a lot more sense. Can I think of mov
as write instead of "moving?
Yes. mov just copies from the source operand to the destination operand. That's why the destination has to be pointed-to memory or a register. But the source operand can be an immediate, register, or memory.
(Of course you can't have both src and dst be memory for a single mov
instruction; there are different forms for different kinds of operands.)
An asm symbol in FASM and NASM works kind of like C char arr[]
.
You can't do arr = x;
- the asm equivalent is mov arr, al
which isn't legal either (in FASM and NASM syntax).
But you can do *arr = x;
which in asm is mov [arr], al
FYI: MASM syntax is different: instead of symbols working as a placeholder for a number in all contexts, mov sym, al
is a store the same as mov [sym], al
and the brackets are optional and meaningless without a register.
If you see any MASM examples or GCC/clang .intel_syntax noprefix
output; that's what's going on.