V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
amiwrong123
V2EX  ›  程序员

x86 汇编 CPU 是如何使用 loop 指令的操作数的?

  •  
  •   amiwrong123 · 2023-01-10 20:50:43 +08:00 · 1268 次点击
    这是一个创建于 443 天前的主题,其中的信息可能已经有所发展或是发生改变。

    loop 指令的功能是重复执行一段相同的代码,处理器在执行它的时候会顺序做两件事:

    • 将寄存器 CX 的内容减一;
    • 如果 CX 的内容不为零,转移到指定的位置处执行,否则顺序执行后面的指令。

    和 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 指令的操作数的?我是这么猜的:

    1. 取出 loop 指令自己所在地址的低 8bit 4A ,然后0x4A + F7 + 2 = 0x143
    2. 然后对 0x143 截取低 8bit ,为 0x43
    3. 然后把自己的地址0x0000_004A的低 8bit 替换为算出来的0x43,得到 要跳转的地址0x0000_0043

    不知道对不对?

    8 条回复    2023-01-11 00:30:36 +08:00
    cpstar
        1
    cpstar  
       2023-01-10 21:07:21 +08:00
    似乎有一个指令地址寄存器,0xf7 直接与指令地址寄存器相计算得到新的指令地址。然后汇编里都是相对地址,实际地址还要有段基址等东西。
    cpstar
        2
    cpstar  
       2023-01-10 21:18:12 +08:00
    另外,指令地址寄存器应该是在遇到 0x4A 的 E2 ,继续读取 0x4B 作为操作数,然后滑向了 0x4C ; 0x4B 的操作数是一个有符号整数,所以按照补码进行加法,获得了新的地址指向 0x43 位置
    amiwrong123
        3
    amiwrong123  
    OP
       2023-01-10 21:30:47 +08:00
    @cpstar #2
    你说的有点道理,不过感觉 CPU 处理有点麻烦阿,

    因为自身的地址 0x0000_004A 是要作为无符号数的,然后操作数则要作为一个 有符号数 来处理(毕竟还可能向 第 9 个 bit 产生进位或借位)。
    Mohanson
        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.
    Mohanson
        5
    Mohanson  
       2023-01-10 21:48:18 +08:00
    补充一下上面: 执行 loop 指令, 判断 ecx 是否等于 0 之前有一步 ecx -= 1 的步骤
    billlee
        6
    billlee  
       2023-01-10 21:54:16 +08:00
    「会顺序做两件事」这个理解就不对,所有操作都是一个时钟周期内完成的,就是一个 CX_out, PC_out = f(CX_in, PC_in) 的组合逻辑,非常简单的一个指令。
    secondwtq
        7
    secondwtq  
       2023-01-11 00:21:33 +08:00
    1. 不要完全用软件的思路揣测硬件实现,硬件可以定制任意位数的加法器的 ...
    2. 不止 LOOP ,JMP 就很常用这样的模式
    3. 由于各种原因,LOOP 这条指令基本早就不用了,编译器也不会生成。
    mxT52CRuqR6o5
        8
    mxT52CRuqR6o5  
       2023-01-11 00:30:36 +08:00 via Android
    4A 处的 loop 指令长度为 2 个字节,下一条指令的地址为 0x4C ,0x4C+0xF7 = 0x43 ,不然这个+2 也太 magic number 了
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   3006 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 14:58 · PVG 22:58 · LAX 07:58 · JFK 10:58
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.