【软件开发底层知识修炼】二十四 ABI之函数调用约定
- 上一篇文章學習了Linux環境下的函數棧幀的形成與摧毀。點擊鏈接查看相關文章:軟件開發底層知識修煉】二十三 ABI-應用程序二進制接口三之深入理解函數棧幀的形成與摧毀
- 本篇文章繼續學習ABI接口相關的內容。函數調用約定
文章目錄
- 1 函數參數如何入棧,返回值在哪里
- 2 函數調用約定的編程實驗
- 2.1 使用gdb調試代碼證明eax存的值是函數返回值
- 2 .2 查看程序的反匯編文件來說明調用約定的不同
- 3 總結
1 函數參數如何入棧,返回值在哪里
前面學過的文章中,已經深入的了解了函數調用過程中函數的棧幀的形成與摧毀。在發生函數調用時,首先入棧的是函數的參數。但是我們知道一般函數的參數都是會比較多。在參數比較多的時候,函數的參數是以什么樣的順序入棧的呢?函數返回時是誰來將參數彈出棧呢?
并且,在函數執行完之后,返回的時候,返回值在哪里?通過什么方式將返回值傳遞給調用者?
首先給出在C語言中默認的調用約定(cdecl):
- 調用函數時,參數從右往左入棧
- 函數返回時,調用者負責將參數彈出棧。這里說是調用者,實際上是編譯器在編譯的時候為調用者添加了相應的指令
- 函數返回值保存在eax寄存器中。前提是函數返回值是基礎數據類型,如果是結構體這種的類型,就另說。
上面的調用約定是C語言默認的函數調用約定。我們平常所熟知的也就是上面的默認的調用約定。當然,或許大多數人是不知道的吧!
- 下面的表格給出了其他各種調用約定
注意:以上三個調用約定,只需要注意__thiscall__約定。它一般是C++中的成員函數的約定,C++成員函數又由隱藏的this指針。如果函數的參數是確定個數的,則this存放于ECX寄存器,函數自身清理棧中的參數。如果成員函數是可變參數,那么久相當于前面的__cdecl__調用約定
在上面的函數調用約定中,還有幾點需要注意:
- 只有使用的__cdecl__約定的函數,才支持可變參數。使用其他調用約定的,不支持可變參數
- 在C++中,當類的成員函數為可變參數時,調用約定自動變為__cedcl__
- 調用約定定義義了函數被編譯后,對應的在符號表中的最終的符號名稱的樣子
2 函數調用約定的編程實驗
2.1 使用gdb調試代碼證明eax存的值是函數返回值
convention.c
#include <stdio.h>int test(int a, int b, int c) //默認的__cdecl__調用約定 {return a + b + c; } //__cdecl__調用約定 void __attribute__((__cdecl__)) func_1(int i) { } //__stdcall__調用約定 void __attribute__((__stdcall__)) func_2(int i) { } //__fastcall__調用約定 void __attribute__((__fastcall__)) func_3(int i) { }int main() {int r = test(1, 2, 3);printf("r = %d\n", r);return 0; }- 上述代碼很簡單,分別將幾個函數強制設定為相應的調用約定,并可以通過查看變量r的內容與寄存器eax的內容來證明函數返回值是存儲在eax寄存器中的。下面就來通過運行該程序,并使用GDB進行查看相應的內存的值。
編譯運行程序,并且記性gdb調試
- gcc -g convention.c -o test.out
- gdb test.out
- start
- break convention.c:6
- continue
- info registers
- continue
因為gdb在前面的文章中已經使用過很多次,并且使用了各種動態圖展示gdb的使用。這里就直接給出相應的命令了。
上述第一個contiue后,運行到convention.c的第6行就停止了。此時再info registers。可以看到如下信息:
可以看到在函數test即將返回時。寄存器eax存的值為6 。 這正好等于test函數的返回值這不是巧合。因為eax寄存器就是用來保存函數的返回值的。當然,后面我們還可以通過查看反匯編文件來分析。
最后的執行continue命令導致整個程序的運行結束
2 .2 查看程序的反匯編文件來說明調用約定的不同
上面的gdb調試方法沒有證明出函數調用約定的不同,下面我么使用查看可執行代碼的反匯編文件進行說明。
使用命令
- objdump -S test.c > test.s
生成可執行文件的反匯編代碼test.s。
在該文件中可以找到
- func_1函數的反匯編代碼
- func_2的反匯編代碼
- func_3的反匯編代碼
- 從以上三個函數的反匯編代碼可以看出,它們的前言和后序是由區別的,這是因為它們分別使用了不同的函數調用約定。使用了不同的 函數調用預定,匯編層面肯定是不一樣的。
3 總結
學會了以下內容
- 函數返回值如果是整形的,通過eax寄存器傳遞返回值給調用者(下一篇文章講解返回值是結構體的類型個時是如何傳遞給調用者的)
- 學會三種不同的調用約定對應的區別(__cdecl__調用約定,__stdcall__調用約定,__fastcall__調用約定)
總結
以上是生活随笔為你收集整理的【软件开发底层知识修炼】二十四 ABI之函数调用约定的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java常用设计模式(面试常考)
- 下一篇: knx智能照明控制系统电路图_智能照明控