3

I'm making a program where the user enters a number, it the program prints out from zero to that number. Here is my code:

SECTION .DATA
len  EQU 32

SECTION .bss
data resw len
other resw len 
SECTION .TEXT

GLOBAL _start
_start:

input:                  ; This section gets the integer from the user
mov eax, 3          ; }
mov ebx, 1          ; }
mov ecx, data       ; } System_read call
mov edx, len        ; }
int 80h             ; }

prelim:
mov ebp, 0

setup:                  ; This section sets up the registers ready for looping 
push ebp
pop other        ; THIS IS THE ERROR LINE!
mov esi, data 

loop:                   ; This section loops, printing out from zero to the number given
mov eax, 4
mov ebx, 1
mov ecx, other 
mov edx, len
int 80h
cmp ebp, esi
je exit
inc ebp
jmp setup
exit:                   ; Exits the program
mov eax, 1          ; }
mov ebx, 0          ; } System_exit call
int 80h             ; }

The problem I am having is that it gives the error invalid combination of opcode and operand. I have tried declaring the variable other a word, double word, byte, and it still says that. Why does it?

In essence, my question is how can I move a value in a register to a value in memory? Such as:

mov memorydata, eax

Where memorydata is data declared in SECTION .data or something of the like.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
Progrmr
  • 1,575
  • 4
  • 26
  • 44
  • `mov symbol, eax` doesn't assemble either. I have no idea what the edit about the segfault on the marked line was trying to say. – Peter Cordes Feb 18 '16 at 08:21

2 Answers2

10

First, it should be pop [other] and not pop other. In NASM, other is just an address, while [other] represents the contents/data at that address. This is how NASM is different from TASM and MASM. pop other is asking NASM to generate an instruction popping data from the stack into a... constant! There's no such instruction and it would not make any sense to make one like that. You want to pop stuff into a register or memory.

Second, unlike TASM and MASM (again), NASM does not assign to label names any kind of type or size. Labels are just that, named locations (addresses) in code or data.

For that reason pop [other] is ambiguous to NASM because pop can pop a word or a double word and you don't specify which one you want and there's no way for NASM to guess the right size for you.

What you should write instead is either

pop word [other]

or

pop some_32_bit_register ; e.g. pop eax
mov [other], that_same_32_bit_register_s_lower_half ; e.g. mov [other], ax

I strongly suggest not to push or pop 16-bit registers or variables or constants. They misalign the stack, which can lead to reduced performance and silly bugs due to attention loss (e.g. you push a 32-bit value and then mistakenly pop it as 16-bit or the other way around).

Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
Alexey Frunze
  • 61,140
  • 12
  • 83
  • 180
  • That doesn't make sense. The label `other` is just a number that represents a location in memory, right? If you have stored, say, the value 5 at the address referred to by `other`, then I would expect that `pop [other]` would translate to `pop 5`. – James M. Lay Sep 05 '15 at 04:40
  • 1
    @JamesM.Lay What you say in the last sentence doesn't make sense. Try to picture it and think why you'd ever do something like what you say. – Alexey Frunze Sep 05 '15 at 17:12
  • 1
    @JamesM.Lay: in NASM syntax, memory operands *always* need `[]` around the address. So `pop [other]` is a pop into a memory destination, using `other` as the addressing mode. x86 doesn't have any double-indirection addressing modes that load a pointer from memory and dereference it. – Peter Cordes Oct 21 '19 at 20:22
  • @AlexeyFrunze To someone learning NASM, it makes perfect sense when you are taught to equate brackets to the dereferencing operator in C. Consider these C examples. The mental model I had was a function pop: `void pop(void * address)`, and `pop other` equating to `pop(other)` vs `pop [other]` equating to `pop(*other)`. The secret they don't tell you is that there are more machine operators than assembly mnemonics. The operation produced by the assembler changes depending on the addressing mode of the operand(s). – James M. Lay Oct 22 '19 at 22:32
-1

You need to pop to a temporary register, then mov into your memory destination:

POP EAX
MOV myVar,EAX

Alternatively, you need to pop with some explicit syntax:

POP WORD PTR[<word_sized_var>]

As for moving a into memory, there are a few syntactical ways:

MOV <var name>,<value>

MOV [<var name>],<value>

In your case, you probably want the first: MOV other,EBP

Necrolis
  • 25,836
  • 3
  • 63
  • 101
  • 2
    NASM uses different syntax compared to TASM and MASM. NASM doesn't have `some_size PTR`. NASM cannot do `MOV myVar,EAX` because `myVar` is a constant, it's the address of the variable and not the variable. – Alexey Frunze Oct 12 '12 at 07:39
  • Could I do `mov [other], eax`? – Progrmr Oct 12 '12 at 07:40
  • @RileyH Yep, that's what you should do with NASM. – Alexey Frunze Oct 12 '12 at 07:42
  • @AlexeyFrunze, exactly! You would want to pop into the address! I would assume at the machine level, the opcode for `pop` takes one numerical operand - the destination. It wouldn't make any sense if you passed the dereferenced value of that address (say, the character 'a') to the pop instruction, would it? Trying to wrap my head around this. – James M. Lay Sep 05 '15 at 04:45
  • @JamesM.Lay: The NASM syntax for giving an instruction a memory address is to put the address in square brackets. `pop` takes a `r/m32` operand, encoded the usual way. So you could `pop [edi + eax*4 - 10]` to pop into that memory location. If your address is just a constant, you write `pop [symbol]`, and the encoding will be an addressing mode with no registers and a 4B displacement. See http://stackoverflow.com/questions/34058101/referencing-the-contents-of-a-memory-location-x86-addressing-modes/34058400#34058400 – Peter Cordes Feb 18 '16 at 08:25
  • Another way to say this: There's no special encoding of `pop` that just takes an absolute address as an immediate operand, instead of using the normal effective-address mod/rm encoding. If there was, `pop symbol` would be the way to use it. – Peter Cordes Feb 18 '16 at 08:28
  • 1
    @PeterCordes My source of confusion back then was that I used to think the assembler was a glorified _find-and-replace_ tool, and that it would see token `pop` and replace with, say, 55. It would see token `bx` and replace with `0x02`. Now I know that the representation of an assembly operation in binary is much more complicated. The opcode is comprised of flags that signify what kind of data the operand is. This finally allowed me to look at NASM as a language with its own philosophy behind how it represents indirect addresses. Anyway, thank you. – James M. Lay Feb 18 '16 at 18:53