C語言函數調用參數壓棧的相關問題

來源:互聯網
上載者:User

標籤:

參數入棧的順序

以前在面試中被人問到這樣的問題,函數調用的時候,參數入棧的順序是從左向右,還是從右向左。當時沒有想清楚,隨口就說從右向左。其實這個回答是不完全正確的。因為其實入棧的順序,不同的體系架構是不一樣的,舉例來說, 看下面的代碼:

#include <stdio.h>int test(int a, int b){    printf("address of a %x.\n", &a);    printf("address of b %x.\n", &b);    if ((unsigned int)&a > (unsigned int)&b) {        printf("Push argument from left to right...\n");    }    else {        printf("Push argument from right to left...\n");    }    return 0;}int main(){    test(1, 2);    return 0;}

在64位Ubuntu的系統下的運行結果是:從左至右。

address of a 1ec62c.
address of b 1ec628.
Push argument from left to right…

32位Ubuntu的結果是:從右至左

address of a bfd03290.
address of b bfd03294.
Push argument from right to left…

先來解釋一下為什麼上面的代碼能夠判別入棧的順序,首先你要明白一點:

C語言中的gcc編譯的棧是從高地址向低地址生長的,也就是說誰先入棧,誰的地址就大,掌握了這一點,應試不難寫出代碼.

函數調用時棧裡都有什麼

以參數從左至右入棧為例:

push arg0 -- High Addresspush arg1...push argnpush eippush ebp  -- Low address
32位系統和64位系統函數調用時,參數入棧方式有不同嗎?

這個問題在不久之前被人問題,當時傻了,我一直以來只關注過32位系統的參數入棧方式,一直以為64位系統也是一樣,沒有什麼不同,現在歸納起來有兩點:

  • 64位系統先把傳入參數放在寄存器裡面,在被調函數的具體實現中把寄存器的值入棧,然後再去棧中取參數
  • 64位系統棧中參數存放的順序是從左至右的(因為先經曆了寄存器傳值)

看下面的反組譯碼:

C代碼同上面一樣Ubuntu 32位反組譯碼:int main(){ 804846d:   55                      push   %ebp 804846e:   89 e5                   mov    %esp,%ebp 8048470:   83 e4 f0                and    $0xfffffff0,%esp 8048473:   83 ec 10                sub    $0x10,%esp    test(1, 2); 8048476:   c7 44 24 04 02 00 00    movl   $0x2,0x4(%esp) 804847d:   00  804847e:   c7 04 24 01 00 00 00    movl   $0x1,(%esp) 8048485:   e8 8a ff ff ff          call   8048414 <test>    return 0; 804848a:   b8 00 00 00 00          mov    $0x0,%eax}int test(int a, int b){ 8048414:   55                      push   %ebp 8048415:   89 e5                   mov    %esp,%ebp 8048417:   83 ec 18                sub    $0x18,%esp    printf("address of a %x.\n", &a); 804841a:   b8 60 85 04 08          mov    $0x8048560,%eax 804841f:   8d 55 08                lea    0x8(%ebp),%edx 8048422:   89 54 24 04             mov    %edx,0x4(%esp) 8048426:   89 04 24                mov    %eax,(%esp) 8048429:   e8 12 ff ff ff          call   8048340 <printf@plt>    return 0; 8048466:   b8 00 00 00 00          mov    $0x0,%eax}Ubuntu 64位反組譯碼:int main(){  40056e:   55                      push   %rbp  40056f:   48 89 e5                mov    %rsp,%rbp    test(1, 2);  400572:   be 02 00 00 00          mov    $0x2,%esi  400577:   bf 01 00 00 00          mov    $0x1,%edi  40057c:   e8 ac ff ff ff          callq  40052d <test>    return 0;  400581:   b8 00 00 00 00          mov    $0x0,%eax}int test(int a, int b){  40052d:   55                      push   %rbp  40052e:   48 89 e5                mov    %rsp,%rbp  400531:   48 83 ec 10             sub    $0x10,%rsp  400535:   89 7d fc                mov    %edi,-0x4(%rbp)  400538:   89 75 f8                mov    %esi,-0x8(%rbp)    printf("address of a %x.\n", &a);  40053b:   48 8d 45 fc             lea    -0x4(%rbp),%rax  40053f:   48 89 c6                mov    %rax,%rsi  400542:   bf 14 06 40 00          mov    $0x400614,%edi  400547:   b8 00 00 00 00          mov    $0x0,%eax  40054c:   e8 bf fe ff ff          callq  400410 <printf@plt>    return 0;  400567:   b8 00 00 00 00          mov    $0x0,%eax}

看32位的ubuntu作業系統, 8048476: 的確是把參數直接入棧,2先入棧,1後入棧。

 8048476:   c7 44 24 04 02 00 00    movl   $0x2,0x4(%esp) 804847d:   00  804847e:   c7 04 24 01 00 00 00    movl   $0x1,(%esp) 8048485:   e8 8a ff ff ff          call   8048414 <test>

再來看64位的ubuntu作業系統,2 和1根本就沒有放入到棧中,而是放到了寄存器esi和edi中。

  40056f:   48 89 e5                mov    %rsp,%rbp    test(1, 2);  400572:   be 02 00 00 00          mov    $0x2,%esi  400577:   bf 01 00 00 00          mov    $0x1,%edi  40057c:   e8 ac ff ff ff          callq  40052d <test>

再來看64位系統test的實現,先把edi入棧,再把esi入棧,這就是為什麼函數看起來像是從左至右入棧的原因了。

  40052d:   55                      push   %rbp  40052e:   48 89 e5                mov    %rsp,%rbp  400531:   48 83 ec 10             sub    $0x10,%rsp  400535:   89 7d fc                mov    %edi,-0x4(%rbp)  400538:   89 75 f8                mov    %esi,-0x8(%rbp)

C語言函數調用參數壓棧的相關問題

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.