Linux彙編—函數調用過程

來源:互聯網
上載者:User

        或許習慣於用進階語言編程的大部分同學都會忽略了函數調用的具體過程是怎樣的,如果想知道這個過程就不得不從彙編入手,但組合語言又晦澀難懂。在這裡謹以一個簡單的例子說說我對函數調用過程的學習心得。

       先上C語言寫的代碼:

 1 #include<stdio.h> 2  3  4 unsigned int test(int a,int b) 5 { 6     int c,d; 7     c = a; 8     d = b; 9     return c;10 }11 12 int main()13 {14     unsigned int r;15 16     r = test(1,2);17     18     return 0;19 }

很簡單,就是在main()函數裡調用test()函數。通過下面的命令編譯:

gcc -g -o test test.c    //加-g選項是為了反編譯時間可以混合顯示源碼和彙編代碼

再通過以下命令將test反編譯:

objdump -d -S test

截取其中反編譯後的一個片段,如下:

 1 08048394 <test>: 2 #include<stdio.h> 3  4  5 unsigned int test(int a,int b) 6 { 7  8048394:    55                       push   %ebp 8  8048395:    89 e5                    mov    %esp,%ebp 9  8048397:    83 ec 10                 sub    $0x10,%esp10     int c,d;11     c = a;12  804839a:    8b 45 08                 mov    0x8(%ebp),%eax13  804839d:    89 45 fc                 mov    %eax,-0x4(%ebp)14     d = b;15  80483a0:    8b 45 0c                 mov    0xc(%ebp),%eax16  80483a3:    89 45 f8                 mov    %eax,-0x8(%ebp)17     return c;18  80483a6:    8b 45 fc                 mov    -0x4(%ebp),%eax19 }20  80483a9:    c9                       leave  21  80483aa:    c3                       ret    22 23 080483ab <main>:24 25 int main()26 {27  80483ab:    55                       push   %ebp28  80483ac:    89 e5                    mov    %esp,%ebp29  80483ae:    83 ec 18                 sub    $0x18,%esp30     unsigned int r;31 32     r = test(1,2);33  80483b1:    c7 44 24 04 02 00 00     movl   $0x2,0x4(%esp)34  80483b8:    00 35  80483b9:    c7 04 24 01 00 00 00     movl   $0x1,(%esp)36  80483c0:    e8 cf ff ff ff           call   8048394 <test>37  80483c5:    89 45 fc                 mov    %eax,-0x4(%ebp)38     39     return 0;40  80483c8:    b8 00 00 00 00           mov    $0x0,%eax41 }42  80483cd:    c9                       leave  43  80483ce:    c3                       ret    44  80483cf:    90                       nop

可以很清楚地看到每一條c語句對應的彙編代碼。

從第27行開始看起,將ebp寄存器的值壓入堆棧;第28行,把esp寄存器的值賦給ebp寄存器;第29行,esp的值自減0x18。假設執行完第29行後堆棧的情況1所示。

                       圖1

第33行,將立即數0x2(test()的第2個實參)放到[esp+0x4]地址裡;第35行,將立即數0x1(test()的第1個實參)放到[esp]地址裡;第36行。調用test()函數,此時會將斷點(返回地址)也壓入堆棧,2所示。

                          圖2

接著從第7行開始執行,將ebp壓棧;第8行,將esp的值賦給ebp;第9行,esp自減0x10,3所示。

                      圖3

 第12行,將[ebp+0x8]地址裡的內容賦給eax,由圖3可以發現,[ebp+0x8]剛好是0x1這個數所在的地址,即把0x1賦給eax寄存器;第13行,把eax的值放到[ebp-4]這個地址裡;第15行,將[ebp+0xc]地址裡的內容賦給eax,[ebp+0xc]剛好是0x2這個數所在的地址,即把0x2賦給eax;第16行,把eax的值放到[ebp-8]這個地址裡。此時,4所示。

                        圖4

第18行,通過eax寄存器儲存函數的傳回值。

     總的來說,就是函數調用時,先將參數從右至左依次壓入堆棧,然後再將斷點、ebp寄存器的值壓棧,從這裡也可以知道為什麼值傳遞不能改變實參原來的值。

             圖5

 

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.