【问题标题】:Assembly 8086, LOOP instruction doesn't stop汇编 8086,LOOP 指令不停止
【发布时间】:2019-01-19 14:42:51
【问题描述】:

以下代码用于汇编 8086,我正在循环使用 LOOP 指令。

循环在CL 变为零后永远继续,并将CX 值更改为 FFFFh。
但如果我将CL 的值更改为最大06h,循环会正确停止。
此外,如果我先删除LOOP AGAIN,它会正常工作。

DATA DB 01001100b

MOV AL, DATA
MOV CL, 08h
SUB BL, BL
SUB DL, DL

AGAIN:
ROL AL, 1  
JC SKIP
INC BL
LOOP AGAIN

SKIP: 
INC DL
LOOP AGAIN

我希望它在CL 变为零时停止。知道为什么它的行为不符合预期吗?

更新 1 我注意到当CL(或使用16位时的CX)达到1并且最后一位为0时,第一个LOOP AGAIN不会跳起来,操作继续到SKIP部分.如果我将 DATA 的最后一位更改为 1,它将使 JC SKIP 一切正常。

【问题讨论】:

  • 循环计数器是cx,而不是cl。如果您将cl 设置为一个值,请确保ch 在此之前为零。
  • 在第一个 loop 之后,cx 为零。如果随后达到第二个 loop,它会减少 cx(即 0 -> 0xFFFF),因此第二个循环将运行 65536 次,然后 cx 将再次达到零,然后它将完成。不明白为什么它会“不停”,它会。 (并在代码中使用完整的 16 位 cx 来设置计数器,cl 只是它的低 8 位,所以你不知道高 8 位是什么(ch))
  • How exactly does the x86 LOOP instruction work? 的可能重复项,但我认为在某处嵌套的loop 指令存在更具体的重复项。 (loop只有在离开CX=0的时候才能通过,也就是说下一个loop不能通过,所以是一个无限循环。)
  • 哦,第二个循环一直在第一个循环之前,我忘了检查,所以是的,这永远不会停止,这是对当前状态的正确描述......所以你想要如果我现在了解您要做什么,可能最终会在第一个循环之后跳转。(分别计算零和一),例如jmp AfterSecondLoop ...但实际上只计算一个计数器,另一个是8 个计数器,因此您可以在循环结束后进行一次减法计算。您的“更新”是正确的。那么你明白它为什么会这样吗?
  • 哦,是的,这看起来像是无意中嵌套的循环,因为尾部复制后意外掉线。不过,我不明白这一点,只是在循环中数一个。您可以通过在循环外使用mov dl, 8 / sub dl, bl 执行8 - bl 来获得零计数。

标签: loops assembly x86-16


【解决方案1】:

简单回答

    MOV  AL, 01001100b
    MOV  CX, 0008h
    SUB  BL, BL
    SUB  DL, DL
AGAIN:
    ROL  AL, 1  
    JC   SKIP
    INC  BL
    LOOP AGAIN    ; The 1st
    JMP  ENDOFLOOP
SKIP:
    INC  DL
    LOOP AGAIN    ; The 2nd
ENDOFLOOP:
  • 8086 上的LOOP 指令始终使用CX 寄存器(全部)。
  • 您的代码错过了第一个LOOP AGAIN 以下的无条件跳转,以防循环应该在那里终止。这是为了避免在程序的 SKIP 部分中失败。

如何失败

    MOV AL, 01001100b
    MOV CL, 08h
    SUB BL, BL
    SUB DL, DL
AGAIN:
    ROL AL, 1  
    JC SKIP
    INC BL
    LOOP AGAIN    ; The 1st
SKIP: 
    INC DL
    LOOP AGAIN    ; The 2nd

这就是代码的作用(假设CH=0):

         ROL AL, 1                         LOOP
AL=01001100b   AL=10011000b   CF=0  BL=1   CX=7  The 1st jumps back
AL=10011000b   AL=00110001b   CF=1  DL=1   CX=6  The 2nd jumps back
AL=00110001b   AL=01100010b   CF=0  BL=2   CX=5  The 1st jumps back
AL=01100010b   AL=11000100b   CF=0  BL=3   CX=4  The 1st jumps back
AL=11000100b   AL=10001001b   CF=1  DL=2   CX=3  The 2nd jumps back
AL=10001001b   AL=00010011b   CF=1  DL=3   CX=2  The 2nd jumps back
AL=00010011b   AL=00100110b   CF=0  BL=4   CX=1  The 1st jumps back
AL=00100110b   AL=01001100b   CF=0  BL=5   CX=0  The 1st FALLS THROUGH!!!

此时由于CX 变为0,第一个LOOP AGAIN 不再跳回。 代码失败并错误地增加了DL 寄存器。第二个LOOP AGAIN 也从CX 中夹断1,产生CX=65535
所以程序愉快地持续了很长时间但它并没有变成无限循环。因为循环计数器不再是 8 的倍数(AL 中的位数),所以在某些时候它将是第二个LOOP AGAIN,这将使CX=0 程序最终停止。

为什么它似乎适用于修改

但如果我将 CL 的值更改为最大 06h,循环会正常停止

这就是代码对CX=6的作用:

         ROL AL, 1                         LOOP
AL=01001100b   AL=10011000b   CF=0  BL=1   CX=5  The 1st jumps back
AL=10011000b   AL=00110001b   CF=1  DL=1   CX=4  The 2nd jumps back
AL=00110001b   AL=01100010b   CF=0  BL=2   CX=3  The 1st jumps back
AL=01100010b   AL=11000100b   CF=0  BL=3   CX=2  The 1st jumps back
AL=11000100b   AL=10001001b   CF=1  DL=2   CX=1  The 2nd jumps back
AL=10001001b   AL=00010011b   CF=1  DL=3   CX=0  The 2nd FALLS THROUGH!!!

因为是第 2 个 LOOP AGAIN 失败,所以没有问题,因为我们处于程序的底部。

如果我将 DATA 的最后一位更改为 1,它将使 JC SKIP 并且一切正常

这就是代码对AL=01001101b的作用:

         ROL AL, 1                         LOOP
AL=01001101b   AL=10011010b   CF=0  BL=1   CX=7  The 1st jumps back
AL=10011010b   AL=00110101b   CF=1  DL=1   CX=6  The 2nd jumps back
AL=00110101b   AL=01101010b   CF=0  BL=2   CX=5  The 1st jumps back
AL=01101010b   AL=11010100b   CF=0  BL=3   CX=4  The 1st jumps back
AL=11010100b   AL=10101001b   CF=1  DL=2   CX=3  The 2nd jumps back
AL=10101001b   AL=01010011b   CF=1  DL=3   CX=2  The 2nd jumps back
AL=01010011b   AL=10100110b   CF=0  BL=4   CX=1  The 1st jumps back
AL=10100110b   AL=01001101b   CF=1  DL=4   CX=0  The 2nd FALLS THROUGH!!!

因为是第 2 个 LOOP AGAIN 失败,所以没有问题,因为我们处于程序的底部。

【讨论】:

  • 感谢您的详细解释(并重新格式化问题;)),我很感激。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-25
  • 1970-01-01
  • 2022-11-25
  • 2018-04-28
  • 1970-01-01
相关资源
最近更新 更多