第一章
时钟频率(f)
:单位时间内完成的时钟周期数,单位为赫兹(Hz)。 例如:800MHz
表示每秒完成 800×106 个周期。
时钟周期(T)
:完成一个时钟周期所需的时间,单位为秒(s)。 例如:800MHz 的时钟周期为
T =800×1061s=1.25ns (纳秒)。
CPI (Cycles 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 的补码:
原码:10000101(符号位为1,其余位为5的二进制)。
取反(符号位保留):11111010(反码)。
加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位补码范围是:-128(10000000)到
+127(01111111)。 -
最小负数(-128) 没有对应的正数(因为 +128 超出范围),其补码直接定义为
10000000,无法通过“取反 + 1”从原码推导(因为原码中不存在
+128)。
移码(Offset
Binary)详解
1. 移码的定义
移码是一种带偏移量的编码方式 ,主要用于表示浮点数的阶码 (Exponent)。其核心思想是将真值(实际数值)加上一个固定的偏移量(Bias),使得所有数值映射到非负数范围 ,从而简化比较和运算。
公式 :
移码 = 真值 + 偏移量
2. 移码的核心作用
简化比较 :
移码将负数范围映射到正数范围,使得可以直接通过无符号整数比较 来判断阶码的大小。
例如:
在浮点数中,阶码 −3 和 +2 的移码分别为 125 和 130 (偏移量为127),直接比较 125 < 130 即可得出 −3 < +2 。
消除负数表示 :
移码将负数转换为正数表示,避免了补码中负数符号位的影响。
3. 偏移量的选择
偏移量通常为 2n − 1 或 2n − 1 − 1 (n 为位数): -
单精度浮点数(32位) :偏移量为 127 (即 27 − 1 )。
- 双精度浮点数(64位) :偏移量为 1023 (即 210 − 1 )。
4. 移码与补码的关系
符号位取反 :
移码可以看作是补码的符号位取反 。例如:
补码 10000000(−128 )的移码为 00000000(−128 + 128 = 0 )。
补码 00000000(0 )的移码为 10000000(0 + 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
(3) 基址寻址(Base Addressing)
语法 :offset(base_register) 或
[base_register + offset]
用途 :访问栈帧中的局部变量或结构体成员。
示例 : 1 movl 8(%ebp), %ecx # 从栈帧偏移8处读取数据到ECX
(4) 变址寻址(Indexed Addressing)比例寻址
2. 组合寻址模式
(1) 基址 + 变址(Base + Index)
**(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字节元素)
**(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 汇编格式中,指令后缀 (如
b、w、l、q)用于明确操作数的大小,确保汇编器正确生成机器码。判断后缀的核心规则是:根据操作数的大小选择对应的后缀 ,尤其是寄存器的位数或内存操作数的显式指定。以下是详细说明:
后缀与操作数大小的对应关系
后缀
操作数大小
示例寄存器/操作数
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]] 对应的写法是:
- 含义 : - (%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)
(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) 已知条件
指令地址 :0x804838e(call
指令的起始地址)。
机器码 :E8 1E 00 00 00。
E8 是 call 的操作码。
1E 00 00 00 是偏移量(小端方式存储)。
(2) 计算步骤
确定指令长度 :
call 指令占 5 字节 (1 字节操作码 + 4
字节偏移量)。
计算下一条指令地址 :
下一条指令地址 = 当前指令地址 + 指令长度
= 0x804838e + 5 = 0x8048393。
解析偏移量 :
偏移量字段为 1E 00 00 00(小端方式)→ 转换为大端顺序为
0x0000001E(十进制 30)。
计算转移目标地址 :
转移目标地址 = 下一条指令地址 + 偏移量
= 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