45

I'm very new to assembly, and have some very basic questions.

What is the difference between these four commands?

mov ebx, eax
mov [ebx], eax
mov ebx, [eax]
mov [ebx], [eax]

They say that the brackets mean "get the value of the address". But what, then, does that very first line really do? Does it not move the value of eax into ebx? If it does, then what are the point of the brackets?

J...
  • 30,968
  • 6
  • 66
  • 143
ineedahero
  • 715
  • 1
  • 5
  • 10
  • 7
    The point of the brackets is to access memory. You can think of it as the `*` operator in C. Also, the last one is invalid. – Jester Feb 04 '18 at 13:15
  • But doesn't the first example access memory without the brackets? – ineedahero Feb 04 '18 at 13:17
  • @ineedahero No, the first example copies the *value* of one register to another register. Registers are not memory. – J... Feb 04 '18 at 13:19
  • So the first and third are equivalent? Then what does the second line do? – ineedahero Feb 04 '18 at 13:23
  • BTW, these all fail to assemble because you left out the comma between the operands. It's obvious what you meant, though, so posting "there's no difference" would be a funny and correct but useless answer. So instead I made an edit to fix the question. – Peter Cordes Feb 04 '18 at 13:29
  • I don't see why the last line in invalid. – ineedahero Feb 04 '18 at 13:37
  • 3
    @ineedahero: The last line is invalid because there is no way to copy from memory to memory. In `[ebx],[eax]`, ebx and eax contain addresses, i.e. both are referencing memory. and you can't copy from memory to memory directly: the processor doesn't have instructions for that. – Rudy Velthuis Feb 04 '18 at 14:00
  • 4
    @RudyVelthuis: not quite true: the instruction set doesn't give a way to encode any instructions with two *explicit* memory operands. But `movs`, `push [mem]` and `pop [mem]` all copy memory to memory, with one or both operands being implicit. x86 instructions have at most one modrm + optional displacement explicit addressing mode. *That's* why `mov` doesn't work but other instructions do. – Peter Cordes Feb 04 '18 at 14:18
  • @ineedahero registers are physically stored inside CPU (their bits). "memory" is different chip on the board, so whenever CPU stores/loads value to/from memory, it has to contact other chip and send it address you want to work with, and then send the data, or receive, which takes lot more effort (and often may take considerably more time), than when you work with the bits inside the CPU (registers). – Ped7g Feb 04 '18 at 14:35
  • @PeterCordes: right, no explicit memory copies. – Rudy Velthuis Feb 04 '18 at 15:04
  • 1
    What brackets mean in MASM: https://stackoverflow.com/questions/25129743/confusing-brackets-in-masm32/25130189#25130189 – Ross Ridge Feb 04 '18 at 18:28
  • Different instructions have different interpretations of the `[]`, check here: https://stackoverflow.com/questions/58959965/square-brackets-why-are-these-used-in-lea – smwikipedia Dec 14 '20 at 10:01
  • Related: [What do the brackets mean in x86 asm?](https://stackoverflow.com/q/2030366). And for MASM specifically, things are sometimes weird with symbols or numbers instead of registers: [Confusing brackets in MASM32](https://stackoverflow.com/q/25129743). Compare NASM: [Basic use of immediates vs. square brackets in YASM/NASM x86 assembly](https://stackoverflow.com/q/10362511) – Peter Cordes Jan 13 '22 at 21:28

2 Answers2

95

Let's make a very simple example and imagine we have a CPU with only two registers, EAX and EBX.

mov ebx, eax

Simply copies the value in eax to the ebx register

 | EAX : 01234567 |   ---->   | EAX : 01234567 |
 | EBX : 00000000 |   ====>   | EBX : 01234567 |

Now let's add some memory space

ADDRESS           VALUE
00000000          6A43210D
00000004          51C9A847
00000008          169B87F1
0000000C          C981A517
00000010          9A16D875
00000014          54C9815F

mov [ebx], eax

Moves the value in eax to the memory address contained in ebx.

 | EAX : 01234567 |   --no-->   | EAX : 01234567 |
 | EBX : 00000008 | --change--> | EBX : 00000008 |

ADDRESS           VALUE
00000000          6A43210D   ->   6A43210D 
00000004          51C9A847   ->   51C9A847 
00000008          169B87F1 =====> 01234567 
0000000C          C981A517   ->   C981A517 
00000010          9A16D875   ->   9A16D875 
00000014          54C9815F   ->   54C9815F 

mov ebx, [eax]

Moves the value from the memory address contained in eax to ebx.

 | EAX : 00000008 |    ->     | EAX : 00000008 |
 | EBX : 01234567 |   ====>   | EBX : 169B87F1 |

[No change to memory]
ADDRESS           VALUE
00000000          6A43210D
00000004          51C9A847
00000008          169B87F1
0000000C          C981A517
00000010          9A16D875
00000014          54C9815F  

mov [ebx], [eax]

This, finally, you would think would move the value from the memory address contained in eax to the memory address contained in ebx.

 | EAX : 00000010 |   --no-->   | EAX : 00000010 |
 | EBX : 00000008 | --change--> | EBX : 00000008 |

ADDRESS           VALUE
00000000          6A43210D   ->   6A43210D 
00000004          51C9A847   ->   51C9A847 
00000008          169B87F1 =====> 9A16D875   
0000000C          C981A517   ->   C981A517 
00000010         *9A16D875   ->   9A16D875 
00000014          54C9815F   ->   54C9815F 

But this combination is disallowed by the x86 architecture. You cannot move from memory to memory.

The use of brackets is therefore equivalent to a dereferencing operation.

J...
  • 30,968
  • 6
  • 66
  • 143
  • So in order for the second line to make sense, the VALUE of ebx must be an ADDRESS in memory? – ineedahero Feb 04 '18 at 13:36
  • @ineedahero yes, it must be a valid memory address. – J... Feb 04 '18 at 13:37
  • Ok thank you. That was the secret I was missing, and your answer was the only one to address it. – ineedahero Feb 04 '18 at 13:39
  • How come everyone else says the last line is invalid? – ineedahero Feb 04 '18 at 13:40
  • 1
    @ineedahero Because it is - I've updated the answer. – J... Feb 04 '18 at 13:42
  • @ineedahero: I answered that in my answer. – zx485 Feb 04 '18 at 13:56
  • Where is this dereferencing documented? I can not find it in GNU AS manual ;( – DannyS Sep 19 '19 at 23:36
  • 1
    @DannyS [9.16.7 - Memory References](https://sourceware.org/binutils/docs/as/i386_002dMemory.html#i386_002dMemory), under section 9.16 (80386 Dependent Features). – J... Nov 27 '19 at 13:24
  • What does `_x$[edp]` mean? for example: `lea eax, DWORD PTR _x$[ebp]` – Moon soon Jun 24 '20 at 06:54
  • @TangMonk That's better asked as a new question. That syntax and is equivalent to `lea eax, DWORD PTR [_x$] + ebp` - effectively it's an array index. – J... Oct 17 '20 at 11:20
  • 2
    @DannyS: [Why isn't movl from memory to memory allowed?](https://stackoverflow.com/q/33794169) goes into detail about why that's not encodeable into machine code. The GAS manual doesn't bother specifying it because it's not a complete ISA manual; just for the *syntax*. The ISA rules are the same regardless of syntax. – Peter Cordes Jan 13 '22 at 21:30
  • 1
    Note for beginners like me: Unlike `MOV` or other instructions, `LEA` is quite special, don't get confused and see [this](https://stackoverflow.com/a/60272214/10027592). Anyways this answer is great. Thanks! – starriet Aug 02 '22 at 09:07
5

You were missing the operand delimiter , in the instructions. I don't know (yet) of any assembler without it. I fixed that in the quotes.

In x86 assembly some registers can be used as data registers or as address registers (a difference to other architectures). These registers are called GPRs ("General Purpose Registers"). They can contain 32-bit-values or 32-bit addresses. Their "names" are EAX,EBX,ECX,EDX,ESI,EDI,ESP,EBP.

mov ebx, eax

does move the value in EAX to EBX.

mov [ebx], eax

does move the value in EAX to the 32-bit DWORD value pointed to by the 32-bit address in EBX

mov ebx, [eax]

does move the 32-bit DWORD value pointed to by the 32-bit address in EAX to EBX

mov [ebx], [eax]

is an invalid instruction in 32-bit Intel assembly, because x86 machine code does not support two arbitrary memory operands in one instruction, only in special cases where at least one memory operand is implicit, like push dword [ebx] reading memory at [ebx] and writing memory at [esp - 4]. See What x86 instructions take two (or more) memory operands?

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
zx485
  • 28,498
  • 28
  • 50
  • 59
  • What is the difference between "the value in EAX" and "the 32-bit DWORD value pointed to by the 32-bit address in EAX"? That is to say, what practical difference is there between the first two lines? – ineedahero Feb 04 '18 at 13:29
  • How could the last line be invalid and not the second line? – ineedahero Feb 04 '18 at 13:41
  • 1
    The last line contains two memory references, and the second line only one. – zx485 Nov 26 '21 at 13:16