[原創文章] 作者:whq_ddd@163.com 歡迎轉載,轉載請指明出處: http://blog.csdn.net/whqwhqwhq/article/details/6853084
GCC的-pg 會為每個function call 插入一個_mcount的routine 功能,這個_mcount的原型為
void _mcount(void);
在linux調試時常不知道driver死在了哪個function中, 如果寫自己的 _mcount 並且在其中列印出caller那不就解決了!
需要解決的兩個問題是
1. 寫自己的 void _mcount(void), 並且注意此function 編譯時間不能加 -pg屬性,否則就會自己無限調用自己,直到stack溢出死機!
2. 在_count 中尋找caller的地址。這是個小痛點。
經測試是可行的。我在mips平台上做的實驗,以下內容的mips32平台相關。
mips利用ra寄存器儲存caller的返回地址,並且儲存在sp中。相當反組譯碼代碼為
00400840 <_mcount>:
400840: 27bdffe0 addiu sp,sp,-32
400844: afbf001c sw ra,28(sp)
400848: afbe0018 sw s8,24(sp)
40084c: 03a0f021 move s8,sp
即ra會儲存在sp+28處,發現sp+28處即為ra地址!只要將sp+28值取出即可,這地址為function執行完後下一次指令。
這裡取了個巧!因為sp是動態,在實際代碼編譯出來之前,你不知道_mcount會用多少sp。先隨便寫一個值,如下
void _mcount(void)
{
int addr_calling;
asm(
"lw %0,12($30)\n"
"addi %0,%0,-8\n"
"nop\n"
:"=r"(addr_calling));
printf("Calling function address: 0x%p\n", addr_calling);
}
然後利用objdump查此處代碼:
00400840 <_mcount>:
400840: 27bdffe0 addiu sp,sp,-32
400844: afbf001c sw ra,28(sp)
400848: afbe0018 sw s8,24(sp)
40084c: 03a0f021 move s8,sp
400850: 23c2000c lw v0,12(s8)
400854: 2042fffc addi v0,v0,-8
400858: 00000000 nop
發現sp利用了32個位元組!將c code更改一下,為
void _mcount(void)
{
int addr_calling;
asm(
"lw %0,28($30)\n"
"addi %0,%0,-8\n"
"nop\n"
:"=r"(addr_calling));
printf("Calling function address: 0x%p\n", addr_calling);
}
在application 中證明是可行的,在調試驅動程式時也應該是可行的,畢竟這是gcc 的特性。
貼整個source code:
file: mcount.c
#include <stdio.h>
void _mcount(void)
{
int addr_calling;
asm(
"lw %0,28($30)\n"
"addi %0,%0,-8\n"
"nop\n"
:"=r"(addr_calling));
printf("Calling function address: 0x%p\n", addr_calling);
}
file: main.c
#include "stdio.h"
extern void _mcount(void);
void call_sub1(int );
int main()
{
int a=10;
printf("in main function.\n");
call_sub1(a);
return 0;
}
void call_sub1(int a)
{
printf("in call_sub1, a is %d \n", a);
}
file: Makefile
CC = /opt/timesys/dbau1300/toolchain/bin/mipsisa32el-timesys-linux-gnu-gcc
OBJDUMP = /opt/timesys/dbau1300/toolchain/bin/mipsisa32el-timesys-linux-gnu-objdump
all:
$(CC) -c main.c -pg
$(CC) -c mcount.c
$(CC) main.o mcount.o -o test1 -pg
$(OBJDUMP) -D test1 >dis-pg.S
~
~