==>开始
void set_task_stack_end_magic(struct task_struct *tsk)
{
unsigned long *stackend;
stackend = end_of_stack(tsk);
*stackend = STACK_END_MAGIC; /* for overflow detection */
}
从注释可以看出,设置魔数的目的是为了进行栈溢出检测(for overflow detection),STACK_END_MAGIC 为栈底魔数,其定义在 include/uapi/linux/magic.h 中的 67 行,和其他魔数定义在一起
#define STACK_END_MAGIC 0x57AC6E9D
显然 end_of_stack 函数接受一个 task_struct 类型的结构体指针,并返回一个 unsigned long 型的指针,指针指向栈底最后一个 long 大小的位置。其定义在 include/linux/sched/task_stack.h 中,如果开启配置 CONFIG_THREAD_INFO_IN_TASK 则此函数为
static inline unsigned long *end_of_stack(const struct task_struct *task)
{
return task->stack;
}
若没有开启 CONFIG_THREAD_INFO_IN_TASK,则此函数为
/*
* Return the address of the last usable long on the stack.
*
* When the stack grows down, this is just above the thread
* info struct. Going any lower will corrupt the threadinfo.
*
* When the stack grows up, this is the highest address.
* Beyond that position, we corrupt data on the next page.
*/
static inline unsigned long *end_of_stack(struct task_struct *p)
{
#ifdef CONFIG_STACK_GROWSUP
return (unsigned long *)((unsigned long)task_thread_info(p) + THREAD_SIZE) - 1;
#else
return (unsigned long *)(task_thread_info(p) + 1);
#endif
}
其中配置 CONFIG_STACK_GROWSUP 配置的意思是内核栈向上扩张。而没有开启此配置时,内核栈是向下扩张的。为了确认内核栈的具体位置,需要搞清楚,task_struct thread_info thread_union 三者的具体关系。
==>thread_info
thread_info 结构体是个架构相关的结构,所以定义在相关架构的目录下,在 arm64 架构下,thread_info 结构体定义在 arch/arm64/include/asm/thread_info.h 中
/*
* low level task data that entry.S needs immediate access to.
*/
struct thread_info {
unsigned long flags; /* low level flags */
mm_segment_t addr_limit; /* address limit */