【问题标题】:Dumping the values of the registers in GCC在 GCC 中转储寄存器的值
【发布时间】:2010-09-21 12:07:20
【问题描述】:

我需要使用 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 来做这件事。

关于如何做的任何其他建议?一些要验证的测试用例也会很有用。

【问题讨论】:

    标签: gcc assembly x86


    【解决方案1】:

    不需要使用汇编程序来获取寄存器。

    您可以只使用 setjmp。这会将所有寄存器写入 jmp_buf 类型的结构中。它甚至有点跨平台,除了 jmp_buf 本身对于每个架构都不同。

    但是,调用 setjmp(以及调用您的汇编代码)会更改一些寄存器,因此您不能真正信任它们。

    有一种方法可以获得真实的快照,但这有点困难并且高度依赖于操作系统:

    1. 为非法的非法操作码扩展安装异常处理程序。处理程序可以是真正的中断、信号处理程序或操作系统异常处理程序(C++ 中的 try/except 块将不起作用)。

    2. 在您的代码中发出非法操作码。

    这里的诀窍是,非法操作码没有寄存器副作用。异常处理程序可以从堆栈或异常信息结构中复制寄存器。

    同样的技巧可能适用于断点中断、强制溢出、陷阱等。通常有不止一种方法可以从一段代码中引发中断。


    关于 EFLAGS:您可以通过堆栈操作获取它们:

      PUSHFD
      POP EAX  
      , eax now contains the EFLAG data
    

    【讨论】:

    • 目前还不清楚如何从 jmp_buf 结构中重构寄存器。我在这里找到了它的来源:ccrma.stanford.edu/courses/250a/docs/avrgcc/… 在生成不更改寄存器的代码方面有什么想法吗?一些 PUSH 可能会有所帮助...
    • 我考虑过获取整个 EFLAGS 寄存器,但是所有的 SH* 来获取正确的位会使发生的事情变得不太清楚。类似于我想用 Jcc 做的事情。
    【解决方案2】:

    恕我直言,使用 gdb 比 gcc 好。

    http://www.unknownroad.com/rtfm/gdbtut/gdbadvanced.html

    HTH

    【讨论】:

    • 这很有用!它帮助我验证我所拥有的是正确的。谢谢!
    【解决方案3】:

    以下内容针对 64 位机器进行了测试。如果您有 32 位机器,请移除 64 位齿轮,并更改 flag64 -> flag32(并使用pushfd 而不是pushfq)。在实践中,我发现我只需要检查标志寄存器中的 CY(进位)和 OV(溢出)(我通常使用 jcjncjojno 来检查)。

    #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;
    }
    

    【讨论】:

      【解决方案4】:

      我认为使用 Jcc 会更长,而且使用内联汇编不太清楚。

      这是我目前拥有的,使用 CMOVcc 的:

      无效转储注册() { 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; 整数 = 0; 整数集 = 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" // 如果 CF = 1 则移动 "movl %eax, -36(%ebp) \n\t" // cf "movl $0, %eax\n\t" "cmovs -52(%ebp),%eax\n\t" // 如果 SF = 1 则移动 "movl %eax, -40(%ebp)\n\t" // sf "movl $0, %eax\n\t" "cmove -52(%ebp),%eax\n\t" // 如果 ZF = 1 则移动 "movl %eax, -44(%ebp)\n\t" // zf "movl $0, %eax\n\t" "cmovo -52(%ebp),%eax\n\t" // 如果 OF = 1 则移动 "movl %eax, -48(%ebp)\n\t" // 的 "movl -4(%ebp), %eax\n\t" // 恢复 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); }

      我还没有解决的一个重要问题是副作用,我希望能够在不干扰状态的情况下调用它,欢迎任何关于这个方向的提示。

      【讨论】:

        【解决方案5】:

        在我的脑海中,如果我错了,请纠正我,但你可以分配一些内存,获取分配的地址,然后简单地用 asm 括号将寄存器内容写在那里...... 或者您可以将其推入堆栈并以某种方式手动读取... 我想这需要一些好的 asm 代码,它可能不是执行此类操作的理想方式,但它会起作用。

        【讨论】:

          猜你喜欢
          • 2015-04-25
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-02-06
          • 2014-03-01
          • 1970-01-01
          相关资源
          最近更新 更多