计算机执行机器代码,用字节序列编码低级的操作。汇编代码是机器代码的文本表示。
程序编码:
linux> gcc -Og -o p p1.c p2.c
命令gcc即GCC C编译器。使用gcc命令将源代码转换成可执行代码。首先,C预处理器扩展源代码,插入所有用#include命令指定的文件,并扩展所有用#define声明指定的宏。其次,编译器产生两个源文件的汇编代码,分别为p1.s p2.s。接下来,汇编器会将汇编代码转换成二进制目标文件代码p1.o p2.o。此时,它还没有填入全局值的地址。最后,链接器将两个目标代码文件和实现库函数代码合并,并产生最终的可执行代码文件p。
机器级代码:
第一种抽象,由指令集体系结构或指令集架构来定义机器级程序的格式和行为,它定义了处理器状态、指令的格式以及每条指令对状态的影响;如,程序计数器、整数寄存器文件、条件码寄存器、向量寄存器;
第二种抽象,机器级程序使用的内存地址是虚拟地址,机器代码将内存看成是一个非常大的、按字节寻址的数组;
程序内存包含:程序的可执行机器代码,操作系统需要的一些信息,用来管理过程调用和返回的运行时栈,以及用户分配的内存块。
使用-S可以看到C语言编译器产生的汇编代码:
linux-> gcc -Og -S mstore.c
使用-c,GCC会编译并汇编该代码,产生目标文件mstore.o,它是二进制格式,无法直接查看。上述汇编指令对应的目标代码(字节序列16进制表示):
总结:机器执行的程序只是一个字节序列,它是对一系列指令的编码,机器产生这些指令的源代码几乎一无所知。
查看机器代码内容:利用反汇编器,根据机器代码生成一种类似于汇编代码的格式。
objdump -d命令,可以进行反汇编:
linux-> objdump -d mstore.o
数据格式:
字:16位数据类型
双字: 32位数
四字:64位数
数据传送指令分为四种:movb(传送字节)、movw(传送字)、movl(传送双字)、movq(传送四字)
访问信息:
最初8086中是8个16位的寄存器(%ax到%bp)->扩展成8个32位寄存器(%aex到%ebp)->增加8个新的寄存器(%r8到%r15)。如下图所示:字节集操作可以访问最低的字节,16位操作可以访问最低的两个字节,32位可以访问最低的4个字节,而64位可以访问整个寄存器。
操作数指示符:
操作数分为3种类型:
第一类:立即数,表示常数值,$后跟一个整数,如$-577或$0x1F。
第二类:寄存器,它表示寄存器内容,16个寄存器的低位1字节、2字节、4字节、8字节中的一个作为操作数。用符号表示任意寄存器a,引用来表示它的值。
第三类:内存引用,它会根据计算出来的地址访问某个内存位置。将内存看成很大的字节数组,符号表示对存储在内存中从地址Addr开始的b个字节值的引用。
如图,有多种不同的寻址模式,允许不同形式的内存引用。引用有四个组成部分,一个是立即数偏移