在ARM Linux中,每个线程在内核堆栈“底部”保留​​的少数字节的目的是什么

问题

为什么在创建内核堆栈的“底部”时保留8个字节?

背景

我们知道struct pt_regsthread_info共享相同的2个连续页面(8192个字节),其中pt_reg位于较高端, thread_info位于较低端。 但是,我注意到这两个页面的最高地址保留了8个字节:

在arch / arm / include / asm / threadinfo.h中

 #define THREAD_START_SP (THREAD_SIZE - 8) 

为什么在创建内核堆栈的“底部”时保留8个字节?

  1. 如果我们在堆栈上保留任何内容,则它必须是8的倍数。
  2. 如果我们在堆栈上方查看,我们希望确保它已映射。

8的倍数

堆栈和用户寄存器需要对齐到8个字节。 这使事情变得更有效率,因为许多ARM具有64位总线,并且内核堆栈上的操作(例如ldrdldrd )可能具有这些要求。 您可以在usr_entry宏中看到保护 。 特别,

 #if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5) && (S_FRAME_SIZE & 7) #error "sizeof(struct pt_regs) must be a multiple of 8" #endif 

ARMv5(体系结构版本5)添加了ldrdldrd指令。 它也是内核的EABI版本的要求(与OABI相比)。 因此,如果我们在堆栈上保留任何内容,则它必须是8的倍数。

偷看堆栈

对于最顶层的框架,我们可能想要查看以前的数据。 为了不经常检查堆栈是否在8K范围内,保留了额外的条目。 具体来说,我认为信号需要窥视堆栈。

这样,您只需读取堆栈指针并屏蔽掉THREAD_SIZE位即可访问thread_info结构(否则SP最初将位于下一个THREAD_SIZE块上)。

 static inline struct thread_info *current_thread_info(void) { register unsigned long sp asm ("sp"); return (struct thread_info *)(sp & ~(THREAD_SIZE - 1)); } 

八个字节来自ARM调用约定, SP需要8字节对齐。

更新: AAPCS 5.2.1.1规定:

进程只能访问(用于读取或写入)由[SP,stack-base-1]定义的整个堆栈的闭合间隔(其中SP是寄存器r13的值)。

由于堆栈是全降序的

 THREAD_START_SP (THREAD_SIZE - 8) 

可能会通过非法访问下一页(分段错误)来强制执行此要求。