关于linux内核0.11中signal机制实现的疑问--
时间:2010-08-06
来源:互联网
//先附上有疑问的源代码do_signal......
void do_signal(long signr,long eax, long ebx, long ecx, long edx,
83 long fs, long es, long ds,
84 long eip, long cs, long eflags,
85 unsigned long * esp, long ss)
86 {
unsigned long sa_handler;
87
88 long old_eip=eip;
89 struct sigaction * sa = current->sigaction + signr - 1; //current->sigaction[signu-1]。
90 int longs;
91 unsigned long * tmp_esp;
92
93 sa_handler = (unsigned long) sa->sa_handler;
// 如果信号句柄为 SIG_IGN(忽略),则返回;如果句柄为 SIG_DFL(默认处理),则如果信号是
// SIGCHLD 则返回,否则终止进程的执行
94 if (sa_handler==1)
95 return;
96 if (!sa_handler) {
97 if (signr==SIGCHLD)
98 return;
else
99
do_exit(1<<(signr-1)); // 为什么以信号位图为参数?不为什么!?☺
100
// 这里应该是 do_exit(1<<(signr))。
101 }
// 如果该信号句柄只需使用一次,则将该句柄置空(该信号句柄已经保存在 sa_handler 指针中)。
102 if (sa->sa_flags & SA_ONESHOT)
103 sa->sa_handler = NULL;
// 下面这段代码将信号处理句柄插入到用户堆栈中,同时也将 sa_restorer,signr,进程屏蔽码(如果
// SA_NOMASK 没置位),eax,ecx,edx 作为参数以及原调用系统调用的程序返回指针及标志寄存器值
// 压入堆栈。因此在本次系统调用中断(0x80)返回用户程序时会首先执行用户的信号句柄程序,然后
// 再继续执行用户程序。
// 将用户调用系统调用的代码指针 eip 指向该信号处理句柄。
*(&eip) = sa_handler;
104
// 如果允许信号自己的处理句柄收到信号自己,则也需要将进程的阻塞码压入堆栈。
// 注意,这里 longs 的结果应该选择(7*4)
8*4),因为堆栈是以 4 字节为单位操作的。
105 longs = (sa->sa_flags & SA_NOMASK)?7:8;
// 将原调用程序的用户堆栈指针向下扩展 7(或
个长字(用来存放调用信号句柄的参数等),
- 145 -
5.9 signal.c 程序
// 并检查内存使用情况(例如如果内存超界则分配新页等)。
106 *(&esp) -= longs;
107 verify_area(esp,longs*4);
// 在用户堆栈中从下到上存放 sa_restorer, 信号 signr, 屏蔽码 blocked(如果 SA_NOMASK 置位),
// eax, ecx, edx, eflags 和用户程序原代码指针。
108 tmp_esp=esp;
109 put_fs_long((long) sa->sa_restorer,tmp_esp++);
110 put_fs_long(signr,tmp_esp++);
111 if (!(sa->sa_flags & SA_NOMASK))
112 put_fs_long(current->blocked,tmp_esp++);
113 put_fs_long(eax,tmp_esp++);
114 put_fs_long(ecx,tmp_esp++);
115 put_fs_long(edx,tmp_esp++);
116 put_fs_long(eflags,tmp_esp++);
put_fs_long(old_eip,tmp_esp++);
117
118 current->blocked |= sa->sa_mask; // 进程阻塞码(屏蔽码)添上 sa_mask 中的码位。
119 }
120
我的问题是:调用do_signal是在内核中进行的,就是在执行内核调用(返回前的)的最后阶段执行的,那么这个时候的堆栈指针照理说是指向内核堆栈的,
那么就是说:地106行: *(&esp) -= longs;
这句话的意思就是取内核堆栈中保存的用户堆栈指针esp的么????
从下面的put_fs_long可以看出确实是的
那么为什么这句话的意思是取内核堆栈中保存的esp的值呢?怎么理解?
void do_signal(long signr,long eax, long ebx, long ecx, long edx,
83 long fs, long es, long ds,
84 long eip, long cs, long eflags,
85 unsigned long * esp, long ss)
86 {
unsigned long sa_handler;
87
88 long old_eip=eip;
89 struct sigaction * sa = current->sigaction + signr - 1; //current->sigaction[signu-1]。
90 int longs;
91 unsigned long * tmp_esp;
92
93 sa_handler = (unsigned long) sa->sa_handler;
// 如果信号句柄为 SIG_IGN(忽略),则返回;如果句柄为 SIG_DFL(默认处理),则如果信号是
// SIGCHLD 则返回,否则终止进程的执行
94 if (sa_handler==1)
95 return;
96 if (!sa_handler) {
97 if (signr==SIGCHLD)
98 return;
else
99
do_exit(1<<(signr-1)); // 为什么以信号位图为参数?不为什么!?☺
100
// 这里应该是 do_exit(1<<(signr))。
101 }
// 如果该信号句柄只需使用一次,则将该句柄置空(该信号句柄已经保存在 sa_handler 指针中)。
102 if (sa->sa_flags & SA_ONESHOT)
103 sa->sa_handler = NULL;
// 下面这段代码将信号处理句柄插入到用户堆栈中,同时也将 sa_restorer,signr,进程屏蔽码(如果
// SA_NOMASK 没置位),eax,ecx,edx 作为参数以及原调用系统调用的程序返回指针及标志寄存器值
// 压入堆栈。因此在本次系统调用中断(0x80)返回用户程序时会首先执行用户的信号句柄程序,然后
// 再继续执行用户程序。
// 将用户调用系统调用的代码指针 eip 指向该信号处理句柄。
*(&eip) = sa_handler;
104
// 如果允许信号自己的处理句柄收到信号自己,则也需要将进程的阻塞码压入堆栈。
// 注意,这里 longs 的结果应该选择(7*4)

105 longs = (sa->sa_flags & SA_NOMASK)?7:8;
// 将原调用程序的用户堆栈指针向下扩展 7(或

- 145 -
5.9 signal.c 程序
// 并检查内存使用情况(例如如果内存超界则分配新页等)。
106 *(&esp) -= longs;
107 verify_area(esp,longs*4);
// 在用户堆栈中从下到上存放 sa_restorer, 信号 signr, 屏蔽码 blocked(如果 SA_NOMASK 置位),
// eax, ecx, edx, eflags 和用户程序原代码指针。
108 tmp_esp=esp;
109 put_fs_long((long) sa->sa_restorer,tmp_esp++);
110 put_fs_long(signr,tmp_esp++);
111 if (!(sa->sa_flags & SA_NOMASK))
112 put_fs_long(current->blocked,tmp_esp++);
113 put_fs_long(eax,tmp_esp++);
114 put_fs_long(ecx,tmp_esp++);
115 put_fs_long(edx,tmp_esp++);
116 put_fs_long(eflags,tmp_esp++);
put_fs_long(old_eip,tmp_esp++);
117
118 current->blocked |= sa->sa_mask; // 进程阻塞码(屏蔽码)添上 sa_mask 中的码位。
119 }
120
我的问题是:调用do_signal是在内核中进行的,就是在执行内核调用(返回前的)的最后阶段执行的,那么这个时候的堆栈指针照理说是指向内核堆栈的,
那么就是说:地106行: *(&esp) -= longs;
这句话的意思就是取内核堆栈中保存的用户堆栈指针esp的么????
从下面的put_fs_long可以看出确实是的
那么为什么这句话的意思是取内核堆栈中保存的esp的值呢?怎么理解?
Screenshot-1.png (119.4 KB) 内核栈和用户栈 |
作者: sunseven1245yah 发布时间: 2010-08-06
回复 sunseven1245yah
首先你应该搞清楚这个esp是什么东东...这个是作为unsigned long *类型的参数传到这个函数的。 映像中这个esp应该是当前进程的用户态栈指针。 esp只是一个变量.不是CPU中的一个寄存器ESP。不要混淆了...
0.11的内核能够访问整个内存空间.所以有了用户态栈指针之后就可以直接访问了...
貌似现在研究Linux内核的人蛮少啊... 这样的帖子挂了几天了都没人回答...
加俺的群吧... 7404853
首先你应该搞清楚这个esp是什么东东...这个是作为unsigned long *类型的参数传到这个函数的。 映像中这个esp应该是当前进程的用户态栈指针。 esp只是一个变量.不是CPU中的一个寄存器ESP。不要混淆了...
0.11的内核能够访问整个内存空间.所以有了用户态栈指针之后就可以直接访问了...
貌似现在研究Linux内核的人蛮少啊... 这样的帖子挂了几天了都没人回答...
加俺的群吧... 7404853
作者: PCliangtao 发布时间: 2010-08-07
相关阅读 更多
热门阅读
-
office 2019专业增强版最新2021版激活秘钥/序列号/激活码推荐 附激活工具
阅读:74
-
如何安装mysql8.0
阅读:31
-
Word快速设置标题样式步骤详解
阅读:28
-
20+道必知必会的Vue面试题(附答案解析)
阅读:37
-
HTML如何制作表单
阅读:22
-
百词斩可以改天数吗?当然可以,4个步骤轻松修改天数!
阅读:31
-
ET文件格式和XLS格式文件之间如何转化?
阅读:24
-
react和vue的区别及优缺点是什么
阅读:121
-
支付宝人脸识别如何关闭?
阅读:21
-
腾讯微云怎么修改照片或视频备份路径?
阅读:28