Reputation: 405
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
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