Сброс значений из регистров в 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.
Любые другие предложения о том, как это сделать? Некоторые контрольные примеры для проверки также были бы полезны.
5 ответов
Нет необходимости использовать ассемблер только для получения регистров.
Вы можете просто использовать setjmp. Это запишет все регистры в структуру типа jmp_buf. Это даже своего рода кроссплатформенность Works за исключением того факта, что сам jmp_buf отличается для каждой архитектуры.
Однако, вызов setjmp (и вызов вашего ассемблерного кода) изменит некоторые регистры, поэтому вы не можете им доверять.
Есть способ получить настоящий снимок, но это немного сложнее и сильно зависит от операционной системы:
установите обработчик исключений для нелегального нелегального расширения кода операции. Обработчик может быть либо действительным прерыванием, обработчиком сигнала, либо обработчиком исключений ОС (блоки try/ исключением из формы C++ не будут работать).
Создайте недопустимый код операции в вашем коде.
Хитрость в том, что нелегальный код операции не имеет побочных эффектов. Обработчик исключений может копировать регистры либо из стека, либо из информационной структуры исключения.
Тот же трюк может работать с прерываниями точки останова, принудительными переполнениями, ловушками и т. Д. Обычно существует более одного способа вызвать прерывание из фрагмента кода.
Относительно EFLAGS: Вы можете получить их через операцию стека:
PUSHFD
POP EAX
, eax now contains the EFLAG data
Последующее было протестировано на 64-битной машине. Если у вас 32-битный компьютер, удалите 64-битную передачу и измените flag64 -> flag32 (и используйте pushfd
вместо pushfq
). На практике я нахожу, что мне нужно только проверять CY (перенос) и OV (переполнение) из регистра флагов (и я обычно делаю это с jc
, jnc
, jo
, а также 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;
}
Из головы, и поправьте меня, если я ошибаюсь, но вы можете просто выделить немного памяти, выделить адрес и просто записать туда содержимое регистра с помощью скобки asm... Или вы можете просто нажать ее в стек и как-то читать его вручную... Я думаю, что потребуется хороший ассемблерный код, и это, вероятно, не идеальный способ сделать что-то подобное, но это будет работать.
Я думаю, что использование 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) как м("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, если CF = 1 "movl% eax, -36 (% ebp) \ n \ t" // cf "movl $ 0,% eax \ n \ t" "cmovs -52 (% ebp),% eax \ n \ t" // mov, если SF = 1 "movl% eax, -40 (% ebp) \ n \ t" // sf "movl $ 0,% eax \ n \ t" "cmove -52 (% ebp),% eax \ n \ t" // mov, если 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" // из "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); }
Одна важная вещь, которую я еще не разработал, - это побочные эффекты, я хочу, чтобы это можно было назвать, не нарушая состояние, любые советы в этом направлении приветствуются.