3
votes

I need to get the values in the registers with GCC.

Something similar to this:

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

Getting the 32-bit registers is easy enough, but I'm not sure what the simplest way to get the flags is.

In the examples for this book: http://kipirvine.com/asm/

They do it by getting the whole EFLAGS register and shifting for the bit in question. I also thought of doing it using Jcc's and CMOVcc's.

Any other suggestions on how to do it? Some test cases to verify would also be useful.

5

5 Answers

4
votes

There is no need to use assembler just to get the registers.

You can just use setjmp. That will write all registers into a stucture of type jmp_buf. It even kind of Works cross platform except for the fact that jmp_buf itself is different for each architecture.

However, calling setjmp (and calling your assembler code as well) will change some of the registers, so you can't really trust them.

There is a way to get a real snapshot, but that's a bit more difficult and highly OS dependent:

  1. install an exception handler for the illegal illegal opcode extension. The handler can be either a real interrupt, a signal handler or a OS exception handler (the try/except blocks form C++ will not work).

  2. Emit an illegal opcode in your code.

The trick here is, that the illegal opcode has no register side-effects. The exception handler can copy the registers either from the stack or from a exception info structure.

The same trick may work with breakpoint interrupts forced overflows, traps or so. There is usually more than one way to raise an interrupt from a piece of code.


Regarding the EFLAGS: You can get them via a stack operation:

  PUSHFD
  POP EAX  
  , eax now contains the EFLAG data
1
votes

The follow was tested for a 64-bit machine. If you have a 32-bit machine, remove the 64-bit gear, and change flag64 -> flag32 (and use pushfd instead of pushfq). In practice, I find I only need to inspect CY (carry) and OV (overflow) from the flags register (and I usually do it with jc, jnc, jo, and jno).

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

I think using Jcc's would be longer and not as clear using inline assembly.

Here is what I currently have, using CMOVcc's:

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

One important thing I haven't worked out yet are side-effects, I want to be able to call this without disturbing the state, any tips in that direction are welcome.

0
votes

Of the top of my head, and correct me if I'm wrong, but you could just allocate some memory, get the address allocated, and simply write the register contents in there with an asm bracket... Or you could just push it into the stack and read it manually somehow... I guess it would take some good asm code and its probably not the ideal way to do something like that, but it'll work.