1

I was experimenting with the NASM assembler, when I came across a problem:

mov (sp),bx
mov [sp],bx

The first instruction is assembled properly while the second one is not, and gives me the error:

error: invalid effective address

Why is this? What's the difference between the two?

Sep Roland
  • 33,889
  • 7
  • 43
  • 76
Suraaj K S
  • 600
  • 3
  • 21
  • 2
    `[]` means memory reference, `()` are just normal arithmetic parentheses which nasm allows for whatever reason. As such your first instruction is just `mov sp, bx` which is valid, but `[sp]` is not because 16 bit mode does not support that form of effective address. – Jester Jan 07 '20 at 14:07
  • assembly language is defined by the assembler the tool not the target (x86) nor style (AT&T vs intel), the assembler defines the language and certainly with x86 over time nuances specific to indirect addressing have evolved/changed, lots of mips educated folks are forcing mips assembler style/habits onto other targets as they develop new tools for those targets. so its a mismash of syntax and is very tool specific so you can will see (blah) or [blah] mean indirect addressing depending on the tool and its implemented assembly language. – old_timer Jan 07 '20 at 20:58
  • some specific version of nasm being a specific tool has a specific language or set of language options that you must conform to, it is a nasm thing not an x86/intel/AT&T thing. have to read the manual or in the case of nasm possibly the source code to find out all the nuances and options. – old_timer Jan 07 '20 at 20:59

1 Answers1

4

(%sp) would be an AT&T syntax addressing mode. (Invalid because 16-bit addressing modes can't use SP directly, only BP|BX + SI|DI NASM x86 16-bit addressing modes; that's also the reason mov [sp], bx is invalid.)

In NASM syntax, square brackets [] mean a memory operand.


In NASM, the parens () around SP are removed just like any compile-time expression,
so mov (sp), bx assembles to 89DC mov sp,bx. Try it yourself by assembling and using ndisasm on the output. (Or assemble into -felf32 and use objdump)

This is a mov between two registers, overwriting the stack pointer. Very likely not what you want, and totally different from storing to memory with mov [bp], bx or whatever.

In NASM, you might use parens when writing something like mov ax, (1+3) * 4 so NASM's expression parser handles parens, and apparently having a register name inside parens doesn't change anything.

I only mentioned AT&T syntax at the top of this answer because that and Plan9/Go syntax are the only time you'd normally put a register name inside parens; it's just confusing in NASM syntax; don't do it.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
  • So does 32 bit mode allow something like mov ebx,[esp] or mov [esp],ebx? – Suraaj K S Jan 07 '20 at 15:49
  • 2
    @SuraajKS: yes. [Referencing the contents of a memory location. (x86 addressing modes)](//stackoverflow.com/q/34058101). That would be a load, not a store. (That's also allowed in 16-bit mode (on a 386 or higher), and could be useful if you know SP is zero-extended into ESP, if you don't want to set up BP as a frame pointer). Segment limits still apply.) – Peter Cordes Jan 07 '20 at 15:52
  • Segment limits meaning? As set up by the descriptor tables (GDT)?? – Suraaj K S Jan 07 '20 at 15:59
  • 2
    @SuraajKS [Segment size in x86 real mode](//stackoverflow.com/q/17786357) explains that using 32-bit addressing modes doesn't bypass the 64k segment limit. Real mode doesn't have a GDT, but yes in 16-bit protected mode, or after switching back to real mode from protected mode, the segment limit loaded from the GDT by `mov ss, something` still applies. – Peter Cordes Jan 07 '20 at 16:07