2015-10-16 26 views

回答

0

假設有一個函數「testfunc」,我們希望找到多少stackspace這個機能的研究使用.....

#include <stdio.h> 
#include <stddef.h> 
ptrdiff_t testfunc (int arg1, int arg2, char *stackbase); 

int main() 
{ 
char *stackbase; 
printf("\nThe amount of stack space used by \"testfunc\" is : %ul  bytes\n",testfunc(10, 5, stackbase)); 

return 0; 
} 

ptrdiff_t testfunc (int arg1, int arg2, char *stackbase) 
{ 
//. 
//all function processing goes here 
//. 
//. 
char temp; 
return stackbase - &temp; 
} 

看到這裏 http://cboard.cprogramming.com/c-programming/90572-determine-functions-stack-size.html

+0

我讀過你提供鏈接的論壇帖子,有人提到「你聲明局部變量的順序和它們在堆棧上的相對位置之間沒有關係。」 – WhatIf

+0

您可以嘗試'gcc-S'來編譯您的代碼,然後查找鏈接中提到的'%esp'的大小調整。 – wrangler

+0

讓我知道它是否有任何幫助。 – wrangler

0

顯然是沒有可移植的方法,因爲編譯器可以用函數做很多事情:從內聯到尾部優化。

但嚴格來說,沒有什麼可衡量的,因爲編譯器完全知道這個數字。那麼,除非你使用非常量大小的堆棧數組(在C99中允許,但不在C++中)。

一個找出愚蠢的辦法是看彙編代碼:

例如,該功能:

int f(int x, int y) 
{ 
    int z = x + y; 
    int h = z - 2; 
    return h; 
} 

被編譯在AMD64到:

f: 
.LFB0: 
.cfi_startproc 
pushq %rbp    ; save the pointer to the caller's frame 
.cfi_def_cfa_offset 16 
.cfi_offset 6, -16 
movq %rsp, %rbp  ; new frame starts from %rsp (current stack ptr) 
          ; starting from this place look how %rbp is used 
          ; the maximum offset is what you're looking for 
.cfi_def_cfa_register 6 
movl %edi, -20(%rbp) 
movl %esi, -24(%rbp) 
movl -20(%rbp), %edx 
movl -24(%rbp), %eax 
addl %edx, %eax 
movl %eax, -8(%rbp) 
movl -8(%rbp), %eax 
subl $2, %eax 
movl %eax, -4(%rbp) 
movl -4(%rbp), %eax 
popq %rbp 
.cfi_def_cfa 7, 8 
ret 

所以,在這個例子中,函數f將8字節的%rbp(舊幀指針)壓入堆棧,然後它使用%rbp-20,%rbp-24,%rbp-8和%rbp-4中的內存。最大偏移量是-24。 使用的總字節數是24個字節加上8個字節的%rbp和8個字節,在這裏對於返回指針是不可見的,如果我沒有遺忘任何東西,總共有40個字節。

我不確定這是不是你問的。

0

首先要看的是函數的C編譯器的彙編輸出,並計算所有調用,推送和堆棧幀。然後,您需要重複呼叫樹中的所有功能,查找最長的路徑以及它的總和。

如果你可以在調試器中運行該函數,只需在函數調用之前記下堆棧指針的值,直到你處於最深點並記下堆棧指針的值。這給你一個真實世界的號碼。

如果您可以重新編譯整個函數樹,請添加一個簡單的序言和結尾宏,以在全局變量中記錄堆棧指針的低水位標記。重新編譯整個項目並運行它。這給了你許多迭代的真實世界的數字。

如果您的函數調用第三方代碼,而您不知道該問題,則問題變得更加棘手。爲此,您可以簡單地將堆棧內存從當前堆棧點開始的40(或更多)字節處memset,調用該函數,然後查找自memset以來未改動的內存。

喜歡的東西(未經測試!):

編輯:哎呀,忘了堆棧增長了下來...

int StackTest() { 
    //marker is on the stack. 
    //"volatile" prevents it from optimized into a register. 
    volatile unsigned int marker= 0xDEADBEEF; 

    //The current stack pointer should be just below marker. 
    //I add 10*4 to move well below the current stack frame. 
    //If the program crashes at this point, try increasing 
    //the size of the buffer zone. 
    char *pStack= (char*)&marker[-10]; 

    //I zap the unused stack space to a recognizable value. 
    //The fill bytes will be overwritten as the stack is used. 
    //The 4096 number may need to be adjusted; it needs to be 
    //larger than the stack bytes used but less than the total 
    //stack space remaining. 
    memset(pStack-4096,0xCD,4096); 

    //Now I call my target function. 
    function(); 

    //Now I search for the first 8 fill bytes in a row. 
    //This number may need to be increased to rule out 
    //false positives, such as buffers (arrays) allocated 
    //on the stack but not completely filled, which leaves 
    //fill bytes untouched inside the buffer. 
    for(n1=0,matchCt=0;n1<4096 && matchCt<8;n1++) { 
    if(*(pStack-n1)==0xCD) 
     matchCt++; 
    else 
     matchCt= 0; 
    } 

    int stackUsed= n1-matchCt; 
    printf("Stack used: %d bytes.\n",stackUsed); 
    return(stackUsed); 
} 

請記住,硬件中斷還可以在隨機時間消耗堆棧。 編輯:這可能不是用戶進程的問題。

+0

我不認爲你可能使用的任何操作系統都會在硬件中斷上消耗用戶堆棧。通用操作系統不是因爲兩個原因:1)如果用戶棧沒有足夠的空間,會發生可怕的事情。 2)除非中斷代碼對堆棧進行消毒(這是棘手和昂貴的),否則對於被中斷的進程可以使用敏感信息。 –

+0

這是否也適用於「軟」中斷,例如定時器? – TeasingDart

+0

當然。所有相同的論點適用。 –

相關問題