loop 指令的功能是重复执行一段相同的代码,处理器在执行它的时候会顺序做两件事:
和 jmp near start 一样,loop digit 后跟的操作数也是一个相对的偏移量,是在编译阶段,编译器用标号 digit 所在位置的汇编地址减去 loop 指令的汇编地址,再减去 loop 指令的长度( 2 )来得到的。
;计算各个数位
mov bx,ax
mov cx,5 ;设置循环次数
mov si,10 ;除数
digit:
xor dx,dx
div si
mov [bx],dl ;保存数位
inc bx
loop digit
图为 lst 文件的内容。
上面 loop 指令的操作数0xF7
,编译阶段是这么算出来的。0x43 - 0x4A - 0x2 = -9
,而-9 截取一个字节的话,就是 F7.
现在的问题是 cpu 是如何使用 loop 指令的操作数的?我是这么猜的:
0x4A + F7 + 2 = 0x143
0x0000_004A
的低 8bit 替换为算出来的0x43
,得到 要跳转的地址0x0000_0043
不知道对不对?
1
cpstar 2023-01-10 21:07:21 +08:00
似乎有一个指令地址寄存器,0xf7 直接与指令地址寄存器相计算得到新的指令地址。然后汇编里都是相对地址,实际地址还要有段基址等东西。
|
2
cpstar 2023-01-10 21:18:12 +08:00
另外,指令地址寄存器应该是在遇到 0x4A 的 E2 ,继续读取 0x4B 作为操作数,然后滑向了 0x4C ; 0x4B 的操作数是一个有符号整数,所以按照补码进行加法,获得了新的地址指向 0x43 位置
|
3
amiwrong123 OP @cpstar #2
你说的有点道理,不过感觉 CPU 处理有点麻烦阿, 因为自身的地址 0x0000_004A 是要作为无符号数的,然后操作数则要作为一个 有符号数 来处理(毕竟还可能向 第 9 个 bit 产生进位或借位)。 |
4
Mohanson 2023-01-10 21:41:59 +08:00
CPU 有个 PC 寄存器, 在执行 loop 前 PC = 0000004A, 将 loop 指令取指后 PC = 0000004A + 2, 之后解码, 得到偏移立即数 0xF7(-9), 最后执行 loop 指令, 如果 ecx !=0, 令 PC = 0000004A + 2 - 9 = 00000043; 如果 ecx == 0, 则不修改 PC.
|
5
Mohanson 2023-01-10 21:48:18 +08:00
补充一下上面: 执行 loop 指令, 判断 ecx 是否等于 0 之前有一步 ecx -= 1 的步骤
|
6
billlee 2023-01-10 21:54:16 +08:00
「会顺序做两件事」这个理解就不对,所有操作都是一个时钟周期内完成的,就是一个 CX_out, PC_out = f(CX_in, PC_in) 的组合逻辑,非常简单的一个指令。
|
7
secondwtq 2023-01-11 00:21:33 +08:00
1. 不要完全用软件的思路揣测硬件实现,硬件可以定制任意位数的加法器的 ...
2. 不止 LOOP ,JMP 就很常用这样的模式 3. 由于各种原因,LOOP 这条指令基本早就不用了,编译器也不会生成。 |
8
mxT52CRuqR6o5 2023-01-11 00:30:36 +08:00 via Android
4A 处的 loop 指令长度为 2 个字节,下一条指令的地址为 0x4C ,0x4C+0xF7 = 0x43 ,不然这个+2 也太 magic number 了
|