为什么这段代码循环16次?

时间:2016-12-09 23:14:45

标签: assembly x86

再次循环将重复多少次?

mov bx,0 
mov cx,0 
again: 
shr cx,1 
inc bx 
loop again

答案是16,但为什么?

当我们shl shr时,答案是:无限循环。为什么呢?

1 个答案:

答案 0 :(得分:4)

有两种基本方法可以理解这样的问题:

  1. 仔细思考并“执行”你头脑中的代码。考虑每条指令的含义,以及它将如何影响代码流。
  2. 将代码键入编辑器,汇编并在调试器下运行。使用调试器单步执行代码,观察寄存器的值及其整体行为。
  3. 请注意,这些基本相同;一个只是让机器做所有的工作,你只是看着魔术发生。如果您对汇编语言比较熟悉,那么在这样的简单情况下,您只需要方法#1即可。如果你只是在学习并且对骨骼里的感觉不太满意,那么“欺骗”并让调试人员帮忙就会非常有用。

    由于Stack Overflow上没有可用的调试器(尽管我仍然鼓励你自己尝试这个),让我们使用我们的大脑采用手动方法:

    mov bx,0 
    mov cx,0 
    

    显然,这会将bxcx寄存器初始化为0。

    请注意,没有真正的汇编程序员会像这样编写代码。他们总是写

    xor bx, bx
    xor cx, cx
    

    这具有相同的效果(任何数字XOR本身都是0),但它更快并且使用更少的代码字节。

    在循环内部,此代码运行:

    shr cx,1 
    inc bx 
    

    SHR将目标操作数(在本例中为cx)向右移动源操作数(在本例中为常量1)。回想一下,右移相当于除以2,但速度更快。因此,这与cx = cx >> 1cx = cx / 2相同。

    INC将其操作数增加1.它与bx = bx + 1相同。

    loop again
    

    {x}程序集编程中LOOP指令不再广泛使用,因为它相对较慢。关于你使用它的唯一时间是小代码比快速代码更重要。因此,我必须查看它的作用。您可以通过Google搜索助记符名称和“x86”来查找此信息,或者您可以在英特尔的手册中找到它,或者您可以在标签维基中的材料中找到它,或者您可以在任何地方找到它您用于学习汇编语言编程的教科书/课程资料。我查了一下here,这是一个网站,其中包含使用Google发现的英特尔手册的在线转录。

    结果是,LOOP指令递减计数寄存器(cx),并且如果cx != 0则执行循环的另一次迭代。否则,如果cx == 0,则会停止循环播放。

    有了这些知识,你就应该能够“执行”你头脑中的代码。 bx发生的事情是无关紧要的。唯一有趣的操作是那些影响cx的操作。令人感兴趣的是,由于cx从0开始,而0 >> 1为0,LOOP指令减1,使其为-1在循环的第一次迭代之后。

    对有符号值使用按位右移有点不寻常(通常是一个错误),但它是x86程序集中定义明确的操作(与C或C ++不同)。基本上,发生的情况是移位的位(在这种情况下,最后一位)消失,空位插槽用零填充。因此,右移1只会在最重要的位置放置0。 (并且,从技术上讲,它会将进位标志中的移位位置放,但这在此代码中无关紧要,因为没有测试进位标志。)

    例如,6 >> 1 == 30000 0110 >> 1 == 0000 0011)。

    现在,您应该充分理解这种行为,以便能够回答第二个后续问题。但是如果你需要提示,look up the behavior of the SHL instruction。它是一个按位左移,相当于乘以2。

    在这种情况下,代码将无限循环,因为cx永远不会为0,这是LOOP指令正在检查的条件!为什么会这样?因为LOOP 首先递减cx,然后然后进行测试以查看它是否为零。正如Peter Cordes指出的那样,或许更好的思考方式是cx是否可以是1. SHL指令确保永远不会出现这种情况,{{1在cx为0之后(在这种情况下SHL会将其递减为-1并因此继续循环),或者> = 2(在这种情况下LOOP将减少它到> = 1然后继续循环)。