是什么

  • 定义控制流转移指令通过修改程序计数器(PC)改变指令执行流;相对寻址以当前指令下一条地址为基准加上偏移量定位目标;溢出异常处理是硬件检测到计算超出表示范围后通过软硬件协同转向异常处理程序。

  • 大白话:条件转移是“满足条件才拐弯”,无条件转移是“走到这就必须拐弯”;相对寻址是“从下一条指令的位置往前或往后走几步”;大小端是“多字节数据的高低位在内存里谁前谁后”;乘法溢出是“高位没能成为低位的纯符号复制品,说明有效数据被挤出去了”。

==下一条指令的地址 = 当前指令首地址 + 当前指令机器码长度==

核心内容

1. 转移指令分类与判别

类别定义与触发机制常见汇编指令408 判别抓手
条件转移指令必须检查标志位 等),条件满足才修改 PC,不满足则顺序执行下一条jle(小于等于)、jl(小于)、jge(大于等于)、jg(大于)、je/jz(等于/为零)、jne/jnz(不等于)、jc/jnc(进位/无进位)、jo/jno(溢出/无溢出)指令助记符以 j 开头且后面跟有条件后缀(如 le, z, o 等)
一定会转移的指令(无条件改变控制流)不需要检测任何标志位,执行到该指令必然修改 PC 跳转1. 无条件跳转jmp(直接跳到目标)




2. 子程序调用call(保存返回地址并跳到函数入口)




3. 子程序返回ret(从栈顶弹出返回地址给 PC)




4. 中断/异常返回iret
只要执行,PC 就绝对不会自然自增到下一条指令

2. PC 相对寻址与 408 核心寻址方式对比

相对寻址(Relative Addressing)

  • 公式

  • 关键定义:== 的值永远是当前指令的下一条指令的虚拟地址==(因为在 CPU 取出当前指令后,硬件会自动执行 )。

 题目中 `EB 09` 和 `7D 32`,操作码是EBH和7DH,所以其中 `09` 和 `32` 是偏移量,
  • 偏移量计算公式

  • 机器表示:若偏移量为负数,必须转换为补码形式存储。

408 常见寻址方式有效地址(EA)计算汇总

其中A是偏移量,注:

  • 算术运算指令时(如 addi

    • 这里的 是参与加法计算的立即数(操作数本身)

  • 当它是访存指令时(如本题的 lw

    • 这里的 充当了基址寻址中的偏移量 ,与寄存器 里的基地址相加,合成有效地址

寻址方式有效地址 EA 公式核心应用场景
直接寻址访问全局变量 / 固定地址
寄存器间接寻址指针访问
基址寻址多道程序、局部变量(以 ebp 为基址)
变址寻址数组遍历、循环访问连续空间
相对寻址代码内部的分支跳转、函数调用

3. 大端方式 vs 小端方式判定

  • 大端方式(Big-Endian):数据的高位字节存放在内存的低地址端(先存高位,符合人类阅读习惯)。(0x12345678就是数据,而12345678就是内存排序,相同的)

  • 小端方式(Little-Endian):数据的低位字节存放在内存的低地址端(先存低位,x86 / ARM 常见)。

快速判别法则(直接两者对比,一样就是大端,相反就是小端)

以 32 位十六进制数 0x12345678(其中 12 是最高有效字节 MSB,78 是最低有效字节 LSB)存放在起始地址 00401000H 为例:

Plaintext

地址顺序从低到高:00401000H  00401001H  00401002H  00401003H
小端存储顺序:     78         56         34         12    (低位在低地址)
大端存储顺序:     12         34         56         78    (高位在低地址)

在机器指令中看偏移量字节顺序:若数值为 0xFFFFFFD6,在机器码中排列为 D6 FF FF FF,低位 D6 出现在最前面的低地址,必为小端方式

4. 乘法溢出判定(为什么高 32 位不全为 0 且不全为 1 时 ?)

两个 32 位数相乘,ALU 会输出 64 位乘积(高 32 位与低 32 位): 在不溢出的情况下,高 32 位全部 32 个 bit,本质上就是低 32 位最高位(符号位)的“完全复制品

  • 计算机存放机制:通常只把低 32 位写回通用寄存器。如果高 32 位包含了运算的有效数据,说明这部分数据被截断丢失了,即发生溢出()。

  • 有符号数的符号扩展规则

    • 若真实结果为正数(低 32 位最高位为 0),没有溢出时,高 32 位应该全部补 0(全 0)。

    • 若真实结果为负数(低 32 位最高位为 1),没有溢出时,高 32 位应该全部补 1(全 1,补码符号扩展)。

  • 核心结论

    • ==未溢出()== 高 32 位与低 32 位的符号位完全一致(高 32 位全 0 且低 32 位最高位为 0,或高 32 位全 1 且低 32 位最高位为 1)。

    • ==溢出()== 高 32 位不全为 0 且不全为 1,或者高 32 位虽全 0/全 1 但与低 32 位的最高符号位不一致。

区分

  • 乘法里的溢出:对有符号乘法看 ;对无符号乘法看 (无符号乘法高 32 位只要不全为 0,即 )。

  • 关注的是符号位截断导致的数值失真,而不是加法中的进位。

5. 溢出异常处理:是不是所有溢出都加 into

  • into 指令的专属性into(Interrupt on Overflow)是 x86 架构专属的溢出中断指令。它的硬件逻辑是:==检测标志位 ,若 则触发 4 号中断/异常;若 则相当于空操作(NOP)==。

  • 其他架构/常见处理方式

    • 其他指令集(如 MIPS/RISC-V):没有 into 指令。MIPS 提供了带溢出捕获的算术指令(如 add, sub),硬件直接触发异常;不带捕获的指令(addu, subu)则忽略溢出。

    • 条件分支跳转(软件模拟):使用 jo Target(若溢出则跳转到异常处理程序),该方式在所有 CISC/RISC 架构中通用。

  • 408 考点定位:考查 x86 汇编中“在算术指令后紧跟一条什么指令可让 CPU 转异常处理”时,标准答案为 ==into==(或写 jo 指令跳转)。

例题

  • 题目

    已知 ,计算 的 C 语言函数及其在 32 位计算机 M 上的部分机器级代码如下:

    C

    int f1(int n) {
        if (n > 1)
            return n * f1(n - 1);
        else
            return 1;
    }
    

    代码段

    ; 行号   虚拟地址     机器指令          汇编指令
    1       00401000    55                push ebp
    ...
    11      00401018    83 7D 08 01       cmp dword ptr [ebp+8], 1
    12      0040101C    7E 17             jle 00401035H
    13      0040101E    8B 45 08          mov eax, dword ptr [ebp+8]
    14      00401021    83 E8 01          sub eax, 1
    15      00401024    50                push eax
    16      00401025    E8 D6 FF FF FF    call 00401000H
    ...
    19      00401030    0F AF C1          imul eax, ecx
    20      00401033    EB 05             jmp 0040103AH
    21      00401035    B8 01 00 00 00    mov eax, 1
    ...
    30      0040104A    C3                ret
    
    1. 上述代码中,哪条指令是条件转移指令?哪几条指令一定会使程序转移执行?

    2. 根据第 16 行的 call 指令,第 17 行指令的虚拟地址是多少?已知第 16 行采用相对寻址方式,该指令中的偏移量是多少?M 是采用大端方式还是小端方式?

    3. 第 19 行的 imul 指令中,当乘法器输出的高、低 32 位乘积之间满足什么条件时,溢出标志 ?要使 CPU 在发生溢出时转异常处理,编译器应在 imul 指令后加一条什么指令?

  • 分析

    1. 条件转移看标志位,仅第 12 行 jle;无条件改变流向包含 call(16 行)、jmp(20 行)、ret(30 行)。

    2. 第 16 行占 5 字节,下条指令地址为 。偏移量 。机器码为 D6 FF FF FF,低字节在低地址,为小端。

    3. 32 位带符号乘法溢出即高 32 位不是低 32 位的符号位扩展(不全为 0 且不全为 1)。x86 下配合使用 into 指令触发中断。

  • 答案

    1)

    • 条件转移指令:第 12 行指令(jle

    • 一定会使程序转移执行的指令:第 16 行(call)、第 20 行(jmp)、第 30 行(ret

    2)

    • 第 17 行指令的虚拟地址

    • 偏移量计算

    • 大小端判断

      偏移量 FFFFFFD6H 的最低有效字节 D6H 存放在最低地址端,因此 M 采用小端方式

    3)

    • 条件:乘法器输出的高 32 位不全为 0 且不全为 1(或高 32 位不是低 32 位的符号扩展)时,

    • 添加指令into(或 jo 跳转到异常处理程序)。

⚠️ 易错点

Warning

  • 相对寻址 PC 计算基准错误 → 绝不能用当前指令首地址相减。必须用 (即下一条指令的虚拟地址)作为被减数基准。

  • 漏认转移指令中的 callretcallret 在本质上都是无条件转移指令(强制改写 PC),不要只盯着 jmp

  • 有符号数乘法与加法溢出的区别 → 加法溢出看最高位与次高位进位();乘法产生双倍字长积,溢出看的是高半部分是否破坏了符号扩展