x86架构与x64架构在函数于栈中调用过程的不同之处

时间:2022-07-23
本文章向大家介绍x86架构与x64架构在函数于栈中调用过程的不同之处,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

本篇原创作者:Rj45

x86架构与x64架构

1、x86架构 x86架构是intel开发的一种32位的指令集。8个32位通用寄存器 eax,ebx,ecx,edx,ebp,esp,esi,edi

2、x64架构 x64架构是64位的,有16个通用寄存器 rax,rbx,rcx,rdx,rsi,rdi,rsp,rbp,r8,r9,r10,r11,r12,r13,r14,r15

程序

1、代码

2、编译链接

32位:
sudo gcc stack.c -o stack -m32

64位:
sudo gcc stack.c -o stack1

x86架构下函数于栈中调用过程

0804840b <Add>:
 804840b:    55                      push   ebp          //将ebp压入栈
 804840c:    89 e5                   mov    ebp,esp      //将esp压入栈
 804840e:    83 ec 08                sub    esp,0x8      //抬高栈帧
 8048411:    8b 55 08                mov    edx,DWORD PTR [ebp+0x8]  //将[ebp+0x8]压入edx
 8048414:    8b 45 0c                mov    eax,DWORD PTR [ebp+0xc]  //将[ebp+0xc]压入eax
 8048417:    01 d0                   add    eax,edx  //将eax与edx中的内容相加赋给eax
 8048419:    83 ec 08                sub    esp,0x8  //抬高栈帧
 804841c:    50                      push   eax  //将eax压入栈
 804841d:    68 e0 84 04 08          push   0x80484e0    //压入x+y=
 8048422:    e8 b9 fe ff ff          call   80482e0 <printf@plt> //调用printf函数
 8048427:    83 c4 10                add    esp,0x10 //调整栈帧
 804842a:    90                      nop
 804842b:    c9                      leave
 804842c:    c3                      ret

0804842d <main>:
 804842d:    8d 4c 24 04             lea    ecx,[esp+0x4]
 8048431:    83 e4 f0                and    esp,0xfffffff0
 8048434:    ff 71 fc                push   DWORD PTR [ecx-0x4]

 8048437:    55                      push   ebp      //将ebp压入栈
 8048438:    89 e5                   mov    ebp,esp  //将esp压入栈
 804843a:    51                      push   ecx      //将ecx压入栈
 804843b:    83 ec 04                sub    esp,0x4  //抬高栈帧,esp=esp+0x4
 804843e:    83 ec 08                sub    esp,0x8  //抬高栈帧
 8048441:    6a 14                   push   0x14     //压入参数20
 8048443:    6a 0a                   push   0xa      //压入参数10
 8048445:    e8 c1 ff ff ff          call   804840b <Add>    //调用Add函数
 804844a:    83 c4 10                add    esp,0x10 //调整栈帧
 804844d:    b8 00 00 00 00          mov    eax,0x0  //清空eax
 8048452:    8b 4d fc                mov    ecx,DWORD PTR [ebp-0x4]  //将[ebp-0x4]内的数据赋给ecx
 8048455:    c9                      leave           //mov esp,ebp;pop ebp
 8048456:    8d 61 fc                lea    esp,[ecx-0x4]    //取[ecx-0x4]中的数据赋给esp
 8048459:    c3                      ret             //pop eip

 804845a:    66 90                   xchg   ax,ax
 804845c:    66 90                   xchg   ax,ax
 804845e:    66 90                   xchg   ax,ax

x64架构下函数于栈中调用过程

0000000000400526 <Add>:
  400526:    55                      push   rbp          //将rbp压入栈中
  400527:    48 89 e5                mov    rbp,rsp      //将rsp压入栈中
  40052a:    48 83 ec 10             sub    rsp,0x10     //抬高栈帧
  40052e:    89 7d fc                mov    DWORD PTR [rbp-0x4],edi  //将edi的值赋给[rbp-0x4]
  400531:    89 75 f8                mov    DWORD PTR [rbp-0x8],esi  //将rsi的值赋给[rbp-0x10]
  400534:    8b 55 fc                mov    edx,DWORD PTR [rbp-0x4]  //将[rbp-0x4]的值赋给edx
  400537:    8b 45 f8                mov    eax,DWORD PTR [rbp-0x8]  //将[rbp-0x8]的值赋给eax
  40053a:    01 d0                   add    eax,edx                  //eax=eax+edx
  40053c:    89 c6                   mov    esi,eax                  //将eax的值赋给esi
  40053e:    bf 04 06 40 00          mov    edi,0x400604         //将0x400604对应的数据赋给edi
  400543:    b8 00 00 00 00          mov    eax,0x0              //清空eax
  400548:    e8 b3 fe ff ff          call   400400 <printf@plt>  //调用printf函数
  40054d:    90                      nop
  40054e:    c9                      leave
  40054f:    c3                      ret

0000000000400550 <main>:
  400550:    55                      push   rbp          //将rbp压入栈中
  400551:    48 89 e5                mov    rbp,rsp      //将rsp压入栈中
  400554:    48 83 ec 10             sub    rsp,0x10     //抬高栈帧
  400558:    89 7d fc                mov    DWORD PTR [rbp-0x4],edi  //将edi的值赋给[rbp-0x4]
  40055b:    48 89 75 f0             mov    QWORD PTR [rbp-0x10],rsi //将rsi的值赋给[rbp-0x10]
  40055f:    be 14 00 00 00          mov    esi,0x14     //将参数20赋给esi
  400564:    bf 0a 00 00 00          mov    edi,0xa      //将参数10赋给edi
  400569:    e8 b8 ff ff ff          call   400526 <Add> //调用Add函数
  40056e:    b8 00 00 00 00          mov    eax,0x0      //清空eax
  400573:    c9                      leave               //mov esp,ebp;pop ebp
  400574:    c3                      ret                 //pop eip
  400575:    66 2e 0f 1f 84 00 00    nop    WORD PTR cs:[rax+rax*1+0x0]
  40057c:    00 00 00
  40057f:    90                      nop

总结

x86架构与x64架构在函数于栈中调用过程的不同之处在于:x86架构下,函数的参数是直接存放到栈帧中的;而x64架构下,函数的参数是通过寄存器传参进入栈帧的。(当寄存器不够用,才会将参数直接存入栈帧)