上一篇文章《linux debugging:使用反彙編了解c++程式函數調用棧》沒想到能得到那麼多人的喜愛,因為那篇文章是以32位的c++普通函數(非類成員函數)為例子寫的,是以隻是一個特殊的例子。本文将函數調用時的參數傳遞方法進行一下總結。總結将為c++普通函數、類成員函數;32位和64位進行總結。
建議還是讀一下linux debugging:使用反彙編了解c++程式函數調用棧,這樣本文的結論将非常容易了解,将非常好的為coredump分析開一個好頭。而且,它也是32位c++ 普通函數的調用的比較好的例子,畢竟從彙編的角度,将參數如何傳遞的進行了比較好的說明。
普通函數的意思是非class member function
main函數的彙編:
1111是第一個參數,放到了esp指向的位址。2222是第二個參數,放到了高位址。因次我們可以知道,在函數func2中,通過ebp+8可以通路到第一個參數1111,通過ebp+12可以通路到第二個參數2222。
下面我們使用gdb通過ebp列印一下傳入的參數:
總結:
1. 參數通過棧查傳遞,底位址傳遞從左邊開始的第一個參數
2. 使用gdb可以很友善列印傳入參數
其實32位的程式也可以使用寄存器傳遞參數。請看下一節。
可以使用gcc的擴充功能__attribute__使得參數傳遞可以使用寄存器。
修改第一節的函數:
__attribute__((regparm(3)))意思是使用寄存器
可以看到,前三個參數分别通過eax/edx/ecx傳遞,第四個參數通過棧傳遞。這種傳遞方式被稱為fastcall
我們通過宏usingstack強制使用棧來傳遞參數。
通過gdb來列印傳入的參數:
可以看到,class成員函數的第一個參數是對象的指針。通過這種方式,成員函數可以和非成員函數以類似的方式進行調用。
在x86-64中,整形和指針型參數的參數從左到右依次儲存到rdi,rsi,rdx,rcx,r8,r9中。浮點型參數會儲存到xmm0,xmm1……。多餘的參數會保持到棧上。
下面這個例子将傳遞九個參數。可以通過它來驗證一下各個寄存器的使用情況:
下面通過gdb驗證各個寄存器的使用情況:
r9存儲的是指針型char *str的字元串。因為寄存器隻能存儲6個整形、指針型參數,注意,test 對象的指針占用了一個。是以
參數e和f隻能通過棧傳遞。注意每個位址空間占8個位元組。是以rbp+2*8存儲的是e,rbp+3*8存儲的是f。
float h是通過xmm0,double i是通過xmm1傳遞的。這類寄存器的size大小是128bits,當然128個bits可以不填滿。gdb将這些寄存器看成下面這些資料的聯合:
列印方式如下:
32位:
1)預設的傳遞方法不使用寄存器,使用ebp+8可以通路第一個參數,ebp+16可以通路第二個參數。。。
2) 可以使用gcc擴充__attribute__将參數放到寄存器上,依次使用的寄存器是eax/edx/ecx
3)對于class 的member function,調用時第一個參數為this(對象指針)位址。是以函數的第一個參數使用ebp+16才可以通路到。
4)ebp存儲的是上層的bp的位址。ebp+4存儲的是函數傳回時的位址指令。
64位:
1)預設的傳遞方法是使用寄存器。當然也可以強制使用棧,方式:函數聲明時使用
2)整形和指針型參數的參數從左到右依次儲存到rdi,rsi,rdx,rcx,r8,r9中。浮點型參數會儲存到xmm0,xmm1……。多餘的參數會保持到棧上。
3)xmm0……是比較特殊的寄存器,通路内容時需要注意。
尊重原創,轉載請注明出處: anzhsoft http://blog.csdn.net/anzhsoft/article/details/18739193