0

I want to get a basic feel for assembly and wrote a program that ought to

  1. displays the string Enter a number:
  2. reads in user input
  3. counts the number read down to 0 and prints the number in each iteration in a loop.

Here is my code.

section .data
   msg  db 'Enter a number:' 
   len equ $ - msg

section .bss
   num resb 1

section  .text
   global _start        ;must be declared for using gcc

_start:                  ;tell linker entry point

   mov   eax,4          ;sys_write
   mov   ebx,1
   mov   ecx,msg        ;the message "Enter a number:"
   mov   edx,len        ;write "enter a number" on the screen
   int 80h

   mov   eax,3          ;reading in user input into num
   mov   ebx,2
   mov   ecx,num
   mov   edx,1
   int 80h

   mov   ecx,num

   jmp loop1
   
   mov   eax,1          ;system call number (sys_exit)
   int   80h           ;call kernel
   
loop1:
   mov   edx,1
   mov   ebx,1          ;file descriptor (stdout)
   mov   eax,4          ;system call number (sys_write)
   int   80h

   loop  loop1

   mov eax,1
   int 80h

When entering loop1 nothing is written to the terminal instead of the countdown I want. Can someone tell me what I fail to see?

  • 2
    1) User input is text (ascii) 2) said input is not necessarily 4 bytes 3) `sys_write` expects a pointer to the thing to be printed – Jester Jan 20 '21 at 11:45
  • You have to convert the decimal digits read from the terminal into a number, use that for the countdown, and convert it back to decimal digits for output. – ecm Jan 20 '21 at 11:45
  • For a simple countdown it's not necessary to convert. – Jester Jan 20 '21 at 11:48
  • I am aware of the fact that the input is not necessarily 4 bytes, so far I have always entered single byte digits this should work right? Also, I updated my code and changed ```mov ecx,[num]``` to ```mov ecx,num``` but now the output is a gibberish string. Can you tell me (again) where the logical flaw is? I also changed the size read in from 4 bytes to 1. – peterparker Jan 20 '21 at 12:38
  • 3
    `mov ecx, num` loads the address correctly for printing but of course you can't use `loop` on the address. You will need something like `dec byte [num]; cmp byte [num], '0'; jae loop1`. – Jester Jan 20 '21 at 14:02
  • But ```loop loop1``` decrements ```ecx``` and then compares it with zero and jumps to the address specified if they are equal right? thats what the internet says I dont get why its supposed to be wrong – peterparker Jan 20 '21 at 14:49
  • 2
    That's exactly what it does. But your `ecx` doesn't contain the count of the number of times you want the loop to repeat; it contains the address of `num` (as it must, because the system call expects the buffer address in `ecx`). So as it stands, the loop will iterate a number of times equal to the *address* of `num`, probably several million, which is not what you want. And on the second iteration, `ecx` will no longer point to `num`, but to `num-1`, so the system call will write the wrong data. Do you see the problem? – Nate Eldredge Jan 20 '21 at 15:55
  • 2
    Basically `loop` only works if you are using `ecx` itself as your loop counter. Here you can't do that, because you need `ecx` for something else. So you'll need to use another register (or memory location, as in Jester's suggestion), and do the `cmp` and conditional jump yourself. Anyway, `loop` isn't recommended in modern programs; though it may seem to be convenient, it's inflexible and slower than the alternative two-instruction sequence. See https://stackoverflow.com/questions/35742570/why-is-the-loop-instruction-slow-couldnt-intel-have-implemented-it-efficiently – Nate Eldredge Jan 20 '21 at 15:58
  • ugh i see, many thanks – peterparker Jan 20 '21 at 16:11
  • 1
    Related, maybe duplicates: [NASM Assembly convert input to integer?](https://stackoverflow.com/q/19309749) / [How do I print an integer in Assembly Level Programming without printf from the c library?](https://stackoverflow.com/a/46301894) – Peter Cordes Jan 20 '21 at 16:20

0 Answers0