复习范围与使用说明
这份手册以 2026 年北京大学 ICS 本地课件和小班研讨题为主线,补充 CS:APP 第 3 版与公开往年题。既整理常考方法,也保留术语、历史背景、特殊边界和研讨拓展。默认平台是 x86-64、Linux、System V AMD64 ABI、AT&T 汇编;其他平台会明确说明。
先确认:这次考什么#
本地 ICS01-overview-20260907.pdf 第 9 页安排:2026-10-12 第一次阶段测验,范围为 第 1~8 课。同页注明教学安排可能调整,最终以教师通知为准。现有文件只到第 7 讲;第 8 讲“Machine Prog: Advanced”暂用教材第 3 章相关部分及 2025 第一次阶段测验补齐,尚不能声称覆盖未提供的课件全部细节。
| 阅读部分 | 范围 | 资料状态 |
|---|---|---|
| 01~08 主线 | 概述、整数、浮点、汇编基础、控制、过程、数据、机器级进阶 | 01~07 有本地课件;08 是补充 |
| 09~11 旧期中扩展 | 处理器、优化、存储器层次与缓存 | 旧卷常见,本次阶段测验范围之外 |
| 12 真题与勘误 | 2025 阶段卷逐题导航、2012~2024 旧卷分类、答案辨析 | 公开仓库来源,区分浏览与细读 |
| 13 小班与边角知识 | 研讨拓展、教材作业题号、易遗漏概念 | 覆盖现有第 2~7 讲研讨主题 |
| 14 覆盖索引 | 课件逐页主题清单、来源、核对边界 | 用于查漏,不等于每页逐字复刻 |
**完整性的边界:**本手册不是只列“重点”的速记表,但也不复制课件、教材或试卷全文。每种知识类型配有解释与代表例子,原题中的每个不同数值、课堂口头补充和未提供的第 8 讲资料不可能凭空补齐。历史试卷范围随年份变化,例如 2012 期中还出现链接内容,不应据此扩大 2026 第一次阶段测验范围。
读题前的四项约定#
- 先写位宽与类型。
int和long、无符号和有符号、C 表达式和机器指令的规则不同。 - **先区分值、位模式与字节顺序。**数值转换改变表示;按位重解释保留位串;大小端只规定多字节对象的字节排列。
- **机器级模型与 C 标准分开。**补码加法器会截断,但 C 有符号溢出不是可移植的“自动回绕”;负有符号数右移在本课程环境按算术右移分析。
- **先读题设再套模板。**流水线、浮点格式、缓存策略经常被题目修改。修改后的机器以题设为准。
建议的复习顺序#
第一遍依次读 02~08,遇到公式手工算一个例子;第二遍做 2025 第一次阶段测验,按第 12 章回查弱项;第三遍用第 13、14 章查遗漏。若确实准备旧式期中,再学习 09~11,最后做近年旧期中卷。
掌握的标准不是“看着懂”:应当能在不看答案的情况下,写出浮点编码推导、跟踪每条汇编的数据流、画出一次调用的栈变化,并说明所有类型与边界假设。
来源与版本#
整理日期:2026-10-01。课程 PDF 保留在项目的 ICS/ 目录;公开参考资料保留在本地 research/,发布目录只包含原创整理和来源链接,不包含扫描教材、课件原件和试卷副本。
本地课件页码均指 PDF 的物理页序;教材题号以用户提供的中文版第 3 版、小班作业单为准。
01 · 系统概述与基本模型
来源:第 1 讲课件 pp.16~42;第 4 讲 pp.12~24;教材第 1 章。第 1 讲的课程历史、组织与成绩说明列于文末,以免与技术内容混淆。
信息就是位加上解释#
同一串比特可以解释为整数、浮点数、字符、地址或指令。例如 0x3F800000 按 IEEE binary32 是 1.0,按无符号整数是 1065353216。机器不会凭位串自动知道程序员“本来想要”的类型;指令、数据布局和语言规则共同决定意义。
源文件通常是文本,字符用编码表示;机器代码、目标文件和可执行文件含二进制结构。ASCII 数字 '0' 是 0x30,并非整数 0。字符串结尾的 \0 是零字节,不等于字符 '0'。
从 C 到执行#
源代码 .c → 预处理 .i → 编译 .s → 汇编 .o → 链接 可执行文件
宏/头文件 汇编文本 机器码 符号解析/重定位
- 预处理展开
#include、宏和条件编译;编译进行语法与类型检查、优化并生成汇编。 - 汇编器把指令编码为字节,目标文件还含符号、节、重定位记录,通常不能直接运行。
- 链接器合并目标文件与库,解析跨文件的符号引用并调整地址。加载与链接是不同步骤。
- 操作系统装入程序并建立进程的执行环境;处理器执行机器指令。
gcc -E看预处理,gcc -Og -S生成汇编,gcc -c生成目标文件,objdump -d反汇编。不同编译器版本和优化级别可能产生不同但等价的代码。- 反汇编的一行通常包含:指令地址、机器码字节、助记符、操作数;标签和调试信息不是每条机器指令必须包含的内容。
处理器与内存#
CPU 中,程序计数器 PC(x86-64 为 %rip)指向执行位置,寄存器保存临时数据,ALU 完成算术和逻辑运算,条件码记录部分结果性质。内存是按字节寻址的存储空间,程序通过地址访问数据。总线传递地址、数据和控制信号。
以 addq %rdx,(%rcx) 为例:取指并译码 → 读 %rcx 得到地址 → 读该地址的 8 字节 → 读 %rdx → ALU 做 64 位加法 → 把低 64 位写回内存 → 更新条件码。额外的进位由 CF 记录,不会自动多写第 9 字节。此处描述的是体系结构语义,不规定现代 CPU 内部必须按这些步骤串行实现。
**ISA 与微体系结构:**ISA 规定软件可见的指令、寄存器、编码和行为;微体系结构决定流水线、执行单元、预测与缓存如何实现这些行为。不同 CPU 可以实现同一个 ISA。
五个贯穿全课的问题#
|问题|具体后果| |机器整数不是数学整数|固定位宽会丢失高位;类型转换改变比较结果| |浮点不是实数|0.1 可能无法精确表示;结合律、分配律可能失效| |必须理解机器代码|定位性能瓶颈、调试、理解栈和调用、识别内存错误| |内存影响正确性与性能|越界、悬空指针、内存泄漏;访问局部性改变速度| |渐近复杂度不等于运行时间|相同 O(n²) 算法因访问顺序、常数、缓存而不同|
C 的数组越界会造成未定义行为,不保证“恰好改坏紧邻的变量”。课件用结构体中的越界写演示浮点变量被破坏,是具体机器布局下的后果,不是可靠的语言语义。
层次、抽象与性能#
寄存器 → L1/L2/L3 缓存 → 主存 → 本地持久存储 → 远程存储,通常越向后容量越大、每字节成本越低、访问越慢。时间局部性是近期用过的内容可能再次使用,空间局部性是附近内容可能很快使用。C 的行优先矩阵按行访问通常比按列访问具有更好的空间局部性。
操作系统提供进程、虚拟内存、文件等抽象:进程是正在运行的程序及其状态;虚拟内存提供每个进程看到的地址空间;文件把多种 I/O 对象表现为字节序列。网络使程序还需要处理消息、延迟、协议和并发。
并发表示多个任务的执行在时间上重叠;并行表示同一时刻实际执行多个操作。可通过多核、指令级并行、SIMD 等层次实现并行。不能把“多线程”直接等同于“更快”。
Amdahl 定律:若原时间中比例 α 的部分加速 k 倍,总加速比为 1 / ((1-α)+α/k)。α=0.8、k=4 时总加速比是 2.5;即使 k 无穷大,上限也只有 5。
不属于计算题但课件出现的内容#
课程源于 CMU 从程序员视角理解系统的教学路线;北大采用大班与小班研讨结合。课件列出 Data、Bomb、Attack、Arch、Cache、Shell、Malloc、Proxy 等实验及其对应主题。课程组织、实验节点与成绩构成是教学安排,复习时查当前课件和通知,不从历史仓库推断今年政策。第 1 讲技术部分之外的页码均在覆盖索引保留。
自检#
能否分别说明编译、汇编、链接与加载做什么?为什么更高主频不能单独保证更快?为什么两个相同复杂度的矩阵遍历会有性能差异?为什么地址相同的位串能有完全不同的解释?
02 · 位、字节与整数
来源:第 2 讲 pp.3~68;小班第 2 讲;教材 §2.1~2.3。以下公式中的 w 是位宽,所有“模运算”都明确指无符号或固定位向量模型。
进制、字长与存储单位#
一个十六进制位恰好对应 4 个二进制位。十六进制便于压缩表示位串且保持位边界,十进制便于人的数量理解。0xDA = 11011010₂ = 218;8 位补码解释则是 218-256=-38。
|类型|Linux x86-64 常见字节数|补充| |char|1|普通 char 是否带符号由实现决定| |short|2|通常 16 位| |int|4|通常 32 位| |long / long long|8 / 8|Windows x64 的 long 常为 4| |float / double|4 / 8|IEEE binary32 / binary64| |指针|8|指针大小与所指对象大小无关|
C 只保证 sizeof(char)==1,一个 C 字节的位数由 CHAR_BIT 指定;本课假设 8 位字节。机器字长、C 的 int、汇编 word 不是同一概念:x86 的 word 是 16 位,quadword 是 64 位。KiB、MiB、GiB 严格对应 2¹⁰、2²⁰、2³⁰ 字节;KB/MB/GB 应看题设和厂商约定。
大小端与字符#
数值 0x1234ABCD 存在地址 p 开始的 4 个字节:
| 地址 | p | p+1 | p+2 | p+3 |
|---|---|---|---|---|
| 小端 | CD | AB | 34 | 12 |
| 大端 | 12 | 34 | AB | CD |
小端的“低”指低有效字节放低地址,不是把字节内部的比特反过来。x86 是小端。字符串按字符次序逐字节存储,不应整体翻转。字符串 "12" 占 3 字节:31、32、00。指针本身也是对象,其字节表示与它指向的内容不同。
网络字节序通常指多字节整数的大端表示。协议实现用 htons/htonl/ntohs/ntohl 等在约定边界转换;网卡不会自动替任意应用层结构体识别并修正全部字段。
可用 unsigned char * 检视对象字节;sizeof 返回 size_t,打印用 %zu。用不同类型指针直接解引用重解释对象可能触及别名或对齐规则,可靠的位复制可用 memcpy。
布尔代数与位向量#
逐位 & | ^ ~ 分别为交、并、异或、补。集合可以用位图表示:第 i 位为 1 表示元素 i 属于集合。x^x=0,x&~x=0,x|~x 是全 1;德摩根律为 ~(x&y)=~x|~y、~(x|y)=~x&~y。
&& || ! 判断零/非零,结果为 int 类型的 0 或 1,并且 &&、|| 从左到右短路。0xF0 & 0x0F=0,但 0xF0 && 0x0F=1。p && *p 在 p 为空时跳过解引用,但不能防止 p 是悬空或其他无效指针。
常用无符号位操作:
/* 前提:0 <= k < 32 */
x & (1u << k) /* 测试第 k 位 */
x | (1u << k) /* 置位 */
x & ~(1u << k) /* 清位 */
x ^ (1u << k) /* 翻转 */
x & (x - 1u) /* 清掉最低的 1;x=0 时仍为 0 */
x & (0u - x) /* 提取最低的 1 */
对 unsigned char 做运算时先发生整数提升;例如 ~(unsigned char)0 的表达式通常是 int 的 -1,而不是 255。需要取低 8 位时再转换或加掩码。
移位#
逻辑右移补 0;算术右移补原符号位;左移低位补 0,越出位宽的高位丢弃(位向量模型)。对位串 10110100 右移 2 位:逻辑结果 00101101,算术结果 11101101。
- C 无符号右移等价于向下取整除以 2ᵏ。
- 本课程 x86/GCC 模型中负有符号数右移是算术右移:
-13 >> 2为 -4;-13 / 4向零截断为 -3。 - C 中移位数为负或不小于提升后左操作数位宽是未定义行为;不能把 x86 对移位计数的硬件掩码当成 C 规则。
- C 有符号左移的条件比无符号更严格;做掩码优先用无符号。
1 << 31与1u << 31的语言含义不同。 - 加减优先级高于移位:
x + y << 2解析为(x+y)<<2。比较、位运算混用时显式加括号,例如(x & mask) == 0。
无符号、原码、反码与补码#
对于位向量 x[w-1]...x[0]:
B2U(x) = Σ x[i]·2^i (i=0...w-1)
B2T(x) = -x[w-1]·2^(w-1) + Σ x[i]·2^i (i=0...w-2)
UMax = 2^w-1
TMin = -2^(w-1) TMax = 2^(w-1)-1
32 位边界:TMin=-2147483648(0x80000000),TMax=2147483647(0x7FFFFFFF),UMax=4294967295(0xFFFFFFFF)。补码的负数比正数多一个,只有一个零。
原码是符号位加绝对值;反码的负值编码由相应正值编码逐位取反获得;二者都有正零和负零。补码用模 2ʷ 的表示统一加减法,避免双零。w 位模型的取负是 ~x+1 (mod 2^w);该位级恒等式对 TMin 也成立,结果位串仍为 TMin。数学上的 -TMin 超出同位宽有符号范围,C 的该取负会溢出,二者须分开。
类型转换、扩展、截断#
同位宽有符号→无符号:非负值不变,负值 x 映射到 x+2ʷ。反向按本课补码实现,若 u> TMax 则解释为 u-2ʷ。在 C 中,把不可表示无符号值转成有符号类型的具体规定应按所用标准和实现,不当作通用数学转换。
加宽:无符号零扩展;有符号符号扩展。例如 8 位 -12 为 F4,扩为 32 位是 FFFFFFF4。截断:只保留低 k 位,再按目标类型解释。加宽后再改成无符号时,应保持原值所要求的扩展,例如 short s=-1; unsigned u=s; 在本平台得到 0xFFFFFFFF,而不是 0x0000FFFF。
通常算术转换先做整数提升,再处理等级和可表示范围,不是只要出现 unsigned 就一律全变 unsigned:
|表达式|本平台解释|
|-1 < 1u|同等级转换为 unsigned int,结果假|
|-1L < 1u|64 位 long 可表示所有 32 位 unsigned int,结果真|
|sizeof(a)-1|结果类型通常是无符号 size_t,零长度时会回绕|
|unsigned char a=255; a+1|先提升为 int,表达式为 256;再存回 a 才变 0|
十进制无后缀字面量与十六进制字面量的候选类型序列不同;-2147483648 是一元负号作用于正字面量,不应未经分析就认定正字面量已经是 int。用 <stdint.h> 固定宽度类型、INT_MIN 等宏有助于明确题设。
加、减、乘与溢出#
无符号加法是 (x+y) mod 2^w;判断溢出可比较结果是否小于任一操作数,或在运算前判断 x > UMax-y。补码硬件加法也保留低 w 位:两个同号数相加得到异号结果才是有符号溢出。异号相加不会有符号溢出。
8 位例子:250+10 的低位结果是 4(无符号进位);100+60 的低位 0xA0 解释为 -96(正溢出);-100-60 的低位 0x60 解释为 96(负溢出)。CF 与 OF 可以不同。
无符号减法也按模 2ʷ 运算;硬件 CF 表示借位。补码减法 a-b 的溢出条件:a、b 异号且结果符号不同于 a。乘法完整积可能需要 2w 位;有符号与无符号乘法的低 w 位相同,高 w 位未必相同。C 中不能先做有符号溢出再用结果检验溢出,可先提升到足够宽类型或做边界比较。
在模 2ʷ 的位向量运算下,加法与乘法仍满足交换、结合和分配律;不能据此证明发生有符号溢出的 C 代码合法。判断恒等式时先写明讨论哪一种模型。
用移位替代常数乘除#
x*10 可分解为 (x<<3)+(x<<1),x*15 可分解为 (x<<4)-x,但这只是位向量或满足语言范围约束时的等价关系。编译器会综合成本选 LEA、移位、加减或乘法,不是所有乘法都必须替换。
对于 0≤k<w,本课算术右移模型下,有符号除 2ᵏ 向零舍入可按负数加偏置实现:
x >= 0: x >> k
x < 0: (x + (2^k - 1)) >> k
例:-13 除 4,先 -13+3=-10,再算术右移 2 位得到 -3。k=0 的偏置为 0。构造 2^k 的 C 代码时还要避免有符号移位本身越界。
完整算例与常见陷阱#
设 8 位 a=0xB5、b=0x5C:无符号 a=181,补码 a=-75;a&b=0x14,逻辑 !!b=1。将 short -12 扩为 int,位模式 FFFFFFF4;若问最低地址的字节,x86 小端答案 F4;若问最高有效字节,才是 FF。“首字节”不明确时必须说明解释。
无符号倒序循环 for (i=n-1; i>=0; i--) 不会靠 i>=0 结束,n=0 还会立即下溢。常用 for (size_t i=n; i>0; --i) use(i-1);。
自检与练习方向#
能从任意 w 位编码算出 B2U/B2T,并反向编码;能给出同位宽的 signed/unsigned 比较反例;能区分整数提升和截断;能解释负数除法的偏置;能写出同一对象的大端、小端字节序。教材作业:2.59(组合字节)、2.60(替换字节)、2.71(字节提取与符号扩展)。
03 · 浮点表示、舍入与运算
来源:第 3 讲 pp.3~48;小班第 3 讲;教材 §2.4;2022、2023、2024 期中第二大题以及 2025 阶段卷第 4~6 题。
二进制小数与定点#
1011.101₂ = 8+2+1+1/2+1/8 = 11.625。有限二进制小数的最简分母只能含因子 2,所以 1/10 不能精确有限表示;1/8 可以。定点预先固定小数点位置,硬件和舍入容易控制、等间距,但固定总位数下动态范围有限。浮点通过指数移动小数点,范围大但间距不均匀。
通用 IEEE 风格公式#
设符号位 s,阶码字段 e 共 k 位,小数字段 f 共 n 位,Bias=2^(k-1)-1,p=n+1 为规格化有效位精度。字段 f 是整数;公式中的 f/2^n 才是二进制小数。
| 类别 | 阶码条件 | M | E | 数值 |
|---|---|---|---|---|
| 规格化 | 0 < e < 2ᵏ-1 | 1+f/2ⁿ | e-Bias | (-1)ˢ·M·2ᴱ |
| 非规格化 | e=0 且 f≠0 | f/2ⁿ | 1-Bias | (-1)ˢ·M·2ᴱ |
| 有符号零 | e=0 且 f=0 | 0 | 1-Bias | +0 或 -0 |
| 无穷 | e=2ᵏ-1 且 f=0 | — | — | +∞ 或 -∞ |
| NaN | e=2ᵏ-1 且 f≠0 | — | — | 非数 |
非规格化数没有隐含的 1,但指数用 1-Bias,不是 -Bias。这让最大非规格化数与最小正规格化数之间恰好仍差一个最小非规格化单位,实现渐进下溢。
| 格式 | s/k/n | 精度 p | Bias | 最小正非规格化 | 最小正规格化 | 最大有限值 |
|---|---|---|---|---|---|---|
| binary32 | 1/8/23 | 24 | 127 | 2⁻¹⁴⁹ | 2⁻¹²⁶ | (2-2⁻²³)·2¹²⁷ |
| binary64 | 1/11/52 | 53 | 1023 | 2⁻¹⁰⁷⁴ | 2⁻¹⁰²² | (2-2⁻⁵²)·2¹⁰²³ |
单精度最大约 3.40×10³⁸,最小正规格化约 1.18×10⁻³⁸,有效十进制数字约 7 位;双精度最大约 1.80×10³⁰⁸,最小正规格化约 2.23×10⁻³⁰⁸,有效数字约 16 位。有效数字是精度概念,不是小数点后固定的位数。
范围、间距与计数#
最小正非规格化 = 2^(1-Bias-n)
最大正非规格化 = (1-2^-n)·2^(1-Bias)
最小正规格化 = 2^(1-Bias)
最大正有限值 = (2-2^-n)·2^((2^k-2)-Bias)
规格化 binade [2^E,2^(E+1)) 内相邻数间距为 2^(E-n);非规格化区域等间距。越接近大数,绝对精度越粗。1 后面的间距是 2⁻ⁿ,最近偶数舍入的常见相对误差界为 2⁻ᵖ(规格化且无溢出等条件下)。1 前面的间距比 1 后面小一半,不能跨边界机械套同一个 ULP。
精度 p 的格式能连续精确表示从 -2ᵖ 到 2ᵖ 的整数(还需指数范围足够),不意味着 2ᵖ 是可精确表示的最大整数。更大的 2 的幂仍可精确表示。
固定符号时 NaN 编码数为 2^n-1,两种符号共 2(2^n-1)。有限位模式数是 2(2^k-1)2^n;若把 +0/-0 视为同一个实数,互异有限实数个数再减 1。增加阶码位、减少小数位,会改变范围、精度和特殊编码数,不仅仅是“同样多的实数换个分布”。
“最大负非规格化”按数值顺序是最接近 0 的负数;“最小负非规格化”是绝对值最大的负非规格化数。必须区别于“最大绝对值”。
编码与解码:完整步骤#
编码 -13.25:绝对值为 1101.01₂=1.10101₂×2³;s=1,e=3+127=130=10000010₂,f=1010100...0(补到 23 位)。最终 binary32 为 0xC1540000。小端内存字节是 00 00 54 C1。
解码 0x40400000:s=0,e=128,f/2²³=0.5,所以 M=1.5、E=1,值为 3。解码时先分字段和分类,再决定隐藏位;不要一律补 1。
自定义 1/3/4 格式:Bias=3,0xBD 的 s=1、e=3、f=13,因此值为 -(1+13/16)·2^0=-1.8125;9/64 是非规格化,单位是 2⁻⁶,f=9,编码 0x09。题目给实数 1 的编码可反推 Bias、指数宽度和小数宽度。
最近偶数舍入#
先比较被丢弃部分与半个间隔;小于半间隔舍去,大于则进位;恰好一半时,选保留后最低位为 0 的结果。“向偶数”不是总舍入到偶数整数。
保留三位二进制小数:
| 原数 | 保留部分 | 舍弃部分 | 结果 |
|---|---|---|---|
| 101.100011 | 101.100 | 011,小于一半 | 101.100 |
| 101.100101 | 101.100 | 101,大于一半 | 101.101 |
| 101.100100 | 101.100 | 100,恰好一半,最低位 0 | 101.100 |
| 101.111100 | 101.111 | 100,恰好一半,最低位 1 | 110.000 |
工程判定:guard 为第一舍弃位,sticky 为其后各位的或,lsb 为最后保留位;最近偶数的进位条件是 guard && (sticky || lsb)。进位可能导致有效数溢出,必须重新规格化。
其他模式:向零、向 +∞、向 -∞。对负数,“向下”是更负而不是靠近 0。默认近偶数减少反复遇到中点时持续单向偏差,但不能说任意数据集都无偏。
加法、乘法与异常#
加法:比较指数 → 小指数有效数右移对阶并保留舍入信息 → 带符号相加/相减 → 规格化 → 舍入 → 检查上溢、下溢、零。相近数相减可能发生严重消去,使已有的相对误差变大。
乘法:符号异或 → 指数相加 → 有效数相乘 → 规格化 → 舍入 → 范围检查。不要把指数字段直接相加后忘记减 Bias;字段编码不是实际 E。
IEEE 默认模式下超出有限范围可能得到无穷,下溢可能得到非规格化或零。浮点状态还包括无效、除零、上溢、下溢、不精确等异常标志;它们不同于程序必须立即抛出异常或终止。
零、无穷与 NaN#
+0 与 -0 比较相等,但符号可由 signbit 或某些运算体现;IEEE 非陷阱语义下 1/+0=+∞、1/-0=-∞。∞-∞、0×∞、0/0 会得到 NaN。NaN 与任何数(包括自己)的 == < <= > >= 都是假,!= 为真。
NaN 有多个有效载荷编码,可区分 quiet/signaling NaN,并携带诊断信息;具体传播与载荷保留规则依实现,不能把 payload 当通用稳定错误码。符号位也存在,但 NaN 不形成普通的数值正负顺序。
对非负有限数,IEEE 位串按无符号比较与数值顺序一致;负数顺序反向,有符号零与 NaN 又需要特殊处理,所以不能对所有 float 直接按 int 比较。
代数性质与 C 转换#
浮点加法和乘法通常可交换,但结合律、分配律不普遍成立;NaN、无穷、有符号零还会影响等式和特殊情形。在固定舍入模式、排除 NaN 的普通数值排序中,正确舍入加法保持弱单调性;精度损失会破坏严格单调性(可能相等),不能把它误说成一定反转大小。乘以非负常数才保持方向,负数会反向,0×∞ 会产生 NaN。
- 32 位 int → double 精确,因为 53 位有效精度足够。
- int → float 可能舍入,32 位 int 的范围不致使 binary32 溢出。
- float → double 对有限值精确;double → float 可能舍入、上溢和下溢。
- 浮点 → 整数向零截断;NaN、无穷或截断后超出目标范围,不能依赖可移植 C 给某个固定整数。
(float)(double)x == (float)x对 32 位 int x 成立;整数先精确进入 double。- 三个 32 位整数转 double 后相加,中间精确和仍远小于 53 位精度极限,所以该特定域内加法结合律成立;这不证明任意 double 的结合律成立。
- 三个整数转 double 后相乘可能超过精度,结合律不保证成立;
dx/dx == dz/dz在某个原整数为零时可能失败。
例:binary32 中 (16777216.0f+1.0f)-16777216.0f 为 0,因为 2²⁴ 之后间距为 2,加 1 恰在中点,舍到偶数有效数。真实数学结果为 1。
FP8 与低精度格式:按题设定义#
2023 期中使用 E5M2 与一种 E4M3:E5M2 可按 1/5/2 的 IEEE 风格计算,Bias=15,最大有限值 57344;题设 E4M3 保留指数、小数全 1 为 NaN、其余扩展有限范围,最大值为 448。不能把该 E4M3 的全 1 指数一律判成无穷。
FP16(1/5/10)、BF16(1/8/7)展示范围和精度的权衡;BF16 指数范围接近 FP32,精度较低。训练/推理中可使用混合精度和高精度累加,但不能从存储格式推定累加也用相同格式。这里解释格式原理,不以某一年的硬件支持列表代替考题约定。
自检#
任选 k、n,能推导四个边界、相邻间距、NaN 数量和两种零;能把十六进制编码和内存字节分开;能处理跨规格化边界的舍入;能用输入范围证明某个表达式成立,而不是只背“浮点不满足结合律”。教材作业 2.86、2.87、2.89。
04 · 机器级编程基础
来源:第 4 讲;第 5 讲 pp.2~8;小班第 4 讲;教材 §3.1~3.5。
历史与抽象层次#
x86 经 8086 的 16 位、80386 的 IA-32 32 位,发展到 x86-64;AMD64 是对 x86 的 64 位扩展,Intel 的 Itanium/IA-64 是不同路线,不能把 IA-64 当作 x86-64 的别名。历史兼容性解释了寄存器别名与多种指令形式。课件中 Coffee Lake 等参数是历史案例,不是 2026 年最新硬件。
机器码是处理器解码的字节;汇编是可读表示。x86 指令变长,反汇编必须从正确的边界开始。ISA 规定可见语义,不要求“每条指令都只用一个时钟周期”。
AT&T 语法#
指令 源,目的;寄存器加 %,立即数加 $,内存由地址表达式表示。movq $8,%rax 写常数,movq 8,%rax 读取绝对地址 8 的内存,含义完全不同。Intel 语法常是目的在前,不可混读。
后缀 b/w/l/q 对应 1/2/4/8 字节;l 是 longword,q 是 quadword。能从寄存器确定宽度时汇编器可能接受省略后缀;仅有立即数和内存时应明确宽度。寄存器名字必须匹配操作宽度,例如 movq %eax,%rbx 不合法。
全部通用寄存器与局部访问#
| 64 位 | 32 位 | 16 位 | 低 8 位 |
|---|---|---|---|
| rax/rbx/rcx/rdx | eax/ebx/ecx/edx | ax/bx/cx/dx | al/bl/cl/dl |
| rsi/rdi/rbp/rsp | esi/edi/ebp/esp | si/di/bp/sp | sil/dil/bpl/spl |
| r8~r15 | r8d~r15d | r8w~r15w | r8b~r15b |
历史高字节 ah/bh/ch/dh 是对应低 16 位的高 8 位,不能与需要 REX 前缀的某些操作数组合使用。
**写 32 位通用寄存器会清零对应 64 位寄存器高 32 位;写 8/16 位通常保留其他位。**若 rax 原为 FFFFFFFFFFFFFFFF,movb $1,%al 后为 FFFFFFFFFFFFFF01;movl $1,%eax 后为 0000000000000001。读取 eax 不会自行改写 rax。
寻址与 LEA#
D(Rb,Ri,S) 的有效地址 = D + R[Rb] + S·R[Ri]
S ∈ {1,2,4,8},省略的项按默认规则处理
Rb 是基址,Ri 是索引,D 是有符号位移。比例因子适合常见元素大小。%rsp 不能作为普通 SIB 索引寄存器。位移前不写 $。
设 rdx=0x1000、rcx=3:0x10(%rdx,%rcx,8) 地址为 0x1028。
movq 0x10(%rdx,%rcx,8),%rax从该地址读 8 字节。leaq 0x10(%rdx,%rcx,8),%rax只把计算出的 0x1028 写入 rax,不访问该地址的内存,也不更新条件码。leaq (%rax,%rax,4),%rdx是乘 5 的整数计算;LEA 的输入无需一定是有效指针。- RIP 相对寻址用于位置无关的代码和全局数据访问;以具体指令给出的 next RIP 与位移算地址。
数据传送和扩展#
普通 mov 支持立即数→寄存器/内存、寄存器→寄存器/内存、内存→寄存器,不支持两个显式内存操作数直接相搬,也不能以立即数为目的。
| 指令族 | 含义与细节 |
|---|---|
| movb/w/l/q | 同宽传送,不改变条件码 |
| movzbl / movzbq / movzwl / movzwq | 零扩展,名字中前后宽度分别指源和目标 |
| movsbl / movsbq / movswl / movswq / movslq | 符号扩展 |
| cltq | eax 符号扩展到 rax,无显式操作数 |
| cqto | 把 rax 符号扩展到 rdx:rax,准备有符号除法 |
| movabsq | 可用完整 64 位立即数装入寄存器 |
没有必要用 movzlq 做 32→64 零扩展,写 32 位寄存器自然清高位。movq 的常见立即数形式使用可符号扩展的 imm32,不能无条件认为任意 64 位立即数都能编码在此形式中;汇编器可能选择其他编码。
算术与逻辑指令#
add S,D 得到 D+S;sub S,D 得到 D-S;二/三操作数 imul 保留目标宽度内的积。inc/dec 加减 1;neg 求补码负值;not 按位取反。and/or/xor 位运算,sal/shl 左移,sar 算术右移,shr 逻辑右移。
变量移位计数通常放在 %cl;64 位移位指令使用计数低 6 位、32 位用低 5 位。这是指令规则,不改变 C 的越界移位规定。
| 操作 | 条件码影响(常用规则) |
|---|---|
| add/sub/neg/cmp | 按结果设置相关标志;neg 非零操作数使 CF=1 |
| inc/dec | 设置算术结果标志,但保持 CF |
| and/or/xor/test | 更新 ZF/SF/PF;CF=OF=0 |
| mov/lea/not | 不修改条件码 |
| shift | 计数 0 不改标志;OF 通常只在计数 1 时有定义,须按指令查表 |
不要把乘除法后的所有标志都当成可用比较结果;例如 imul 主要通过 CF/OF 指示截断,除法后相关算术标志未定义。
双倍宽乘除#
64 位单操作数 mulq S:无符号 rdx:rax = rax*S;imulq S:有符号的 128 位乘积。二操作数 imulq S,D 与单操作数形式不同,不能混淆隐含寄存器。
divq S/idivq S 用 rdx:rax 作为 128 位被除数,商写 rax、余数写 rdx。无符号 64 位被除数通常先清 rdx;有符号先 cqto。除数为零或商超出目标寄存器范围触发除法异常;TMin / -1 是常见边界。idiv 商向零截断,余数与被除数同号或为零。
# long x / long y,x 在 rdi,y 在 rsi
movq %rdi, %rax
cqto
idivq %rsi # 商 rax,余数 rdx
解读代码的方法#
为每个寄存器写一个符号表达式,逐条替换;只在内存读写时引入 M[address]。例如:
leaq (%rdi,%rdi,2), %rax # 3*x
leaq (%rax,%rsi,4), %rax # 3*x + 4*y
subq %rdx, %rax # 3*x + 4*y - z
ret
计数访问时先看题目是否排除取指。movq (%rdi),%rax 有地址寄存器读取、数据寄存器写入和一次数据内存读取;与“几个操作数”不是同一个计数口径。2025 阶段卷 swap 四条 mov 按其口径共 8 次通用寄存器访问、4 次数据内存访问。
自检#
能检查任意 mov 是否有非法操作数组合;区分地址计算和解引用;追踪子寄存器写入;解释乘除的隐含寄存器;把复杂算式还原为 C,并保留类型/溢出的前提。教材作业 3.58、3.59。
05 · 条件码、分支、循环与 switch
来源:第 5 讲 pp.9~64;小班第 5 讲;教材 §3.6;2025 阶段卷第 10~14 题。
四个主要条件码#
CF:最高位的进位或减法借位,用于无符号判断。ZF:结果为零。SF:结果最高位为 1。OF:有符号溢出。PF 表示低字节中 1 的个数为偶数,浮点比较还会用它表达无序结果。
8 位加法:0x7F+1=0x80,CF=0、OF=1、SF=1、ZF=0;0xFF+1=0,CF=1、OF=0、SF=0、ZF=1。CF 不能替代 OF,SF 也不能单独判断带溢出的有符号大小。
cmp b,a 计算 a-b 的标志而不保存差值;test b,a 计算 a&b 的标志而不保存结果。test x,x 判断零/负;test mask,x 检查特定位。
条件选择表#
下表假设前一条设置标志的是 cmp b,a,要判断 a 与 b。后缀可用于 jcc、setcc、cmovcc(具体操作宽度限制不同)。
| 含义 | 后缀 | 标志条件 |
|---|---|---|
| 等于 | e / z | ZF |
| 不等于 | ne / nz | !ZF |
| 有符号小于 | l / nge | SF xor OF |
| 有符号小于等于 | le / ng | (SF xor OF) or ZF |
| 有符号大于 | g / nle | !(SF xor OF) and !ZF |
| 有符号大于等于 | ge / nl | !(SF xor OF) |
| 无符号小于 | b / c / nae | CF |
| 无符号小于等于 | be / na | CF or ZF |
| 无符号大于 | a / nbe | !CF and !ZF |
| 无符号大于等于 | ae / nb / nc | !CF |
| 负 / 非负 | s / ns | SF / !SF |
| 溢出 / 未溢出 | o / no | OF / !OF |
为什么 l 是 SF xor OF?若 a-b 不溢出,差值符号就是真实大小关系;若溢出,截断后的符号翻转,OF=1 正好把 SF 反过来。例如 8 位 -128-1 得到 127,SF=0、OF=1,但 -128<1 仍为真。
set、jump 与 cmov#
setle %al 只写一个字节,要返回完整 int 布尔值常接 movzbl %al,%eax。不能把 setle %rax 当作合法的 64 位 set 指令。
条件跳转根据标志修改控制流;无条件跳转 jmp label 是直接跳转,jmp *%rax 或 jmp *table(,%rdi,8) 是间接跳转。相对跳转目标是下一条指令地址 + 带符号位移。例如 0x100: eb fe 长 2 字节,目标 0x102-2=0x100。
cmov 根据条件把源值复制到目标寄存器;目标不能是内存,没有普通 8 位 cmov 形式。它通常先计算候选值,再选择结果,减少错误分支预测带来的代价。代价是候选表达式都可能执行:昂贵函数、不安全解引用、可见副作用不能随便提前执行。内存源 cmov 不保证在条件不满足时避免访存异常。
# 返回 x<=y 的布尔值,x、y 是 long
cmpq %rsi, %rdi
setle %al
movzbl %al, %eax
ret
读分支时检查最后一次修改标志的指令,不能无视中间的 add/sub/test;mov 和 lea 则通常保留原标志。
if 与条件表达式#
先画控制流图:比较块 → 真分支/假分支 → 汇合。编译器可能让真分支顺序执行、假分支跳转,也可能相反;不要按标签位置猜真假。
if (test) A else B
↓
if (!test) goto else_part;
A; goto done;
else_part: B;
done:
条件传送示例:先算 r=x-y、t=y-x,再以 x>y 选择 t;得到的是 x<=y ? x-y : y-x,是非正的差值,不能只看函数名 absdiff 就认定为绝对值。2025 阶段卷中的同名函数正是一个提醒。
三种循环与边界#
- do-while:先执行 Body,再 Test,至少执行一次。
- while 跳到中间版本:入口先跳 Test,条件成立转 Body,Body 后回 Test。
- while guarded-do 版本:入口先否定条件检查,失败直接结束;成功后采用 do-while。
- for:Init → Test → Body → Update → Test;
continue应进入 Update,不能把它错误地直连 Test。
还原汇编时依次找初始化、循环体、测试、更新、出口、返回值。循环不一定有单独的“索引 i”,可能通过指针推进或移位掩码控制。
/* unsigned 版本明确位级行为;限制 1<=n<=63 才保证推进 */
unsigned long pick(unsigned long x, unsigned n) {
unsigned long result = 0;
for (unsigned long mask=1; mask!=0; mask<<=n)
result |= x & mask;
return result;
}
n=0 会使 mask 不变化;n≥位宽的 C 移位不合法,硬件低位掩码也不等于修复了源代码。Popcount 可逐位累加 (x&1) 再右移,也可反复 x&=x-1;x86 的 POPCNT 是专门指令,但编译器是否采用取决于目标 ISA、选项和识别能力。
switch 与跳转表#
稠密 case 常用跳转表,稀疏 case 可能采用比较树。流程通常为:索引归一化 → 范围检查 → 间接跳转 → 各 case 代码。
subq $3, %rdi # 原 case 从 3 开始
cmpq $4, %rdi
ja .Ldefault # 无符号检查同时排除原值<3 或 >7
jmp *.Ltable(,%rdi,8) # 每项是 8 字节代码地址
表中的第 0 项对应原值 3,不一定对应 case 0。多个 case 可共享同一地址;缺失值可指向 default;fall-through 表现为执行一个代码块后直接接另一个块,不意味着两个标签必须相同。
位置无关代码可能用 4 字节相对偏移表:先读有符号表项,再加表基址得到目标,因此“所有跳转表表项必为 8 字节”错误。一定看 .quad/.long 和加载指令。
调试时 x/8xg 地址 可显示 8 个 8 字节十六进制单元;这是显示内存表项,不自动执行跳转。反汇编区分机器码、表中数据与真实指令边界。
自检#
给任意 cmp 顺序,能选择正确的 signed/unsigned 条件;能解释 set 后为什么需要零扩展;能给出不适合 cmov 的具体例子;能从循环还原初值、终止条件和更新;能处理 switch 的默认分支、重复标签和穿透。教材作业 3.60、3.63。
06 · 过程调用、栈与 ABI
来源:第 6 讲 pp.4~75;小班第 6 讲;教材 §3.7;2025 阶段卷第 15~17 题。
调用要完成三件事#
传递控制:保存返回位置并进入被调用者;传递数据:参数、返回值;管理存储:局部变量、跨调用保存值、栈帧分配与回收。ABI(应用二进制接口)规定不同编译模块如何在二进制层面配合,包括调用约定、类型大小/对齐、寄存器保存、对象文件与链接等。
call/ret 的硬件行为来自 ISA;“第一个参数放 rdi”是 ABI 约定,不是 call 指令固有的强制功能。改变约定需要调用者、被调用者、库、编译器和调试/展开信息协同。
栈的方向与四条指令#
栈向低地址增长,rsp 指向当前栈顶。普通 64 位 push/pop 每次改变 8 字节。
| 指令 | 主要语义 |
|---|---|
pushq S |
先取得源值,rsp←rsp-8,把值写到新栈顶 |
popq D |
读旧栈顶,rsp←rsp+8,把取出的值写到 D |
call target |
压入下一条指令的地址,再把 RIP 转到 target |
ret |
从栈顶取返回地址到 RIP,rsp 增加 8 |
对 pushq %rsp、popq %rsp 之类特殊目的/源不能仅按普通寄存器例子机械替换:push 压入的是原 rsp;pop 到 rsp 时最终 rsp 取栈中弹出的值。内存目的含 rsp 时也需要按指令规定的求址时序分析。
pop 不会主动清零旧内存,只是移走栈顶。栈帧没有 C 层面可持久引用的寿命,返回后使用局部变量地址无效,即使原字节暂时还在。
一次调用的地址跟踪#
假设地址 0x400644 的 call 长 5 字节,执行前 rsp=0x110。执行后 rsp=0x108,M8[0x108]=0x400649,RIP 为目标函数入口。目标的 ret 执行后 rsp=0x110,RIP=0x400649。
小端展开返回地址 0x400649 的 8 字节是 49 06 40 00 00 00 00 00。返回地址不是 call 自身地址,也不是目标函数地址。若题目列出若干 push/sub,逐条累计后再确定偏移。
System V AMD64 参数与返回值#
| 项目 | 规则(普通标量参数) |
|---|---|
| 前 6 个整数/指针参数 | rdi、rsi、rdx、rcx、r8、r9 |
| 更多整数/指针参数 | 经栈传递;callee 入口的第 7 个普通整数参数通常位于 8(%rsp) |
| 普通整数/指针返回值 | rax(较小类型使用其低部分) |
| 浮点参数 | xmm0~xmm7,按浮点参数序列分配 |
| float/double 返回值 | xmm0 |
| 调用前栈对齐 | 常见规则为 call 执行前 rsp 为 16 的倍数;入口 rsp+8 为 16 的倍数 |
参数类型与布局还可能要求更强的对齐;聚合类型按 ABI 分类,不适用“一切前六个都按一个整数参数算”。整数与浮点有各自的分配序列,例如 f(long a,double b,long c,float d) 分别在 rdi、xmm0、rsi、xmm1。
caller-saved / callee-saved#
| 类别 | 通用寄存器 | 责任 |
|---|---|---|
| 被调用者保存 | rbx、rbp、r12~r15 | callee 若修改,返回前恢复 |
| 调用者保存 | rax、rcx、rdx、rsi、rdi、r8~r11 | caller 若需调用后继续使用旧值,自行保存 |
| 栈指针 | rsp | 按调用约定恢复栈结构,不当普通临时值使用 |
System V 下 XMM 通常为调用者保存。没有要求“每个函数必须把所有寄存器都保存一次”;只保存实际需要维护的值。rbp 可作帧指针,也可以在省略帧指针时当普通的 callee-saved 寄存器。
例如第三个参数 dest 在 rdx,而调用另一个函数可能破坏 rdx:可以先 push rbx 保存调用者的旧 rbx,再把 dest 放 rbx,call 后经 rbx 写回结果,最后 pop 恢复。callee-saved 不表示值永不变化,而是跨调用边界的约定值能保持。
栈帧与局部存储#
常见传统序言和尾声:
pushq %rbp
movq %rsp, %rbp
subq $32, %rsp # 局部区/对齐
# 局部对象在 rbp 的负偏移,返回地址通常在 8(%rbp)
leave # mov rbp,rsp; pop rbp 的效果
ret
不是所有函数都有该形式。叶函数可能完全不分配栈;System V 用户态允许使用 rsp 以下的 128 字节 red zone,适合不跨调用保存的临时数据。内核、Windows 等环境不可直接套用。动态长度数组或 alloca 可能需要运行时计算栈空间并对齐。
局部量放内存的常见原因:取地址、数组/结构体存储、寄存器不足、跨调用保留。优化可能消除对象或传播常量,因此源代码变量与栈槽不存在永远一一对应关系。
递归:每一层有什么不同#
每个递归调用都有自身返回地址与需要保留的局部状态。硬件不需要“递归专用指令”,普通 call/ret、栈与编译器约定已经足够。递归深度、总调用次数和同时存活的帧数不同。
unsigned long count(unsigned long x) {
if (x == 0) return 0;
return (x & 1) + count(x >> 1);
}
当前层的 x&1 必须在递归调用之后仍可获得:可放 callee-saved 寄存器或栈。返回时再加到子调用的返回值。若最高 1 位在第 k 位(0 起算),不优化时非零层有 k+1 层,再加 x=0 的基例层;按是否计基例说明答案。
带两个递归子调用的组合数程序总调用次数可能很大,但栈同时只保存一条尚未返回的路径。尾调用若被优化为跳转,帧数又可能变化;考试按给定汇编追踪。
聚合类型传参与返回#
小结构体可能按一个或两个 eightbyte 分类到整数寄存器或 XMM;大的或被分类为 MEMORY 的返回对象通常由 caller 提供缓冲区地址作为隐藏参数。常见 MEMORY 返回约定:调用时目标地址在 rdi,返回时 rax 也给出该地址;显式整数参数位置相应后移。不是所有结构体返回都使用隐藏指针。 这也是 2024 期中选择题第 7 题发生歧义的原因。
ABI 对比(小班拓展)#
Windows x64 普通整数参数主要使用 rcx、rdx、r8、r9;前四个位置对应浮点参数使用相应 XMM 槽位,caller 预留 32 字节 shadow space。其保存寄存器和 System V 不同,不能把 Linux 表直接套用。IA-32 常见 cdecl 主要栈传参、eax 返回,caller 清理参数;stdcall/fastcall 等又有差异,“32 位 Windows/Linux 只存在一个约定”不成立。详见 Microsoft x64 调用约定。
自检#
能逐条画出 call/push/pop/ret 前后的 rsp、返回地址和数据;能识别每个参数;能解释为什么用 rbx 保留指针;能区分栈帧数量与调用次数;能说明某个变量是否需要有地址。第 6 讲作业合并到第 7 讲。
07 · 数组、结构体、指针与浮点汇编
来源:第 7 讲 pp.3~51(包括附加材料);小班第 7 讲;教材 §3.8~3.9、§3.11;2025 阶段卷第 18~22 题。
一维数组与指针算术#
T A[N] 为 N 个连续 T 对象分配 N·sizeof(T) 字节。&A[i] = base+i·sizeof(T),A[i]=*(A+i)。指针加 1 是增加一个所指对象的跨度,而不是一字节。
同一数组中的指针相减得到元素个数(类型 ptrdiff_t),不是字节数;跨不相关对象相减不满足 C 的定义。可以形成末尾后一个指针用于比较或循环终止,但不能解引用它。
数组对象不是指针变量。A 在很多表达式中退化为首元素指针,sizeof(A) 和 &A 是重要例外;作为函数形参的 int a[10] 调整为指针参数,所以在函数内 sizeof(a) 是指针大小。
二维、变长与多级数组#
C 的 T A[R][C] 是 R 个“含 C 个 T 的数组”,行优先:
&A[i][j] = base + (i*C+j)*sizeof(T)
A+i 的跨度 = C*sizeof(T)
&A+1 的跨度 = R*C*sizeof(T)
int A[3][5] 中 sizeof(A)=60、sizeof(*A)=20、sizeof(**A)=4、sizeof(&A)=8。这些数值默认本课 LP64。
int fixed(int a[3][5], size_t i, size_t j) { return a[i][j]; }
int variable(size_t n, int a[n][n], size_t i, size_t j) {
return a[i][j];
}
变长数组的列数要在运算时参与乘法;形参调整后的类型是指向整行的指针,不是 int**。固定列数常能用移位或 LEA 算行偏移。
int *rows[R] 是指针数组:先从表里读 rows[i],再通过所得指针读第 j 项,通常两次数据读取;各行可独立分配、不连续或不同长度。int A[R][C] 只需一次最终元素读取,行地址可直接算出。将连续二维数组强转 int** 不会自动变成行指针表。
类型声明与 sizeof 表#
从变量名出发,先结合括号内的结构,再按 []、() 优先于 * 读声明。
| 声明 | A 是什么 | sizeof A | sizeof *A | sizeof **A | sizeof ***A |
|---|---|---|---|---|---|
| int A[3][5] | 二维 int 数组 | 60 | 20 | 4 | 非法类型表达式 |
| int *A[3][5] | 二维 int 指针数组 | 120 | 40 | 8 | 4 |
| int (*A)[3][5] | 指向整个二维数组的指针 | 8 | 60 | 20 | 4 |
| int (*A[3])[5] | 3 个指针,每个指向 5 个 int 的数组 | 24 | 8 | 20 | 4 |
| int *(*A[2])[3] | 2 个指针,每个指向 3 个 int* 的数组 | 16 | 8 | 24 | 8 |
最后一行不是“指针指向指针再指向 int 数组”的随意层叠:括号与数组位置决定了元素类型。再解引用一级 ****A 才得到 int,sizeof 为 4。
sizeof(*p) 对非 VLA 类型通常不求值,因此 sizeof 不会真的解引用 p;但在普通值表达式中读 *p 需要有效对象。课件附表的 “Bad pointer” 是讨论实际访问风险,不应误读成所有 sizeof 都发生访存。VLA 相关 sizeof 可能运行时求值,要单独分析。
结构体布局与对齐#
编译器按声明顺序排列成员,不会为了省空间擅自重排。每个成员从满足其 alignment 的最小偏移开始;最终结构体大小向其最大成员对齐要求的整数倍取整,保证结构体数组每个元素也正确对齐。
align_up(x,a) = ceil(x/a)*a
成员偏移 = align_up(当前末尾, 成员对齐)
结构体大小 = align_up(最后成员末尾, 结构体对齐)
struct S { char c; int i; short s; double d; };
/* 本课 ABI:offset(c)=0, i=4, s=8, d=16, sizeof=24, align=8 */
c 后补 3 字节;s 后结束于 10,再补 6 字节使 d 在 16。如果改成 double d; int i; short s; char c;,偏移 0/8/12/14,总大小 16。这说明程序员改变顺序可节省空间;编译器不能偷偷改变对外布局。
数组和嵌套结构体作为完整成员参与布局。结构体整体起始地址必须满足所有成员的对齐,不能只满足第一个 char。x86 支持许多未对齐访问不意味着 C/ABI 可以忽略对齐;未对齐还可能跨缓存块并影响性能。#pragma pack、不同 ABI 和向量类型可能改变规则。
用 <stddef.h> 的 offsetof(struct S,i) 核对偏移,用 _Alignof 核对对齐;不通过手写空指针解引用技巧猜布局。
从汇编反推布局#
先看访问宽度判断候选类型,再看偏移;对数组维度列出约束而非凭一个地址猜答案。2025 阶段卷第 21 题:
str1: int x[A][B]; long y; y 在 184
str2: char array[B]; int t; short s[A]; long u;
t 在 8,u 在 32
得到 align_up(B,4)=8,所以 5≤B≤8;align_up(12+2A,8)=32,所以 7≤A≤10;align_up(4AB,8)=184,所以 AB∈{45,46}。唯一满足正整数范围的解是 A=9,B=5。注意尾部 y 的地址不是简单假定为 4AB,必须先考虑 padding。
链表读取中区分取成员地址与读成员值:leaq 8(%rdi),%rax 返回成员地址;movq 8(%rdi),%rax 读该处 8 字节;后面再 movq (%rax),%rax 才是一次额外指针追踪。
SSE / XMM 与 SIMD#
XMM 寄存器宽 128 位,标量运算只处理指定低位标量,packed 运算处理多个元素。YMM、ZMM 是更宽的扩展寄存器;本课代码主要看 XMM。
| 指令/后缀 | 意义 |
|---|---|
| ss / sd | scalar single / scalar double,单精度/双精度标量 |
| ps / pd | packed single / packed double,4 个 float / 2 个 double |
| movss / movsd | 移动浮点标量位模式 |
| addss/addsd、mulss/mulsd、sub、div 同族 | 相应精度标量运算 |
| cvtss2sd / cvtsd2ss | float ↔ double 数值转换 |
| cvtsi2sd / cvtsi2ss | 有符号整数转换成浮点 |
| cvttsd2si / cvttss2si | 浮点向零截断转换为有符号整数 |
| ucomiss / ucomisd | 设置浮点比较结果标志 |
| xorpd %xmm0,%xmm0 | 清零,形成 +0 位模式 |
移动位模式不是数值转换;movq 的整数/向量寄存器间形式也不等于 cvt。标量操作对寄存器其他位的效果与具体 SSE/AVX 编码有关,不只凭 ss/sd 后缀泛化。
浮点参数与比较#
double mix(long *a,double *b,float c):a 在 rdi,b 在 rsi,c 在 xmm0;指向浮点的指针仍走整数寄存器,只有浮点值走 XMM。若计算 *a+*b+c,先加载、转换为 double,再加,结果在 xmm0。
对于 ucomis 的逻辑左值与右值比较(AT&T ucomisd src,dst 比较 dst 对 src):
| 关系 | ZF | PF | CF |
|---|---|---|---|
| 大于 | 0 | 0 | 0 |
| 小于 | 0 | 0 | 1 |
| 相等 | 1 | 0 | 0 |
| 无序(NaN) | 1 | 1 | 1 |
因此不能仅用 ZF 断言浮点相等,还要排除 PF=1 的无序情形;编译器可能组合 setnp 等指令。OF/SF 清零,不能套整数 signed 比较条件。NaN 的异常细节还需区别 quiet/signaling 和比较指令种类。
自检#
能按类型一步步求 sizeof;能解释数组形参与对象的差异;能列结构体偏移表;能从汇编反推维度;能判断浮点指针和浮点值各在哪类寄存器;能解释 unordered。教材作业 3.66、3.67、3.68。
08 · 机器级进阶与内存安全
**补充章:本地尚无第 8 讲课件。**依据课程日程中的 Machine Prog: Advanced、CS:APP §3.9~3.10 和 2025 第一次阶段测验第 23~24 题整理。最终范围、例子和课堂拓展需拿到第 8 讲后核对。
union:共享存储而非转换数值#
union 所有成员从相同偏移开始共享存储,总大小至少容纳最大成员,并按最严格成员对齐要求取整。写某个成员会改变其他成员所看到的底层字节。
union U { unsigned char c[8]; unsigned int i[2]; };
/* 本平台常见 sizeof(U)=8,alignment=4 */
若 c 依次写 C0 C1 C2 C3 C4 C5 C6 C7:大端下 i[0]=C0C1C2C3,小端下 i[0]=C3C2C1C0。(int)float_value 进行数值转换;以整数解释 float 的原位串通常是完全不同的数。C 与 C++ 对读取非活动 union 成员的语言规则也不同,不能把课上的位重解释练习泛化成跨语言保证。
需要检查 float 对象的位时,使用等大小的无符号整数和 memcpy 可避免通过不兼容指针别名直接读取的问题。IEEE 格式和端序仍须明确。
C 指针的完整概念#
指针类型决定解引用宽度和指针算术步长;强转类型不会移动对象,也不会自动创建目标对象。void* 可持有对象指针,但标准 C 不定义 void 的大小,因此 void* 算术不是可移植的标准写法;GCC 的相关扩展不能当成语言一般规则。
函数指针指向可调用函数,类型还包含参数和返回类型。数组可以存函数指针;函数不能按普通对象数组直接存储。空指针、未初始化指针、悬空指针、越界指针是不同情况;只检查非空不足以保证可访问。
调试与反汇编#
| 命令概念 | 用途 |
|---|---|
| break / run / continue | 断点、运行、继续 |
| step / next | 源代码级步入/步过 |
| stepi / nexti | 指令级步入/步过 |
| info registers | 观察寄存器 |
| disassemble | 反汇编函数 |
| x/Nfu address | 查看 N 个单元,f 为显示格式,u 为单元宽度 |
| backtrace / frame | 调用栈和栈帧选择 |
常见 x 显示宽度 b/h/w/g 是 1/2/4/8 字节;与 C 的 sizeof(long) 没有自动对应关系。打印地址时区分“地址值”和“该地址处的内容”。优化会让变量消失、合并或移到寄存器,调试器显示不出变量不一定是编译错误。
内存错误分类#
数组越界、错误的指针步长、未初始化读取、对象寿命结束后访问、释放后使用、重复释放、格式化字符串错误、错误分配大小都会导致问题。内存泄漏是已分配对象不再能被正常释放,和悬空指针不同;前者未必立即崩溃,后者可能指向已经无效的对象。
从给定汇编研究栈上 char buf 的边界时,先画出 buf、填充、保存寄存器、返回地址的位置。布局依编译器、优化和保护选项变化,不能固定背“数组长度加 8 就到返回地址”。写入字符串还要计入结尾 NUL。
缓冲区越界与防护#
| 机制 | 主要作用 | 限制 |
|---|---|---|
| 边界检查与正确长度的输入函数 | 阻止越界写本身 | 需要正确传入容量并处理截断/结尾 |
| ASLR | 让栈、堆、映射或代码位置更难预测 | 是地址随机化,不修复越界 |
| NX / XD / DEP | 把数据页设置为不可执行 | 依赖硬件页权限与 OS 配合,不阻止所有代码复用 |
| 栈金丝雀 | 在返回前检查哨兵是否变化 | 需编译插桩,覆盖范围和检查时机有限 |
| PIE | 使可执行文件代码可被随机布置 | 与 ASLR 配合,不能等同于所有程序自动随机化 |
2025 试题把使用安全输入函数视为需改源码、需重编译;栈地址随机化通常无需重编译普通用户程序;金丝雀通常需重编译、不必改源码;执行权限位依赖 CPU 支持。试卷的“是否需要换 CPU”是在比较机制的硬件前提,现代已经支持 NX 的机器不需要为了启用它再换硬件。
fgets(buf,sizeof buf,stdin) 可限制读取量,但仍需要处理保留换行、EOF、截断和缓冲区剩余输入。“使用某个函数”不自动证明整个程序安全。
动态栈与特殊控制#
变长局部数组根据运行时 n 分配空间,通常按对齐向上取整后减少 rsp,可能需要保存稳定帧基址。退出作用域或函数时恢复栈指针。局部数组不因返回其指针而延长寿命。
关于代码注入与代码复用,只需从体系结构角度理解:越界可能改变控制数据;不可执行栈限制执行数据;代码复用使用已有可执行指令,所以与 NX 解决的问题不同。实验中仍需按课程规则独立完成,不把现成攻击字符串当复习目标。
自检#
能计算 union 的大小与字节覆盖;能说明位重解释与强转不同;能分析一段栈图中的对象寿命和边界;能比较 ASLR、NX、金丝雀和边界检查各解决什么问题。第 8 讲课件到齐后,应优先用覆盖索引补差。
09 · 旧期中扩展:处理器体系结构
**不在当前日程所示第一次阶段测验第 1~8 讲内。**为覆盖旧期中真题补充,主线对应教材第 4 章。不同年份有 Y86-32 与 Y86-64,必须先确认字长、寄存器和编码长度。
Y86-64 程序员模型#
15 个 64 位通用寄存器(x86-64 的 r15 不在教材 Y86-64 的普通寄存器集合),PC,ZF/SF/OF,字节寻址内存,状态码 AOK/HLT/ADR/INS。RNONE(0xF)表示不使用寄存器,不是实际寄存器。
| 指令 | 功能 | 教材常见长度 |
|---|---|---|
| halt / nop / ret | 停止 / 空操作 / 返回 | 1 字节 |
| rrmovq / cmovXX、OPq、pushq/popq | 寄存器/条件传送、算逻、入栈出栈 | 2 字节 |
| irmovq / rmmovq / mrmovq | 立即数传送、存内存、取内存 | 10 字节 |
| jXX / call | 条件或无条件跳转、调用 | 9 字节 |
首字节含 icode/ifun,可能再有 rA/rB 字节、8 字节小端 valC。Y86 的 jXX/call 使用题设定义的目标编码,不要套 x86 相对偏移的规则。Y86-64 没有完整 x86 指令集,不能凭空用硬件未支持的乘除或寻址形式。
组合逻辑、状态与 HCL#
组合电路输出由当前输入决定;时序电路含寄存器、存储器等状态。时钟周期必须容纳关键组合路径加寄存器开销。位与逻辑布尔、字比较、集合包含和多路选择器是 HCL 的基础。
word value = [
condition1 : expression1;
condition2 : expression2;
1 : default_expression;
];
从上到下选第一个成立条件,不是“所有分支并行赋值”。x in {A,B} 表示比较集合成员。控制逻辑描述硬件选择,不是带无限临时存储的普通 C 程序。
SEQ 的六个逻辑阶段#
F 取指:读 icode/ifun、寄存器字段、常数、算 valP;D 译码:读源寄存器 valA/valB;E 执行:ALU 得 valE、判断条件并可能更新 CC;M 访存:读得 valM 或写内存;W 写回:写 dstE、dstM;更新 PC:选 valP、valC 或 valM。SEQ 在一个较长周期内完成一条指令的这些逻辑工作。
| 指令 | 执行/访存核心 | 写回 | next PC |
|---|---|---|---|
| OPq rA,rB | valE=R[rB] op R[rA],设置 CC | rB←valE | valP |
| irmovq V,rB | valE=V | rB←valE | valP |
| rmmovq rA,D(rB) | 地址 R[rB]+D,写 R[rA] | 无 | valP |
| mrmovq D(rB),rA | 地址 R[rB]+D,读 valM | rA←valM | valP |
| pushq rA | valE=rsp-8,M8[valE]=valA | rsp←valE | valP |
| popq rA | valE=rsp+8,valM=M8[旧 rsp] | rsp←valE,rA←valM | valP |
| call Dest | rsp-8;把 valP 写新栈顶 | rsp←valE | valC |
| ret | 读旧栈顶返回地址;rsp+8 | rsp←valE | valM |
| cmovXX | 条件成立才给有效 dstE | 条件成立写 rB | valP |
| jXX | 计算 Cnd | 无 | Cnd?valC:valP |
popq %rsp 同时涉及两路写回同一寄存器,按教材优先级处理,不是任意顺序都等价。设计新指令时必须列出每阶段读写、资源是否够用、条件码时机、异常行为和 PC。
流水线的吞吐与延迟#
k 级流水线、n 条理想指令,从第一条进入 F 到最后一条离开 W 需 n+k-1 周期。实际还要加停顿和错误路径处罚,避免漏灌入/排空。时间=周期数×周期时长。
若各阶段组合延迟 tᵢ、寄存器开销 r,流水线时钟至少 max(tᵢ)+r;单条延迟约 k 个周期,吞吐可近似每周期一条。分级不均匀、寄存器开销、分支与数据冒险使加速达不到 k 倍。算频率时 ps 与 ns 换算不可漏掉 r。
数据冒险与前递#
后续指令要读前面尚未写回的寄存器,形成 RAW 数据依赖。前递把新结果送到使用位置,优先采用程序顺序上最近的生产者。教材 PIPE 的译码前递常用优先级:e_valE → M 阶段加载的 m_valM → M_valE → W_valM → W_valE → 寄存器文件。
D 阶段的 call/jXX 所需 valA 是 D_valP,须优先处理。条件传送不成立时 e_dstE 应为 RNONE,避免转发不存在的更新。不能只比较 E_dstE 而忽略条件。
load/use:紧邻 mrmovq/popq 的消费者在下一周期 E 阶段需要值,但加载到 M 阶段末才可得,教材默认前递仍需一个停顿:F stall、D stall、E bubble,前面的加载继续向 M/W 前进。
L = E_icode in {IMRMOVQ, IPOPQ}
&& E_dstM in {d_srcA, d_srcB}
2024 题加了 M→E 的 store-data 前递,可消除“加载值仅用作 push/store 写入数据”的某些停顿;若加载结果是 store 的地址基址,地址生成仍在 E 需要它,不能同样消除。
控制冒险与 PIPE 控制#
教材 PIPE 常预测 jXX 跳转;在 E 得知不该跳转时冲刷错误路径。ret 的目标来自内存,要等待返回地址,不能像直接 jmp 提前知道。
R = IRET in {D_icode,E_icode,M_icode}
B = E_icode==IJXX && !e_Cnd
F_stall = L || R
D_stall = L
D_bubble = B || (!L && R)
E_bubble = B || L
这里是教材普通 PIPE 模型的关键部分;完整实现还包括异常的 M/W 控制、CC 更新门控、预测 PC 选择等。异常指令后面的指令不能提交可见副作用。题目修改分支决策阶段、加载延迟或返回机制后,重新画时空图,不硬背固定处罚。
stall 保持该流水线寄存器,bubble 注入空操作,normal 接受下一组值;二者不是同义词。同周期既要 stall 又 bubble 的冲突必须由逻辑消除。
新指令设计通用答题法#
- 写出不可歧义的 ISA 语义:旧值/新值、内存宽度、条件失败行为。
- 标注编码、长度与 valP;确认所需 rA/rB/valC。
- 为 F/D/E/M/W/PC 分别列信号;检查一次内存访问和两个写回端口是否足够。
- 判断结果产生阶段、消费者使用阶段,补充前递、暂停和冲刷。
- 用别名寄存器(尤其 rsp)、条件失败、异常、相邻依赖做边界推演。
RISC/CISC 与性能拓展#
RISC 常强调较简单指令和寻址、load/store 结构;CISC 常有复杂指令与多种编码。但“RISC 所有指令固定长”“RISC 必比 CISC 短/快”不是普遍定理。现代实现可能把指令拆为内部操作,ISA 标签不能直接预测性能。
自检:能独立填写 push/pop/call/ret 六阶段表、推导 load/use、画五级时空图、计总周期、说明新指令为何需要某条额外数据通路。
10 · 旧期中扩展:程序性能优化
对应教材第 5 章及旧卷优化题;不属于日程所示第一次阶段测验范围。
先保持语义,再谈快慢#
编译器受语言语义、别名、函数副作用、可见 I/O、溢出规则和浮点舍入约束。两个数学等式不一定是等价 C 程序。优化后要按相同输入、编译器、选项、硬件与计时口径比较。
| 阻碍 | 为什么不能随便改 |
|---|---|
| 函数调用 | f() 可能改变状态,两次 f() 不一定相同 |
| 指针别名 | 写 *p 可能影响随后读 *q |
| 浮点重结合 | 改变舍入次序,结果可能不同 |
| volatile / 可见 I/O | 访问次数与顺序可能本身就是语义 |
| 未定义行为 | 不能用一次“恰巧运行成功”证明合法性 |
异或交换在 p、q 指同一对象时会把值清零;临时变量交换则保留值。把循环中的 B[i] 缓存到临时变量,只有确认 A/B 不发生相关别名写读依赖后才可保语义。
计量与瓶颈#
总时间、周期数、CPI(每指令周期)、IPC、CPE(每元素周期)不同。循环常用 T(n)≈CPE·n+固定开销,从多组规模的斜率估计 CPE;只比较小 n 会把调用/计时开销误当循环成本。
指令延迟是一个输入到结果可用需要多久;发射间隔/吞吐是连续开始多少次运算的能力。某乘法器延迟 4 周期、每周期可发射一次,独立乘法可并行,但依赖链仍每步等 4 周期。
常见源代码优化#
- 消除循环不变量:长度不变时把 strlen 放循环外;如果循环会修改字符串,不能直接移动。
- 减少函数调用:在确认 getter/length 语义后消除重复调用。
- 减少内存访问:把累积值保存在局部变量,循环后写回,但要检查别名。
- 强度削减:用地址递增或便宜运算代替重复乘法;现代编译器也可能自动做。
- 循环展开:减少分支与索引更新,暴露更多独立工作;要保留尾部元素处理。
- 多路累积:拆开依赖链;浮点结果通常改变,只有题设允许时使用。
- 重结合与 SIMD:提高并行度,同时检查代数与内存边界、对齐和剩余项。
展开可能增加代码体积、寄存器压力、溢出到栈的 spill 和指令缓存压力,因此展开越多不一定越快。
延迟界与吞吐界#
考虑每元素一次乘法,运算延迟 L、机器吞吐每周期最多 U 次乘法。单累积链的 CPE 通常受 L 限制;k 个独立累积链理想依赖界约 L/k,同时受吞吐界 1/U 限制,还受 load、地址生成与分支资源约束。
例如 L=4、U=1:1 个累积器依赖界 4,2 个约 2,4 个约 1;再加到 8 个并不能突破每周期一个乘法的吞吐界。这里只是约束下界,不是保证实测必然达到。
微体系结构视角#
现代处理器可能超标量、乱序执行、寄存器重命名与分支预测。真数据依赖(RAW)不能靠重命名消除;名字依赖(WAR/WAW)可通过物理寄存器重命名处理。加载可能在存储之前执行,但要检测地址依赖;同址写后读可能依赖 store-to-load forwarding。
条件传送可减少不可预测分支,但会增加数据依赖和候选计算;高度可预测分支不一定比 cmov 慢。链表指针追逐因为下一个地址依赖前一个加载,难以并行,数组连续访问则更容易预取和向量化。
存储访问、分块与剖析#
矩阵循环交换改善行优先空间局部性,但要确保依赖允许交换。分块让一小片工作集在 cache 中反复使用,降低容量与冲突失效。结构体数组(AoS)与成员数组(SoA)对只访问部分字段、向量化等场景有不同效果,没有一劳永逸的最佳布局。
剖析先找热点,再针对瓶颈修改。Amdahl 定律解释为什么只优化占总时间很小的代码收益有限;不仅比较“某函数快了几倍”,还应看整个程序时间。
自检#
给一个优化能指出所有语义前提;能解释展开与多路累积的不同;能画出累积依赖链;能计算 CPE 下界并列出硬件资源限制;能说明 strlen 外提何时合法。
11 · 旧期中扩展:存储器与缓存
对应教材第 6 章;旧期中缓存大题与选择题。不属于日程所示第一次阶段测验范围。
存储技术与组织#
SRAM 用双稳态电路保持状态,通常更快、更贵、密度低,用于缓存;DRAM 以电容电荷存储,需要刷新,密度高,用于主存。二者通常断电丢失数据。ROM/PROM/EPROM/EEPROM/Flash 是非易失类别,写入/擦除特性不同,不能因有“RAM”或“ROM”名字就推断所有访问规则。
DRAM 以行列组织,RAS 选行装入行缓冲,CAS 选列;复用地址引脚降低引脚需求。同一行连续访问可以复用行缓冲。FPM 是快页模式,EDO 延长数据输出有效时间并重叠后续访问,SDRAM 与时钟同步,DDR 在时钟两边沿传输。宽度、频率、通道数和有效传输率共同影响带宽。
SSD 的 NAND Flash 按页读写、按更大块擦除,需要地址映射、垃圾回收和磨损均衡;随机读延迟低于旋转盘,但写放大和擦写寿命等不能忽略。磁盘也会机械磨损,不能说“只有 SSD 会磨损”。
磁盘容量与时间#
容量 = 盘片数×每片有效面数×每面磁道数×每道扇区数×每扇区字节数。实际分区记录使不同 zone 的扇区数可不同,应按题设求和或平均。GB 通常按 10⁹,GiB 按 2³⁰。
每转时间 = 60/RPM 秒 = 60000/RPM 毫秒
平均旋转延迟 = 半转 = 30000/RPM 毫秒
传送一扇区时间 = 每转时间/每道扇区数
访问时间 ≈ 寻道 + 旋转延迟 + 传送 (+ 题设控制器开销)
7200 RPM 时一转约 8.333 ms,平均旋转约 4.167 ms。最短时间可能无需等待一整次平均旋转;题目给出磁头初始位置、方向和访问次序时按几何位置分析。RPM 是转/分钟,不能直接当转/秒。
局部性与缓存层次#
时间局部性:重复使用最近访问的对象;空间局部性:访问邻近地址。取指本身也有局部性;即使没有数据数组,循环也可能体现指令时间/空间局部性。
缓存把下层数据按块复制到上层。命中时间、失效率与失效处罚共同决定性能,命中率高不一定总时间短。块越大有利于空间局部性,但减少固定容量中块的数量、增加传送代价与污染。
参数与地址划分#
S = 2^s 组;每组 E 行;每块 B = 2^b 字节
数据容量 C = S·E·B
m 位地址分为 tag(t=m-s-b) | set index(s) | block offset(b)
block = address // B
set = block % S
tag = block // S
offset= address % B
E 是相联度,不是块大小;容量 C 通常不含 tag、valid、dirty 等元数据。常规位切分要求 S、B 是 2 的幂,E 不必须是 2 的幂,t 是位数更不必是 2 的幂。直接映射 E=1;全相联 S=1;组相联介于两者之间。
若题目问实际总存储位数,要加 S·E·(8B+t+valid位+dirty位),再按题设计 LRU 等状态。改 E 不改变地址的 set/offset 划分;改 S 或 B 会改变划分,这是 2024 扩容题的关键。
一次访问的流程#
取组索引 → 在该组中检查 valid 且 tag 相等的行 → 命中则按 offset 取字节 → 未命中则找空行或按替换策略淘汰 → 装入整个对齐块 → 更新元数据。tag 相同但 valid=0 不是命中。跨块访问可能需要访问两块,不能只检查起始地址。
LRU 淘汰最久未被访问的行,命中也更新新旧顺序;FIFO 按进入先后,命中不改变排队次序;随机替换另按题设。所有策略只在对应组内选牺牲行,不跨组比较年龄。
手工模拟完整例子#
m=5、B=4、S=2、E=2,初始空、LRU。序列:2、23、13、9、20、15、13、10。
| 地址 | 块号 | 组 | tag | 结果 | 解释 |
|---|---|---|---|---|---|
| 2 | 0 | 0 | 0 | miss | 载入 M[0..3] |
| 23 | 5 | 1 | 2 | miss | 载入 M[20..23] |
| 13 | 3 | 1 | 1 | miss | 载入 M[12..15] |
| 9 | 2 | 0 | 1 | miss | 载入 M[8..11] |
| 20 | 5 | 1 | 2 | hit | 23 已带入该块 |
| 15 | 3 | 1 | 1 | hit | 13 已带入该块 |
| 13 | 3 | 1 | 1 | hit | 更新时间 |
| 10 | 2 | 0 | 1 | hit | 9 已带入该块 |
总 4 次命中、4 次失效,命中率 50%。地址跨度不等于缓存次数,块内连续字节通常共享一次带入。
写策略是两组独立选择#
| 场景 | 选项 | 行为 |
|---|---|---|
| 写命中 | write-through 直写 | 同时向下一层传递写入 |
| 写命中 | write-back 写回 | 只改本层并置 dirty,淘汰脏块时写回 |
| 写失效 | write-allocate 写分配 | 把块带入再修改 |
| 写失效 | no-write-allocate 不写分配 | 绕过本层向下层写,不装入该块 |
常见搭配是写回+写分配、直写+不写分配,但并非逻辑上唯一合法组合。写回不表示“所有淘汰都写”,只有脏块需要写。写失效次数与总内存传输次数不同,可能同时有脏块写回、读入新块和写入。
失效类型与平均访问时间#
冷/强制失效:第一次访问块。冲突失效:同组映射竞争,即使总容量足够仍相互替换。容量失效:工作集太大,理想同容量全相联也装不下。并发系统还可有一致性失效,本课基本模型通常不涉及。
AMAT = hit time + miss rate × miss penalty,前提 miss penalty 是命中探测后的额外代价;如果题目给“失效总时间”,应写加权平均而不重复加命中时间。多级时 L2 局部失效率与全局失效率不同:全局 L2 miss 率通常为 L1 miss 率×L2 local miss 率。
数组、步长与 memory mountain#
若 int 为 4 字节、B=64 字节,一个对齐块容纳 16 个 int;顺序读冷数组通常每 16 个元素一次强制失效,但行首对齐、跨块、写分配、共享缓存和冲突都可能改变结果。步长 ≥ 块大小可能每次碰新块;多个数组基址映射同组会抖动。
二维数组按行内 j 递增通常空间局部性好;按列跨行步长为列数×元素宽度。分块需要让同时使用的小块工作集适合 cache,还应避免组冲突。Memory mountain 中工作集大小轴展示不同层次容量效应,步长轴展示空间局部性效应。
Victim cache 保存刚被主 cache 淘汰的块,通常小而全相联,用来缓解冲突;按题设跟踪主缓存与 victim 之间的交换,不把它简单等同于扩大某一组。
自检#
能从 C/S/E/B 求位划分和反求地址;能按 LRU 模拟读写并统计流量;能分清写命中与写失效策略;能计算磁盘时间;能分析遍历顺序和工作集;能对题目新增“不缓存某些块”规则重新执行状态机。
12 · 往年题导航与勘误
来源为用户指定的 公开仓库。本章原创概括题型与解题路径,不转载整卷。2025 第一次阶段测验与当前第 1~8 讲范围最接近,应当优先于旧式期中卷。
本次核对程度#
已下载 2012~2024 共 13 份带答案期中卷、2024 勘误、2025 两份阶段卷及期中复习细节。细读了 2025 第一次阶段卷的所有题目、2024 期中及勘误的主要题组、2022/2023 的浮点与机器代码相关题组;更早试卷用于逐页题型索引,不声称已逐题独立验算全部历史答案。2014 部分文本提取乱码,页码定位可以使用,但未据乱码推断精确公式。
2025 第一次阶段测验:逐题回查#
| 题号 / PDF 页 | 考察点 | 复习位置 | 作答检查 |
|---|---|---|---|
| 1 / p.2 | 进制、按位与、逻辑非 | 02 | 值与编码解释要分开 |
| 2 / p.2 | signed/unsigned 常量比较 | 02 | 先做通常算术转换 |
| 3 / p.2 | short 扩展成 int 的字节 | 02、下方勘误 | 最高有效字节与最低地址字节不同 |
| 4 / p.2 | ∞ 编码、float 字段解码 | 03 | e、E、M 不混淆 |
| 5 / p.2 | 二进制最近偶数舍入 | 03 | 恰好一半才看保留最低位 |
| 6 / pp.2~3 | 整数转浮点、表达式恒等性 | 03 | 结合具体输入范围判断 |
| 7 / p.3 | 寄存器别名 | 04 | 32 位名与低字节名 |
| 8 / p.3 | 寄存器和数据内存访问计数 | 04 | 是否排除取指,地址寄存器也算访问 |
| 9 / p.3 | 比例寻址 | 04 | 先算地址,不读取内存值 |
| 10 / p.3 | cmp/sub,test/and | 05 | 是否保存运算结果 |
| 11 / p.4 | setcc、零扩展、32 位写入 | 04、05 | movzbl 的显式与隐含效果 |
| 12 / pp.4~5 | 分支与条件传送 | 05 | 按代码语义判断,别被函数名误导 |
| 13 / p.5 | 移位掩码循环 | 05 | 还原四要素并检查 n 的边界 |
| 14 / p.5 | 跳转表 | 05 | 索引从 0 起,每项跨度 |
| 15 / p.6 | pop 操作次序 | 06 | 旧栈顶读取与 rsp 增量 |
| 16 / p.6 | call/ret、参数与 rbx 保存 | 06 | 返回地址是 call 的下一条 |
| 17 / pp.6~7 | 局部变量寄存器/内存 | 06 | 取地址和题设“不高级优化” |
| 18 / p.7 | 固定二维数组寻址 | 07 | 行跨度与元素宽度 |
| 19 / pp.7~8 | VLA 传参 | 07 | n 参与运行时乘法 |
| 20 / p.8 | 线性地址与二维数组 | 07 | 逐项定位元素再求和 |
| 21 / pp.8~9 | 结构体偏移反求维度 | 07 | 用对齐不等式联立求解 |
| 22 / p.9 | 混合参数、浮点转换 | 07 | 指针走通用寄存器,float 值走 XMM |
| 23 / p.10 | union 与大端 | 08 | 共享位串,不是转换数值 |
| 24 / p.10 | 缓冲区防护机制 | 08 | 源码、编译、OS 与硬件支持分开 |
从这份卷的覆盖看,不应只复习汇编填空:低字节寄存器、访问计数、零扩展的隐含效果、混合浮点 ABI 等边角知识都直接成为独立小问。各章已据此补齐。
近年旧期中:可迁移的方法#
| 年份与位置 | 主题 | 应学的方法 |
|---|---|---|
| 2024 第二大题 pp.10~12 | 内存字节→float、自定义 FP8、union | 先还原端序,再分字段;数值转换与位重解释分开 |
| 2024 第三大题 pp.13~17 | 递归字符串变换、栈与跳转位移 | 逐条恢复语义,按每层有效字符串长度计递归深度 |
| 2024 第四大题 pp.18~21 | PIPE 前递扩展 | 区分写入数据依赖与地址基址依赖 |
| 2024 第五大题 pp.22~23 | 相联度扩容、LRU、特殊不缓存规则 | 参数变化与逐次状态机模拟 |
| 2023 第二大题 pp.13~15 | E5M2/E4M3、量化、运算次序 | 特殊值规则可被题目修改,不能套统一 FP8 |
| 2023 第三大题 pp.16~18 | 组合数递归与汇编填空 | 参数保留、双递归与活跃栈深度 |
| 2023 第四大题 pp.19~21 | 间接条件跳转、新指令、访存延迟 | 按结果可用阶段重新设计控制 |
| 2022 第二大题 p.10 | 1/3/4 格式、数量、反推格式 | 计算间距与范围,而非只背 FP32 |
| 2022 第三大题 pp.11~13 | switch+结构体+链式间接寻址 | 表项、fall-through、字段偏移共同还原 |
| 2022 第四大题 pp.14~17 | 条件 pop 与流水线 | 条件失败时副作用、rsp 写回、冒险 |
| 2022 第五大题 pp.18~20 | 局部性与 cache | 明确写分配与替换更新 |
2012~2021 题型索引#
以下是对已提取文本的主题定位,属于选题导航,不是每题答案校验报告。
| 年份 | 值得挑选的题组(PDF 页) | 注意 |
|---|---|---|
| 2012 | 浮点 pp.4~5;排序/递归栈 pp.6~10;cache pp.11~12;链接 p.13 | 历史范围含链接,别推定本次也考 |
| 2013 | 表达式 p.5;机器代码 pp.6~9;流水线 p.10;新指令 p.11;cache p.13 | 有 32 位 Y86 语境 |
| 2014 | 数据表示 p.9;机器级/栈 pp.10~13;流水线 pp.14~17;cache p.18 | 部分 OCR 乱码,需直接看原页 |
| 2015 | 数据表示 pp.9~10;汇编/布局 pp.11~14;处理器 pp.15~18;cache pp.19~20 | 注意 IA-32 字长 |
| 2016 | 浮点/表达式 pp.6~8;机器代码 pp.9~11;PIPE pp.12~14;cache pp.15~16 | 延迟口径可能按题目另设 |
| 2017 | 数据表示 p.7;汇编 pp.8~9;处理器 pp.10~12;cache p.13 | 条件访存改变可用阶段 |
| 2018 | 位操作 pp.9~11;机器代码 pp.12~14;流水线 pp.15~17;cache pp.18~19;性能 pp.20~21 | 普通 char 的符号性要看假设 |
| 2019 | 整数/浮点 pp.8~9;机器代码与哨兵 pp.10~15;PIPE pp.16~18;victim cache pp.19~20;memory mountain pp.21~22 | 图题要看原图 |
| 2020 | 数据表示 pp.6~7;机器代码与栈 pp.8~11;leave/enter 新指令 pp.12~13;cache pp.14~16 | 失效时间是否包含命中探测有歧义 |
| 2021 | 数据表示 pp.11~12;递归栈 pp.13~16;处理器 pp.16~20;cache pp.21~23;优化 pp.24~26 | 周期数从 F 到 ret 完成,题设非常关键 |
全部原卷入口:期中目录。更早试卷不能用“同名题型”掩盖平台和标准差异。
应当明确区分的答案问题#
2025 第 3 题:“首字节”的歧义#
short -12 扩为 32 位 int 的位模式为 FFFFFFF4;小端内存从低到高为 F4 FF FF FF。原答案写 FF,只能与“最高有效字节”的解释一致。若按 show_bytes 从最低地址开始打印,第一个字节应为 F4。本手册保留这一判断依据,不把参考答案当作没有歧义的权威结论。
2024:建议处理与最终评分不是一回事#
2024 勘误文件 先列“建议”,最后另有“最终评分方式修改”。最终明确选择第 7 题 A/C、第 9 题 B/C 均算对;选择第 2 题以及 cache 第五题并没有按前文建议普遍改评分。阅读时应以最后的最终处理为准。
第 7 题的核心是结构体返回地址:调用时隐藏缓冲区指针可在 rdi,返回时在 rax;未交代时机就有歧义。第 9 题“转发次数”按通路事件还是按使用次数计数不明确,应写出口径。
cache 的特殊规则称“不缓存包含 10 倍数的块”,但示例答案仍缓存含地址 0 的块。数学上 0 也是 10 的倍数;按给定答案可推测意图是正的倍数。遇到此类自然语言规则应主动说明是否包含 0,而非把隐含约定当成通用规则。
2022 自定义浮点:“不溢出域内无舍入”与边界舍入#
1/3/4 格式最大有限值为 15.5,可精确表示整数 0~15;原题把 unsigned char 转换概括为“会溢出,不会舍入”。这里可理解为考察可表示范围内的整数均可精确编码;从完整 IEEE 转换过程看边界值仍需进行舍入并可能引发溢出,不宜把它泛化为所有转换都无需舍入逻辑。
同年 switch 题部分路径没有初始化 val 就写结构体,适合按给定汇编还原,不适合作为没有未定义行为的 C 编程范例。本手册的原理解释不依赖这些路径具有可移植结果。
参考笔记中需要纠正的说法#
| 容易误记的表述 | 本手册采用的准确版本 |
|---|---|
| sizeof(int*) 是 int 的大小 | sizeof(p) 是指针大小;sizeof(*p) 才是所指类型大小 |
| 数组名就是指针 | 数组是对象,很多表达式中发生退化;sizeof/& 等有例外 |
| TMin 不满足位级 ~x+1 取负 | 模 2ʷ 恒等式仍成立;数学正值不可表示,C 有符号取负溢出 |
| 复杂声明可以靠数星号理解 | 必须从变量名按括号和 []/() 优先级解析 |
| 缓存容量 C=S×B | 一般 C=S×E×B,仅 E=1 时可省 E |
| S、B、t 都必须为 2 的幂 | 通常 S、B 为 2 的幂;E 可非 2 的幂;t 是 tag 位数 |
| mov 的源/目的顺序可混写 | AT&T 源在前、目的在后 |
| movs 的 s 是 symbol | s 指 sign,符号扩展 |
| l 后缀是 linguist | l 指 longword;记忆法不能替代正式术语 |
这些结论来自位宽、类型和地址布局推导,并与教材/官方勘误交叉核对。引用仓库是为了补充题型和经验,不代表无条件认可所有笔记内容。
真题驱动的复习闭环#
做题时给每一空标一个错误类别:概念、类型、位宽、端序、地址/值、控制流、边界、计算。错后先写“错误前提是什么”,再找一个最小反例,最后做一题改变位宽或类型的变式。只有重做后能独立推出,才算真正掌握。
13 · 小班拓展、边角知识与作业路线
逐项归并本地第 2~7 讲研讨主题;本章保留课堂提出的开放讨论与术语,不把它们伪装成只有唯一标准答案的计算题。
第 2 讲:表示与整数#
研讨 1 的进制转换、位运算/逻辑运算、短路与移位见第 02 章。补充的设计问题:二进制容易用两种稳定物理状态表示,数字电路有噪声容限;十六进制是在不损失位边界的前提下缩短书写。8 位字节有历史、字符表示、寻址与硬件生态原因,不是数学上唯一最优方案。字更长能表示更大范围/地址,也提高存储、传输和硬件成本;嵌入式设备可采用不同取舍。
研讨 2 的原码/反码比较、补码取负证明、混合类型比较、扩展截断、三类加法溢出、常数乘法和大小端均见第 02 章。补码取负证明:w 位下 ~x=2^w-1-x,所以 ~x+1 ≡ -x (mod 2^w);其位向量意义对所有 x 成立。
设计自测:8 位用 DA 与 6F 做所有位运算;16 位用 0、1、-1、32767、-32768 做 B2U/B2T;用同一个 32 位常量画两种端序。要说清中间表达式是否先提升为 int。
第 3 讲:浮点的术语与设计#
| 术语 | 含义 |
|---|---|
| sign / s | 符号 |
| significand / M | 有效数;规格化形式含隐含前导 1 |
| exponent / E | 实际指数 |
| exp / e | 存储的阶码字段 |
| fraction / frac | 存储的小数位字段,不包含隐藏的 1 |
| MSB / LSB | 最高/最低有效位 |
| bias | 指数偏置 |
| equispaced | 等间距,非规格化区域相邻值差固定 |
| ULP | 给定格式与位置的最后一位单位 |
偏置编码让正的浮点数主要按指数再按小数有序排列;全 0、全 1 阶码留给特殊类别,配合隐藏位提高规格化精度。指数正负数量不完全对称是偏置、保留编码及边界选择共同的结果,不应仅解释成“正数比较重要”。
非规格化把零附近的断层补成均匀步长;正负零保留趋近方向等信息,同时让某些普通等式与位比较不能直接互换。无穷允许溢出或除零的结果继续传播,但不修复数值算法本身。NaN 让无效结果显式传播,其载荷含义不能跨平台随意假设。
阿贝尔群要求封闭性、结合律、单位元、逆元与交换律;浮点加法集合不能简单视为实数加法的阿贝尔群,因为舍入破坏结合律等条件。关于单调性,区分弱单调/严格单调,乘数的正负以及 NaN;详见第 03 章。
两个事故案例及应当学到什么#
Ariane 5 首飞失败的调查指出惯性参考软件中一次数值转换溢出及未妥善保护、复用假设不适用等问题;不要简单概括为“浮点精度不足导致爆炸”。Patriot 的历史事故与时间表示截断误差长期积累有关。复习价值在于单位、可表示范围、转换、误差随时间累积与异常处理,而不是背损失金额。参考 ESA 调查报告 与 美国 GAO 报告。
AI 格式的原理比较见第 03 章。常用格式与硬件生态不断变化,课上的开放调研应注明时间与具体设备,不能用一份不带日期的“主流排名”当永久知识点。
第 4 讲:硬件与指令拓展#
课件里的市场产品/主频/制程/核数是历史案例。看硬件参数时区分 ISA、实现、制造工艺命名、基准/睿频、核心/线程、功耗设计口径;制程标签不是每个晶体管某一长度的直接测量值,GHz 也不能跨微体系结构单独比较性能。
CPU 数据通路、C→目标文件、反汇编字段、寄存器局部写入、传送类型、寻址、LEA 和算逻指令见第 01/04 章。没有普通 memory-to-memory mov 是编码和指令设计约束,不意味着 x86 完全没有涉及两处内存的字符串操作。不能把“普通 mov 的操作数组合”扩大为整个 ISA 的定律。
实操可写一个小的 swap/算术函数,用 gcc -Og -S 比较汇编,再用 objdump 看指令字节。编译器、PIE、栈保护和优化级别不同都会影响结果;核心语义比和旧课件逐行完全一致更重要。
第 5 讲:控制流拓展#
CF/ZF/SF/OF、cmp/test 对照、set 返回、分支反转、cmov 不适用情形、三种循环转换与跳转表见第 05 章。cmov 的性能收益来自避免不可预测分支,而不是“少算了一边”;预测很准或一边特别昂贵时不一定有益。
POPCNT 支持要看目标机器与编译选项。分析 if-else 链最多跳转次数时必须给出具体编译形态,不能只数 C 的 if 个数;一次路径可能包含条件跳转和合流的无条件跳转。跳转表也是先做范围检查,不是免费一步覆盖所有输入。
第 6 讲:ABI 与递归拓展#
传递控制、数据、存储三条线以及调用者/被调用者保存规则见第 06 章。硬件规定 call 写返回地址,软件规定参数寄存器;Windows 与 Linux 的差异是 ABI,不是 CPU 在两种 OS 上换了一套基本 call 语义。
历史上某些语言实现不支持或限制递归,常与静态分配局部存储、运行时约束或语言设计有关;支持递归需要每次调用能保存独立活动记录,也可不用传统机器栈实现。递归不等于必须创建 OS 线程。
第 7 讲:数组、对齐与浮点拓展#
各种元素宽度的数组图、数组表达式、二维行优先、多级间接、VLA、结构体与混合参数见第 07 章。Fortran 常用列优先,C 用行优先;二维存储次序是语言/库约定,和 CPU 的大小端是两个不同维度。第三方数组库还可能使用视图和可变 stride。
Windows x64 采用 LLP64,long 与 Linux LP64 不同;结构体布局同时受类型大小、ABI、编译器扩展和 packing 控制。通过 sizeof/offsetof/_Alignof 核验,比从操作系统名字猜全部偏移可靠。
SIMD 是一条指令对多个数据元素做同类运算;标量 XMM 指令不因寄存器宽 128 位就自动处理四个 float。浮点地址仍由通用寄存器形成,数值计算在浮点寄存器进行。
指定教材作业:题号与应掌握的方法#
| 讲次 | 题号 | 方法目标 |
|---|---|---|
| 2 | 2.59、2.60、2.71 | 字节掩码组合、指定字节替换、符号扩展与移位 |
| 3 | 2.86、2.87、2.89 | 不同浮点格式、边界值、表达式恒等性 |
| 4 | 3.58、3.59 | 算逻数据流还原、双倍宽乘法 |
| 5 | 3.60、3.63 | 循环掩码、switch 跳转表与穿透 |
| 6 | 并入第 7 讲 | 过程调用规则 |
| 7 | 3.66、3.67、3.68 | 数组维度、聚合类型传参/返回、结构布局反推 |
只列题号与方法,不复刻教材完整题文。不同版次/国际版的题号可能不一致,作者官网也专门提醒国际版习题存在差异。以本地中文版作业单指定页面和题文为准。
最后一次边界检查清单#
- int/long/指针的宽度是否写清?普通 char 是否有符号?
- 小整数是否先提升?signed 与 unsigned 是否发生类型变化?
- 是否遇到 TMin、全 1、零、移位 0 或位宽、除以 -1?
- 浮点是否为 ±0、非规格化、∞、NaN、恰好中点、舍入进位?
- 汇编目的寄存器宽度是否匹配?32 位写是否清高位?
- 条件码是否已被中途改写?分支 signed/unsigned 是否选择正确?
- 地址与内存值是否分开?相对位移是否加到下一条指令?
- 返回地址、对齐、保存寄存器、递归深度是否逐条跟踪?
- 数组退化、函数形参、sizeof 不求值、VLA 是否区分?
- 结构体内部与末尾 padding、union 共享存储是否都算了?
- 旧题是否切换 IA-32/Y86-32?修改后的机器是否仍能套原公式?
14 · 课件覆盖索引与来源
这里保留全部现有课件的页码主题,包括附加材料。页题名由 PDF 文本抽取清理,少数无题页用内容起始行标识;它是回查索引,正文按知识主题合并重复例子。
覆盖情况#
| 来源 | 页数 | 对应章节 | 状态 |
|---|---|---|---|
| ICS01-overview-20260907.pdf | 50 | 01,相关补充见 13 | 已提取全部页面主题,按主题整理 |
| ICS02-bits-bytes-ints-20260910.pdf | 68 | 02,相关补充见 13 | 已提取全部页面主题,按主题整理 |
| ICS03-float-20260914.pdf | 48 | 03,相关补充见 13 | 已提取全部页面主题,按主题整理 |
| ICS04-machine-basics-20260917.pdf | 47 | 04,相关补充见 13 | 已提取全部页面主题,按主题整理 |
| ICS05-machine-control-20260921.pdf | 64 | 05,相关补充见 13 | 已提取全部页面主题,按主题整理 |
| ICS06-machine-procedures-20260924.pdf | 75 | 06,相关补充见 13 | 已提取全部页面主题,按主题整理 |
| ICS07-machine-data-20260928.pdf | 51 | 07,相关补充见 13 | 已提取全部页面主题,按主题整理 |
小班研讨题第 2~7 讲共 6 份、每份 2 页,已全文读取并归并到正文与第 13 章。教材扫描版仅提取前部信息作为版次参考,正文公式基于课件、CS:APP 通用原理及官方资料核对;没有宣称逐页阅读整本扫描教材。
第 8 讲课件未提供;该章标为教材/往年题补充。09~11 是旧期中扩展。历史题阅读深度见第 12 章。
逐页主题清单#
ICS01-overview-20260907#
| PDF 页 | 页内主题 / 内容起始 | 正文回查 |
|---|---|---|
| 1 | Course Overview 课程概述 · 1st Lecture, Sep 7, 2026 第一讲,2026年9月7日 | 01 |
| 2 | 主要内容 · ¢ 课程起源 | 01 |
| 3 | 课程起源 · ¢ 创立: | 01 |
| 4 | 合作建设课程 · 课程特点: | 01 |
| 5 | 小班教学的启动 · ¢ 2010-2011 学年,本科班级规模的初步统计 | 01 |
| 6 | 北京大学本科生“研讨型小班教学”试点 · ¢ 2012年秋开展第一批试点 | 01 |
| 7 | 主要内容 · ¢ 课程起源 | 01 |
| 8 | 本课程的教学方式 · ¢ 研讨型教学的两种主要方式 | 01 |
| 9 | 课程安排 · 周次 日期 大班课 主题 日期 小班课 日期 大班课 主题 LAB节点 | 01 |
| 10 | 大班课程安排 · ¢ 上半学期的主体内容 | 01 |
| 11 | 大班课程安排 · ¢ 下半学期的主体内容 | 01 |
| 12 | 课程特点: · 课时多,教学内容多 | 01 |
| 13 | 课程特点: · 大班教学和小班研讨结合 | 01 |
| 14 | 实验题系统 课程特点: · 学生在指定系统上完成实验题 | 01 |
| 15 | 主要内容 · ¢ 课程起源 | 01 |
| 16 | 本课程关注的问题和目标 · ¢ 本课程关注的问题: | 01 |
| 17 | 本课程独特的视角 · ¢ 本课程是从编程者角度出发,描述计算机系统 | 01 |
| 18 | 问题1:整型不是整数,浮点型不是实数 · Ints are not Integers, Floats are not Reals | 01 |
| 19 | 计算机系统中的算术 ≠ 数学中的算术(1/2) · ¢ 整数性质 | 01 |
| 20 | 计算机系统中的算术 ≠ 数学中的算术(2/2) · ¢ 有些性质在计算机系统中并不成立 | 01 |
| 21 | 问题2:了解汇编 (1/4) · You’ve Got to Know Assembly | 01 |
| 22 | 问题2:了解汇编 (2/4) · You’ve Got to Know Assembly | 01 |
| 23 | 问题2:了解汇编 (3/4) · You’ve Got to Know Assembly | 01 |
| 24 | 问题2:了解汇编 (4/4) · You’ve Got to Know Assembly | 01 |
| 25 | 问题3:内存对程序性能的影响至关重要 · Memory Matters Random Access Memory Is | 01 |
| 26 | 内存引用错误 (1/3) · typedef struct { | 01 |
| 27 | 内存引用错误 (2/3) · typedef struct { fun(0) à 3.14 | 01 |
| 28 | 内存引用错误 (3/3) · ¢ C 和 C++ 并没有提供对此类错误的防范机制, | 01 |
| 29 | 问题4:算法性能分析结果 ≠ 实际程序性能 · There’s more to performance than asymptotic | 01 |
| 30 | 内存性能影响程序性能 · void copyij (int src[2048][2048], void copyji (int src[2048][2048], | 01 |
| 31 | 为什么性能有这些差别 · copyij | 01 |
| 32 | 问题5:计算机网络环境下的新问题 · Computers do more than execute programs | 01 |
| 33 | 问题5:计算机网络环境下的新问题 · Computers do more than execute programs | 01 |
| 34 | 主要内容 · ¢ 课程起源 | 01 |
| 35 | 课程主体内容 · ① 程序与数据 Programs and Data | 01 |
| 36 | 一、程序与数据 · Programs and Data (1/2) | 01 |
| 37 | 一、程序与数据 · Programs and Data (2/2) | 01 |
| 38 | 二、处理器体系结构 和 程序性能 · Processor Architecture & Performance | 01 |
| 39 | 三、分级存储器体系 · The Memory Hierarchy | 01 |
| 40 | 四、异常控制流 · Exceptional Control Flow | 01 |
| 41 | 五、虚拟内存 · Virtual Memory | 01 |
| 42 | 六、网络和并发 · Networking, and Concurrency | 01 |
| 43 | 实验题(LAB) · L1 Datalab 位级数据操作实验 | 01 |
| 44 | 每个实验必须独立完成(不得由AI代做) · ¢ 每次LAB都有可能抽查代码重合度,对比对象包 | 01 |
| 45 | 主要内容 · ¢ 课程起源 | 01 |
| 46 | 课程主页 http://course.pku.edu.cn · 课程通知,课后作业等 | 01 |
| 47 | 课程教材 · ¢ Computer Systems: A Programmer's Perspective(3rd Edition) | 01 |
| 48 | 成绩评定占比 · ¢ 期末考试:30分 | 01 |
| 49 | 需要注意的问题 · Q:为什么教学网的小班和安排的不一致? | 01 |
| 50 | 页脚 / 结束页 | 01 |
ICS02-bits-bytes-ints-20260910#
| PDF 页 | 页内主题 / 内容起始 | 正文回查 |
|---|---|---|
| 1 | Bits, Bytes, and Integers · 2nd Lecture, Sep 10, 2026 | 02 |
| 2 | Today: Bits, Bytes, and Integers · ¢ Representing information as bits | 02 |
| 3 | Binary Representations · ¢ Base 2 Number Representation | 02 |
| 4 | Encoding Byte Values · al y | 02 |
| 5 | Data Representations · C Data Type Typical 32-bit Intel IA32 x86-64 | 02 |
| 6 | Today: Bits, Bytes, and Integers · ¢ Representing information as bits | 02 |
| 7 | Boolean Algebra · ¢ Developed by George Boole in 19th Century | 02 |
| 8 | General Boolean Algebras · ¢ Operate on Bit Vectors | 02 |
| 9 | Example: Representing & Manipulating Sets · ¢ Representation | 02 |
| 10 | Bit-Level Operations in C · ¢ Operations &, /, ~, ^ Available in C | 02 |
| 11 | Contrast: Logic Operations in C · ¢ Contrast to Logical Operators | 02 |
| 12 | Shift Operations · ¢ Left Shift: x << y Argument x 01100010 | 02 |
| 13 | Today: Bits, Bytes, and Integers · ¢ Representing information as bits | 02 |
| 14 | Encoding Integers · Unsigned Two’s Complement | 02 |
| 15 | Two-complement: Simple Example · -16 8 4 2 1 | 02 |
| 16 | Encoding Example (Cont.) · x = 15213: 00111011 01101101 | 02 |
| 17 | Numeric Ranges · ¢ Unsigned Values | 02 |
| 18 | Values for Different Word Sizes · W | 02 |
| 19 | Unsigned & Signed Numeric Values · X B2U(X) B2T(X) ¢ Equivalence | 02 |
| 20 | Today: Bits, Bytes, and Integers · ¢ Representing information as bits | 02 |
| 21 | Mapping Between Signed & Unsigned · Two’s Complement Unsigned | 02 |
| 22 | Mapping Signed « Unsigned · Bits Signed Unsigned | 02 |
| 23 | Mapping Signed « Unsigned · Bits Signed Unsigned | 02 |
| 24 | Relation between Signed & Unsigned · Two’s Complement Unsigned | 02 |
| 25 | Conversion Visualized · ¢ 2’s Comp. ® Unsigned | 02 |
| 26 | Signed vs. Unsigned in C · ¢ Constants | 02 |
| 27 | Casting Surprises · ¢ Expression Evaluation | 02 |
| 28 | Summary · Casting Signed ↔ Unsigned: Basic Rules | 02 |
| 29 | Today: Bits, Bytes, and Integers · ¢ Representing information as bits | 02 |
| 30 | Sign Extension · ¢ Task: | 02 |
| 31 | Sign Extension: Simple Example · Positive number Negative number | 02 |
| 32 | Sign Extension Example · short int x = 15213; | 02 |
| 33 | Truncation: Simple Example · No sign change Sign change | 02 |
| 34 | Summary: · Expanding, Truncating: Basic Rules | 02 |
| 35 | Today: Bits, Bytes, and Integers · ¢ Representing information as bits | 02 |
| 36 | Unsigned Addition · Operands: w bits u ••• | 02 |
| 37 | Unsigned Addition · Operands: w bits u ••• | 02 |
| 38 | Visualizing (Mathematical) Integer Addition · ¢ Integer Addition Add4(u , v) | 02 |
| 39 | Visualizing Unsigned Addition · ¢ Wraps Around Overflow | 02 |
| 40 | Two’s Complement Addition · Operands: w bits u ••• | 02 |
| 41 | TAdd Overflow · ¢ Functionality True Sum | 02 |
| 42 | Visualizing 2’s Complement Addition · NegOver | 02 |
| 43 | Characterizing TAdd · Positive Overflow | 02 |
| 44 | Multiplication · ¢ Goal: Computing Product of w-bit numbers x, y | 02 |
| 45 | Unsigned Multiplication in C · u ••• | 02 |
| 46 | Signed Multiplication in C · u ••• | 02 |
| 47 | Power-of-2 Multiply with Shift · ¢ Operation | 02 |
| 48 | Unsigned Power-of-2 Divide with Shift · ¢ Quotient of Unsigned by Power of 2 | 02 |
| 49 | Today: Bits, Bytes, and Integers · ¢ Representing information as bits | 02 |
| 50 | Arithmetic: Basic Rules · ¢ Addition: | 02 |
| 51 | Why Should I Use Unsigned? · ¢ Don’t use without understanding implications | 02 |
| 52 | Counting Down with Unsigned · ¢ Proper way to use unsigned as loop index | 02 |
| 53 | Why Should I Use Unsigned? (cont.) · ¢ Do Use When Performing Modular Arithmetic | 02 |
| 54 | Today: Bits, Bytes, and Integers · ¢ Representing information as bits | 02 |
| 55 | Byte-Oriented Memory Organization · •0 •F | 02 |
| 56 | Machine Words · ¢ Any given computer has a “Word Size” | 02 |
| 57 | Word-Oriented Memory Organization · 32-bit 64-bit | 02 |
| 58 | Example Data Representations · C Data Type Typical 32-bit Typical 64-bit x86-64 | 02 |
| 59 | Byte Ordering · ¢ So, how are the bytes within a multi-byte word ordered in | 02 |
| 60 | Byte Ordering Example · ¢ Example | 02 |
| 61 | Decimal: 15213 · Representing Integers Binary: 0011 1011 0110 1101 | 02 |
| 62 | Examining Data Representations · ¢ Code to Print Byte Representation of Data | 02 |
| 63 | show_bytes Execution Example · int a = 15213; | 02 |
| 64 | Representing Pointers · int B = -15213; | 02 |
| 65 | Representing Strings · char S[6] = "18213"; | 02 |
| 66 | Reading Byte-Reversed Listings · ¢ Disassembly | 02 |
| 67 | Summary · ¢ Representing information as bits | 02 |
| 68 | Integer C Puzzles · x < 0 Þ ((x*2) < 0) | 02 |
ICS03-float-20260914#
| PDF 页 | 页内主题 / 内容起始 | 正文回查 |
|---|---|---|
| 1 | Floating Point · 3rd Lecture, Sep. 14, 2026 | 03 |
| 2 | Today: Floating Point · ¢ Background: Fractional binary numbers | 03 |
| 3 | Fractional binary numbers · ¢ What is 1011.1012? | 03 |
| 4 | Fractional Binary Numbers · 2i | 03 |
| 5 | Fractional Binary Numbers: Examples · ¢ Value Representation | 03 |
| 6 | Representable Numbers · ¢ Limitation #1 | 03 |
| 7 | Today: Floating Point · ¢ Background: Fractional binary numbers | 03 |
| 8 | IEEE Floating Point · ¢ IEEE Standard 754 | 03 |
| 9 | This is important! · ¢ Ariane 5 explodes on maiden voyage: $500 MILLION dollars lost | 03 |
| 10 | (Binary) Scientific Notation · ¢ What are the parts of a number in scientific notation? | 03 |
| 11 | Floating Point Representation · Example: | 03 |
| 12 | Precision options · ¢ Single precision: 32 bits | 03 |
| 13 | Three “kinds” of floating point numbers · s exp frac | 03 |
| 14 | “Normalized” Values v = (–1)s M 2E · ¢ When: exp ≠ 000…0 and exp ≠ 111…1 | 03 |
| 15 | Normalized Encoding Example v = (–1)s M 2E · E = Exp – Bias | 03 |
| 16 | Denormalized Values v = (–1)s M 2E · E = 1 – Bias | 03 |
| 17 | Special Values · ¢ Condition: exp = 111…1 | 03 |
| 18 | C float Decoding Example v = (–1)s M 2E · E = exp – Bias | 03 |
| 19 | C float Decoding Example #1 v = (–1)s M 2E · E = exp – Bias | 03 |
| 20 | C float Decoding Example #1 v = (–1)s M 2E · E = exp – Bias | 03 |
| 21 | C float Decoding Example #2 v = (–1)s M 2E · E = 1 – Bias | 03 |
| 22 | C float Decoding Example #2 v = (–1)s M 2E · E = 1 – Bias | 03 |
| 23 | Visualization: Floating Point Encodings · −¥ +¥ | 03 |
| 24 | Today: Floating Point · ¢ Background: Fractional binary numbers | 03 |
| 25 | Tiny Floating Point Example · s exp frac | 03 |
| 26 | v = (–1)s M 2E · Dynamic Range (s=0 only) norm: E = exp – Bias | 03 |
| 27 | Distribution of Values · ¢ 6-bit IEEE-like format | 03 |
| 28 | Distribution of Values (close-up view) · ¢ 6-bit IEEE-like format | 03 |
| 29 | Special Properties of the IEEE Encoding · ¢ FP Zero Same as Integer Zero | 03 |
| 30 | Today: Floating Point · ¢ Background: Fractional binary numbers | 03 |
| 31 | Floating Point Operations: Basic Idea · ¢ x +f y = Round(x + y) | 03 |
| 32 | Rounding · ¢ Rounding Modes (illustrate with $ rounding) | 03 |
| 33 | Closer Look at Round-To-Even · ¢ Default Rounding Mode | 03 |
| 34 | Rounding Binary Numbers · ¢ Binary Fractional Numbers | 03 |
| 35 | FP Multiplication · ¢ (–1)s1 M1 2E1 x (–1)s2 M2 2E2 | 03 |
| 36 | Floating Point Addition · ¢ (–1)s1 M1 2E1 + (-1)s2 M2 2E2 | 03 |
| 37 | Mathematical Properties of FP Add · ¢ Compare to those of Abelian Group | 03 |
| 38 | Mathematical Properties of FP Mult · ¢ Compare to Commutative Ring | 03 |
| 39 | Today: Floating Point · ¢ Background: Fractional binary numbers | 03 |
| 40 | Floating Point in C · ¢ C Guarantees Two Levels | 03 |
| 41 | Floating Point Puzzles · ¢ For each of the following C expressions, either: | 03 |
| 42 | Summary · ¢ IEEE Floating Point has clear mathematical properties | 03 |
| 43 | Additional Slides | 03 |
| 44 | Creating Floating Point Number · ¢ Steps s exp frac | 03 |
| 45 | Normalize s exp frac · 1 4-bits 3-bits | 03 |
| 46 | Rounding 1.BBGRXXX · Guard bit: LSB of result | 03 |
| 47 | Postnormalize · ¢ Issue | 03 |
| 48 | Interesting Numbers {single,double} · Description exp frac Numeric Value | 03 |
ICS04-machine-basics-20260917#
| PDF 页 | 页内主题 / 内容起始 | 正文回查 |
|---|---|---|
| 1 | Machine-Level Programming I: Basics · 4th Lecture, Sep. 17, 2026 | 04 |
| 2 | Today: Machine Programming I: Basics · ¢ History of Intel processors and architectures | 04 |
| 3 | Intel x86 Processors · ¢ Dominate laptop/desktop/server market | 04 |
| 4 | Intel x86 Evolution: Milestones · Name Date Transistors MHz | 04 |
| 5 | Intel x86 Processors, cont. · ¢ Machine Evolution | 04 |
| 6 | Intel x86 Processors, cont. · ¢ Past Generations Process technology | 04 |
| 7 | 2018 State of the Art: Coffee Lake · ¢ Mobile Model: Core i7 ¢ Server Model: Xeon E | 04 |
| 8 | x86 Clones: Advanced Micro Devices (AMD) · ¢ Historically | 04 |
| 9 | Intel’s 64-Bit History · ¢ 2001: Intel Attempts Radical Shift from IA32 to IA64 | 04 |
| 10 | Our Coverage · ¢ IA32 | 04 |
| 11 | Today: Machine Programming I: Basics · ¢ History of Intel processors and architectures | 04 |
| 12 | Definitions · ¢ Architecture: (also ISA: instruction set architecture) The | 04 |
| 13 | Assembly/Machine Code View · CPU Memory | 04 |
| 14 | Turning C into Object Code · § Code in files p1.c p2.c | 04 |
| 15 | Compiling Into Assembly · C Code (sum.c) Generated x86-64 Assembly | 04 |
| 16 | What it really looks like · .globl sumstore | 04 |
| 17 | What it really looks like · .globl sumstore | 04 |
| 18 | Assembly Characteristics: Data Types · ¢ “Integer” data of 1, 2, 4, or 8 bytes | 04 |
| 19 | Assembly Characteristics: Operations · ¢ Transfer data between memory and register | 04 |
| 20 | Object Code · Code for sumstore | 04 |
| 21 | Machine Instruction Example · ¢ C Code | 04 |
| 22 | Disassembling Object Code · Disassembled | 04 |
| 23 | Alternate Disassembly · Disassembled | 04 |
| 24 | What Can be Disassembled? · % objdump -d WINWORD.EXE | 04 |
| 25 | Today: Machine Programming I: Basics · ¢ History of Intel processors and architectures | 04 |
| 26 | x86-64 Integer Registers · %rax %eax %r8 %r8d | 04 |
| 27 | Some History: IA32 Registers Origin · (mostly obsolete) | 04 |
| 28 | Moving Data %rax · ¢ Moving Data %rcx | 04 |
| 29 | movq Operand Combinations · Source Dest Src,Dest C Analog | 04 |
| 30 | Simple Memory Addressing Modes · ¢ Normal (R) Mem[Reg[R]] | 04 |
| 31 | Example of Simple Addressing Modes · void swap | 04 |
| 32 | Understanding Swap() · Memory | 04 |
| 33 | Understanding Swap() · Memory | 04 |
| 34 | Understanding Swap() · Memory | 04 |
| 35 | Understanding Swap() · Memory | 04 |
| 36 | Understanding Swap() · Memory | 04 |
| 37 | Understanding Swap() · Memory | 04 |
| 38 | Simple Memory Addressing Modes · ¢ Normal (R) Mem[Reg[R]] | 04 |
| 39 | Complete Memory Addressing Modes · ¢ Most General Form | 04 |
| 40 | Address Computation Examples · %rdx 0xf000 | 04 |
| 41 | Today: Machine Programming I: Basics · ¢ History of Intel processors and architectures | 04 |
| 42 | Address Computation Instruction · ¢ leaq Src, Dst | 04 |
| 43 | Some Arithmetic Operations · ¢ Two Operand Instructions: | 04 |
| 44 | Some Arithmetic Operations · ¢ One Operand Instructions | 04 |
| 45 | Arithmetic Expression Example · arith: | 04 |
| 46 | Understanding Arithmetic Expression · Example arith: | 04 |
| 47 | Machine Programming I: Summary · ¢ History of Intel processors and architectures | 04 |
ICS05-machine-control-20260921#
| PDF 页 | 页内主题 / 内容起始 | 正文回查 |
|---|---|---|
| 1 | Machine-Level Programming II: Control · 5th Lecture, Sep. 21, 2026 | 05 |
| 2 | Recall: ISA = Assembly/Machine Code View · CPU Memory | 05 |
| 3 | Recall: Turning C into Object Code · § Code in files p1.c p2.c | 05 |
| 4 | Recall: Move & Arithmetic Operations · ¢ Some Two Operand Instructions: | 05 |
| 5 | Recall: Addressing Modes · ¢ Most General Form | 05 |
| 6 | Memory operands and LEA · ¢ In most instructions, a memory operand accesses memory | 05 |
| 7 | Why use LEA? · ¢ CPU designers’ intended use: calculate a pointer to an object | 05 |
| 8 | Sidebar: instruction suffixes · ¢ Most x86 instructions can be written with or without a | 05 |
| 9 | Today · ¢ Control: Condition codes | 05 |
| 10 | Control flow · extern void op1(void); | 05 |
| 11 | Control flow in assembly language · extern void op1(void); decision: | 05 |
| 12 | Control flow in assembly language · extern void op1(void); decision: | 05 |
| 13 | Processor State (x86-64, Partial) · ¢ Information about | 05 |
| 14 | Condition Codes (Implicit Setting) · ¢ Single bit registers | 05 |
| 15 | ZF set when · 000000000000…00000000000 | 05 |
| 16 | SF set when · yxxxxxxxxxxxx... | 05 |
| 17 | CF set when · 1xxxxxxxxxxxx... | 05 |
| 18 | OF set when · yxxxxxxxxxxxx... a | 05 |
| 19 | Condition Codes (Explicit Setting: Compare) · ¢ Explicit Setting by Compare Instruction | 05 |
| 20 | Condition Codes (Explicit Setting: Test) · ¢ Explicit Setting by Test instruction | 05 |
| 21 | Reading Condition Codes · ¢ SetX Instructions | 05 |
| 22 | Example: setl (Signed <) · ¢ Condition: SF^OF | 05 |
| 23 | x86-64 Integer Registers · %rax %al %r8 %r8b | 05 |
| 24 | Reading Condition Codes (Cont.) · ¢ SetX Instructions: | 05 |
| 25 | Explicit Reading Condition Codes (Cont.) · SetX Instructions: | 05 |
| 26 | Today · ¢ Control: Condition codes | 05 |
| 27 | Jumping · ¢ jX Instructions | 05 |
| 28 | Conditional Branch Example (Old Style) · ¢ Generation Get to this shortly | 05 |
| 29 | Expressing with Goto Code · ¢ C allows goto statement | 05 |
| 30 | General Conditional Expression · Translation (Using Branches) | 05 |
| 31 | Using Conditional Moves · ¢ Conditional Move Instructions | 05 |
| 32 | Conditional Move Example · long absdiff | 05 |
| 33 | Bad Cases for Conditional Move · Expensive Computations | 05 |
| 34 | Exercise · SetX Condition Description | 05 |
| 35 | Exercise · SetX Condition Description | 05 |
| 36 | Today · ¢ Control: Condition codes | 05 |
| 37 | “Do-While” Loop Example · C Code Goto Version | 05 |
| 38 | General “Do-While” Translation · C Code Goto Version | 05 |
| 39 | “Do-While” Loop Compilation · Goto Version | 05 |
| 40 | General “While” Translation #1 · ¢ “Jump-to-middle” translation | 05 |
| 41 | While Loop Example #1 · C Code Jump to Middle | 05 |
| 42 | General “While” Translation #2 · While version | 05 |
| 43 | While Loop Example #2 · C Code Do-While Version | 05 |
| 44 | “For” Loop Form Init · General Form i = 0 | 05 |
| 45 | “For” Loop à While Loop · For Version | 05 |
| 46 | For-While Conversion · long pcount_for_while | 05 |
| 47 | “For” Loop Do-While Conversion · Goto Version | 05 |
| 48 | Today · ¢ Control: Condition codes | 05 |
| 49 | long switch_eg · (long x, long y, long z) Switch Statement | 05 |
| 50 | Jump Table Structure · Switch Form Jump Table Jump Targets | 05 |
| 51 | Switch Statement Example · long switch_eg(long x, long y, long z) | 05 |
| 52 | Switch Statement Example · long switch_eg(long x, long y, long z) | 05 |
| 53 | Assembly Setup Explanation · ¢ Table Structure Jump table | 05 |
| 54 | Jump Table · Jump table | 05 |
| 55 | Code Blocks (x == 1) · switch(x) { .L3: | 05 |
| 56 | Handling Fall-Through · long w = 1; | 05 |
| 57 | Code Blocks (x == 2, x == 3) · .L5: # Case 2 | 05 |
| 58 | Code Blocks (x == 5, x == 6, default) · switch(x) { .L7: # Case 5,6 | 05 |
| 59 | Summarizing · ¢ C Control | 05 |
| 60 | Summary · ¢ Today | 05 |
| 61 | Additional Slides | 05 |
| 62 | Finding Jump Table in Binary · 00000000004005e0 <switch_eg>: | 05 |
| 63 | Finding Jump Table in Binary (cont.) · 00000000004005e0 <switch_eg>: | 05 |
| 64 | Finding Jump Table in Binary (cont.) · % gdb switch | 05 |
ICS06-machine-procedures-20260924#
| PDF 页 | 页内主题 / 内容起始 | 正文回查 |
|---|---|---|
| 1 | Machine-Level Programming III: · Procedures | 06 |
| 2 | Objectives · ¢ Basic functionality of the pairs: push / pop and call / ret | 06 |
| 3 | Today · ¢ Procedures | 06 |
| 4 | Mechanisms in Procedures · P(…) { | 06 |
| 5 | Mechanisms in Procedures · P(…) { | 06 |
| 6 | Mechanisms in Procedures · P(…) { | 06 |
| 7 | Mechanisms in Procedures · P(…) { | 06 |
| 8 | Mechanisms in Procedures · P(…) { | 06 |
| 9 | Today · ¢ Procedures | 06 |
| 10 | x86-64 Stack · ¢ Region of memory managed | 06 |
| 11 | x86-64 Stack · ¢ Region of memory Stack “Bottom” | 06 |
| 12 | x86-64 Stack · ¢ Region of memory managed | 06 |
| 13 | x86-64 Stack: Push · ¢ pushq Src | 06 |
| 14 | x86-64 Stack: Push · ¢ pushq Src | 06 |
| 15 | x86-64 Stack: Pop · ¢ popq Dest Stack “Bottom” | 06 |
| 16 | x86-64 Stack: Pop · ¢ popq Dest Stack “Bottom” | 06 |
| 17 | x86-64 Stack: Pop · ¢ popq Dest Stack “Bottom” | 06 |
| 18 | Today · ¢ Procedures | 06 |
| 19 | void multstore · (long x, long y, long *dest) Code Examples | 06 |
| 20 | Procedure Control Flow · ¢ Use stack to support procedure call and return | 06 |
| 21 | Control Flow Example #1 • · 0000000000400540 <multstore>: | 06 |
| 22 | Control Flow Example #2 • · 0000000000400540 <multstore>: | 06 |
| 23 | Control Flow Example #3 • · 0000000000400540 <multstore>: | 06 |
| 24 | Control Flow Example #4 • · 0000000000400540 <multstore>: | 06 |
| 25 | Today · ¢ Procedures | 06 |
| 26 | Procedure Data Flow · Registers Stack | 06 |
| 27 | void multstore · Data Flow (long x, long y, long *dest) | 06 |
| 28 | Today · ¢ Procedures | 06 |
| 29 | Stack-Based Languages · ¢ Languages that support recursion | 06 |
| 30 | Call Chain Example · Example | 06 |
| 31 | Stack Frames Previous · Frame | 06 |
| 32 | Stack · Example | 06 |
| 33 | Stack · Example | 06 |
| 34 | Stack · Example | 06 |
| 35 | Stack · Example | 06 |
| 36 | Stack · Example | 06 |
| 37 | Stack · Example | 06 |
| 38 | Stack · Example | 06 |
| 39 | Stack · Example | 06 |
| 40 | Stack · Example | 06 |
| 41 | Stack · Example | 06 |
| 42 | Stack · Example | 06 |
| 43 | x86-64/Linux Stack Frame · ¢ Current Stack Frame (“Top” to | 06 |
| 44 | Example: incr · long incr(long *p, long val) { | 06 |
| 45 | Example: Calling incr #1 · Initial Stack Structure | 06 |
| 46 | Example: Calling incr #2 · Stack Structure | 06 |
| 47 | Example: Calling incr #2 · Stack Structure | 06 |
| 48 | Example: Calling incr #2 · Stack Structure | 06 |
| 49 | Example: Calling incr #3a Stack Structure · long call_incr() { | 06 |
| 50 | Example: Calling incr #3b Stack Structure · long call_incr() { | 06 |
| 51 | Example: Calling incr #4 Stack Structure · long call_incr() { | 06 |
| 52 | Example: Calling incr #5a Stack Structure · long call_incr() { | 06 |
| 53 | Example: Calling incr #5b · long call_incr() { Updated Stack Structure | 06 |
| 54 | Register Saving Conventions · ¢ When procedure yoo calls who: | 06 |
| 55 | Register Saving Conventions · ¢ When procedure yoo calls who: | 06 |
| 56 | x86-64 Linux Register Usage #1 · ¢ %rax Return value %rax | 06 |
| 57 | x86-64 Linux Register Usage #2 · ¢ %rbx, %r12, %r13, %r14 %rbx | 06 |
| 58 | Callee-Saved Example #1 · Initial Stack Structure | 06 |
| 59 | Callee-Saved Example #2 · Initial Stack Structure | 06 |
| 60 | Callee-Saved Example #3 · Initial Stack Structure | 06 |
| 61 | Callee-Saved Example #4 Stack Structure · long call_incr2(long x) { | 06 |
| 62 | Callee-Saved Example #5 Stack Structure · long call_incr2(long x) { | 06 |
| 63 | Callee-Saved Example #6 Stack Structure · long call_incr2(long x) { | 06 |
| 64 | Callee-Saved Example #7 Stack Structure · long call_incr2(long x) { | 06 |
| 65 | Callee-Saved Example #8 Initial Stack Structure · long call_incr2(long x) { | 06 |
| 66 | Today · ¢ Procedures | 06 |
| 67 | Recursive Function pcount_r: · movl $0, %eax | 06 |
| 68 | Recursive Function Terminal Case · /* Recursive popcount */ pcount_r: | 06 |
| 69 | Recursive Function Register Save · pcount_r: | 06 |
| 70 | Recursive Function Call Setup · /* Recursive popcount */ pcount_r: | 06 |
| 71 | Recursive Function Call · /* Recursive popcount */ pcount_r: | 06 |
| 72 | Recursive Function Result · /* Recursive popcount */ pcount_r: | 06 |
| 73 | Recursive Function Completion · pcount_r: | 06 |
| 74 | Observations About Recursion · ¢ Handled Without Special Consideration | 06 |
| 75 | x86-64 Procedure Summary · ¢ Important Points | 06 |
ICS07-machine-data-20260928#
| PDF 页 | 页内主题 / 内容起始 | 正文回查 |
|---|---|---|
| 1 | Machine-Level Programming IV: · Data | 07 |
| 2 | Today · ¢ Arrays | 07 |
| 3 | Array Allocation · ¢ Basic Principle | 07 |
| 4 | Array Access · ¢ Basic Principle | 07 |
| 5 | Array Access · ¢ Basic Principle | 07 |
| 6 | Array Access · ¢ Basic Principle | 07 |
| 7 | Array Example · #define ZLEN 5 | 07 |
| 8 | Array Accessing Example · zip_dig cmu; 1 5 2 1 3 | 07 |
| 9 | Array Loop Example · void zincr(zip_dig z) { | 07 |
| 10 | Multidimensional (Nested) Arrays · ¢ Declaration A[0][0] • • • A[0][C-1] | 07 |
| 11 | Nested Array Example · #define PCOUNT 4 | 07 |
| 12 | Nested Array Row Access · ¢ Row Vectors | 07 |
| 13 | Nested Array Row Access Code · 1 5 2 0 6 1 5 2 1 3 1 5 2 1 7 1 5 2 2 1 | 07 |
| 14 | Nested Array Element Access · ¢ Array Elements | 07 |
| 15 | Nested Array Element Access Code · 1 5 2 0 6 1 5 2 1 3 1 5 2 1 7 1 5 2 2 1 | 07 |
| 16 | Multi-Level Array Example · zip_dig cmu = { 1, 5, 2, 1, 3 }; ¢ Variable univ denotes | 07 |
| 17 | Element Access in Multi-Level Array · int get_univ_digit | 07 |
| 18 | Array Element Accesses · Nested array Multi-level array | 07 |
| 19 | N X N Matrix #define N 16 · typedef int fix_matrix[N][N]; | 07 |
| 20 | 16 X 16 Matrix Access · ¢ Array Elements | 07 |
| 21 | n X n Matrix Access · ¢ Array Elements | 07 |
| 22 | Example: Array Access · #include <stdio.h> | 07 |
| 23 | Example: Array Access · #include <stdio.h> | 07 |
| 24 | Today · ¢ Arrays | 07 |
| 25 | Structure Representation · r | 07 |
| 26 | Generating Pointer to Structure Member · r r+4*idx | 07 |
| 27 | struct rec { · Following Linked List int a[4]; | 07 |
| 28 | Structures & Alignment · ¢ Unaligned Data struct S1 { | 07 |
| 29 | Alignment Principles · ¢ Aligned Data | 07 |
| 30 | Specific Cases of Alignment (x86-64) · ¢ 1 byte: char, … | 07 |
| 31 | Satisfying Alignment with Structures · ¢ Within structure: struct S1 { | 07 |
| 32 | Meeting Overall Alignment Requirement · ¢ For largest alignment requirement K struct S2 { | 07 |
| 33 | Arrays of Structures · struct S2 { | 07 |
| 34 | Accessing Array Elements struct S3 { · short i; | 07 |
| 35 | Saving Space · ¢ Put large data types first | 07 |
| 36 | Today · ¢ Arrays | 07 |
| 37 | Background · ¢ History | 07 |
| 38 | Programming with SSE3 · XMM Registers | 07 |
| 39 | Scalar & SIMD Operations · n Scalar Operations: Single Precision addss %xmm0,%xmm1 | 07 |
| 40 | FP Basics · ¢ Arguments passed in %xmm0, %xmm1, ... | 07 |
| 41 | FP Memory Referencing · ¢ Integer (and pointer) arguments passed in regular registers | 07 |
| 42 | Other Aspects of FP Code · ¢ Lots of instructions | 07 |
| 43 | Summary · ¢ Arrays | 07 |
| 44 | Additional Slides | 07 |
| 45 | Understanding Pointers & Arrays #1 · Decl An *An | 07 |
| 46 | Understanding Pointers & Arrays #1 · Decl An *An | 07 |
| 47 | Understanding Pointers & Arrays #2 · Decl An *An **An | 07 |
| 48 | Understanding Pointers & Arrays #2 · Decl An *An **An | 07 |
| 49 | Understanding Pointers & Arrays #3 · Decl An *An **An | 07 |
| 50 | Allocated pointer Declaration · Allocated pointer to unallocated int | 07 |
| 51 | Understanding Pointers & Arrays #3 · Decl An *An **An | 07 |
可核对的外部来源#
- 指定 GitHub 仓库:公开试卷、2024 勘误、复习细节。作者也提醒笔记可能有错误,本手册已单列纠正。
- CS:APP 第 3 版官方勘误:用于核对移位、扩展等细节;可继续到其中文版勘误链接。
- Intel 官方手册:指令的最终机器语义参考。
- System V AMD64 ABI 项目:Linux x86-64 调用与类型布局参考。
- Microsoft x64 ABI:Windows 对比。
使用与维护#
知识点使用原创表述与重新推导的例子;题目仅给出处、题号、页码与解法导向。网站没有发布扫描教材和课堂 PDF。更新时优先补新的课件,再更新正文和此清单;考试政策以教师最新通知为准。
已知限制#
- 尚缺第 8 讲课件以及当前考试最终通知。
- 2014 旧卷存在 OCR 乱码,精确作答应看原始 PDF。
- 早年卷仅完成题型浏览,没有对所有标准答案做独立验算。
- 部分开放调研(如最新 CPU 产品排行)不属于稳定知识,这里解释比较方法而不编造当前市场表。
- 课堂口头补充不在本地文件中,未纳入“已覆盖”的承诺。