汇编概述#
架构(ISA)是 CPU 设计的一部分,决定了汇编语言的形式。指令集充当了软件和硬件的接口,定义了
系统状态(state),例如寄存器、内存、程序计数器等
CPU 可以执行的指令(instruction)
每个指令对系统状态的影响(effect)
不同的处理器家族有不同的指令集架构,常见的例如 x86-64、ARM 以及 Risk-V。
微架构(Microarchitecture)是 ISA 的某种实现,比如高通的晓龙和苹果的 M1 处理器,虽然都是 ARM 架构,但其内部实现截然不同。
数据以二进制形式表示,代码也同样以二进制形式表示。GCC 将 C 代码转换成二进制机器码。而二进制的机器码一般较难以阅读,所以有了汇编语言——这是一种比较容易阅读的形式(human-readable machine language)。一条 C 代码,通常会转化成多条汇编指令。
一般情况下,我们不会直接编写汇编程序,通过现代编译器可以将 C 程序转化为不同平台的汇编指令,甚至可以自动优化指令。即便如此,理解汇编程序对理解机器级的执行模式依然很有帮助:
更好地了解程序的漏洞是如何出现的以及防御措施
分析代码中隐含的低效部分,优化程序的性能
在分布式系统中,可以通过底层直接观察数据的形式
利用在线网站 godbolt.org 也可以很方便地查看 C 代码转换后的汇编形式,注意编译选项需要添加 -Og -std=gnu99
。通过命令行工具使用 objdump -d
也可以得到类似的结果。
int sum_array(int arr[], int nelems) {
int sum = 0;
for (int i = 0; i < nelems; i++) {
sum += arr[i];
}
return sum;
}
0000000000401136 <sum_array>:
401136: b8 00 00 00 00 mov $0x0,%eax
40113b: ba 00 00 00 00 mov $0x0,%edx
401140: eb 09 jmp 40114b <sum_array+0x15>
401142: 48 63 c8 movslq %eax,%rcx
401145: 03 14 8f add (%rdi,%rcx,4),%edx
401148: 83 c0 01 add $0x1,%eax
40114b: 39 f0 cmp %esi,%eax
40114d: 7c f3 jl 401142 <sum_array+0xc>
40114f: 89 d0 mov %edx,%eax
401151: c3 ret
第 1 行是函数的名称和函数的内存地址,这是函数指令的起点。如果定义一个函数指针,则可以指向这个位置。
第 2~11 行冒号之前的部分,是函数每一条指令的内存地址,按序依次存储在内存中。
中间部分则是字节的位模式,以十六进制显示,这是真实的机器指令。本质是 0/1 组成的 ISA 指令,不同指令,长度不一。
为了便于阅读,后半部分显示了每一条机器指令对应的汇编指令。