2

I am just starting studying Assembly (x86, NASM) in university and I am really confused about how it works. Out of the many questions I have about it, this keeps bugging me.

When do I need to speficify the size of the operand? Is there a rule? For example:

segment  data use32 class=data
    a  db 10
    b  dw 40
segment  code use32 class=code
start:
    mov  AX, [b]
    div  BYTE [a]

Here we specified the size of the operand in the div opcode as BYTE. If I delete that BYTE part, I get an error, so we need to specify it.

segment  data use32 class=data
    a  db 10
    b  dw 40
segment  code use32 class=code
start:
    mov  AH, 2
    mul  AH

Here, we didn't need to specify the size of the operand 2. It just works.

So when do I have to specify the size? Is it as simple as: when I have a variable declared in memory, specify its size? Considering the examples given above, I am inclined to think so, but through my short experience with Assembly I found that it tends to defy my logic as to how things should work.

Also, after illuminating me about when we need to specify the size, can you please also tell me WHY we need to do this? When we need to do it, why do we need to do it? I mean, we already declared the variable, so the type of the variable should be visible to the program, shouldn't it? Why do we need to specify the size, else we get an error?

user010517720
  • 2,127
  • 2
  • 7
  • 15
  • 2
    To the assembler you haven't actually declared a variable, you've defined a symbol. The assembler doesn't know and doesn't care that you're using this symbol to access a variable at the location the symbol refers to. NASM symbols don't have types and this was an intentional design decision, distinguishing it from MASM which does give symbols types. – Ross Ridge Oct 12 '20 at 20:42
  • Almost a duplicate: [Why do we need to disambiguate when adding an immediate value to a value at a memory address](https://stackoverflow.com/q/47445362) implies that it's needed when there's no register operand, only an addressing mode and/or immediate. – Peter Cordes Oct 12 '20 at 21:08
  • @RossRidge Can you please explain what exactly is the difference (at least to the assembler) between a symbol and a variable? What do these 2 things do? – user010517720 Oct 13 '20 at 15:43
  • 1
    A memory **variable** is one, two or more bytes reserved in data section of your program. **Symbol** is a name assigned by you to this variable, and it represents the address of the first byte of this memory variable. – vitsoft Oct 14 '20 at 08:09

1 Answers1

6

You don't need to specify an operand size if it can be inferred from something else you did specify. For example, mov only works on two operands of the same size, and AX is a word-sized register, so in mov AX, [b], it can infer that [b] must be word-sized. But you only specify one operand to div, so you have to tell it what size [a] is since it doesn't have any information to infer it from.

  • How about addition with constants? How come I can just add a value like 2 to a register without specifying anything? – user010517720 Oct 13 '20 at 15:46
  • @user010517720 You can add 2 to a register that way because registers always have fixed sizes (e.g., `eax` is always a dword). – Joseph Sible-Reinstate Monica Oct 13 '20 at 16:08
  • So then it automatically treats 2 as a dword? Since `eax` is a dword? – user010517720 Oct 13 '20 at 16:12
  • @user010517720: An instruction with at least one register operand implies the operand-size for all the other operands, i.e. for the whole instruction. The only exceptions are rare cases where the operands can be different sizes, like `shl [mem], cl` or `movzx eax, [mem]` which have a register operand but the size of the memory operand is still ambiguous. [How does x86 handle byte vs word addressing when executing instructions and reading/writing data?](https://stackoverflow.com/q/58628157) – Peter Cordes Apr 13 '22 at 05:05