signal原型分析

在linux-0.11內核中,我們找到signal函數原型:

void (*signal(int _sig, void (*_func)(int)))(int);

這個函數很難理解,先複習看一些基礎知識。


1、函數指針定義

int  (*f)(int);                     //定義f爲   有一個int類型參數,返回值爲int的   函數指針

int p(int); // 我們可以通過 f = &p; 對f進行賦值。

char ( *pf(long) )(int) {}        //定義pf爲有一個long類型參數,返回值爲(有一個int類型參數,返回值爲char類型函數指針)  的函數     


那麼void (*signal(int _sig, void (*_func)(int)))(int); 

即是 聲明瞭一個帶有2個參數,返回值爲帶有一個int類型參數,返回值爲void的函數指針 的函數


2、通過小例子進一步學習

#include <stdio.h>

void pt(int){
	printf("2\n");
}

void (*f(int, void (*fun)(int)))(int){
	return fun;	
}

int main(){
	f(0, pt);
	printf("----\n");
	(*f(0, pt))(0);
}
這個小程序的輸出爲:


f(0, pt); 調用後,返回fun的地址,即將fun的地址推送到eax, 但是並未執行。

(*f(0, pt))(0); 調用後, 將eax的地址作爲一個函數進行調用, 所以這樣的輸出就不難理解了。


3、signal源碼分析

signal通過int0x80調用系統中斷sys_signal. 實現和上面的f基本一樣, 其實f就是signal的簡化版。

int sys_signal(int signum, long handler, long restorer)
{
	struct sigaction tmp;

	if (signum<1 || signum>32 || signum==SIGKILL)
		return -1;
	tmp.sa_handler = (void (*)(int)) handler;
	tmp.sa_mask = 0;
	tmp.sa_flags = SA_ONESHOT | SA_NOMASK;
	tmp.sa_restorer = (void (*)(void)) restorer;
	handler = (long) current->sigaction[signum-1].sa_handler;
	current->sigaction[signum-1] = tmp;
	return handler;
}
這個函數將signal(SIG_NUM, handle)傳遞的參數在進程上下文(信號處理表)中進行註冊, 同時返回舊的handle地址。

該函數和上面的f一樣,只是將handle地址存放到eax寄存器,當做調用的返回, 並未實際執行函數。


4、更好的方法

typedef void (*__sighandler_t) (int);       

//引入 __sighandler_t   類型    爲 一個帶int類型參數,返回值爲void的函數指針     的關鍵字


extern __sighandler_t __sysv_signal (int __sig, __sighandler_t __handler)       

 //聲明一個返回值爲函數指針的函數



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章