您的当前位置:首页正文

linux0.11-内核信号

2024-11-22 来源:个人技术集锦

如何在ubuntu 上编译linux-0.11 :

linux内核中的信号

include/signal.h

#define SIGHUP		 1
#define SIGINT		 2
#define SIGQUIT		 3
#define SIGILL		 4
#define SIGTRAP		 5
#define SIGABRT		 6
#define SIGIOT		 6
#define SIGUNUSED	 7
#define SIGFPE		 8
#define SIGKILL		 9
#define SIGUSR1		10
#define SIGSEGV		11
#define SIGUSR2		12
#define SIGPIPE		13
#define SIGALRM		14
#define SIGTERM		15
#define SIGSTKFLT	16
#define SIGCHLD		17
#define SIGCONT		18
#define SIGSTOP		19
#define SIGTSTP		20
#define SIGTTIN		21
#define SIGTTOU		22

系统如何调用接受的信号与作用

do_signal函数是内核系统调用中断(int 0X80)中断处理子程序的预处理程序,该函数的主要作用是将信号的处理句柄插入到用户程序堆栈中,系统调用后就会执行

为什么0x80是系统调用:在代码中有相关设置

	//设置系统中断
	set_system_gate(0x80,&system_call);

sys_signal由函数库提供,用于恢复系统调用后的返回值和一些寄存器。编译链接时由libc函数库提供,用于 在信号处理程序结束后清理用户态堆栈,并恢复系统调用存放在eax中的返回值。

 

信号处理的流程

在system_call.s中,可以看到首先调用的是do_signal进行预处理,再调用sys_signal信号处理 。

_system_call:
	cmpl $nr_system_calls-1,%eax  // 比较当前的调用号和当前最大调用号 nr_system_calls = 72  0.11 仅仅有72个系统调用
	ja bad_sys_call
	push %ds
	push %es
	push %fs
	pushl %edx
	pushl %ecx		# push %ebx,%ecx,%edx as parameters
	pushl %ebx		# to the system call
	movl $0x10,%edx		# set up ds,es to kernel space
	mov %dx,%ds
	mov %dx,%es
	movl $0x17,%edx		# fs points to local data space
	mov %dx,%fs
	call _sys_call_table(,%eax,4)    //调用系统调用函数表中对应的系统调用
	pushl %eax
	movl _current,%eax
	cmpl $0,state(%eax)		# state
	jne reschedule
	cmpl $0,counter(%eax)		# counter
	je reschedule
ret_from_sys_call:
	movl _current,%eax		# task[0] cannot have signals
	cmpl _task,%eax
	je 3f
	cmpw $0x0f,CS(%esp)		# was old code segment supervisor ?
	jne 3f
	cmpw $0x17,OLDSS(%esp)		# was stack segment = 0x17 ?
	jne 3f
	movl signal(%eax),%ebx
	movl blocked(%eax),%ecx
	notl %ecx
	andl %ebx,%ecx
	bsfl %ecx,%ecx
	je 3f
	btrl %ecx,%ebx
	movl %ebx,signal(%eax)
	incl %ecx
	pushl %ecx
	call _do_signal     //执行do_signal 系统调用
	popl %eax
3:	popl %eax
	popl %ebx
	popl %ecx
	popl %edx
	pop %fs
	pop %es
	pop %ds
	iret

由于C函数是传值函数,因此给eip赋值时需要使用'*(&eip)'的形式。


//系统调用中断处理程序中的信号处理程序
void do_signal(long signr,long eax, long ebx, long ecx, long edx,
	long fs, long es, long ds,
	long eip, long cs, long eflags,
	unsigned long * esp, long ss)
{
	unsigned long sa_handler;
	long old_eip=eip;
	
	/*
	struct sigaction sigaction[32];
	current->sigaction + signr - 1 指向对应signr的sigaction  
	 */
	struct sigaction * sa = current->sigaction + signr - 1;
	int longs;
	unsigned long * tmp_esp;

	sa_handler = (unsigned long) sa->sa_handler;

	
	//#define SIG_DFL		((void (*)(int))0)	/* default signal handling */
	//#define SIG_IGN		((void (*)(int))1)	/* ignore signal */	
	if (sa_handler==1)/* ignore signal */	
		return;
	if (!sa_handler) {/* default signal handling */
		if (signr==SIGCHLD)//signr=SIGCHLD 没有定义处理函数 则返回
			return;
		else
		//do_exit 处理当前进程退出过程,当前进程已经死亡
			do_exit(1<<(signr-1));
	}
	if (sa->sa_flags & SA_ONESHOT)//该信号句柄仅仅需要使用一次,sa->sa_handler 置空
		sa->sa_handler = NULL;

    //将信号处理函数插入到用户堆栈。本次系统调用中断(0x80)返回用户程序时会先执行该信号处理函数
	//然后继续执行用户程序
	*(&eip) = sa_handler;
	longs = (sa->sa_flags & SA_NOMASK)?7:8;
	*(&esp) -= longs;
	verify_area(esp,longs*4);
	tmp_esp=esp;
	put_fs_long((long) sa->sa_restorer,tmp_esp++);
	put_fs_long(signr,tmp_esp++);
	if (!(sa->sa_flags & SA_NOMASK))
		put_fs_long(current->blocked,tmp_esp++);
	put_fs_long(eax,tmp_esp++);
	put_fs_long(ecx,tmp_esp++);
	put_fs_long(edx,tmp_esp++);
	put_fs_long(eflags,tmp_esp++);
	put_fs_long(old_eip,tmp_esp++);
	current->blocked |= sa->sa_mask;
}

sys_signal

 signal()系统调用。类似于sigaction()。为指定的信号安装新的信号句柄(信号处理程序)。 信号句柄可以是用户指定的函数,也可以是SIG_DFL(默认句柄)或SIG_IGN(忽略)。参数signum --指定的信号;handler --指定的句柄;restorer --恢复函数指针,该函数由Libc库提供。用于在信号处理程序结束后恢复系统调用返回时几个寄存器的原有值以及系统 调用的返回值,就好像系统调用没有执行过信号处理程序而直接返回到用户程序一样。 函数返回原信号句柄。
 

int sys_signal(int signum, long handler, long restorer)
{
	设置分配一个信号结构体
	struct sigaction tmp;
	检索信号范围要在1-32并且不是终止信号			
	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;
}

显示全文