x86 LOOP指令究竟是如何工作的?

时间:2017-10-23 02:49:52

标签: loops assembly x86

            mov    ecx, 16
looptop:    .
            .
            .
            loop looptop

此循环执行多少次?

如果ecx = 0开始会怎样?在这种情况下loop是跳跃还是跳过?

1 个答案:

答案 0 :(得分:6)

loopdec ecx / jnz完全相同,只是它没有设置标记

它类似于C中do{} while(--ecx != 0);的底部。如果执行以ecx = 0进入循环,则回绕意味着循环将运行2 ^ 32次。 (或者在64位模式下为2 ^ 64次,因为它使用RCX)。

rep movsb/stosb/etc.不同,它在递减之前不检查ECX = 0,仅在之后。

地址大小决定了它是使用CX,ECX还是RCX。因此,在64位代码中,addr32 loopdec ecx / jnz类似,而常规loopdec rcx / jnz类似。或者在16位代码中,它通常使用CX,但地址大小前缀(0x67)将使其使用ecx。正如英特尔的手册所说,它忽略了REX.W,因为它设置了操作数大小,而不是地址大小。

相关:Why are loops always compiled like this?了解有关asm中的循环结构的更多信息,while(){}do{}while()以及如何将它们布局。

额外的调试提示

如果您想了解指令的详细信息,请查看手册:Intel's official vol.2 PDF instruction set reference manual或html提取,其中每个条目位于不同的页面(http://felixcloutier.com/x86/)。但请注意,HTML中省略了有关如何解释内容的详细信息的介绍和附录,例如,当add等指令显示“根据结果设置标志”时。

你可以(而且应该)只在调试器中尝试一些东西:单步并观察寄存器的变化。为ecx使用较小的起始值,以便更快地进入有趣的ecx=1部分。另请参阅the x86 tag wiki以获取底部手册,指南和asm调试技巧的链接。

而BTW,如果未显示的说明修改ecx ,则可能会循环任意次。要使问题具有简单而独特的答案,您需要保证标签与loop指令之间的指令不会修改ecx。 (他们可以保存/恢复它,但如果你要这样做,通常最好只使用一个不同的寄存器作为循环计数器。循环中的push / pop会使你的代码变得困难读出。)

即使您已经需要在循环中增加其他内容,也要过度使用LOOPLOOP不是循环的唯一方式,通常是最差的。

除非以速度because it's slow为代价优化代码大小,否则通常不应使用循环指令。编译器不使用它。 (因此CPU供应商不打算快速实现;赶上22.)使用dec / jnz或完全不同的循环条件。 (另请参阅http://agner.org/optimize/以了解有关效率的更多信息。)

循环甚至不必使用计数器;将指针与结束地址进行比较或检查其他条件通常也是好的。 (毫无意义地使用loop是我的烦恼之一,特别是当你已经在另一个寄存器中有一些东西可以用作循环计数器时。)使用cx作为循环计数器通常只是绑定其中一个如果您可以在另一个正在递增的寄存器上使用cmp / jcc,那么您珍贵的少数寄存器。

IMO,loop应被视为初学者不应分心的那些模糊的x86指令之一。与stosd(没有rep前缀),aamxlatb一样。但是,在优化代码大小时,它确实具有实际用途。 (这在机器代码的现实生活中有时很有用(比如引导扇区),而不仅仅是像code golf这样的东西。)

IMO,只是教导/了解条件分支如何工作,以及如何从中产生循环。然后你就不会想到使用loop的循环有一些特殊之处。我已经看到一个SO问题或评论说“我认为你必须声明循环”,并没有意识到loop只是一个指令。

</rant>。就像我说的那样,loop是我的宠儿之一。这是一个模糊的代码打高尔夫教学指令,除非你为实际的8086进行优化。