第三章 程序的机器级表示
gcc c语言编译器 -> 汇编
汇编代码是机器代码的文本表示
平坦寻址模式
Intel IA32 和 x86-64
3.2 程序编码
一个c程序,有2个文件p1.c和p2.c
unix$ gcc -o1 -o p p1.c p2.c
gcc gcc c编译器,也可以用cc启动
-o1 编译器使用第一级优化,级别越高编译时间越长
-
步骤:
- 1.编译器插入所有#include命令指定的文件,并扩展#define声明的宏
- 2.编译器产生2个源代码的汇编代码,p1.s和p2.s
- 3.汇编器将汇编代码转为二进制目标代码,p1.o和p2.o
- 4.连接器将2个目标代码文件和库函数的代码合并,生成可执行代码p
3.2.1 机器级代码
指令集体系结构(ISA):定义了处理器状态、指令的格式、指令对状态的影响
机器级程序使用的存储器地址是虚拟地址,操作系统将虚拟地址转化为物理地址
3.2.2 代码示例
int accum = 0;
int sum(int x, int y)
{
int t = x + y;
accum += t;
return t;
}
gcc运行编译器,产生一个汇编文件code.s
unix$ gcc -o1 -S code.c -o code.s
产生一个二进制文件,无法直接查看
unix$ gcc -o1 -c code.c -o code.o
反汇编器:
unix$ objdump -d code.o
macos下可以用tool代替:
macos$ otool -tV code.o
生成实际可执行的代码需要一组目标代码运行连接器,这一组目标代码必须包含main函数
int main()
{
return sum(1, 3);
}
unix$ gcc -o1 code.o main.c -o prog
进行反汇编
macos$ otool -tV prog
下面给出MacOS和Linux下,system.s:
MacOS:
Linux:
3.3 数据格式
movb(传送字节)、movw(传送字)、movl(传送双字)
3.4 访问信息
IA32cpu包含一组8个存储32位的寄存器,8个寄存器一%e开头。大多数情况下,前6个寄存器可以看为通用寄存器,后2个寄存器保存着指向程序堆栈中重要位置的指针。
3.4.1 操作数指示符
指令包含一个或多个操作数,源操作数:立即数、寄存器、存储器,目的操作数:寄存器、存储器。‘$’后一个用标准c表示法表示的整数表示立即数,如$-577或$0x1F。%eax 表示32位寄存器,%ax 表示16位寄存器,%ah或%al 表示8位寄存器。
寻址方式:
练习题3.1
答案:0x100、0xAB、0x108、0xFF、0xAB、0x11、0x13、0xFF、0x11
3.4.2 数据传送指令
MOV S, D
PS:源操作数和目的操作数不能同为存储器。
// Assume initially that %dh = 0xCD, %eax = 98765432
movb %dh, %al %eax = 987654CD
movsbl %dh, %eax %eax = FFFFFFCD
movzbl %dh, %eax