x86_64架構下函數調用過程分析

//被分析的C程序
int
test1(int a1,int b1)
{
    int c1;
    c1 = a1+b1;
    return c1;
}

int
test2(int a2,char b2)
{
    int c2;
    c2 = test1(30,40);
    return c2;
}


int 
main(int argc,char **argv)
{

    int main_c;
    int x=2,y=1,z=3;
    main_c = test2(10,20);

    return main_c;
}

//通過gcc得到可執行文件test.out

/*
    通過命令:objdump -d test.out > func.txt 得到反彙編文件;
    結合圖1 “典型的存儲空間安排” 去看,可以知道以下各指令依次存儲在正文段中。
*/
test.out:     file format elf64-x86-64


Disassembly of section .init:

0000000000400390 <_init>:
  400390:   48 83 ec 08             sub    $0x8,%rsp
  400394:   48 8b 05 5d 0c 20 00    mov    0x200c5d(%rip),%rax        # 600ff8 <_DYNAMIC+0x1d0>
  40039b:   48 85 c0                test   %rax,%rax
  40039e:   74 05                   je     4003a5 <_init+0x15>
  4003a0:   e8 2b 00 00 00          callq  4003d0 <__libc_start_main@plt+0x10>
  4003a5:   48 83 c4 08             add    $0x8,%rsp
  4003a9:   c3                      retq   

Disassembly of section .plt:

00000000004003b0 <__libc_start_main@plt-0x10>:
  4003b0:   ff 35 52 0c 20 00       pushq  0x200c52(%rip)        # 601008 <_GLOBAL_OFFSET_TABLE_+0x8>
  4003b6:   ff 25 54 0c 20 00       jmpq   *0x200c54(%rip)        # 601010 <_GLOBAL_OFFSET_TABLE_+0x10>
  4003bc:   0f 1f 40 00             nopl   0x0(%rax)

00000000004003c0 <__libc_start_main@plt>:
  4003c0:   ff 25 52 0c 20 00       jmpq   *0x200c52(%rip)        # 601018 <_GLOBAL_OFFSET_TABLE_+0x18>
  4003c6:   68 00 00 00 00          pushq  $0x0
  4003cb:   e9 e0 ff ff ff          jmpq   4003b0 <_init+0x20>

Disassembly of section .plt.got:

00000000004003d0 <.plt.got>:
  4003d0:   ff 25 22 0c 20 00       jmpq   *0x200c22(%rip)        # 600ff8 <_DYNAMIC+0x1d0>
  4003d6:   66 90                   xchg   %ax,%ax

Disassembly of section .text:

00000000004003e0 <_start>:
  4003e0:   31 ed                   xor    %ebp,%ebp
  4003e2:   49 89 d1                mov    %rdx,%r9
  4003e5:   5e                      pop    %rsi
  4003e6:   48 89 e2                mov    %rsp,%rdx
  4003e9:   48 83 e4 f0             and    $0xfffffffffffffff0,%rsp
  4003ed:   50                      push   %rax
  4003ee:   54                      push   %rsp
  4003ef:   49 c7 c0 d0 05 40 00    mov    $0x4005d0,%r8
  4003f6:   48 c7 c1 60 05 40 00    mov    $0x400560,%rcx
  4003fd:   48 c7 c7 17 05 40 00    mov    $0x400517,%rdi
  400404:   e8 b7 ff ff ff          callq  4003c0 <__libc_start_main@plt>
  400409:   f4                      hlt    
  40040a:   66 0f 1f 44 00 00       nopw   0x0(%rax,%rax,1)

0000000000400410 <deregister_tm_clones>:
  400410:   b8 37 10 60 00          mov    $0x601037,%eax
  400415:   55                      push   %rbp
  400416:   48 2d 30 10 60 00       sub    $0x601030,%rax
  40041c:   48 83 f8 0e             cmp    $0xe,%rax
  400420:   48 89 e5                mov    %rsp,%rbp
  400423:   76 1b                   jbe    400440 <deregister_tm_clones+0x30>
  400425:   b8 00 00 00 00          mov    $0x0,%eax
  40042a:   48 85 c0                test   %rax,%rax
  40042d:   74 11                   je     400440 <deregister_tm_clones+0x30>
  40042f:   5d                      pop    %rbp
  400430:   bf 30 10 60 00          mov    $0x601030,%edi
  400435:   ff e0                   jmpq   *%rax
  400437:   66 0f 1f 84 00 00 00    nopw   0x0(%rax,%rax,1)
  40043e:   00 00 
  400440:   5d                      pop    %rbp
  400441:   c3                      retq   
  400442:   0f 1f 40 00             nopl   0x0(%rax)
  400446:   66 2e 0f 1f 84 00 00    nopw   %cs:0x0(%rax,%rax,1)
  40044d:   00 00 00 

0000000000400450 <register_tm_clones>:
  400450:   be 30 10 60 00          mov    $0x601030,%esi
  400455:   55                      push   %rbp
  400456:   48 81 ee 30 10 60 00    sub    $0x601030,%rsi
  40045d:   48 c1 fe 03             sar    $0x3,%rsi
  400461:   48 89 e5                mov    %rsp,%rbp
  400464:   48 89 f0                mov    %rsi,%rax
  400467:   48 c1 e8 3f             shr    $0x3f,%rax
  40046b:   48 01 c6                add    %rax,%rsi
  40046e:   48 d1 fe                sar    %rsi
  400471:   74 15                   je     400488 <register_tm_clones+0x38>
  400473:   b8 00 00 00 00          mov    $0x0,%eax
  400478:   48 85 c0                test   %rax,%rax
  40047b:   74 0b                   je     400488 <register_tm_clones+0x38>
  40047d:   5d                      pop    %rbp
  40047e:   bf 30 10 60 00          mov    $0x601030,%edi
  400483:   ff e0                   jmpq   *%rax
  400485:   0f 1f 00                nopl   (%rax)
  400488:   5d                      pop    %rbp
  400489:   c3                      retq   
  40048a:   66 0f 1f 44 00 00       nopw   0x0(%rax,%rax,1)

0000000000400490 <__do_global_dtors_aux>:
  400490:   80 3d 99 0b 20 00 00    cmpb   $0x0,0x200b99(%rip)        # 601030 <__TMC_END__>
  400497:   75 11                   jne    4004aa <__do_global_dtors_aux+0x1a>
  400499:   55                      push   %rbp
  40049a:   48 89 e5                mov    %rsp,%rbp
  40049d:   e8 6e ff ff ff          callq  400410 <deregister_tm_clones>
  4004a2:   5d                      pop    %rbp
  4004a3:   c6 05 86 0b 20 00 01    movb   $0x1,0x200b86(%rip)        # 601030 <__TMC_END__>
  4004aa:   f3 c3                   repz retq 
  4004ac:   0f 1f 40 00             nopl   0x0(%rax)

00000000004004b0 <frame_dummy>:
  4004b0:   bf 20 0e 60 00          mov    $0x600e20,%edi
  4004b5:   48 83 3f 00             cmpq   $0x0,(%rdi)
  4004b9:   75 05                   jne    4004c0 <frame_dummy+0x10>
  4004bb:   eb 93                   jmp    400450 <register_tm_clones>
  4004bd:   0f 1f 00                nopl   (%rax)
  4004c0:   b8 00 00 00 00          mov    $0x0,%eax
  4004c5:   48 85 c0                test   %rax,%rax
  4004c8:   74 f1                   je     4004bb <frame_dummy+0xb>
  4004ca:   55                      push   %rbp
  4004cb:   48 89 e5                mov    %rsp,%rbp
  4004ce:   ff d0                   callq  *%rax
  4004d0:   5d                      pop    %rbp
  4004d1:   e9 7a ff ff ff          jmpq   400450 <register_tm_clones>

00000000004004d6 <test1>:
  4004d6:   55                      push   %rbp
  4004d7:   48 89 e5                mov    %rsp,%rbp
  4004da:   89 7d ec                mov    %edi,-0x14(%rbp)
  4004dd:   89 75 e8                mov    %esi,-0x18(%rbp)
  4004e0:   8b 55 ec                mov    -0x14(%rbp),%edx
  4004e3:   8b 45 e8                mov    -0x18(%rbp),%eax
  4004e6:   01 d0                   add    %edx,%eax
  4004e8:   89 45 fc                mov    %eax,-0x4(%rbp)
  4004eb:   8b 45 fc                mov    -0x4(%rbp),%eax
  4004ee:   5d                      pop    %rbp
  4004ef:   c3                      retq   

00000000004004f0 <test2>:
  4004f0:   55                      push   %rbp
  4004f1:   48 89 e5                mov    %rsp,%rbp
  4004f4:   48 83 ec 18             sub    $0x18,%rsp
  4004f8:   89 7d ec                mov    %edi,-0x14(%rbp)
  4004fb:   89 f0                   mov    %esi,%eax
  4004fd:   88 45 e8                mov    %al,-0x18(%rbp)
  400500:   be 28 00 00 00          mov    $0x28,%esi
  400505:   bf 1e 00 00 00          mov    $0x1e,%edi
  40050a:   e8 c7 ff ff ff          callq  4004d6 <test1>
  40050f:   89 45 fc                mov    %eax,-0x4(%rbp)
  400512:   8b 45 fc                mov    -0x4(%rbp),%eax
  400515:   c9                      leaveq 
  400516:   c3                      retq   

0000000000400517 <main>:
  400517:   55                      push   %rbp
  400518:   48 89 e5                mov    %rsp,%rbp
  40051b:   48 83 ec 20             sub    $0x20,%rsp
  40051f:   89 7d ec                mov    %edi,-0x14(%rbp)
  400522:   48 89 75 e0             mov    %rsi,-0x20(%rbp)
  400526:   c7 45 f0 02 00 00 00    movl   $0x2,-0x10(%rbp)
  40052d:   c7 45 f4 01 00 00 00    movl   $0x1,-0xc(%rbp)
  400534:   c7 45 f8 03 00 00 00    movl   $0x3,-0x8(%rbp)
  40053b:   be 14 00 00 00          mov    $0x14,%esi
  400540:   bf 0a 00 00 00          mov    $0xa,%edi
  400545:   e8 a6 ff ff ff          callq  4004f0 <test2>
  40054a:   89 45 fc                mov    %eax,-0x4(%rbp)
  40054d:   8b 45 fc                mov    -0x4(%rbp),%eax
  400550:   c9                      leaveq 
  400551:   c3                      retq   
  400552:   66 2e 0f 1f 84 00 00    nopw   %cs:0x0(%rax,%rax,1)
  400559:   00 00 00 
  40055c:   0f 1f 40 00             nopl   0x0(%rax)

0000000000400560 <__libc_csu_init>:
  400560:   41 57                   push   %r15
  400562:   41 56                   push   %r14
  400564:   41 89 ff                mov    %edi,%r15d
  400567:   41 55                   push   %r13
  400569:   41 54                   push   %r12
  40056b:   4c 8d 25 9e 08 20 00    lea    0x20089e(%rip),%r12        # 600e10 <__frame_dummy_init_array_entry>
  400572:   55                      push   %rbp
  400573:   48 8d 2d 9e 08 20 00    lea    0x20089e(%rip),%rbp        # 600e18 <__init_array_end>
  40057a:   53                      push   %rbx
  40057b:   49 89 f6                mov    %rsi,%r14
  40057e:   49 89 d5                mov    %rdx,%r13
  400581:   4c 29 e5                sub    %r12,%rbp
  400584:   48 83 ec 08             sub    $0x8,%rsp
  400588:   48 c1 fd 03             sar    $0x3,%rbp
  40058c:   e8 ff fd ff ff          callq  400390 <_init>
  400591:   48 85 ed                test   %rbp,%rbp
  400594:   74 20                   je     4005b6 <__libc_csu_init+0x56>
  400596:   31 db                   xor    %ebx,%ebx
  400598:   0f 1f 84 00 00 00 00    nopl   0x0(%rax,%rax,1)
  40059f:   00 
  4005a0:   4c 89 ea                mov    %r13,%rdx
  4005a3:   4c 89 f6                mov    %r14,%rsi
  4005a6:   44 89 ff                mov    %r15d,%edi
  4005a9:   41 ff 14 dc             callq  *(%r12,%rbx,8)
  4005ad:   48 83 c3 01             add    $0x1,%rbx
  4005b1:   48 39 eb                cmp    %rbp,%rbx
  4005b4:   75 ea                   jne    4005a0 <__libc_csu_init+0x40>
  4005b6:   48 83 c4 08             add    $0x8,%rsp
  4005ba:   5b                      pop    %rbx
  4005bb:   5d                      pop    %rbp
  4005bc:   41 5c                   pop    %r12
  4005be:   41 5d                   pop    %r13
  4005c0:   41 5e                   pop    %r14
  4005c2:   41 5f                   pop    %r15
  4005c4:   c3                      retq   
  4005c5:   90                      nop
  4005c6:   66 2e 0f 1f 84 00 00    nopw   %cs:0x0(%rax,%rax,1)
  4005cd:   00 00 00 

00000000004005d0 <__libc_csu_fini>:
  4005d0:   f3 c3                   repz retq 

Disassembly of section .fini:

00000000004005d4 <_fini>:
  4005d4:   48 83 ec 08             sub    $0x8,%rsp
  4005d8:   48 83 c4 08             add    $0x8,%rsp
  4005dc:   c3                      retq   


/*
    在對彙編進行分析之前,我們首先簡單介紹一下基本的彙編命令
*/

特殊用途的寄存器:
ax:存放函數返回值
bp:存放棧底
sp:存放棧頂
ip:存放下一條執行指令
di,si:依次對應函數的第一個參數、第二個參數.....

push  %rbp 等價於://先把sp-2,再把rbp值mov進內存
    sub 0x02,%rsp 
    mov %rbp,(%rsp)

pop %rbp 等價於:
    mov (%rsp),%rbp
    add 0x02,%rsp

call指令:首先將返回地址壓入棧頂,然後跳轉,相當於push和jump

ret指令則是將棧頂的返回地址彈出到eip,然後按對應指令繼續運行

leave 等價於:
    movl %ebp %esp
    pop %ebp

/*
    下面我們摘取最熟悉的main函數進行分析
*/

00000000004004d6 <test1>:

   /*
      進入test1後,同樣進行當前棧底入棧保存,但可以發現存在不同點:rsp不下偏,進行新的棧幀空間開闢。
      這是因爲test1函數不會繼續調用子函數,所以它使用的局部變量不需要繼續使用。
   */
  4004d6:   55                      push   %rbp
  4004d7:   48 89 e5                mov    %rsp,%rbp

  //同樣的,將保存在寄存器中入參值寫入內存進行保存
  4004da:   89 7d ec                mov    %edi,-0x14(%rbp)
  4004dd:   89 75 e8                mov    %esi,-0x18(%rbp)

  //進行運算
  4004e0:   8b 55 ec                mov    -0x14(%rbp),%edx
  4004e3:   8b 45 e8                mov    -0x18(%rbp),%eax
  4004e6:   01 d0                   add    %edx,%eax
  4004e8:   89 45 fc                mov    %eax,-0x4(%rbp)

  //ax寄存器被用來存儲函數返回值,所以把返回結果寫入eax寄存器
  4004eb:   8b 45 fc                mov    -0x4(%rbp),%eax

  /*由於此時rsp沒有下偏開闢新的棧空間,因此rsp指向內存地址的值爲調用函數的棧底,
    因此通過pop將棧底寄存器值恢復成被調用函數棧底地址
  */
  4004ee:   5d                      pop    %rbp

  //將棧頂的返回地址彈出到eip,然後按對應指令繼續運行
  4004ef:   c3                      retq   

00000000004004f0 <test2>:

  /*當函數被調用時,主要工作包括:
    1.保存調用函數的棧幀情況,主要是棧底地址,因此需要將當前棧底地址push入棧。
    2.保存調用函數棧底後,被調用函數即以當前棧頂爲棧底,隨後棧底下偏,相當於開闢一段棧空間給被調用函數使用。
  */
  4004f0:   55                      push   %rbp  //同樣的,進入後首先將棧底地址壓棧
  4004f1:   48 89 e5                mov    %rsp,%rbp
  4004f4:   48 83 ec 18             sub    $0x18,%rsp

  //同樣的,將保存在寄存器中入參值寫入內存進行保存
  4004f8:   89 7d ec                mov    %edi,-0x14(%rbp)
  4004fb:   89 f0                   mov    %esi,%eax
  4004fd:   88 45 e8                mov    %al,-0x18(%rbp)

  /*
    如同main函數,test2內部也將調用一個子函數,爲此將做相同的準備工作,包括:
    1.將需要傳遞的參數從右向左依次存入對應的寄存器進行保存和傳遞;
    2.使用callq指令,調用test1;
    3.callq指令首先把返回地址push壓棧,使得當函數返回時,可從該地址繼續執行,隨後jump至對應的內存地址(處於正文段)進行執行。
  */
  400500:   be 28 00 00 00          mov    $0x28,%esi
  400505:   bf 1e 00 00 00          mov    $0x1e,%edi
  40050a:   e8 c7 ff ff ff          callq  4004d6 <test1>

  //從test1函數返回後,將返回值寫入ax寄存器保存、傳遞
  40050f:   89 45 fc                mov    %eax,-0x4(%rbp)
  400512:   8b 45 fc                mov    -0x4(%rbp),%eax

  /*由於此時rsp下偏開闢新的棧空間,因此不能向test1中直接pop,需要使用leaveq命令;
    leaveq命令首先將rbp值複製給rsp,再pop,同樣的都是將棧底寄存器值恢復成被調用函數棧底地址
  */
  400515:   c9                      leaveq 

  //將棧頂的返回地址彈出到eip,然後按對應指令繼續運行
  400516:   c3                      retq   

0000000000400517 <main>:
  400517:   55                      push   %rbp   //首先把當前棧底壓入棧中,即將當前棧底指向的內存地址保存下來

  //下面兩句通過使改變rsp、rbp寄存器值來使棧頂和棧底指向不同的內存地址,相當於開闢了一段棧空間供調用函數使用,具體開闢多大,在編譯時就已經計算完畢。
  400518:   48 89 e5                mov    %rsp,%rbp  //把rsp所存儲的棧頂地址賦值給rbp寄存器
  40051b:   48 83 ec 20             sub    $0x20,%rsp //rsp存儲的內存地址向下偏移0x20

  //下面兩句將main函數的兩個入參分別寫入內存,進行保存
  40051f:   89 7d ec                mov    %edi,-0x14(%rbp)  //把edi寄存器值放入rbp下偏0x14的內存地址中
  400522:   48 89 75 e0             mov    %rsi,-0x20(%rbp)  //把rsi寄存器值放入rbp下偏0x20的內存地址中

  //將函數內部定義的局部變量依次寫入內存進行保存
  400526:   c7 45 f0 02 00 00 00    movl   $0x2,-0x10(%rbp)
  40052d:   c7 45 f4 01 00 00 00    movl   $0x1,-0xc(%rbp)
  400534:   c7 45 f8 03 00 00 00    movl   $0x3,-0x8(%rbp)

  /*
    可以看到main函數即將調用子函數test2,爲此將做一些準備工作,包括:
    1.將需要傳遞的參數從右向左依次存入對應的寄存器進行保存和傳遞;
    2.使用callq指令,調用test2;
    3.callq指令首先把返回地址push壓棧,使得當函數返回時,可從該地址繼續執行,隨後jump至對應的內存地址(處於正文段)進行執行。
  */
  40053b:   be 14 00 00 00          mov    $0x14,%esi
  400540:   bf 0a 00 00 00          mov    $0xa,%edi
  400545:   e8 a6 ff ff ff          callq  4004f0 <test2>

  //從test2函數返回後,將存儲在ax中的被調用函數返回值寫入內存保存
  40054a:   89 45 fc                mov    %eax,-0x4(%rbp)

  //main函數返回值寫入ax寄存器
  40054d:   8b 45 fc                mov    -0x4(%rbp),%eax

  //下面與test2中同理
  400550:   c9                      leaveq 
  400551:   c3                      retq   


  400552:   66 2e 0f 1f 84 00 00    nopw   %cs:0x0(%rax,%rax,1)
  400559:   00 00 00 
  40055c:   0f 1f 40 00             nopl   0x0(%rax)  
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章