Chapter 1
不同层次的抽象:
经典图例,完美展示了讨论的范畴和抽象层级:
- process 其实已经算是最高级别的抽象了,它几乎等价于一台完整的计算机。也即是,它是整个计算机的一份 resource mirror。
- 将 process 剖析开来,则获得经典的三类 resource:
- I/O device:files
- memory:virtual memory
- CPU:instruction set architecture
- virtual memory 本身其实还涉一重抽象:
- memory 本身
- I/O device:files
Chapter 3
整个 assembly code 都是围绕着 CPU、register、memory 打转,特别是 register 值得格外重视,它是整个 instruction 的枢纽中心。
如果按照 instruction 操作来分类,assembly code 的结构其实很简单,仅 6 类:
- access data(register、memory)
- arithmetic、logical operation
- control(if, loop)
- procedure(function call)
- array(allocation、access)
- heterogeneous data structure(struct、union)
这些 32 位寄存器有多种用途,但每一个都有 “专长”,有各自的特别之处(前缀 e 是因为从 16-bit 扩大到了 32-bit 来标明 extend):
- arithmetic operation**:**
- eax(accumulator):是 “累加器”,它是很多加法乘法指令的 default 寄存器。
- ecx(counter): 是计数器,是重复(rep)前缀指令和 loop 指令的内定计数器。
- edx(divider): 则总是被用来放整数除法产生的余数。
- ebx(base): 是 “基地址” 寄存器,在内存寻址时存放基地址。
- source/destination**:**
- esi(source index):分别叫做 “源索引寄存器”(source index),因为在很多字符串操作指令中,DS:ESI 指向源串,而 ES:EDI 指向目标串.
- edi(destination index):目标索引寄存器(destination index)
- pointer**:**
- esp(stack pointer):栈顶(stack top)指针。
- ebp(base pointer):是 “基址指针”(base pointer),它最经常被用作高级语言「函数调用」(function call)的 “框架指针”(frame pointer)
- PC(program counter)**:**
- eip:寄存器存放下一个 CPU 指令存放的内存地址,当 CPU 执行完当前的指令后,从 EIP 寄存器中读取下一条指令的内存地址,然后继续执行。
可以总结的规律是:
- 「有括号」的表达式,都会被映射为 M [] 操作
- 最 general 的形态:
Imm(Eb, Ei, s) = M[ Imm + R[Eb] + R[Ei] * s ]
.
- 最 general 的形态:
- 「 没有括号」时,分三种情况:
- 以 % 开头的,映射为 R [] 操作
- 以 $ 开头的,映射为常数值
- 单纯的常数值,映射为 M [] 操作
- %eax = R[%eax] = 0x100
- 0x104 = M[0x104] = 0xAB
- $0x108 = 0x108
- (%eax) = M[ R[%eax] ] = M[0x100] = 0xFF
- 4(%eax) = M[4 + R[%eax]] = M[4 + 0x100] = M[0x104] = 0xAB
- 9(%eax, %edx) = M[9 + R[%eax] + R[%edx]] = M[9 + 0x100 + 0x3] = M[0x10C] = 0x11
- 260(%ecx, %edx) = M[260 + R[%ecx] + R[%edx]] = M[260 + 0x1 + 0x3] = M[0x104 + 0x4] = M[0x108] = 0x13
- 0xFC(, %ecx, 4) = M[0xFC + R[%ecx] 4] = M[0xFC + 0x1 4] = M[0x100] = 0xFF
- (%eax, %edx, 4) = M[R[%eax] + R[%edx] 4] = M[0x100 + 0x3 4] = M[0x100 + 0xC] = M[0x10C] = 0x11
可以看到:
mov
操作的后缀:- 仅有数量单位 b, w, l
- 后缀 s(sign-extended),紧接数量单位转换
- 后缀 z(zero-extended),紧接数量单位转换
pushl
操作,实际是由两步构成的:- 将 register % esp 的值,修改为 R [% esp] - 4;(即 memory 中的地址值减 4)
- 之后,再将 S 的值复写到 register % esp 的值所指向的 memory 区域;(即将 S 复写到 M [R [% esp] ] .)
popl
操作,也是由两步构成:- 将当前 register % esp 所指向的 memory 区域的值,复写到 D;(即将 M [R [% esp] ] 的值写到 D)
- 再将 register % esp 保存的地址值,更新,即自增 4。
leal
操作可用于 compactly describe 线性操作,例如:ax+b 可以通过 b leal(%eax, %eax, (a-1))
来实现。