簡體   English   中英

需要幫助了解堆棧框架布局

[英]Need help understanding stack frame layout

在為調試器實現堆棧遍歷器時,我正在努力將參數提取到函數調用並顯示它們。 為簡單起見,我從純32位(調試器和debuggee)開始使用cdecl約定,該函數帶有3個參數。 但是,盡管嘗試了幾天,但我無法理解為什么堆棧跟蹤中的參數與cdecl定義的參數相比是亂序的(從右到左,寄存器中沒有內容)。

這是我嘗試堆棧跟蹤的函數調用的表示形式:

void Function(unsigned long long a, const void * b, unsigned int c) {
    printf("a=0x%llX, b=%p, c=0x%X\n", a, b, c);
    _asm { int 3 }; /* Because I don't have stepping or dynamic breakpoints implemented yet */
 }
 int main(int argc, char* argv[]) {
     Function(2, (void*)0x7A3FE8, 0x2004);
     return 0;
 }

這是功能(毫不奇怪)打印到控制台的內容:

a=0x2, c=0x7a3fe8, c=0x2004

這是在斷點處生成的堆棧跟蹤(調試器捕獲了該斷點,然后我嘗試遍歷堆棧):

0x3EF5E0: 0x10004286 /* previous pc */
0x3EF5DC: 0x3EF60C   /* previous fp */
0x3EF5D8: 0x7A3FE8   /* arg b --> Wait... why is b _above_ c here? */
0x3EF5D4: 0x2004     /* arg c */
0x3EF5D0: 0x0        /* arg a, upper 32 bit */
0x3EF5CC: 0x2        /* arg a, lower 32 bit */

負責轉儲堆棧幀的代碼(雖然使用DIA SDK實現,但我認為這與我的問題無關)如下所示:

ULONGLONG stackframe_top = 0;
m_frame->get_base(&stackframe_top); /* IDiaStackFrame */

/* dump 30 * 4 bytes */
for (DWORD i = 0; i < 30; i++)
{
    ULONGLONG address = stackframe_top - (i * 4);
    DWORD value;
    SIZE_T read_bytes;
    if (ReadProcessMemory(m_process, reinterpret_cast<LPVOID>(address), &value, sizeof(value), &read_bytes) == TRUE)
    {
        debugprintf(L"0x%llX: 0x%X\n", address, value); /* wrapper around OutputDebugString */
    }
}

我正在編譯測試程序,而沒有在vs2015 Update 3中進行任何優化。

我已經通過使用dia2dump示例應用程序在pdb中查找來驗證是否確實將其編譯為cdecl。 我不明白是什么導致堆棧看起來像這樣,它與我學到的內容都不匹配,也與Microsoft提供文檔不匹配。
我還對Google進行了大量檢查(包括osdev Wiki頁面,msdn博客文章等),並檢查了我的(到現在可能已經過時的)有關32位x86匯編編程的書(這些書在64位CPU存在之前就已發布) 。

非常感謝您的任何解釋或鏈接!

正如Raymond所指出的那樣,與棧框架的基礎相比,我以某種方式誤解了函數調用的參數最終出現在內存中的情況。 這是固定的代碼段:

ULONGLONG stackframe_top = 0;
m_frame->get_base(&stackframe_top); /* IDiaStackFrame */

/* dump 30 * 4 bytes */
for (DWORD i = 0; i < 30; i++)
{
    ULONGLONG address = stackframe_top + (i * 4); /* <-- Read before the stack frame */
    DWORD value;
    SIZE_T read_bytes;
    if (ReadProcessMemory(m_process, reinterpret_cast<LPVOID>(address), &value, sizeof(value), &read_bytes) == TRUE)
    {
        debugprintf(L"0x%llX: 0x%X\n", address, value); /* wrapper around OutputDebugString */
    }

}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM