【ARM Linux 系统稳定性分析入门及渐进 4 -- 栈分类】

文章目录

    • 1.1 RT-Thread 的系统栈
    • 1.2 RT-Thread 进程栈
      • 1.2.1 线程栈溢出检查

1.1 RT-Thread 的系统栈

系统栈底的值如果是 gcc 编译器,一般会在系统链接脚本 link.lds 中设置, 如下配置系统栈的大小为 1K
_system_stack_size = 0x400;

在系统启动阶段一般都是先通过汇编代码进行部分处理,比如data 段中的数据copy, 及 bss 段的清零,然后一般会跳转到C代码,在使用C代码之前需要设置好栈的地址,我们知道C代码实现的函数通过反汇编可以看到:在函数之间的调用处会保存一些关键信息,比如 PC/LR/SP/FP,及相关参数到栈中,所以在跳转到C代码之前一定要配置好栈的地址。系统栈地址的配置一般都是在汇编阶段给 SP指针赋值,在 RT-Thread 中BSP目录下一般会有个名叫 startup.s 的文件,在该文件中的会对 SP 进行赋值:

ldr sp, =_estack

_estack 即为栈底(栈底是高地址)的位置,该值会在连接脚本中赋值, 如下:

.stack :
{
	. = ALIGN(4);
	__sstack = .;
	. = . + system_stack_size;
	. = ALIGN(4)
	_estack = .;	
}> RAM

在 RT-Thread 中需要知道系统栈(中断栈)与进程栈不是一回事

1.2 RT-Thread 进程栈

在多线程系统中,每个线程都是独立的、互不干扰的,所以要为每个线程都分配独立的栈空间。这个栈空间可以是:

  • 一个预先定义好的全局数组,定义线程栈的示例代码如下:
ALIGN(RT_ALIGN_SIZE)
 
rt_uint8_t thread1_stack[512];
rt_uint8_t thread2_stack[1024];
  • 也可以是动态分配的一段内存空间:

thread->stack_addr = (void *)RT_KERNEL_MALLOC(stack_size);

static rt_err_t _thread_init(struct rt_thread *thread, ...)
{
	... 
    /* stack init */
    thread->stack_addr = stack_start;
    thread->stack_size = stack_size;
 
    /* init thread stack */
    rt_memset(thread->stack_addr, '#', thread->stack_size);
	...

从上面可以看到 task 初始化的时候会将栈空间填入'#',

1.2.1 线程栈溢出检查

OS 在调度时 (rt_scheudle) 主动检查栈是否溢出:

  • 线程栈底部预留内存是不是有被修改;
  • sp是否超出线程栈范围
    栈增长方向不同,略有区别,原理一样,ARM 架构通常使用向下增长方式。
#ifdef RT_USING_OVERFLOW_CHECK
static void _rt_scheduler_stack_check(struct rt_thread *thread)
{
    RT_ASSERT(thread != RT_NULL);

#ifdef ARCH_CPU_STACK_GROWS_UPWARD
    if (*((rt_uint8_t *)((rt_ubase_t)thread->stack_addr + thread->stack_size - 1)) != '#' ||
#else
    if (*((rt_uint8_t *)thread->stack_addr) != '#' ||
#endif /* ARCH_CPU_STACK_GROWS_UPWARD */
        (rt_ubase_t)thread->sp <= (rt_ubase_t)thread->stack_addr ||
        (rt_ubase_t)thread->sp >
        (rt_ubase_t)thread->stack_addr + (rt_ubase_t)thread->stack_size)
    {
        rt_ubase_t level;

        rt_kprintf("thread:%s stack overflow\n", thread->name);

        level = rt_hw_interrupt_disable();
        while (level);
    }
    ... ...
}
#endif /* RT_USING_OVERFLOW_CHECK */
stack frame addr
栈底: thread->stack_addr low
stack size
栈顶:thread->stack_addr + thread->stack_size high

你可能感兴趣的:(#,系统稳定性分析入门及渐进,arm,linux)