Assembly Loop
eryar@163.com
我觉得循环指令是程序的核心,是计算机不厌其烦地执行机械、重复枯燥劳动的基础。本文来学习下汇编程序中的LOOP指令。Loop指令的格式是:loop 标号,CPU执行loop指令的时候,要进行两步操作:
v (cx)=(cx)-1
v 判断cx中的值,不为零则转到标号处执行程序,如果为零则向下执行。
由上可知,cx中的值影响着loop指令的执行结果。通常我们用loop指令来实现循环功能,用cx来存放循环次数。类似于C中的for循环:
for (int i = cx; i != 0; --i)
{
}
学习了loop后,想着把原来那个输出WELCOME TO ASM!的程序修改下,利用循环来实现。
assume cs:codeseg
codeseg segment
;WELCOME TO ASM! (15)
dw 0257h,0245h,034ch,0443h,054fh,064dh,0745h,0220h,0854h,094fh,0220h,1241h,1353h,144dh,1521h
mov bx,0b800h
mov ds,bx
mov bx,0
mov cx,15
output: mov ax,cs:[bx]
mov ds:[bx],ax
add bx,2
loop output
mov ax,4c00h
int 21h
codeseg ends
end
改成这样后,编译、连接成功,但是程序运行时好像进入了死循环。最后看书中的描述才找到了原因:那是因为用dw在代码段定义了数据后,当程序运行时IP指向的是数据部分,并不是指令部分,所以导致运行出错。使程序成功运行的方法有可以在debug中手动修改IP,使其指向真正的指令开始的地方,可是这样一来程序只能在debug中才能正确运行。如何让程序编译、连接后可以在系统中直接运行呢?我们可以在源码中指定程序的入口所在,即在源码的第一条指令的前面加上一个标号main,而这个标号在伪指令end的后面出现。因为我觉得这有点像C中的main函数,所以将这个标号命名为main,修改程序后程序运行正确:
assume cs:codeseg
codeseg segment
;WELCOME TO ASM! (15)
dw 0257h,0245h,034ch,0443h,054fh,064dh,0745h,0220h,0854h,094fh,0220h,1241h,1353h,144dh,1521h
main: mov bx,0b800h
mov ds,bx
mov bx,0
mov cx,15
output: mov ax,cs:[bx]
mov ds:[bx],ax
add bx,2
loop output
mov ax,4c00h
int 21h
codeseg ends
end main
程序运行结果如下图所示:
综上所述,将数据放到代码段CS中时,会导致IP还是指向的CS的开始部分,而起始部分并不是指令,而是数据,从而导致程序直接运行时出现问题。为了解决这个问题,可以在指令起始的地方加个标号,这样就好了。