天天看點

Linux Debugging(三): C++函數調用的參數傳遞方法總結(通過gdb+反彙編)1. 32位程式普通函數2. 32位普通函數-通過寄存器傳遞參數3. 32位 class member function 參數傳遞方式4. x86-64 class member function 的參數傳遞5. 總結

         上一篇文章《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