2013-08-21 130 views
5

Tôi muốn viết chương trình C sẽ in nội dung của bộ đếm chương trình PC. Điều này có thể được thực hiện từ không gian người dùng, hoặc lắp ráp, hoặc một số thói quen hạt nhân cụ thể được sử dụng?Cách in giá trị chính xác của bộ đếm chương trình trong C

+0

Điều khiển mã của trình gỡ lỗi/truy cập PC nên có cách tôi nghĩ bằng cách sử dụng lắp ráp nội tuyến. –

+0

@GrijeshChauhan: Bạn có nghĩ rằng có thể có phần mở rộng GCC cho bộ đếm chương trình không? –

+1

Có, tôi không chắc lắm nhưng tôi cảm thấy có một số cách để giải quyết vấn đề này: nếu trong một đoạn mã bạn có một 'lable:' thì bạn có thể in địa chỉ của nó bằng '& lable' (điều này làm cho tôi nói có). Mã rất phía sau (hợp pháp) sử dụng loại hướng dẫn này nhưng thường sử dụng trong mã phần mềm độc hại để một Tính năng tốt của nó. –

Trả lời

11

Bạn sẽ có thể xác định máy tính bằng cách sử dụng các __current_pc() intrinsic trong trình biên dịch ARM toolchain (trình biên dịch ARM hỗ trợ nhiều của cùng một phần mở rộng như GCC). * Đây là đặc biệt đến ARM:

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

* Nhờ FrankH. để chỉ ra sự hiện diện của __current_pc()

Nói chung, PC được lưu làm địa chỉ trả lại trong cuộc gọi hàm. Trên các hệ thống không phải ARM với GCC, bạn có thể gọi __builtin_return_address(0) để lấy địa chỉ trả về của ngữ cảnh cuộc gọi hàm hiện tại. Việc truy cập bộ đếm chương trình theo cách này sẽ gây ra hình phạt khi thêm một cuộc gọi hàm, nhưng nó tránh việc lắp ráp nội tuyến, vì vậy kỹ thuật này có thể di chuyển đến bất kỳ hệ thống nào được GCC hỗ trợ.

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

Khi tôi chạy chương trình trên trên hệ thống x86 của tôi, nó tạo ra kết quả:

0x8048432 
0x8048447 
0x804845c 

Khi tháo rời trong 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

địa chỉ trả lại và PC ('EIP' /' RIP') là _not_ cùng một điều. –

+0

xin lỗi, trong ARM tôi nên nói, địa chỉ trả về ('LR') và' PC' là _not_ cùng một điều. –

+0

Và nhiều hơn nữa ... lý do tại sao bạn làm việc là vì bạn _force một hàm call_ (mà làm cho 'LR' trong func của bạn' PC' của trang gọi). Đây là _không cần thiết. –

2

Tôi nghĩ bạn có thể lấy thông tin bằng cách chèn các khối lắp ráp bên trong mã C của bạn. Điều này sẽ hoàn toàn phụ thuộc vào trình biên dịch của bạn và bộ đăng ký của nền tảng của bạn. tôi đã làm nó như thế này:

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

On ARM, bạn có thể sử dụng:

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

Hoặc cái này nên làm việc cũng như:

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

Các nội tuyến buộc là quan trọng ở đây, bởi vì đó đảm bảo bạn lấy PC theo trang web của cuộc gọi.

Chỉnh sửa: chỉ cần nhớ, __current_pc() ARM intrinsic. GCC cũng nên có điều này.