5.1.2 不同架构下汇编指令分析
1.鲲鹏架构
针对5.1.1节在鲲鹏架构下编译的程序kunpeng_demo,通过反汇编工具查看它的汇编指令,详细步骤如下:
步骤1:安装反汇编工具objdump。objdump在工具包binutils中,可以通过yum安装该工具包,命令如下:
yum install -y binutils
步骤2:反编译kunpeng_demo,命令及回显如下(因为反编译后的汇编代码太多,这里只保留与main方法相关的汇编代码):
这样,就得到了C语言代码对应的汇编代码。
下面对main函数的代码逐行分析,同时对鲲鹏架构指令和寄存器进行简单介绍。
1)sub sp,sp,#0x10
sp寄存器保持栈顶位置,这里向下扩展了16字节,这16字节可以用来给后面的变量分配内存空间,栈默认最小扩展空间是16字节,每次扩展空间是16字节的整数倍。
2)mov w0,#0x1
把操作数1赋值给寄存器w0。
3)str w0,[sp,#12]
把w0寄存器的值传送到栈顶开始的第12字节对应的内存中。也就是给变量a赋值。
4)mov w0,#0x2
把操作数2赋值给寄存器w0。
5)str w0,[sp,#8]
把w0寄存器的值传送到栈顶开始的第8字节对应的内存中,也就是给变量b赋值。
6)str wzr,[sp,#4]
把零寄存器的值传送到栈顶开始的第4字节对应的内存中,也就是给变量c赋值。零寄存器的值总是0。
7)ldr w1,[sp,#12]
把栈顶开始的第12字节对应的内存数据传送给w1寄存器,也就是把变量a读到寄存器w1。
8)ldr w0,[sp,#8]
同上,把变量b读到寄存器w0。
9)add w0,w1,w0
把w0和w1相加,存到w0寄存器中。
10)str w0,[sp,#4]
把寄存器w0的值写到变量c中。
11)ldr w0,[sp,#4]
把变量c中的值写回寄存器w0,w0用来作为返回值寄存器。
12)add sp,sp,#0x10
恢复栈空间,释放内存。
注意:这里使用了objdump的-S选项,该选项将代码段反汇编的同时,将反汇编代码和源代码交替显示。该选项需要gcc在编译时使用-g的选项。
2.x86架构
针对5.1.1节在x86架构下编译的程序x86_demo,通过反汇编工具查看它的汇编指令,详细步骤如下:
步骤1:安装反汇编工具objdump。objdump在工具包binutils中,可以通过yum安装该工具包,命令如下:
yum install -y binutils
步骤2:反编译x86_demo,命令及回显如下(只保留与main方法相关的汇编代码):
对main函数的每行代码简要解释如下:
1)push %rbp
将调用函数的栈帧栈底地址入栈,即将bp寄存器的值压入调用栈中。
2)mov %rsp,%rbp
建立新的栈帧,将main函数的栈帧栈底地址放入bp寄存器中。sp和bp是两个指针寄存器,一般的函数调用都会使用上述两个指令。
3)movl $0x1,-0x4(%rbp)
把1传送给变量a(整型变量占用4字节,所以这里是-0x4)。
4)movl $0x2,-0x8(%rbp)
把2传送给变量b。
5)movl $0x0,-0xc(%rbp)
把0传送给变量c。
6)mov -0x8(%rbp),%eax
把变量b的值传送给eax寄存器。
7)mov -0x4(%rbp),%edx
把变量a的值传送给edx寄存器。
8)add %edx,%eax
edx和eax寄存器相加并存入eax寄存器。
9)mov %eax,-0xc(%rbp)
把eax寄存器的值传送给变量c。
10)mov -0xc(%rbp),%eax
把变量c的值传送给寄存器eax,eax作为返回值寄存器。
11)pop %rbp
恢复上一栈帧的bp。