void
void

Reputation: 405

What is the correct way to loop if I use ECX in loop (Assembly)

I am currently learning assembly language, and I have a program which outputs "Hello World!" :

        section .text                                                                                    
        global _start                                                                                    
_start:                                                                                                                                                                                               
        mov ebx, 1                                                                                       
        mov ecx, string                                                                                  
        mov edx, string_len                                                                              
        mov eax, 4                                                                                      
        int 0x80                                                                                                                                                                          
        mov eax, 1                                                                                       
        int 0x80                                                                                         

        section .data                                                                                    
        string db "Hello World!", 10, 0                                                                  
        string_len equ $ - string

I understand how this code works. But, now, I want to display 10 times the line. The code which I saw on the internet to loop is the following:

 mov ecx, 5
 start_loop:
 ; the code here would be executed 5 times
 loop start_loop

Problem : I tried to implement the loop on my code but it outputs an infinite loop. I also noticed that the loop needs ECX and the write function also needs ECX. What is the correct way to display 10 times my "Hello World!" ?

This is my current code (which produces infinite loop):

        section .text                                                                                    
        global _start                                                                                    
_start:                                                                                                  
        mov ecx, 10                                                                                      
myloop:                                                                                                  
        mov ebx, 1 ;file descriptor                                                                                      
        mov ecx, string                                                                                 
        mov edx, string_len                                                                             
        mov eax, 4   ; write func                                                                                    
        int 0x80                                                                                         
        loop myloop                                                                                      
        mov eax, 1   ;exit                                                                                    
        int 0x80                                                                                         

        section .data                                                                                    
        string db "Hello World!", 10, 0                                                                  
        string_len equ $ - string

Thank you very much

Upvotes: 4

Views: 3114

Answers (1)

Johan
Johan

Reputation: 76617

loop uses the ecx register. This is easy the remember because the c stands for counter. You however overwrite the ecx register so that will never work!

The easiest fix is to use a different register for your loop counter, and avoid the loop instruction.

    mov   edi,10                      ;registers are general purpose
loop:
    ..... do loop stuff as above
    ;push edi                         ;no need save the register
    int   0x80
    ....                              ;unless you yourself are changing edi
    int   0x80
    ;pop  edi                         ;restore the register. Remember to always match push/pop pairs.                      
    sub   edi,1                       ;sub sometimes faster than dec and never slower
    jnz   loop

There is no right or wrong way to loop.
(Unless you're looking for every last cycle, which you are not, because you've got a system call inside the loop.)

The disadvantage of loop is that it's slower than the equivalent sub ecx,1 ; jnz start_of_loop.

The advantage of loop is that it uses less instruction bytes. Think of it as a code-size optimization you can use if ECX happens to be a convenient register for looping, but at the cost of speed on some CPUs.


Note that the use of dec reg + jcc label is discouraged for some CPUs (Silvermont / Goldmont being still relevant, Pentium 4 not). Because dec only alters part of the flags register it can require an extra merging uop. Mainstream Intel and AMD rename parts of EFLAGS separately so there's no penalty for dec / jnz (because jnz only reads one of the flags written by dec), and can even micro-fuse into a dec-and-branch uop on Sandybridge-family. (But so can sub). sub is never worse, except code-size, so you may want to use sub reg,1 for the forseeable future.

A system call using int 80h does not alter any registers other than eax, so as long as you remember not to mess with edi you don't need the push/pop pair. Pick a register you don't use inside the loop, or you could just use a stack location as your loop counter directly instead of push/pop of a register.

Upvotes: 6

Related Questions