Linux 信号处理从内核到应用

前言

学习笔记,基于 Linux0.11 简单介绍下 Linux 信号处理流程
以前看完 Linux0.11 的时候,感觉没什么用,到后面看的书多了才有了感觉,这本书写的都是内核的骨的感觉啊。。。
因为信号会用内核态调用到用户态中,与硬件高度相关,这大概就是 《Linux 内核设计与实现》中没有介绍他的原因吧,可惜了。

参考资料:
x86 堆栈切换相关知识
《Linux 内核完全注释》
《 Unix 环境高级编程》

应用编程

表 10-1 UNIX 系统信号

在这里插入图片描述

例子程序

在这里插入图片描述

signal() 与 sigaction() 区别

在这里插入图片描述

内核流程

信号处理位置

信号处理是在系统调用完成后,返回用户空间前检查信号处理的

在这里插入图片描述

在这里插入图片描述

处理处理函数:
在这里插入图片描述

地址空间与堆栈

下面简单介绍下 Linux0.11 中程序的地址空间,在 Linux0.11 上,内核将 32 总线寻址的 4G 地址空间以 64M 为单位分给各个进程使用,
每个进程使用不同的地址空间
在这里插入图片描述

针对每个进程,其内部划分又如下所示,分为代码段,数据段,bss, 堆栈,环境参数块
在这里插入图片描述

其中堆栈用于保存函数调用帧,比如函数 1 调用到函数 2 时,会将相关参数与返回地址保存在栈中,结构如下:

在这里插入图片描述

所以函数调用后,不想返回之前的调用函数,则可以通过修改调用栈实现。但这里有个问题,就是针对信号处理,
因为信号是在内核态检查的,内核态与用户态的堆栈是不一样的,所以还涉及到一个堆栈切换的问题。

但核心思想不变,如果想让用户态程序调用到我们自己定义的信号处理函数,那就要修改用户态的调用栈

内核态与用户态

硬件特权级示意图:
在这里插入图片描述

软件上权限体现在哪里呢?体现在代码段数据段的 DPL 字段中
在这里插入图片描述

再细一点,就是体现在 GDT 表中各程序的代码段数据段中,表示不同的特权级:
在这里插入图片描述

那会在哪里用到中转呢?毕竟切换前后会不会特权级变化,起码需要保存当前的特权级,然后跟要换入的任务比较,
这里就是通过 TR 指向的 TSS 保存当前程序的代码段,数据段的,里面有当前进程物特权级:

在这里插入图片描述

这也就引出了堆栈段,因为不同的特权级执行的代码是需要隔离的,所以堆栈也是使用各自的,不然有些用户程序,修改特权级堆栈瞎搞,
这不是会出事嘛。

所以特权级切换也会有堆栈切换,堆栈切换时,会传入参数及原堆栈指针位置:

在这里插入图片描述
在这里插入图片描述

用户栈与内核栈

用户栈位置前面已经有图描述过了,在用户地址空间中位置如下:
在这里插入图片描述

而内核堆栈则在分配 task_struct 结构体所在一页内存的高端地址中,所以堆栈大小是有限的,需要注意调用栈不能嵌套太深
在这里插入图片描述

信号调用流程

前面巴拉巴拉那么多,就是引出两个概念:

1. 用户态跟内核态使用的堆栈是不一样的
2. 函数调用过程有调用栈,可以通过修改调用栈来改变返回时的函数调用路径

所对针对信号调用处理流程就是类似这样的:
在这里插入图片描述

 	1. 系统调用,在内核态检查信号,如果有,就修改:
 			1.1 内核态堆栈,让其返回用户态时,直接去调用信号处理程序
 			1.2 用户态堆栈,让其执行完信号处理程序后,调用 sa_restorer 恢复用户堆栈至没调用信号处理函数一样
	2. 信号处理程序执行完成后,因为用户态堆栈也会修改了,会执行 sa_restorer 恢复信号调用前堆栈,从而继续执行系统调用下一条

相关堆栈修改如下:
在这里插入图片描述
在这里插入图片描述

插一句,这个 sa_restorer() 是标志 C 库里面的。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值