《深入理解计算机系统》

时间:2021-05-11 16:14:14

2 信息的表示和处理

2.1 信息存储

2.1.4 寻址和字节顺序

对于跨越多字节的程序对象,我们需要确认:

  1. 对象的地址,几乎所有机器上对象地址都是字节序列中的最小地址
  2. 存储器中如何对这些字节排序,有两种规则:小端法和大端法

例如,变量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

3.6.4 翻译条件分支语句