點擊(此處)摺疊或打開
-
int* fun_a();
- int* (*fun_b)();
點擊(此處)摺疊或打開
-
#include <stdio.h>
-
-
int fun_a(void);
-
int fun_b(void);
-
int fun_c(void);
-
int fun_d(void);
-
-
int main(void)
-
{
-
int i ;
-
void (*fp[4])(); /* 定義一個函數數組指針 */
-
-
fp[0] = (int*)fun_a; /* 將函數的地址賦給定義好的指針,同時強制轉化爲int* */
-
fp[1] = (int*)fun_b;
-
fp[2] = (int*)fun_c;
-
fp[3] = (int*)fun_d;
-
-
for(i=0;i<4;i++)
-
{
-
fp[i]();
-
printf("%p\n",fp[i]);
-
}
-
-
return 0;
-
}
-
-
int fun_a(void)
-
{
-
printf("This is fun_a !\n");
-
return 0;
-
}
-
-
int fun_b(void)
-
{
-
printf("This is fun_b !\n");
-
return 0;
-
}
-
-
int fun_c(void)
-
{
-
printf("This is fun_c !\n");
-
return 0;
-
}
-
-
int fun_d(void)
-
{
-
printf("This is fun_d !\n");
-
return 0;
- }
點擊(此處)摺疊或打開
- ~/audio$ gcc -g -o test test.c
點擊(此處)摺疊或打開
-
lishuo@lishuo-Rev-1-0:~/audio$ ./test
-
This is fun_a !
-
0x8048481
-
This is fun_b !
-
0x804849a
-
This is fun_c !
-
0x80484b3
-
This is fun_d !
- 0x80484cc
點擊(此處)摺疊或打開
- (gdb) set disassembly-flavor intel
點擊(此處)摺疊或打開
- (gdb) disassemble main
- Dump of assembler code for function main:
- 0x08048414 <+0>: push ebp
- 0x08048415 <+1>: mov ebp,esp ;將esp保存到ebp中,防止在函數執行過程中破壞esp。
- 0x08048417 <+3>: and esp,0xfffffff0
- 0x0804841a <+6>: sub esp,0x30 ;上面兩句的目的是,開闢一塊48字節大小的棧區,用於保存函數運行過程中的數據和地址
- 0x0804841d <+9>: mov eax,0x8048481 ;此爲fun_a的地址,後面會詳細講到
- 0x08048422 <+14>: mov DWORD PTR [esp+0x1c],eax ;將fun_a的地址壓棧到esp+0x1c處,方便調用該函數的時候取出。
- 0x08048426 <+18>: mov eax,0x804849a
- 0x0804842b <+23>: mov DWORD PTR [esp+0x20],eax
- 0x0804842f <+27>: mov eax,0x80484b3
- 0x08048434 <+32>: mov DWORD PTR [esp+0x24],eax
- 0x08048438 <+36>: mov eax,0x80484cc
- 0x0804843d <+41>: mov DWORD PTR [esp+0x28],eax ;這兩個也是一個道理,將fun_b,fun_c的地址壓棧,方便調用。
- => 0x08048441 <+45>: mov DWORD PTR [esp+0x2c],0x0 ;將0壓入esp+0x2c處,實際此處保存的是i變量的值。
- 0x08048449 <+53>: jmp 0x8048473 <main+95> ;開始for循環,它跳轉到cmp指令處,實際就是比較i和4的大小關係,從而決定函數流程
- 0x0804844b <+55>: mov eax,DWORD PTR [esp+0x2c] ;將i的值賦給eax寄存器
- 0x0804844f <+59>: mov eax,DWORD PTR [esp+eax*4+0x1c];此處實際是將fp[i]的值賦給eax
- 0x08048453 <+63>: call eax ;調用fp[i],也就是依次調用fun_a,fun_b,fun_c
- 0x08048455 <+65>: mov eax,DWORD PTR [esp+0x2c]
- 0x08048459 <+69>: mov edx,DWORD PTR [esp+eax*4+0x1c];將fp[i]的值賦給edx
- 0x0804845d <+73>: mov eax,0x80485c0
- 0x08048462 <+78>: mov DWORD PTR [esp+0x4],edx ;將edx值壓棧到esp+0x4處
- 0x08048466 <+82>: mov DWORD PTR [esp],eax ;將地址0x80485c0壓入esp處,此地址爲存儲字符串的位置,例如“This is fun_a !”。
- 0x08048469 <+85>: call 0x8048320 <printf@plt> ;它是printf函數調用必須的參數
- 0x0804846e <+90>: add DWORD PTR [esp+0x2c],0x1 ;i++
- 0x08048473 <+95>: cmp DWORD PTR [esp+0x2c],0x3 ;比較i和3的大小
- 0x08048478 <+100>: jle 0x804844b <main+55> ;如果i <= 3,那麼跳轉到main+55處;否則結束for循環。
- 0x0804847a <+102>: mov eax,0x0 ;通常情況下eax保存返回值。這裏其實就是return 0 ;。
- 0x0804847f <+107>: leave ;將ebp彈棧,同時恢復esp原有值。
- 0x08048480 <+108>: ret
- End of assembler dump.
點擊(此處)摺疊或打開
- (gdb) print fp[0]
- $1 = (void (*)()) 0x8048481 <fun_a>
- (gdb) print fp[1]
- $2 = (void (*)()) 0x804849a <fun_b>
點擊(此處)摺疊或打開
- (gdb) x /25xh 0x8048481
- 0x8048481 <fun_a>: 0x8955 0x83e5 0x18ec 0x04c7 0xc424 0x0485 0xe808 0xfe9d
- 0x8048491 <fun_a+16>: 0xffff 0x00b8 0x0000 0xc900 0x55c3 0xe589 0xec83 0xc718
- 0x80484a1 <fun_b+7>: 0x2404 0x85d4 0x0804 0x84e8 0xfffe 0xb8ff 0x0000 0x0000
- 0x80484b1 <fun_b+23>: 0xc3c9
- (gdb) x /25xh 0x804849a
- 0x804849a <fun_b>: 0x8955 0x83e5 0x18ec 0x04c7 0xd424 0x0485 0xe808 0xfe84
- 0x80484aa <fun_b+16>: 0xffff 0x00b8 0x0000 0xc900 0x55c3 0xe589 0xec83 0xc718
- 0x80484ba <fun_c+7>: 0x2404 0x85e4 0x0804 0x6be8 0xfffe 0xb8ff 0x0000 0x0000
- 0x80484ca <fun_c+23>: 0xc3c9
點擊(此處)摺疊或打開
- (gdb) disassemble 0x8048481
- Dump of assembler code for function fun_a:
- 0x08048481 <+0>: push ebp
- 0x08048482 <+1>: mov ebp,esp
- 0x08048484 <+3>: sub esp,0x18
- 0x08048487 <+6>: mov DWORD PTR [esp],0x80485c4 ;此處的將第一個字符串地址壓棧,方便後面函數的調用。
- 0x0804848e <+13>: call 0x8048330 <puts@plt>
- 0x08048493 <+18>: mov eax,0x0
- 0x08048498 <+23>: leave
- 0x08048499 <+24>: ret
- End of assembler dump.
- (gdb) disassemble 0x804849a
- Dump of assembler code for function fun_b:
- 0x0804849a <+0>: push ebp
- 0x0804849b <+1>: mov ebp,esp
- 0x0804849d <+3>: sub esp,0x18
- 0x080484a0 <+6>: mov DWORD PTR [esp],0x80485d4 ;此處的將第二個字符串地址壓棧,方便後面函數的調用。
- 0x080484a7 <+13>: call 0x8048330 <puts@plt>
- 0x080484ac <+18>: mov eax,0x0
- 0x080484b1 <+23>: leave
- 0x080484b2 <+24>: ret
- End of assembler dump.
點擊(此處)摺疊或打開
- (gdb) x /16cb 0x80485c4
- 0x80485c4: 84 'T' 104 'h' 105 'i' 115 's' 32 ' ' 105 'i' 115 's' 32 ' '
- 0x80485cc: 102 'f' 117 'u' 110 'n' 95 '_' 97 'a' 32 ' ' 33 '!' 0 '\000'
- (gdb) x /16cb 0x80485d4
- 0x80485d4: 84 'T' 104 'h' 105 'i' 115 's' 32 ' ' 105 'i' 115 's' 32 ' '
- 0x80485dc: 102 'f' 117 'u' 110 'n' 95 '_' 98 'b' 32 ' ' 33 '!' 0 '\000'