Assembly 为什么这个代码循环16次?
REACH循环将重复多少次Assembly 为什么这个代码循环16次?,assembly,x86,Assembly,X86,REACH循环将重复多少次 mov bx,0 mov cx,0 again: shr cx,1 inc bx loop again 答案是16,但为什么 当我们有shl而不是shr时,答案是:无限循环。为什么?理解这样的问题有两种基本方法: 仔细思考并“执行”头脑中的代码。考虑每个指令意味着什么,以及它将如何影响代码的流动。 在编辑器中键入代码,组装代码,然后在调试器下运行。使用调试器单步执行代码,观察寄存器的值及其整体行为 请注意,这些基本上是相同的事情;一个是让机器完成所有的工作
mov bx,0
mov cx,0
again:
shr cx,1
inc bx
loop again
答案是16,但为什么
当我们有
shl
而不是shr
时,答案是:无限循环。为什么?理解这样的问题有两种基本方法:
bx
和cx
寄存器初始化为0
请注意,没有一个真正的汇编程序员会像这样编写代码。他们总是写信
xor bx, bx
xor cx, cx
这具有相同的效果(任何数字XOR本身都是0),但速度更快,使用的代码字节更少
在循环内部,此代码运行:
SHR
将目标操作数(在本例中为cx
)右移源操作数(在本例中为常量1
)。回想一下,右移相当于除以2,但速度更快。因此,这与cx=cx>>1
或cx=cx/2
相同
INC
将其操作数递增1。它与bx=bx+1
相同
在x86汇编编程中,循环
指令不再广泛使用,因为它相对较慢。大概只有在小代码比快速代码更重要的情况下才会使用它。因此,我必须查看它的功能。您可以通过谷歌搜索助记符名称和“x86”来找到这些信息,也可以在英特尔的手册中找到,也可以在tag wiki的资料中找到,也可以在学习汇编语言编程所用的任何教科书/课程资料中找到。我查了一下,这是一个包含英特尔手册在线抄本的网站,是用谷歌找到的
结果是,循环
指令递减计数寄存器(cx
),如果cx!=0
。否则,如果cx==0
,它将停止循环并失败
有了这些知识,你应该能够在头脑中“执行”代码。bx上发生的事情与此无关。唯一有趣的操作是那些影响cx
的操作。有趣的是,由于cx
从0开始,并且0>>1
是0,因此循环
指令将其递减1,使其在循环的第一次迭代后为-1
对有符号值使用按位右移有点不寻常(通常是一个bug),但它在x86汇编中是一个定义良好的操作(与C或C++中不同)。基本上,发生的情况是移位的位(在本例中,最后一位)消失,空位槽被零填充。所以,右移1只会在最高有效位上放置一个0。(从技术上讲,它会将移位的位放在进位标志中,但这在这段代码中并不重要,因为没有任何东西在测试进位标志。)
例如,6>>1==3
(0000 0110>>1==0000 0011
)
现在,您应该充分理解该行为,以便能够回答第二个后续问题。但是如果你需要一个提示。它是按位左移,相当于2的乘法
在这种情况下,代码将无限循环,因为
cx
永远不会为0,这是loop
指令正在检查的条件!为什么会这样?因为LOOP
首先递减cx
,然后测试它是否为零。正如Peter Cordes所指出的,也许更好的思考方式是cx
是否可以是1。SHL
指令确保永远不会出现这种情况,因为SHL
之后的cx
的结果是0(在这种情况下LOOP
将把它减少到-1,从而继续循环),或者>=2(在这种情况下LOOP
将把它减少到>=1,从而继续循环).理解这样的问题有两种基本方法:
bx
和cx
寄存器初始化为0
请注意,没有一个真正的汇编程序员会像这样编写代码
xor bx, bx
xor cx, cx
shr cx,1
inc bx
loop again