我目前正在学习汇编语言,我有一个输出“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
我理解这段代码是如何工作的。但是,现在,我希望显示10倍的线。我在互联网上看到的代码循环如下:
mov ecx, 5
start_loop:
; the code here would be executed 5 times
loop start_loop
问题:我试图在我的代码上实现循环,但它输出一个无限循环。我还注意到循环需要ECX
,写函数也需要ECX
。显示10次“Hello World!”的正确方法是什么? ?
这是我当前的代码(产生无限循环):
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
非常感谢
答案 0 :(得分:5)
loop
使用ecx
寄存器。这很容易记住,因为c
代表counter
。但是,您会覆盖ecx
寄存器,以便永远不会工作!
更改代码如下:
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
没有正确或错误的循环方式 除非您正在寻找最后一个周期,否则您不会,因为您已经在循环中进行了系统调用。
loop
的缺点是它比同等sub ecx,1 - jnz start_of_loop
略慢。
loop
的优点是它使用较少的指令字节。
请注意,对于稍微较旧的CPU(过去3年),不建议使用dec reg + jcc label
。由于dec
仅改变标志寄存器的一部分,因此可能导致部分寄存器写入停顿,导致后续读取jnz
的标志寄存器停止一个周期。
这已在最新的英特尔和AMD处理器中得到修复。 sub reg,1 + jnz
在未来5年仍然是一个好主意。
使用int 80h
进行的系统调用不会改变除eax
以外的任何寄存器,因此只要您记得不要弄乱edi
,您就不需要推送/ {流行对。