p1.c p2.c
两个文件生成一个可执行文件
linux> gcc -Og -o p p1.c p2.c
编译选项 -Og 告诉编译器使用会生成符合原始C代码整体结构的机器代码的优化等级。(太高的优化等级会使代码严重变形,与源代码关系不易理解)
3.2.1 机器级代码
计算机系统使用了多种不同形式的抽象,利用更简单的抽象模型来隐藏实现的细节。对于机器级编程来说,有两种抽象尤为重要。第一种:指令集体系结构或指令集架构(Instruction Set Architecture,ISA)来定义机器级程序格式和行为,它定义了处理器状态、指令的格式,以及每条指令对状态的影响。第二种:机器级程序使用的内存地址是虚拟地址,提供的内存模型看上去是一个非常大的字节数组。
1) 程序计数器(通常称为“PC”,在 x86-64 中用 %rip 表示)给出将要执行的下一条指令内存中的地址。
2) 整数寄存器文件包含16个命名的位置,分别存储64位的值。
3) 条件码寄存器保存着最近执行的算术或者逻辑指令的状态信息。
4) 一组向量寄存器可以存放一个或多个整数或浮点数值。
程序内存包含:程序的可执行机器代码,操作系统需要的一些信息,用来管理过程调用和返回的运行时栈,以及用户分配的内存块(比如说用 malloc 库函数分配的)。
一条机器指令只执行一个非常基本的操作。
3.2.2 代码示例
#include<stdio.h>
/* mstore.c */
long mult2(long, long);
void multstore(long x, long y, long *dest){
long t = mult2(x, y);
*dest = t;
}
生成汇编代码mstore.s
.
linux> gcc -Og -S mstore.c
生成目标代码文件mstore.o
.
linux> gcc -Og -o mstore.c
反汇编目标代码文件
linux> objdump -d mstore.o
gcc
产生Intel
汇编代码
linux> gcc -Og -S -masm=intel mstore.c
写一个C代码文件 mstore.c , 包含如下的函数定义:
long mult2(long,long);
void multstore(long x,long y,long*dest){
long t = mult2(x,y);
*dest = t;
}
在命令行上使用“-S"选项,就能看到编译器产生的汇编代码,查看 mstroe.s 即可。
Linux> gcc -Og -S mstore.c
Linux> cat ./mstore.s
内容如下:
其中有一段代码是这样的:
multstore:
pushq %rbx
movq %rdx, %rbx
call mult2
movq %rax, (%rbx)
popq %rbx
ret
以上从 multstore 之后开始的每一条代码都对应一条机器指令。比如, pushq 表示将寄存器 %rbx 的内容压入栈。
可以使用”-C"选项对其编译并汇编,如:
Linux> gcc -Og -c mstore.c Linux>objdump -d mstore.o
机器代码就是左侧的数字
53 48 89 d3 e8 00 00 00 00 48 89 03 5b c3
右边就是等价的汇编语言。
一些机器代码和它的反汇编表示的特性:
1) x86-64 的指令长度从 1 到 15 个字节不等。
2) 设计指令格式的方式是,从某个给定位置开始,可以将字节唯一地解码成机器指令。
3) 反汇编器指数基于机器代码文件中的字节序列来确定汇编代码。它不需要访问该程序的源代码或汇编代码。
4) 反汇编其使用的指令命名规则与GCC生成的汇编代码使用的有些细微的差别。
# include <stdio.h>
void multstore(long , long , long * );
int main(){
long d;
multstore(2 , 3 , &d);
printf("2 * 3 --> %ld/n" , d);
return 0; } long mult2(long a , long b){ long s = a * b ;
return s ; }
同样的方法生成机器代码
Linux>gcc -Og -o prog main.c mstore.c
Linux>objdump -d prog
反汇编器会抽取出各种代码序列,其中包含下面这段:
几乎与前面的 mstroe.c 产生的代码一样。