2 信息的表示和处理
2.1 信息存储
2.1.4 寻址和字节顺序
对于跨越多字节的程序对象,我们需要确认:
- 对象的地址,几乎所有机器上对象地址都是字节序列中的最小地址
- 存储器中如何对这些字节排序,有两种规则:小端法和大端法
例如,变量x
类型为int
,值为0x01234567
,位于地址0x100
处,大端法和小端法存储为:
大端法:
地址 | 0x100 | 0x101 | 0x102 | 0x103 |
---|---|---|---|---|
数据 | 01 | 23 | 45 | 67 |
小端法:
地址 | 0x100 | 0x101 | 0x102 | 0x103 |
---|---|---|---|---|
数据 | 67 | 45 | 23 | 01 |
2.1.7 布尔代数和环
整数运算:<Z , +, x, -, 0 ,1>
(0, 1 为加法和乘法的单位元)
布尔代数:<{0, 1}, |, &, ~, 0, 1>
上面两种结构有很多相似性,但注意~ a 不是 a 在 | 运算下的逆元(a | ~a != 0
, a + -a == 0
)
PS:
- 布尔代数满足分配性、相补性、幂等性、吸收性、DeMorgan 定律
- 布尔与和异或(EXCLUSIVE-OR)相当于模 2 的乘法和加法
2.4 浮点
浮点数及其运算的标准:IEEE(读作 I-Triple-E) 标准 754
符号 | 指数 | 有效数 | |
---|---|---|---|
单精度(32bit) | 1 | 8 | 23 |
双精度(64bit) | 1 | 11 | 52 |
指数采用二进制移码(Exponent bias)表示。
- 规格化值:指数域不全为 0 且不全 1
- 非规格化值:指数域全为 0,此时指数值为
1 - Bias
(Bias 是指数域对应了二进制原码值) - 特殊值:指数域全为 1
3 程序的机器表示
3.4 访问信息
3.2 程序编码
// code.c
int accum = 0;
int sum(int x,int y){
int t = x + y;
accum += t;
return t;
}
生成汇编文件:$ gcc -O2 -S code.c
编译:$ gcc -O2 -c code.c
反编译:$ objdump -d code.o
,结果入下
ubuntu@DESKTOP-5JD9B9T:~$ objdump -d code.o
code.o: 文件格式 elf64-x86-64
Disassembly of section .text:
0000000000000000 <sum>:
0: 8d 04 37 lea (%rdi,%rsi,1),%eax
3: 01 05 00 00 00 00 add %eax,0x0(%rip) # 9 <sum+0x9>
9: c3 retq
3.4.1 操作指示符
寻址的通用形式Imm(Eb, Ei, s)
,其地址是Memory[Immediate + Register[Eb] + Register[Ei] * scale]
(立即数 + 基址 + 变址)
3.4.2 数据传送指令
mov S, D
:S ---> D
3.5 算数和逻辑操作
3.5.1 加载有效地址
加载有效地址(Load Effective Address)指令 leal 实际上是 movl 指令的变形。
这条指令将第一个操作数计算出的地址写入第二个操作数。
例如:leal 7(%edx, %edx, 4), %eax
将设置%eax
的值为7 + %edx + 4 * %edx
。(%edx
为 3,则%eax
设置为 22)
3.5.2 一元和二元操作
一元操作:只有一个操作数,既是源又是目的。
二元操作:第二个操作数既是源又是目的。
3.6 控制
3.6.3 跳转指令和它们的编码
跳转(jump)指令会导致执行切换到程序中的一个全新的位置。这些跳转的目的地通常用一个标号(label)指明。
执行 PC 相关寻址时,程序计数器的值是跳转指令后面的那条指令的值,而不是跳转指令本身的地址。处理器会将更新程序计数器作为执行一条指令的第一步。例如:
地址
指令1 0x08
指令2 0x0a
...
指令n 0x1b
如果指令1的操作是跳转到指令n,则偏移为0x11,因为0x0a + 0x11 = 0x1b