2008-11-09 116 views
3

我需要使用GCC獲取寄存器中的值。轉儲GCC中寄存器的值

事情與此類似:

 
EAX=00000002 EBX=00000001 ECX=00000005 EDX=BFFC94C0 
ESI=8184C544 EDI=00000000 EBP=0063FF78 ESP=0063FE3C 
CF=0 SF=0 ZF=0 OF=0 

獲取32位寄存器是很容易的,但我不知道該怎麼弄的標誌最簡單的方法是。

在這本書中的例子:http://kipirvine.com/asm/

他們通過讓整個EFLAGS寄存器和有問題的位移做它。我也想過使用Jcc和CMOVcc做它。

有關如何做到這一點的其他建議?一些要驗證的測試用例也是有用的。

回答

4

沒有必要使用匯編器來獲取寄存器。

你可以使用setjmp。這會將所有寄存器寫入jmp_buf類型的結構中。它甚至可以跨平臺工作,除了jmp_buf本身對於每個體系結構都不同的事實。

但是,調用setjmp(並調用匯編代碼)會改變一些寄存器,所以你不能真正相信它們。

有一種方式來獲得一個真正的快照,但是這是一個有點難度,高度依賴於操作系統的:

  1. 安裝一個異常處理程序非法違法碼擴展。處理程序可以是一個真正的中斷,一個信號處理程序或一個操作系統異常處理程序(try/except塊形式的C++將不起作用)。

  2. 在您的代碼中發出非法操作碼。

這裏的技巧是,非法操作碼沒有寄存器副作用。異常處理程序可以從堆棧或異常信息結構中複製寄存器。

同樣的技巧可以用於斷點中斷強制溢出,陷阱等等。通常有多種方法可以從一段代碼中引發中斷。


關於EFLAGS:您可以通過一個棧的操作讓他們:

PUSHFD 
    POP EAX 
    , eax now contains the EFLAG data 
+0

如何從jmp_buf結構中重建寄存器並不是很清楚。我在這裏找到它的源代碼: http://ccrma.stanford.edu/courses/250a/docs/avrgcc/setjmp_8h-source.html 生產不改變寄存器的代碼的任何想法?有些PUSH可以幫助... – 2008-11-09 17:55:17

+0

我認爲得到整個EFLAGS寄存器,但所有SH *得到正確的位會使它不清楚發生了什麼。類似於我想要用Jcc做的事情。 – 2008-11-09 17:57:13

0

我認爲使用Jcc將會更長,並且不會像使用內聯彙編那樣清晰。

這是我目前有使用過CMOVcc的:

 
void dump_regs() 
{ 
    int eax = 0; 
    int ebx = 0; 
    int ecx = 0; 
    int edx = 0; 

    int esi = 0; 
    int edi = 0; 
    int ebp = 0; 
    int esp = 0; 

    int cf = 0; 
    int sf = 0; 
    int zf = 0; 
    int of = 0; 

    int set = 1; // -52(%ebp) 

    asm( 
    "movl %eax, -4(%ebp)\n\t" 
    "movl %ebx, -8(%ebp)\n\t" 
    "movl %ecx, -12(%ebp)\n\t" 
    "movl %edx, -16(%ebp)\n\t" 
    "movl %esi, -20(%ebp)\n\t" 
    "movl %edi, -24(%ebp)\n\t" 
    "movl %ebp, -28(%ebp)\n\t" 
    "movl %esp, -32(%ebp)\n\t" 

    "movl $0, %eax\n\t" 
    "cmovb -52(%ebp),%eax\n\t" // mov if CF = 1 
    "movl %eax, -36(%ebp) \n\t" // cf 

    "movl $0, %eax\n\t" 
    "cmovs -52(%ebp),%eax\n\t" // mov if SF = 1 
    "movl %eax, -40(%ebp)\n\t" // sf 

    "movl $0, %eax\n\t" 
    "cmove -52(%ebp),%eax\n\t" // mov if ZF = 1 
    "movl %eax, -44(%ebp)\n\t" // zf 

    "movl $0, %eax\n\t" 
    "cmovo -52(%ebp),%eax\n\t" // mov if OF = 1 
    "movl %eax, -48(%ebp)\n\t" // of 

    "movl -4(%ebp), %eax\n\t" // restore EAX 
); 

    printf("EAX = %#08x\tEBX = %#08x\tECX = %#08x\tEDX = %#08x\n",eax,ebx,ecx,edx); 
    printf("ESI = %#08x\tEDI = %#08x\tEBP = %#08x\tESP = %#08x\n",esi,edi,ebp,esp); 
    printf("CF = %d\tSF = %d\tZF = %d\tOF = %d\n",cf,sf,zf,of); 
} 

一個重要的事情我還沒有制定出尚未有副作用,我希望能夠把這種無干擾狀態下,任何在這方面的提示是受歡迎的。

0

在我的頭頂,糾正我,如果我錯了,但你可以只分配一些內存,分配地址,並簡單地寫在那裏的寄存器內容與asm括號... 或你可以將它推入堆棧並以某種方式手動讀取它... 我想這需要一些很好的asm代碼,它可能不是執行此類操作的理想方式,但它會起作用。

1

的後續是爲一個64位的機測試。如果您有32位機器,請刪除64位齒輪,然後更改flag64 - > flag32(並使用pushfd而不是pushfq)。實際上,我發現我只需要檢查標誌寄存器中的CY(進位)和OV(溢出)(我通常使用jc,jnc,jojno進行檢測)。

#include <stdio.h> 
#include <stdint.h> 

#define HIGH32(x) ((uint32_t)(((uint64_t)x)>>32)) 
#define LOW32(x) ((uint32_t)(((uint64_t)x)& 0xFFFFFFFF)) 

int main(int argc, char** argv) 
{ 
    uint32_t eax32, ebx32, ecx32, edx32; 
    uint64_t rax64, rbx64, rcx64, rdx64; 

    asm (
     "movl %%eax, %[a1] ;" 
     "movl %%ebx, %[b1] ;" 
     "movl %%ecx, %[c1] ;" 
     "movl %%edx, %[d1] ;" 

     "movq %%rax, %[a2] ;" 
     "movq %%rbx, %[b2] ;" 
     "movq %%rcx, %[c2] ;" 
     "movq %%rdx, %[d2] ;" 
     : 
     [a1] "=m" (eax32), [b1] "=m" (ebx32), [c1] "=m" (ecx32), [d1] "=m" (edx32), 
     [a2] "=m" (rax64), [b2] "=m" (rbx64), [c2] "=m" (rcx64), [d2] "=m" (rdx64) 
     ); 

    printf("eax=%08x\n", eax32); 
    printf("ebx=%08x\n", ebx32); 
    printf("ecx=%08x\n", ecx32); 
    printf("edx=%08x\n", edx32); 

    printf("rax=%08x%08x\n", HIGH32(rax64), LOW32(rax64)); 
    printf("bax=%08x%08x\n", HIGH32(rbx64), LOW32(rbx64)); 
    printf("cax=%08x%08x\n", HIGH32(rcx64), LOW32(rcx64)); 
    printf("dax=%08x%08x\n", HIGH32(rdx64), LOW32(rdx64)); 

    uint64_t flags; 

    asm (
     "pushfq  ;" 
     "pop %[f1] ;" 
     : 
     [f1] "=m" (flags) 
     ); 

    printf("flags=%08x%08x", HIGH32(flags), LOW32(flags)); 

    if(flags & (1 << 0)) // Carry 
     printf(" (C1"); 
    else 
     printf(" (C0"); 

    if(flags & (1 << 2)) // Parity 
     printf(" P1"); 
    else 
     printf(" P0"); 

    if(flags & (1 << 4)) // Adjust 
     printf(" A1"); 
    else 
     printf(" A0"); 

    if(flags & (1 << 6)) // Zero 
     printf(" Z1"); 
    else 
     printf(" Z0"); 

    if(flags & (1 << 7)) // Sign 
     printf(" S1"); 
    else 
     printf(" S0"); 

    if(flags & (1 << 11)) // Overflow 
     printf(" O1)\n"); 
    else 
     printf(" O0)\n"); 

    return 0; 
}