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 を呼び出す (およびアセンブラー コードも呼び出す) と、一部のレジスターが変更されるため、それらを信頼することはできません。

実際のスナップショットを取得する方法はありますが、それは少し難しく、OS に大きく依存します。

  1. 不正な不正オペコード拡張の例外ハンドラをインストールします。ハンドラーは、実際の割り込み、シグナル ハンドラー、または OS 例外ハンドラーのいずれかです (C++ の try/except ブロックは機能しません)。

  2. コードで不正なオペコードを発行します。

ここでの秘訣は、不正なオペコードにはレジスタの副作用がないということです。例外ハンドラは、スタックまたは例外情報構造体からレジスタをコピーできます。

同じトリックは、強制的なオーバーフローやトラップなどのブレークポイント割り込みでも機能する場合があります。通常、コードから割り込みを発生させる方法は複数あります。


EFLAGS について: スタック操作で取得できます。

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

以下は64ビットマシンでテストされました。32ビットマシンを使用している場合は、64ビットギアを取り外し、flag64-> flag32を変更します(pushfdの代わりに使用しますpushfq)。実際には、フラグレジスタからCY(キャリー)とOV(オーバーフロー)を検査するだけでよいことがわかります(通常、、、、、およびを使用して検査しjcます)。jncjojno

#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 に答える
1

私見、gdbを使用することはgccよりも優れています。

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

HTH

于 2008-11-09T11:56:50.510 に答える
0

Jcc を使用すると長くなり、インライン アセンブリを使用すると明確ではなくなると思います。

CMOVccを使用して、私が現在持っているものは次のとおりです。

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

  int esi = 0;
  int エディ = 0;
  int ebp = 0;
  int esp = 0;

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

  int セット = 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" // of

    "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);
}

まだ解決していない重要なことの 1 つは副作用です。状態を乱すことなくこれを呼び出すことができるようにしたいと考えています。その方向のヒントは大歓迎です。

于 2008-11-09T09:35:49.653 に答える
0

私の頭のてっぺんから、私が間違っている場合は修正してください。ただし、メモリを割り当て、割り当てられたアドレスを取得し、asmブラケットを使用してレジスタの内容をそこに書き込むことができます...または、単にプッシュすることもできますスタックに入れ、何らかの方法で手動で読み取ります...それにはいくつかの優れたasmコードが必要であり、おそらくそのようなことを行う理想的な方法ではないと思いますが、うまくいきます。

于 2008-11-09T09:48:36.057 に答える