3

我需要使用 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

5 回答 5

4

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

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

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

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

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

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

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

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


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

  PUSHFD
  POP EAX  
  , eax now contains the EFLAG data
于 2008-11-09T11:32:37.250 回答
1

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

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

高温高压

于 2008-11-09T11:56:50.510 回答
1

以下是针对 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;
}
于 2011-06-19T20:59:05.790 回答
0

我认为使用 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);
}

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

于 2008-11-09T09:35:49.653 回答
0

我的头顶,如果我错了,请纠正我,但你可以分配一些内存,获得分配的地址,然后用一个asm括号将寄存器内容写在那里......或者你可以只是推它进入堆栈并以某种方式手动读取它......我想它需要一些好的asm代码,它可能不是做类似事情的理想方式,但它会起作用。

于 2008-11-09T09:48:36.057 回答