0

I have been following an example of a loop that is in the following page:

https://www.tutorialspoint.com/assembly_programming/assembly_loops.htm

and the code is:

section .text
   global _start        ;must be declared for using gcc
    
_start:                 ;tell linker entry point
   mov ecx,10
   mov eax, '1'        
    
l1:
   mov [num], eax       ;move eax to *num
   mov eax, 4           ;invoke to sys_write
   mov ebx, 1           ;data written to stdout
   push ecx
    
   mov ecx, num        
   mov edx, 1           ;number of bytes to show     
   int 0x80
    
   mov eax, [num]       ;move the value of *[num] into eax
   sub eax, '0'
   inc eax
   add eax, '0'
   pop ecx
   loop l1
    
   mov eax,1             ;system call number (sys_exit)
   int 0x80              ;call kernel
section .bss
num resb 1

I tried to follow the program, but I cannot understand the use of an stack in this program. I have added some comments on the code, so feel free to correct me if I am wrong in some parts. For what I see the value of eax increments from one to one and then print this value. However, I do not know if the use of an stack here is needed, from the trace I made I see that the values of 1,2,.. and so on are pushed, but then are popped up almost immediately. So, why is needed an stack here?

An additional question is about the instruction sub and add that are given in the following instructions:

sub eax, '0'
add eax, '0'

Are these instructions to convert the number into a char or string?

Update

I have get rid of some instructions and pass the entire 32 registers to the 64 registers, so my program is as follows:

section .text
   global _start        ;must be declared for using gcc
    
_start:                 ;tell linker entry point
   mov ecx,10
   mov eax, '1'
    
l1:
   mov [num], eax  ;move eax value to [num] address
   mov eax, 4    ;invoke to sys_write 
   mov ebx, 1    ;data is written to stdout
   push rcx   ;push whole cx register in 64 mode
    
   mov ecx, num        
   mov edx, 1       ;number of bytes to show 
   int 80h
    
   mov eax, [num]  ;move the value of the address of [num] into eax
   inc eax
   pop rcx
   loop l1
    
   mov eax,1             ;system call number (sys_exit)
   int 80h              ;call kernel
section .bss
num resb 1

However, when I comment the stack section the following output is printed:

enter image description here

halfer
  • 19,824
  • 17
  • 99
  • 186
Little
  • 3,363
  • 10
  • 45
  • 74
  • 4
    `loop` implictly uses `ecx` as the loop counter, and you also need to use `ecx` for one of the system call arguments. – Michael Mar 20 '21 at 16:17
  • 2
    `mov [num], eax` and `mov eax, [num]` are technically incorrect though, since `resb 1` only reserved 1 byte of space, while `eax` is a 32-bit (4 bytes) register. – Michael Mar 20 '21 at 16:23
  • And the adding and subtracting of `'0'` seem pointless in this particular program. – Michael Mar 20 '21 at 16:24
  • 3
    You *shouldn't* use the stack, just use a different register for the loop counter ([and avoid the slow `loop` instruction](https://stackoverflow.com/questions/35742570/why-is-the-loop-instruction-slow-couldnt-intel-have-implemented-it-efficiently)); pick a register that isn't one of the first 3 arg-passing registers for Linux's 32-bit int 0x80 ABI like `dec esi / jnz l1`. Or don't waste a register when you're already counting an ASCII code up toward '9', use `cmp` on that. – Peter Cordes Mar 20 '21 at 16:28
  • 2
    It's also totally pointless to `sub eax, '0'` / `add eax, '0'` around `inc eax`; just increment the ASCII code. You're not even using the integer value (`eax - '0'`) as a loop counter or something to compare against. (So this is one of those cases where a tutorial over-complicates things, as well as having bugs like Michael pointed out; `mov [num], al` would be correct.) – Peter Cordes Mar 20 '21 at 16:31
  • thank @PeterCordesl, but when I delete the part of the stack the program prints strange characters. – Little Mar 20 '21 at 18:51
  • Yeah, of course it does if you keep using ECX as the loop counter (via the `loop` instruction), and thus overwrite it inside the loop. Also, this is 32-bit code so you should just build + link it into a 32-bit executable ([Assembling 32-bit binaries on a 64-bit system (GNU toolchain)](https://stackoverflow.com/a/36901649)) or if you want to use 64-bit, use the 64-bit `syscall` ABI ([What happens if you use the 32-bit int 0x80 Linux ABI in 64-bit code?](https://stackoverflow.com/q/46087730)). (But `syscall` itself overwrites RCX.) – Peter Cordes Mar 20 '21 at 19:28

0 Answers0