基础概念:
- 程序的执行过程:程序(高级语言写的代码)-- 汇编语言 – 到机器语言(CPU可识别的机器代码)
- 相关汇编语言词汇解释:
mov
:赋值操作,例:mov DWORD PTR [rbp-0x4],0x1;
jne
: (jump if not equal 如果不等于就跳转),例:jne 4a <main+0x4a>
jmp
: (jump)跳转,例:jmp 51 <main+0x51>
je
:(jump if equal 如果等於则跳转),例:je 4a <main+0x4a>
cmp
:(compare 比较),例:DWORD PTR [rbp-0x4],0x0
简单熟悉
我们以c语言代码为例,我们先熟悉一下分析流程:
// test.c
#include <time.h>
#include <stdlib.h>
int main()
{
srand(time(NULL));
int r = rand() % 2;
int a = 10;
if (r == 0)
{
a = 1;
} else {
a = 2;
}
}
通过一下命令将代码转化为汇编代码,并打印出来:
$ gcc -g -c test.c
$ objdump -d -M intel -S test.o
//其中左边的数字是机器代码,显然不是给人看的。右边是汇编代码,是给程序员看的,我们跟着序号看
if (r == 0)
3b: 83 7d fc 00 cmp DWORD PTR [rbp-0x4],0x0 //1.比较[rbp-ox4]和0x0,如果相等则将零标志条件码设置为1,反之为0
//DWORD PTR 代表操作的数据类型是 32 位的整数。[rbp-ox4]表示r变量的内存地址
3f: 75 09 jne 4a <main+0x4a> //2.判断零标志条件码的结果,如果不是1则跳转到4a(在最左侧,代表行数),加载4a的地址的指令到CPU开始执行
{
a = 1;
41: c7 45 f8 01 00 00 00 mov DWORD PTR [rbp-0x8],0x1 //3.如果在第2步没有跳转,那么将执行到这里。把0x1赋值给[rbp-0x8]地址代表的变量a
48: eb 07 jmp 51 <main+0x51> //4.直接跳到51代表的行
}
else
{
a = 2;
4a: c7 45 f8 02 00 00 00 mov DWORD PTR [rbp-0x8],0x2 //5.把0x2赋值给[rbp-0x8]地址代表的变量a
51: b8 00 00 00 00 mov eax,0x0 //6.结束,继续往下执行
}
注:我们回过头去看前面的 if 条件,如果满足的话,在赋值的 mov 指令执行完成之后,有一个 jmp
的无条件跳转指令。跳转的地址就是这一行的地址 51。我们的 main 函数没有设定返回值,而 mov eax, 0x0 其实就是给 main
函数生成了一个默认的为 0 的返回值到累加器里面。if 条件里面的内容执行完成之后也会跳转到这里,和 else
里的内容结束之后的位置是一样的。
分析if…else和switch:
相比到这里,大家应该已经具备汇编语言的阅读能力了,可以尝试自己分析一下!
2段代码如下:
转化成汇编代码如下:
由于博主比较懒,大家就自己分析一下吧,希望大家能分析出来为什么我们在写代码的时候,3层判断以内if…else比switch优秀,大于3层的时候,则switch更优。有问题欢迎评论沟通!继续努力!