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。