CSAPP 3 程序的机器层面表达
CSAPP 3 程序的机器层面表达
这一章主要从汇编程序和机器码的角度看程序。包括call stack
, local variable
, 以及一些基本的数据结构,比如array
, structure
, union
等等。
Fun fact: 64位寻址空间是
2**48
而不是2**64
。为什么?
IA32机器码与C语言代码不同,可以接触到一些CPU 的计算状态:
- 程序指针,PC
- 寄存器文件,regiester file
- 条件寄存器,
- 浮点数寄存器
机器码层面,类型已经不能存在了,一切都是内存上的字节。
指令集中操作包括:
- 访问内存地址
- 计算
- 控制
- Procedures
Procedures
寄存器的使用规则一般是依靠规定,比如eax
, edx
,ecx
是调用者(caller)保留使用的。ebx
esi
edi
是被调用函数(callee)保留使用的。换句话说,callee必须在执行其他操作前,将 eax
, edx
,ecx
进栈保存,然后再返回以前,恢复这三个寄存器的值。
Array Allocation
我们需要两个寄存器来进行 Arrary 的读取,一个用来存储Array的地址,另一个用来存储index,例如 (%edx,%ecx,4)
就是一个char *D[5]
数列的读取命令,edx存储D的位置,ecx存储需要访问的index,而4就是char *
的长度(32位内存地址)。
Structure 和 Union
一般栈内存分配都是 4 byte 为单位的。Structure就是每个格子长度大小不一致的Array,也是一块连续的内存空间。而union则会划分一块类型不确定的内存空间,可以存储任意类型(长度允许的情况下)。
Union会容易导致bug,但是可以有效的节约内存。比如如下二叉树节点:
1 | struct NODE_S { |
Problems
Problem 3.1
值包括三种:register, memory, immediate.
%eax
: 0x100,register0x104
: 0xAB, memory$0x108
: 0x108, Immediate(%eax)
: 0xFF,Memory,Address 0x1004(%eax)
: 0xAB,偏移量 4 byte, Address 0x1049(%eax,%edx)
: 0x11, EAX + 9 + EDX260(%ecx,%edx)
: 0xAB, ECX + 260 + EDX,260是十进制的0xFC(,%ecx,4)
: 0xFF, 0xFC + ECX * 4, 0x4 + 0xFC = 0x100(%eax,%edx,4)
: 0x11, address of 0x10C
Problem 3.2
1 word = 2 byte = 16 bits,所以一个32位寄存器包含4个byte或者2个word或者32bit。
一个16进制的单位,包含4个bit。所以16进制经常是两个两个写在一起,代表一个byte的宽度。
1 | movl %eax, (%esp) 将 EAX 寄存器的内容移动到 ESP 指向的内存空间 |
例子:栈操作
1 | subl $4, %esp |
Problem 3.3
1 | movb $0xF, (%bl) bl 只有 8 bit,不能作为 32 bit 内存地址 |
Problem 3.4
1 | stc_t v; |
src_t | dest_t | 指令 |
---|---|---|
int | int | movl %eax,(%edx) |
char | int | movsbl %al,(%edx) |
char | unsigned | movsbl %al,(%edx) |
Problen 3.5
1 | void decode1(int *xp, int *yp, int *zp) |
Problem 3.6
1 | leal 6(%eax),%edx 6+x |
Problem 3.7
1 | addl %ecx,(%eax) 0x100 0x100 |
Problem 3.30
1 | call next |
%eax
的值应该是栈顶刚被推出的值,而call
会首先将返回地址压进栈顶,所以%eax
应该是函数的返回值地址。但是这不是一个Procedure call,也没有对应的ret
指令。这是一个IA32指令集的trick,用来获取 PC 的地址。
Problem 3.32
*p
是第3个参数,d
是第二个参数,
short c, char d, int *p, int x
Problen 3.43
1 | 在第七行: |