1

I'm trying to make a simple x86 program that reverses a string, in this case: "ciao".

section .data
        msg db "ciao"
        len equ $ - msg

section .text
global _start
_start:
        lea eax, [msg]
        mov ebx, len
        add eax, ebx-1
reverseloop:
        push [eax]
        sub eax, 1
        cmp eax, [msg]
        jl reverseloop

When I try to assemble it, I get the error:

main.asm:14: error: operation size not specified

So, I tried to specify the size, by modifying line 14 to:

push byte [eax]

And now I get the error:

main.asm:14: error: invalid combination of opcode and operands

I don't really understand what is the problem here.
The command I use to compile is:

nasm -f elf32 main.asm -o main.o

Sep Roland
  • 33,889
  • 7
  • 43
  • 76
Patientes
  • 113
  • 1
  • 1
  • 7
  • 2
    In 32-bit modes `push` with a memory operand only supports pushing a word or a dword. You can't push a byte. So you could only do `push word [eax]` or `push dword [eax]` but you can't do `push byte [eax]` . See an Instruction Set Architecture document like: https://www.felixcloutier.com/x86/push – Michael Petch Jan 05 '23 at 22:23

1 Answers1

4
push [eax]

NASM does not know the size of the memory operand that you would like to push. You need to specify it as push dword [eax].
It is not an option to use push byte [eax] because the stack operations don't do single bytes.

add eax, ebx-1

This is your next error! The source operand ebx-1 is invalid.
You could first decrement EBX and then add that to EAX, but as I will show below you don't need this decrement.

cmp eax, [msg]
jl reverseloop

This is not doing what you want either. The cmp compares EAX to a dword from memory, but you want this to be a comparison between addresses. Use cmp eax, msg.
And in order to continu the loop for all characters of the string, you need to conditionally jump for as long as the address in EAX is GreaterOrEqual msg.

  mov   eax, msg
  add   eax, len
reverseloop:
  dec   eax
  movzx ebx, byte [eax]
  push  ebx
  cmp   eax, msg
  ja    reverseloop

Now I don't see how this code will reverse anything. The characters land on the stack in the same order as they were in the memory (interspersed with some zero bytes of course).

  mov   eax, msg
  mov   ecx, len
reverseloop1:
  movzx ebx, byte [eax]
  push  ebx
  inc   eax
  dec   ecx
  jnz   reverseloop1

  mov   eax, msg
  mov   ecx, len
reverseloop2:
  pop   ebx
  mov   [eax], bl
  inc   eax
  dec   ecx
  jnz   reverseloop2

Solutions that don't use the stack exist and generally would be better.

Sep Roland
  • 33,889
  • 7
  • 43
  • 76
  • `lea eax, [eax+ebx-1]` is a valid instruction that can do what they were trying to. Oh, but `ebx` was set with `mov ebx, len` so that's silly, just `mov eax, msg+len-1` or transform like you did. – Peter Cordes Jan 06 '23 at 01:03
  • 2
    For `push`, it's interesting that NASM [will default to DWORD operand-size for immediates like `push 123`](https://stackoverflow.com/questions/45127993/how-many-bytes-does-the-push-instruction-push-onto-the-stack-when-i-dont-specif), but requires disambiguation of `word` vs `dword` for memory operands like `push [eax]`. It's probably just as rare that you'd ever want `push word [mem]` as `push word immediate`, but that's the design choice NASM made. But probably even more important to be explicit about memory operand sizes for push and pop; bugs with that might be less obvious. – Peter Cordes Jan 06 '23 at 01:04