复习范围与使用说明
这份手册以 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 真题与勘误 | 2025 阶段卷逐题导航、范围内例题与答案辨析 | 仅保留第 1~8 讲相关题型 |
| 10 小班与边角知识 | 研讨拓展、教材作业题号、易遗漏概念 | 覆盖现有第 2~7 讲研讨主题 |
| 11 覆盖索引 | 课件逐页主题清单、来源、核对边界 | 用于查漏,不等于每页逐字复刻 |
**完整性的边界:**本手册不是只列“重点”的速记表,但也不复制课件、教材或试卷全文。每种知识类型配有解释与代表例子,原题中的每个不同数值、课堂口头补充和未提供的第 8 讲资料不可能凭空补齐。历史试卷范围随年份变化,例如 2012 期中还出现链接内容,不应据此扩大 2026 第一次阶段测验范围。
读题前的四项约定#
- 先写位宽与类型。
int和long、无符号和有符号、C 表达式和机器指令的规则不同。 - **先区分值、位模式与字节顺序。**数值转换改变表示;按位重解释保留位串;大小端只规定多字节对象的字节排列。
- **机器级模型与 C 标准分开。**补码加法器会截断,但 C 有符号溢出不是可移植的“自动回绕”;负有符号数右移在本课程环境按算术右移分析。
- **先读题设再套模板。**浮点格式、字长、端序和调用约定可能被题目修改,分析时以题设为准。
建议的复习顺序#
第一遍依次读 02~08,遇到公式手工算一个例子;第二遍做 2025 第一次阶段测验,按第 09 章回查弱项;第三遍用第 10、11 章查遗漏。资料范围限定在第 1~8 讲及对应小班内容。
掌握的标准不是“看着懂”:应当能在不看答案的情况下,写出浮点编码推导、跟踪每条汇编的数据流、画出一次调用的栈变化,并说明所有类型与边界假设。
来源与版本#
整理日期: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 · 往年题导航与勘误
来源为用户指定的 公开仓库。本章原创概括题型与解题路径,不转载整卷。2025 第一次阶段测验与当前第 1~8 讲范围最接近,应当优先于旧式期中卷。
本章范围#
以 2025 第一次阶段测验为主;历史题仅选数据表示和机器级程序相关内容。处理器设计、流水线、程序优化、缓存及链接题不纳入本手册。
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 | 递归字符串变换、栈与跳转位移 | 逐条恢复语义,按每层有效字符串长度计递归深度 |
| 2023 第二大题 pp.13~15 | E5M2/E4M3、量化、运算次序 | 特殊值规则可被题目修改,不能套统一 FP8 |
| 2023 第三大题 pp.16~18 | 组合数递归与汇编填空 | 参数保留、双递归与活跃栈深度 |
| 2022 第二大题 p.10 | 1/3/4 格式、数量、反推格式 | 计算间距与范围,而非只背 FP32 |
| 2022 第三大题 pp.11~13 | switch+结构体+链式间接寻址 | 表项、fall-through、字段偏移共同还原 |
应当明确区分的答案问题#
2025 第 3 题:“首字节”的歧义#
short -12 扩为 32 位 int 的位模式为 FFFFFFF4;小端内存从低到高为 F4 FF FF FF。原答案写 FF,只能与“最高有效字节”的解释一致。若按 show_bytes 从最低地址开始打印,第一个字节应为 F4。本手册保留这一判断依据,不把参考答案当作没有歧义的权威结论。
2024:结构体返回值的时机#
2024 勘误文件 中选择第 7 题最终允许 A/C 两种答案。核心是结构体返回地址:调用时隐藏缓冲区指针可在 rdi,返回时在 rax;未交代时机就有歧义。答题时要区分“传入结果缓冲区”和“函数返回”。
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 有符号取负溢出 |
| 复杂声明可以靠数星号理解 | 必须从变量名按括号和 []/() 优先级解析 |
| mov 的源/目的顺序可混写 | AT&T 源在前、目的在后 |
| movs 的 s 是 symbol | s 指 sign,符号扩展 |
| l 后缀是 linguist | l 指 longword;记忆法不能替代正式术语 |
这些结论来自位宽、类型和地址布局推导,并与教材/官方勘误交叉核对。引用仓库是为了补充题型和经验,不代表无条件认可所有笔记内容。
真题驱动的复习闭环#
做题时给每一空标一个错误类别:概念、类型、位宽、端序、地址/值、控制流、边界、计算。错后先写“错误前提是什么”,再找一个最小反例,最后做一题改变位宽或类型的变式。只有重做后能独立推出,才算真正掌握。
10 · 小班拓展、边角知识与作业路线
逐项归并本地第 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?修改后的机器是否仍能套原公式?
11 · 课件覆盖索引与来源
这里保留全部现有课件的页码主题,包括附加材料。页题名由 PDF 文本抽取清理,少数无题页用内容起始行标识;它是回查索引,正文按知识主题合并重复例子。
覆盖情况#
| 来源 | 页数 | 对应章节 | 状态 |
|---|---|---|---|
| ICS01-overview-20260907.pdf | 50 | 01,相关补充见 10 | 已提取全部页面主题,按主题整理 |
| ICS02-bits-bytes-ints-20260910.pdf | 68 | 02,相关补充见 10 | 已提取全部页面主题,按主题整理 |
| ICS03-float-20260914.pdf | 48 | 03,相关补充见 10 | 已提取全部页面主题,按主题整理 |
| ICS04-machine-basics-20260917.pdf | 47 | 04,相关补充见 10 | 已提取全部页面主题,按主题整理 |
| ICS05-machine-control-20260921.pdf | 64 | 05,相关补充见 10 | 已提取全部页面主题,按主题整理 |
| ICS06-machine-procedures-20260924.pdf | 75 | 06,相关补充见 10 | 已提取全部页面主题,按主题整理 |
| ICS07-machine-data-20260928.pdf | 51 | 07,相关补充见 10 | 已提取全部页面主题,按主题整理 |
小班研讨题第 2~7 讲共 6 份、每份 2 页,已全文读取并归并到正文与第 10 章。教材扫描版仅提取前部信息作为版次参考,正文公式基于课件、CS:APP 通用原理及官方资料核对;没有宣称逐页阅读整本扫描教材。
第 8 讲课件未提供;该章标为教材/往年题补充。本手册只整理第 1~8 讲标准内容;范围内真题导航见第 09 章。
逐页主题清单#
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 产品排行)不属于稳定知识,这里解释比较方法而不编造当前市场表。
- 课堂口头补充不在本地文件中,未纳入“已覆盖”的承诺。