ARM64 Linux各种栈-1-分类
在 ARM64 Linux 内核中,栈的管理分为多种类型,每种栈都有其特定的用途和实现机制。以下是详细的分类说明:
一、用户栈(User Stack)
1. 简介
用途:用户态进程执行时的栈空间。
特点:位于用户空间虚拟地址的高地址区域(向下增长)
通过 mmap 动态分配,默认大小 8MB(可通过 ulimit -s 调整) //Arm64上应该不对..
分配方式:
arch_pick_mmap_layout(struct mm_struct *mm) { //mmap.c mm->mmap_base = TASK_UNMAPPED_BASE; // 0x0000_7fff_ffc0_0000 }
二、内核栈(Kernel Stack)
1. 简介
用途:进程在内核态执行时的私有栈(系统调用、异常处理)
特点:固定大小 16KB(THREAD_SIZE = 16384,定义于 arch/arm64/include/asm/thread_info.h)
包含 struct thread_info 元数据(位于栈底)
分配方式:
dup_task_struct(struct task_struct *tsk) { //fork.c stack = alloc_thread_stack_node(tsk, node); // 通过 vmalloc 分配 }
2. 调试
cat /sys/kernel/debug/kmemleak //查看内核栈使用量
"kernel stack overflow" //内核栈溢出在 arm64/kernel/traps.c 中有打印
三、中断栈(IRQ Stack)
1. 简介
用途:处理硬件中断的专用栈(避免内核栈溢出)
特点:每个 CPU 独占 32KB 中断栈(定义于 arch/arm64/include/asm/irq.h),支持嵌套中断处理(最多支持4级嵌套)
内存布局:
--------------------------------------------
栈类型 大小 地址范围示例
--------------------------------------------
Primary IRQ 32KB ffff8000_7fff_0000
Secondary 32KB ffff8000_7fff_8000
--------------------------------------------
切换逻辑(arch/arm64/kernel/entry.S):
kernel_ventry: msr sp_el0, x21 // 保存用户态SP ldr x21, [tsk, #TSK_STACK] // 加载内核栈 msr sp_el1, x21 // 切换到内核栈
四、信号栈(Signal Stack)
1. 简介
用途:用户态信号处理函数的替代执行栈.
特点:通过 sigaltstack() 系统调用显式设置。默认禁用,启用后大小为 2MB(SIGSTKSZ = 2097152)
内核管理:
__setup_rt_frame(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs) { //signal.c arm64上没这个函数,是x86上的 if (on_sig_stack(regs->sp)) // 检查是否在信号栈上 altstack = current->sas_ss_sp; }
五、异常栈(Exception Stack)
1. 简介
用途:处理系统异常(如缺页、指令异常)
特点:复用当前上下文的内核栈。通过 ESR_EL1 寄存器判断异常类型
处理流程:
A[异常触发] --> B[读取ESR_EL1]
B --> C{异常类型?}
C -->|Data Abort| D[do_mem_abort]
C -->|Instruction Abort| E[do_el0_ia]
C -->|其他| F[panic]
六、特殊场景栈-启动栈(Boot Stack)
1. 简介
用途:内核启动早期的临时栈。
特点:定义于链接脚本(arch/arm64/kernel/vmlinux.lds.S),大小4KB,仅用于初始化阶段。
__initdata_begin = .; . = ALIGN(4096); .boot.stack : { *(.boot.stack) } //启动栈段
七、特殊场景栈-调试栈(Debug Stack)
1. 简介
用途:KGDB/KDB 调试器专用栈
特点:独立于其他栈空间
通过 CONFIG_DEBUG_STACK 启用 //注: 这个配置宏在4.14和5.4上都不存在
void debug_stack_set(void) { //process.c set_percpu_stack(cpu, debug_stack); //切换调试栈 }
九、总结
1. 栈类型对比
------------------------------------------------------------- 栈类型 大小 归属 生命周期 关键宏定义 ------------------------------------------------------------- 用户栈 动态 用户进程 进程生存期 TASK_SIZE 内核栈 16KB 进程 进程生存期 THREAD_SIZE 中断栈 32KB Per-CPU 内核运行期 IRQ_STACK_SIZE 信号栈 2MB 用户进程 显式设置后 SIGSTKSZ 启动栈 4KB 全局 启动阶段 __initdata_begin -------------------------------------------------------------
posted on 2025-05-20 17:25 Hello-World3 阅读(155) 评论(0) 收藏 举报