Posted on 2012-10-15 10:37
鑫龙 阅读(555)
评论(0) 编辑 收藏 引用 所属分类:
linux内核
Linux通过slab分配器动态分配task_struct结构,该结构定义在了<include/linux/sched.h>文件中,进程描述符中包含一个具体进程的所有信息,各个进程的task_struct存放在它们内核栈的尾端。在栈底(对于向下增长的栈)或栈顶(对于向上增长的栈)创建一个新的结构struct thread_info。利用这个新的机构来迅速的找到task_struct的位置。 下面是kernel2.6.32.10里task_struct的定义(对于x86类型的CPU来说文件位于:arch/x86/include/asm /include/asm/thread_info.h):- struct thread_info {
- struct task_struct *task; /* main task structure */
- struct exec_domain *exec_domain; /* execution domain */
- __u32 flags; /* low level flags */
- __u32 status; /* thread synchronous flags */
- __u32 cpu; /* current CPU */
- int preempt_count; /* 0 => preemptable, <0 => BUG */
- mm_segment_t addr_limit;
- struct restart_block restart_block;
- void __user *sysenter_return;
- #ifdef CONFIG_X86_32
- unsigned long previous_esp; /* ESP of the previous stack in case of nested (IRQ) stacks*/
- __u8 supervisor_stack[0];
- #endif
- int uaccess_err;
- };
其中的task的值就为task_struct的位置。kernel利用current宏寻找task_struct的位置,假设栈的大小为8k(13个二进制位),我们可以将进程栈的地址的后13位屏蔽掉,这样得到的刚好就是进程栈的起始地址,而thread_info刚好就是位于进程栈的底部,所以进程栈的起始地址就是struct thread_info的地址,得到了thread_info的地址,我们就很容易找到task_struct的地址了。汇编实现过程为movl %-8192 ,%eaxandl %esp ,%eax寄存器esp存放进程栈的当前地址,eax最后存放的就是进程栈的起始地址。current使用current_thread_info来实现这个过程。kernel源码(对于x86类型的CPU来说文件位于arch/x86/include/asm //include/asm/thread_info.h)- /* how to get the current stack pointer from C */
- register unsigned long current_stack_pointer asm("esp") __used;
- /* how to get the thread information struct from C */
- static inline struct thread_info *current_thread_info(void)
- {
- return (struct thread_info *)
- (current_stack_pointer & ~(THREAD_SIZE - 1));
- };
其中current_stack_pointer为进程栈的当前地址,THREAD_SIZE为进程栈的大小。所以current_thread_info()->task即为task_struct()的地址。