解读汇编代码的准备工作
了解各个寄存器的用途
解读汇编代码(在不看源代码的情况下)
multstore: pushq %rbx //%rbx是被调用者保存寄存器,由于函数multstore会被其他函数调用,因此将%rbx内的值存入栈中 move %rdx, %rbx //%rdx是调用者保存寄存器,%rbx是被调用者保存寄存器,将%rdx中的值放入%rbx,以保证在执行mult2的过程中,%rdx中的值一直都被保存在寄存器或内存的某个地方 call mult2 //调用mult2函数,将控制转移给过程mult2 move %rax, (%rbx) //将mult2的返回值写入%rbx(存储的是一个地址)所指向的位置 popq %rbx //与pushq %rbx相对应,恢复%rbx的值 ret
对应的源代码
long mult2(long,long); void multstore(long x, long y, long *dest){ long t=mult2(x,y); *dest=t; }
工具:GCC
命令行:linux> gcc -Og -c mstore.c
linux>表示在linux的终端环境下;gcc是一种编译器程序,可以源代码转换成汇编代码进而转换成机器代码;-Og,-c和mstore.o为传入gcc程序的三个参数,表示将源代码文件mstore.c编译成机器代码文件mstore.o
机器代码是机器执行的程序,只是一个字节序列,机器对产生它的源代码一无所知
机器代码 mstore.o 53 48 89 d3 e8 00 00 00 00 48 89 03 5b c3
工具:反汇编器程序
将机器代码映射成类汇编代码
命令行:linux> objdump -d mstore.o
linux>表示在linux的终端环境下;objdump表示运行名为objdump的可执行程序;-d和mstore.o为传入objdump程序的两个参数,表示对目标代码文件mstore.o进行反汇编
0000000000000000 <multstore>: 0: 53 push %rbx 1: 48 89 d3 mov %rdx,%rbx 4: e8 00 00 00 00 callq 9 <multstore+0x9>(?) 9: 48 89 03 mov %rax,(%rbx) c: 5b pop %rbx d: c3 retq
关于机器代码和反汇编的特性
x86-64的指令从1~15个字节不等。常用的指令以及操作数较少的指令所需的字节数较少,那些不太常用或字节数较多的指令所需字节数较多
设计指令格式的方式是,从某个置顶位置开始,可以将字节唯一地解码成机器指令。例如只有pushq %rbx一条指令是53开头的
生成可执行代码需要对一组目标代码文件运行链接器,而这一组目标代码中必须有一个main函数
命令行:linux> gcc -Og -o prog main.c mstore.c
linux>表示在linux的终端环境下;gcc也具有链接的功能;-Og,-o,prog,main.c和mstore.c为传入gcc程序的五个参数,表示将main.c源文件和mstore.c源文件编译并链接成可执行文件prog(变成了8655字节!远远多于14字节!原因是链接时包含了用来启动终止程序的代码,以及用来与操作系统交互的代码)
下面是prog文件的一小段代码
0000000000400540 400540:53 push %rbx 400541:48 89 d3 move %rdx,%rbx 400544:e8 42 00 00 00 calls 40058b <mult2> 400549:48 89 03 mov %rax,(%rbx) 40054c:5b pop %rbx 40054d:c3 retq 40054e:90 nop 40054f:90 nop
与mstore.c反汇编产生的代码几乎一样
区别有:
左侧地址不同,原因是链接器将这段代码的地址移到了一段不同的地址范围里
链接器填上了callq指令调用函数mult2所需的地址,原因是链接器的任务之一是为函数调用找到可执行代码的位置
多了两行代码:为了使函数代码变为16字节