NASM中MOV指令访问内存为何需用方括号?操作数位置差异解析
Great question—this is one of those classic NASM gotchas that trips up folks new to x86 assembly, especially if you’ve dabbled in other assemblers like MASM before. Let’s break this down clearly:
First, let’s recap what you already know (since you got the read operations right) to set the stage:
- When you write
mov rax, test, NASM treatstestas the memory address of your variable (0x00000052 in your example). So rax gets loaded with that address value. - When you write
mov rax, [test], the square brackets tell NASM: "Don’t use the address itself—go to that address in memory and grab the value stored there." So rax gets 0x01, which is correct.
Now, let’s tackle the write operation confusion. Your initial logic had a small misstep, so let’s clear that up:
Why mov test, 0x01 doesn’t work (and isn’t what you think it is)
In NASM, the symbol test always represents its address value (0x52 here)—no exceptions, whether it’s in the source or destination operand. So mov test, 0x01 is equivalent to trying to run mov 0x00000052, 0x01.
But the x86 instruction set doesn’t allow moving an immediate value to another immediate value—there’s no mov imm, imm instruction. The destination operand of a mov has to be either a register or a memory location. That’s why this line would throw an assembly error, not write to address 0x52 like you guessed.
Why mov [test], 0x01 does write to address 0x52
The square brackets here serve the same purpose as they did in the read operation: they tell NASM to treat the operand as a memory location, not an immediate address value.
So [test] translates to "the memory address pointed to by test" (which is 0x52). This makes the instruction valid: it’s a mov mem, imm operation, where we’re writing the immediate value 0x01 into the memory location at 0x52.
The key rule to remember for NASM
- A bare symbol (like
test) is always an immediate value equal to the symbol’s memory address. - Wrapping a symbol in square brackets (
[test]) tells NASM to perform memory access at that address—reading from it if it’s the source operand, writing to it if it’s the destination.
Your initial confusion probably came from thinking square brackets in the destination would "dereference twice" (i.e., use the value at test as an address to write to), but that’s not how NASM works. If you wanted to do that (write to the address stored inside test), you’d need to first load that value into a register, like:
mov rax, [test] ; rax gets 0x01 (the value stored at test's address) mov [rax], 0x02 ; now write 0x02 to address 0x01
内容的提问来源于stack exchange,提问作者Pedro Palhari

