2013-08-21 10 views
5

Chcę napisać program w języku C, który wydrukowałby zawartość licznika programu PC. Czy można to zrobić z przestrzeni użytkownika, zespołu lub z niektórych konkretnych procedur jądra?Jak wydrukować dokładną wartość licznika programu w C

+0

Kontrola kodu debuggera/dostęp do komputera, więc powinien być sposób, w jaki myślę przy użyciu wbudowanego zestawu. –

+0

@GrijeshChauhan: Czy sądzisz, że może istnieć rozszerzenie GCC dla licznika programu? –

+1

Tak, nie jestem do końca pewny, ale uważam, że powinno być jakiś sposób obejścia tej notatki: jeśli w kodzie masz 'label: ', możesz wydrukować jego adres używając' & lable' (to sprawia, że ​​mówię tak). Bardzo kod tylny (zgodny z prawem) używa tego rodzaju instrukcji, ale często używa go w kodzie złośliwego oprogramowania, więc jest to dobra funkcja. –

Odpowiedz

11

Powinieneś być w stanie określić komputer za pomocą __current_pc() intrinsic w toolchain ARM kompilatora (kompilator ARM obsługuje wiele tych samych rozszerzenia jako GCC). * Jest to szczególnie ARM:

int main() { 
    printf("%#x\n", __current_pc()); 
    printf("%#x\n", __current_pc()); 
    printf("%#x\n", __current_pc()); 
    return 0; 
} 

* Dzięki FrankH. za wskazanie obecności __current_pc()

W ogóle, komputer zostaje zapisany jako adres zwrotny w wywołaniu funkcji. W systemach innych niż ARM z GCC można wywołać __builtin_return_address(0), aby uzyskać adres powrotu bieżącego kontekstu wywołania funkcji. Uzyskanie licznika programu w ten sposób pociąga za sobą karę dodania wywołania funkcji, ale unika on wbudowanego zestawu, więc technika ta jest przenośna do dowolnego systemu obsługiwanego przez GCC.

void * get_pc() { return __builtin_return_address(0); } 
int main() { 
    printf("%p\n", get_pc()); 
    printf("%p\n", get_pc()); 
    printf("%p\n", get_pc()); 
    return 0; 
} 

Kiedy uruchomić powyższy program w moim systemie x86, produkuje wyjście:

0x8048432 
0x8048447 
0x804845c 

Podczas demontażu w gdb:

Dump of assembler code for function main: 
    0x08048424 <+0>: push %ebp 
    0x08048425 <+1>: mov %esp,%ebp 
    0x08048427 <+3>: and $0xfffffff0,%esp 
    0x0804842a <+6>: sub $0x10,%esp 
    0x0804842d <+9>: call 0x804841c <get_pc> 
    0x08048432 <+14>: mov %eax,0x4(%esp) 
    0x08048436 <+18>: movl $0x8048510,(%esp) 
    0x0804843d <+25>: call 0x80482f0 <[email protected]> 
    0x08048442 <+30>: call 0x804841c <get_pc> 
    0x08048447 <+35>: mov %eax,0x4(%esp) 
    0x0804844b <+39>: movl $0x8048510,(%esp) 
    0x08048452 <+46>: call 0x80482f0 <[email protected]> 
    0x08048457 <+51>: call 0x804841c <get_pc> 
    0x0804845c <+56>: mov %eax,0x4(%esp) 
    0x08048460 <+60>: movl $0x8048510,(%esp) 
    0x08048467 <+67>: call 0x80482f0 <[email protected]> 
    0x0804846c <+72>: mov $0x0,%eax 
    0x08048471 <+77>: leave 
    0x08048472 <+78>: ret  
End of assembler dump. 
+1

adres zwrotny i komputer ('EIP' /' RIP') to _nie to samo. –

+0

Przepraszam, w ARM, powiem, adres zwrotny ('LR') i' PC' są _nie_ to samo. –

+0

I więcej ... powód, dla którego działa twój, polega na tym, że _force wywołuje funkcję call_ (która czyni 'LR' w twoim funku' PC' strony wywołania). Jest to niepotrzebnie nieefektywne. –

2

Cóż, myślę, że można uzyskać informacje, wstawiając bloki montażowe do kodu C. To będzie całkowicie zależało od twojego kompilatora i zestawu rejestrów twojej platformy. zrobiłem to tak:

int get_counter1() 

{ 

    __asm__ ("lea (%rip), %eax ") ; 
} 

int get_counter2() 

{ 

    int x = 0; 
    __asm__ ("lea (%rip), %eax") ; 
} 

int main() 

{ 

    printf("%x\n",get_counter1()); 
    printf("%x\n",get_counter2()); 
    return 0; 
} 

4004ce

4004e1

5

na ramieniu, można użyć:

static __inline__ void * get_pc(void) { 
    void *pc; 
    asm("mov %0, pc" : "=r"(pc)); 
    return pc; 
} 

Albo ten powinien działać jak dobrze:

static __inline__ void * get_pc(void) { 
    register void * pc __asm__("pc"); 
    __asm__("" : "=r"(pc)); 
    return pc; 
} 

Wymuszony inline jest tutaj ważne, bo gwarantuje Ci odzyskać PC jak na miejscu wywołania.

Edytuj: Właśnie zapamiętany, __current_pc() ARM intrinsic. GCC również powinno to mieć.

Powiązane problemy