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

Cod*_*Now 8 c arm linux-kernel

问题:

为什么在创建内核堆栈的"底部"时保留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)
Run Code Online (Sandbox Code Playgroud)

aus*_*len 6

这样,您thread_info只需通过读取堆栈指针和屏蔽掉THREAD_SIZE位来访问结构(否则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));
}
Run Code Online (Sandbox Code Playgroud)

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

更新: AAPCS 5.2.1.1声明:

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

由于堆栈是全降序的

THREAD_START_SP (THREAD_SIZE - 8)
Run Code Online (Sandbox Code Playgroud)

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


art*_*ise 1

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

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

八的倍数

堆栈和用户寄存器需要对齐到8字节。这只会使事情变得更加高效,因为许多 ARM 都有 64 位总线,并且内核堆栈上的操作(例如ldrdstrd)可能有这些要求。您可以在宏中看到保护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
Run Code Online (Sandbox Code Playgroud)

ARMv5(架构版本5)添加了ldrdstrd指令。这也是 EABI 版本内核(相对于 OABI)的要求。因此,如果我们在堆栈上保留任何内容,它必须是 8 的倍数。

窥视堆栈

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