计算机系统基础——期末复习

第一章

时钟频率(f) :单位时间内完成的时钟周期数,单位为赫兹(Hz)。 例如:800MHz 表示每秒完成 800×106 个周期。

时钟周期(T) :完成一个时钟周期所需的时间,单位为秒(s)。 例如:800MHz 的时钟周期为 T=800×1061​s=1.25ns (纳秒)。

CPICycles Per Instruction,每条指令所需的时钟周期数)是衡量计算机体系结构性能的关键指标之一,用于描述CPU执行一条指令平均需要多少个时钟周期。它直接影响程序的执行速度和系统性能。

  • CPI 表示每条指令执行所需的平均时钟周期数,计算公式为: $$ \text{CPI} = \frac{\text{总时钟周期数}}{\text{总指令数}} $$
  • 执行时间 与 CPI 的关系: 执行时间 = 指令数 × CPI × 时钟周期时间 其中,时钟周期时间 = 1 / 时钟频率。

MIPS(Million Instructions Per Second) 是衡量计算机处理器性能的一个经典指标,表示 每秒执行的百万条指令数,用于量化 CPU 的指令处理能力。其核心思想是:数值越大,性能越强,但需注意其局限性。

  • MIPS = 指令数 / (执行时间 × 10⁶)
  • 或通过 时钟频率CPI(Cycles Per Instruction) 计算:
    $$ \text{MIPS} = \frac{\text{时钟频率(Hz)}}{\text{CPI} \times 10^6} $$

举例
- 若 CPU 主频为 2 GHz(2×10⁹ Hz),平均 CPI=4,则:
$$ \text{MIPS} = \frac{2 \times 10^9}{4 \times 10^6} = 500 \text{ MIPS} $$

数量级:

G,吉,十的九次方

n,纳,十的负九次方

m(milli,毫)的数量级是 10−3 (千分之一)

第二章

补码

1. 补码的定义

补码(Two’s Complement)是计算机中表示有符号整数的标准方法,其核心作用是将减法运算转化为加法运算,从而简化硬件设计。

2. 如何求一个数的补码?

8位二进制 为例: - 正数:补码 = 原码(符号位为0,其余位直接表示数值)。
例如:+5 的补码是 00000101

  • 负数:补码 = 原码的符号位不变,其余位取反(反码),然后末位加1。
    例如:求 -5 的补码:
    1. 原码:10000101(符号位为1,其余位为5的二进制)。
    2. 取反(符号位保留):11111010(反码)。
    3. 加1:11111010 + 1 = 11111011(补码)。

3. 数学原理:模运算

补码的本质是基于 模(Modulo)运算
- 对于 n位二进制数,其模为 2n
- 负数的补码表示为:
x ≡ 2n − x (mod 2n) 例如,8位二进制数的模是 28 = 256,因此:
−5 的补码 = 256 − 5 = 251,二进制表示为 11111011

4. 为什么“取反 + 1”有效?

  • 取反:相当于将数值部分取反(即 x → (2n − 1 − 1 − x))。
  • 加1:最终得到 2n − x,即补码的数学定义。

-5 为例(8位): 1. 原码:10000101(符号位为1,数值部分为5)。 2. 取反:11111010(数值部分取反,符号位保留)。 3. 加1:11111010 + 1 = 11111011,即 251 = 256 − 5

5. 补码的优势

  • 唯一零表示:补码中只有 一个零00000000),而原码和反码存在 +0-0 的问题。
  • 加减统一:所有加减运算均通过加法器完成,无需单独的减法器。
    例如:5 - 3 = 5 + (-3),直接通过补码相加即可。
  • 溢出自动处理:超过范围的高位会自然丢弃(模运算特性)。

6. 特殊情况:最小负数

对于 n位补码,能表示的范围是:
[−2n − 1, 2n − 1 − 1] - 例如,8位补码范围是:-12810000000)到 +12701111111)。 - 最小负数(-128) 没有对应的正数(因为 +128 超出范围),其补码直接定义为 10000000,无法通过“取反 + 1”从原码推导(因为原码中不存在 +128)。

移码(Offset Binary)详解

1. 移码的定义

移码是一种带偏移量的编码方式,主要用于表示浮点数的阶码(Exponent)。其核心思想是将真值(实际数值)加上一个固定的偏移量(Bias),使得所有数值映射到非负数范围,从而简化比较和运算。

公式
移码 = 真值 + 偏移量

2. 移码的核心作用

  • 简化比较
    移码将负数范围映射到正数范围,使得可以直接通过无符号整数比较来判断阶码的大小。
    • 例如:
      在浮点数中,阶码 −3+2 的移码分别为 125130(偏移量为127),直接比较 125 < 130 即可得出 −3 < +2
  • 消除负数表示
    移码将负数转换为正数表示,避免了补码中负数符号位的影响。

3. 偏移量的选择

偏移量通常为 2n − 12n − 1 − 1n 为位数): - 单精度浮点数(32位):偏移量为 127(即 27 − 1)。
- 双精度浮点数(64位):偏移量为 1023(即 210 − 1)。

4. 移码与补码的关系

  • 符号位取反
    移码可以看作是补码的符号位取反。例如:
    • 补码 10000000−128)的移码为 00000000−128 + 128 = 0)。
    • 补码 000000000)的移码为 100000000 + 128 = 128)。
  • 本质区别
    • 补码:用于定点数的加减运算,支持负数和正数的统一处理。
    • 移码:用于浮点数阶码的表示,便于直接比较大小。

5. 移码的应用场景

  • IEEE 754浮点数标准
    移码用于表示浮点数的阶码(Exponent),使得阶码可以直接按无符号整数比较。
    • 单精度(32位)
      阶码占8位,偏移量为127。
      真值 E 的移码为 E + 127
    • 双精度(64位)
      阶码占11位,偏移量为1023。
      真值 E 的移码为 E + 1023

浮点数表示

【CSAPP-深入理解计算机系统】2-4.浮点数(上)_哔哩哔哩_bilibili

【计算机知识】定点数与浮点数(2)浮点数法表示方法!_哔哩哔哩_bilibili

进制转换

【计算机基础】进制转换(3) 小数部分如何进行转换?_哔哩哔哩_bilibili

整数加减

浮点数加减

浮点数加减法运算 白中英计算机组成原理期末速成_哔哩哔哩_bilibili

(自用)计算机组成原理 题型三 浮点数加减法运算题_哔哩哔哩_bilibili

浮点运算(浮点数加减运算)计算机组成原理(看了包会)_哔哩哔哩_bilibili

ieee

计算机组成原理期末复习(5分钟):IEEE754浮点数加减计算!_哔哩哔哩_bilibili

位数

short 16位

第三章 程序的转换与机器级表示

结构体与联合体

【CSAPP-深入理解计算机系统】3-9.结构体与联合体_哔哩哔哩_bilibili

数组的分配和访问

【CSAPP-深入理解计算机系统】3-8.数组的分配和访问_哔哩哔哩_bilibili

过程调用

C程序在内存中的栈_哔哩哔哩_bilibili

【CSAPP-深入理解计算机系统】3-7. 过程(函数调用)_哔哩哔哩_bilibili

AT&T格式

AT&T格式是汇编语言中的一种语法风格,主要用于x86/x64架构的汇编代码编写。它与Intel格式并列为最常见的两种汇编语法,两者在语法细节上有显著差异。以下是AT&T格式的核心特点、示例及常见用途:

主要特点

特性 AT&T格式语法 对比Intel格式语法
寄存器 前缀 %(如 %eax 无前缀(如 eax
立即数 前缀 $(如 $0x10 直接使用数值(如 10
操作数顺序 源操作数在前,目标在后 目标在前,源在后
内存寻址 offset(base, index, scale) [base + index*scale + offset]
指令后缀 通过后缀标明操作数大小(如 l 表示32位) 无后缀,由操作数推断

寄存器种类

  • 8 个通用寄存器,其中
    • EAX, EBX, ECX, EDX 均为 32 位寄存器
    • AX, BX, CX, DX 均为 16 位寄存器
    • AH, BH, CH, DH 均为高 8 位寄存器
    • AL, BL, CL, DL 均为低 8 位寄存器
  • 2 个专用寄存器
  • 6 个段寄存器

操作数寻址方式

1. 基础内存寻址模式

(1) 直接寻址(Direct Addressing) cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc

  • 语法offset(AT&T格式)或 [offset](Intel格式)。
  • 用途:直接访问全局变量或静态数据。
  • 示例
    1
    movl var(%rip), %eax  # AT&T格式(RIP相对寻址,64位模式推荐)
    1
    mov eax, [var]        # Intel格式(32位模式)

(2) 寄存器间接寻址(Register Indirect Addressing)

  • 语法(base_register)[base_register]
  • 用途:指针解引用。
  • 示例
    1
    movl (%eax), %ebx     # 将EAX指向的内存值传入EBX
    1
    mov ebx, [eax]

(3) 基址寻址(Base Addressing)

  • 语法offset(base_register)[base_register + offset]
  • 用途:访问栈帧中的局部变量或结构体成员。
  • 示例
    1
    movl 8(%ebp), %ecx    # 从栈帧偏移8处读取数据到ECX
    1
    mov ecx, [ebp + 8]

(4) 变址寻址(Indexed Addressing)比例寻址

  • 语法array(, index_register, scale)[array + index_register*scale]

  • 用途:数组元素访问。

  • 示例

    1
    movl array(,%eax,4), %edx  # 数组array + EAX*4位置的值传入EDX(数组索引)
    1
    mov edx, [array + eax*4]

2. 组合寻址模式

(1) 基址 + 变址(Base + Index)

  • 语法(base_register, index_register)[base_register + index_register]

  • 用途:访问二维数组或动态分配的数组。

  • 示例

    1
    movl (%ebx, %esi), %edi  # 将EBX + ESI指向的内存值传入EDI
    1
    mov edi, [ebx + esi]

**(2) 基址 + 比例变址(Base + Index*Scale)**

  • 语法(base_register, index_register, scale)[base_register + index_register*scale]
  • 用途:按元素大小(scale)访问数组。
  • 示例
    1
    movl (%ebx, %esi, 4), %edi  # 将EBX + ESI*4指向的内存值传入EDI(4字节元素)
    1
    mov edi, [ebx + esi*4]

**(3) 基址 + 比例变址 + 偏移(Base + Index*Scale + Offset)**

  • 语法offset(base_register, index_register, scale)[base_register + index_register*scale + offset]
  • 用途:访问结构体数组或复杂数据结构。
  • 示例
    1
    movl 12(%ebx, %esi, 8), %edi  # 结构体数组中第ESI个元素的偏移12处数据传入EDI
    1
    mov edi, [ebx + esi*8 + 12]

3.总结

寻址模式 AT&T格式语法 Intel格式语法
直接寻址 var(%rip) [rip + var](64位)或 var
寄存器间接寻址 (%eax) [eax]
基址寻址 8(%ebp) [ebp + 8]
变址寻址 array(,%eax,4) [array + eax*4]
基址+比例变址 (%ebx, %esi, 4) [ebx + esi*4]
基址+比例变址+偏移 12(%ebx, %esi, 8) [ebx + esi*8 + 12]

指令后缀

在 AT&T 汇编格式中,指令后缀(如 bwlq)用于明确操作数的大小,确保汇编器正确生成机器码。判断后缀的核心规则是:根据操作数的大小选择对应的后缀,尤其是寄存器的位数或内存操作数的显式指定。以下是详细说明:

后缀与操作数大小的对应关系

后缀 操作数大小 示例寄存器/操作数
b byte(8位) %al, $0x10, 12(%ebp)(需显式指定)
w word(16位) %ax, %bx, 12(%ebp)(需显式指定)
l long(32位) %eax, %ebx, 12(%ebp)(需显式指定)
q quad(64位) %rax, %rbx, 12(%ebp)(需显式指定)

立即数默认为32位

判断“指针”与“临时变量

(1)%edx:临时变量

  • 特征:直接从寄存器 %edx 读取数据,不涉及内存地址的间接访问。
  • 对应C语言
    如果 %edx 存储的是某个局部变量或计算结果(如 temp = a + b),则对应临时变量

(2)(%ecx):指针

  • 特征%ecx 中存储的是内存地址,(%ecx) 表示解引用该地址(类似C语言的 *ptr)。
  • 对应C语言
    如果 %ecx 存储的是一个指针变量(如 int *ptr),则 (%ecx) 对应指针解引用

关键结论

操作数 类型 判断依据
%edx 临时变量 直接从寄存器读取数据,无间接内存访问(无括号)。
(%ecx) 指针 使用括号 (%ecx) 表示解引用内存地址(类似C语言的 *ptr)。

常见模式对比

汇编指令 C语言对应操作 解释
movl %eax, (%ebx) *ptr = temp; %ebx 是指针(存储地址),%eax 是临时变量。
movl (%ebx), %eax temp = *ptr; 从指针 ptr 读取值到临时变量 temp
movl $0x1, %eax temp = 1; %eax 是临时变量,直接赋值。

汇编语言中M的作用

在汇编语言中,M 通常表示 内存(Memory),用于指示操作数来自内存地址。在你的问题中,M[R[eax]] 的含义是:

M 的作用

  • M[地址] 表示从 内存地址为 地址 的位置读取数据
  • R[eax] 表示寄存器 EAX 的值(即 EAX 中存储的内容)。
  • 因此,M[R[eax]] 的含义是: > EAX 寄存器的值作为内存地址,从该地址读取数据

** AT&T 汇编中的等价写法**

在 AT&T 汇编语法中,M[R[eax]] 对应的写法是:

1
addl (%eax), %edx
- 含义: - (%eax):以 EAX 的值为内存地址,读取该地址的内容(默认是 4 字节,即 32 位)。 - addl:执行 32 位加法。 - %edx:目标寄存器,存储结果。

关键点总结

符号 含义 示例
R 寄存器(Register) R[eax]EAX 的值
M 内存(Memory) M[地址] → 从地址读取数据
() AT&T 汇编中表示内存寻址 (%eax) → 等价于 M[R[eax]]

常见AT&T格式汇编指令

指令类型 操作目的 影响标志位 典型用途
addl 加法 OF, SF, ZF, CF 数值运算、地址偏移
subl 减法 OF, SF, ZF, CF 数值运算、条件判断
orl 按位或 OF=0, SF, ZF, CF=0 位掩码操作
testl 按位与测试 OF=0, SF, ZF, CF=0 条件判断(如检查位是否设置)
imull 有符号乘法 OF, CF 数值运算
leal 地址计算 无影响 高效数组索引计算
decl 递减 OF, SF, ZF, CF 循环计数、边界检查

sall(Shift Arithmetic Left)—— 左移指令

功能

  • 作用 :将操作数的二进制位 向左移动 指定的位数,低位补0。
  • 效果 :相当于将操作数乘以 2n (n 为移动的位数)。

and(Logical AND)—— 逻辑与指令

功能

  • 作用 :对两个操作数进行 按位与运算 ,结果写入目标操作数。
  • 效果 :只有对应位都为1时,结果位才为1。

shrl逻辑右移指令 (Shift Right Logical),用于对操作数进行 无符号右移 ,即高位补 0,低位移出。

leal加载有效地址(Load Effective Address) 的指令,其功能是 计算内存地址并存储到目标寄存器 ,但 不会访问内存 。它常用于 地址计算高效算术运算

标志位

以下是 x86/x64 架构中常见的四个状态标志位(OF、SF、ZF、CF)的详细说明及其判断方法:

1. 标志位概述

标志 全称 含义
CF Carry Flag 无符号溢出标志:表示无符号数运算是否产生进位或借位。
ZF Zero Flag 零标志:表示运算结果是否为零。
SF Sign Flag 符号标志:表示运算结果的最高位(符号位)是否为1(负数)。
OF Overflow Flag 溢出标志:表示有符号数运算是否溢出(结果超出数据类型表示范围)。

2. 判断方法详解

(1) 进位标志(CF)

  • 用途:判断 无符号数运算 是否溢出。
  • 判断规则
    • 加法:若结果最高位(最高有效位)发生进位(超过数据类型的最大值),CF=1。
    • 减法:若结果需要借位(被减数 < 减数),CF=1。

(2) 零标志(ZF)

  • 用途:判断运算结果是否为零。
  • 判断规则
    • 结果为0 → ZF=1
    • 结果非0 → ZF=0

(3) 符号标志(SF)

  • 用途:表示运算结果的符号(正/负)。
  • 判断规则
    • 结果最高位为1(负数)→ SF=1
    • 结果最高位为0(正数)→ SF=0

(4) 溢出标志(OF)

  • 用途:判断 有符号数运算 是否溢出。
  • 判断规则
    • 溢出条件:两个正数相加结果为负,或两个负数相加结果为正 → OF=1。
    • 无溢出:其他情况 → OF=0。

栈帧布局和参数偏移计算规则

【CSAPP-深入理解计算机系统】3-3.栈与数据传送指令_哔哩哔哩_bilibili

1. 参数压栈顺序

C语言默认使用 cdecl 调用约定,参数从右到左压入栈中。例如,函数调用 operate(x, y, z, k) 的压栈顺序为:

1
2
3
4
5
push k;     // 第四个参数(最右边)
push z; // 第三个参数
push y; // 第二个参数
push x; // 第一个参数(最左边)
call operate;
栈中参数布局(高地址 → 低地址):
1
2
3
4
5
6
7
高地址
| k (参数4) | ← 栈顶(ESP)
| z (参数3) |
| y (参数2) |
| x (参数1) |
| 返回地址 |
低地址

2. 栈帧建立过程

进入函数 operate 后,通过以下指令建立栈帧:

1
2
pushl %ebp        ; 保存旧的EBP(栈帧基址)
movl %esp, %ebp ; 将当前栈顶(ESP)赋值给EBP,作为新栈帧的基址
此时栈帧布局如下:
1
2
3
4
5
6
7
8
高地址
| k (参数4) | ← EBP + 20
| z (参数3) | ← EBP + 16
| y (参数2) | ← EBP + 12
| x (参数1) | ← EBP + 8
| 返回地址 | ← EBP + 4
| 旧 EBP | ← EBP
低地址

3. 参数地址的计算逻辑

  • EBP + 4:返回地址(由 call 指令自动压栈)。
  • EBP + 8:第一个参数(x)。
  • EBP + 12:第二个参数(y)。
  • EBP + 16:第三个参数(z)。
  • EBP + 20:第四个参数(k)。

原因
1. 参数顺序:参数从右到左压栈,导致第一个参数(x)位于栈的最低地址(EBP + 8),而第四个参数(k)位于最高地址(EBP + 20)。
2. 偏移计算:每个参数占用4字节(32位系统中 int 和指针大小),因此偏移量依次递增4。
3. 栈帧基址EBP 指向旧的 EBP 值,其上方是返回地址(EBP + 4),再上方是参数。

汇编语言表示程序函数的过程调用

超硬核!408考研重点!汇编语言表示程序函数的过程调用!23王道计算机组成原理指令系统_哔哩哔哩_bilibili

反汇编

反汇编代码是将二进制机器码(如可执行文件、内存转储)转换为 人类可读的汇编指令 的结果。它是逆向工程、漏洞分析、调试等领域的核心工具。以下是详细说明:

1. 反汇编代码的定义

  • 本质:将机器码(二进制/十六进制)转换为对应的汇编指令。
  • 作用:帮助开发者理解程序逻辑、分析恶意软件、调试崩溃原因或研究编译器优化。

2. 反汇编代码的典型格式

反汇编代码通常包含以下部分: | 字段 | 说明 | 示例 | | ————————- | ————————————————– | —————————- | | 地址(Address) | 指令在内存中的地址(十六进制)。 | 0x804838c | | 机器码(Opcode) | 对应的原始十六进制机器码(机器指令的二进制表示)。 | 74 08 | | 汇编指令(Mnemonic) | 汇编助记符(如 mov, jmp, call)及操作数。 | je 0x8048396 | | 注释(Comment, 可选) | 开发者添加的注释(某些工具会自动生成符号信息)。 | ; if (eax == 0) goto label |

示例反汇编代码(AT&T格式)

1
2
3
4
0804838c <main>:
804838c: 74 08 je 8048396 <main+0xa>
804838e: b8 00 00 00 00 mov $0x0, %eax
8048393: e9 0e 00 00 00 jmp 80483a6 <main+0x1a>

大端小端

小端方式(Little-Endian) 是一种 数据在内存中的存储顺序,其核心特点是: > 数据的低位字节(LSB, Least Significant Byte)存储在内存的低地址处,高位字节(MSB, Most Significant Byte)存储在高地址处

1. 小端 vs 大端

特性 小端(Little-Endian) 大端(Big-Endian)
存储顺序 低位字节在前(低地址),高位在后 高位字节在前(低地址),低位在后
示例 0x12345678 → 存储为 78 56 34 12 0x12345678 → 存储为 12 34 56 78
常见平台 x86/x64 架构(Intel/AMD 处理器) ARM(部分模式)、网络协议(TCP/IP)

2. 小端方式的直观理解

示例:32位整数 0x12345678

  • 内存地址分配
    1
    2
    3
    4
    地址 →    0x1000    0x1001    0x1002    0x1003
    +---------+---------+---------+---------+
    | 0x78 | 0x56 | 0x34 | 0x12 |
    +---------+---------+---------+---------+
  • 解释
    • 数据的最低位字节 0x78 存储在最低地址 0x1000
    • 高位字节 0x12 存储在最高地址 0x1003

转移目标地址的计算

在 IA-32(x86)架构中,转移目标地址的计算依赖于 指令的长度相对偏移量(Displacement)。以下是详细分析:

1. 转移指令的基本原理

  • 相对跳转(Relative Jump):转移目标地址 = 下一条指令地址 + 偏移量
  • 偏移量:有符号的 8 位、16 位或 32 位整数,表示从 下一条指令地址 开始的偏移(正向或负向)。
  • 小端方式(Little-Endian):多字节偏移量需按小端方式存储(低位字节在前)。

2. 示例:call 指令的地址计算

(1) 已知条件

  • 指令地址0x804838ecall 指令的起始地址)。
  • 机器码E8 1E 00 00 00
    • E8call 的操作码。
    • 1E 00 00 00 是偏移量(小端方式存储)。

(2) 计算步骤

  1. 确定指令长度
    • call 指令占 5 字节(1 字节操作码 + 4 字节偏移量)。
  2. 计算下一条指令地址
    • 下一条指令地址 = 当前指令地址 + 指令长度
      = 0x804838e + 5 = 0x8048393
  3. 解析偏移量
    • 偏移量字段为 1E 00 00 00(小端方式)→ 转换为大端顺序为 0x0000001E(十进制 30)。
  4. 计算转移目标地址
    • 转移目标地址 = 下一条指令地址 + 偏移量
      = 0x8048393 + 0x1E = 0x80483B1

3. 核心公式 目标地址 = (当前指令地址 + 指令长度) + 偏移量 - 当前指令地址:指令的起始地址(如 0x804838e)。 - 指令长度:由操作码和操作数决定(如 call 占 5 字节)。 - 偏移量:从指令的操作数中提取并转换为有符号整数。

9. 其他指令示例

(1) je 指令

1
804838c:    74 08                   je     0x8048396
  • 当前地址0x804838c
  • 指令长度:2 字节。
  • 偏移量0x08(单字节,无需反转)。
  • 目标地址0x804838c + 2 + 0x08 = 0x8048396

(2) jmp 指令

1
80483a4:    E9 F6 FF FF FF          jmp    0x804839f
  • 当前地址0x80483a4
  • 指令长度:5 字节。
  • 偏移量F6 FF FF FF(小端)→ 补码为 -10(十进制)。
  • 目标地址0x80483a4 + 5 + (-10) = 0x804839f

计算下一条指令地址

下一条指令地址=当前指令地址+当前指令长度

第四章 程序的链接

重定位

【CSAPP-深入理解计算机系统】7-6. 重定位_哔哩哔哩_bilibili

其他

3分钟彻底理解链接器_哔哩哔哩_bilibili

计算机系统基础摘记——程序的链接_引入链接的好处是什么-CSDN博客

【CSAPP-深入理解计算机系统】7-5. 静态库的解析过程_哔哩哔哩_bilibili

其他

gdb调试

一分钟学会GDB程序调试_哔哩哔哩_bilibili

参考资料

深入理解计算机系统合集(周更中)_哔哩哔哩_bilibili