Project

General

Profile

DetectStackOverflow » History » Version 1

mole lord, 09/09/2020 02:39 PM

1 1 mole lord
# DetectStackOverflow
2
3
{{>toc}}
4
5
## FreeRTOSスケジューラ起動前のスタックオーバフロー検出
6
7
STM32F4には Core Coupled Memory (以降CCM) が 0x1000_0000 番地にあります。(リファレンスマニュアルを参照)
8
リンカスクリプトをいじってCCMの先頭部分にスタック領域を配置すれば、スタックオーバフローがRAMが存在しない領域へのWriteとなり、 Hard Fault を起こします。
9
10
乱暴ですが、Hard Faultをもってスタックオーバフロー検出ができます。
11
(グローバル変数を破壊して摩訶不思議な挙動をされるよりはよいです)
12
13
CCMRAMにスタックを置くデメリットは、スタック上の値をDMACが扱えなくなることですが、
14
15
具体的には、 STM32F429ZITx_FLASH.ld を開いて、
16
17
~~~ c
18
/* Highest address of the user mode stack */
19
_estack = 0x20030000;    /* end of RAM */
20
/* Generate a link error if heap and stack don't fit into RAM */
21
_Min_Heap_Size = 0x0;      /* required amount of heap  */
22
_Min_Stack_Size = 0x400; /* required amount of stack */
23
~~~
24
25
を以下のように書き換えます。
26
27
~~~ c
28
/* Generate a link error if heap and stack don't fit into RAM */
29
_Min_Heap_Size = 0x0;      /* required amount of heap  */
30
_Min_Stack_Size = 0x400; /* required amount of stack */
31
/* Highest address of the user mode stack */
32
_estack = 0x10000000 + _Min_Stack_Size;
33
~~~
34
35
また、._user_heap_stackの部分を削除し、
36
37
~~~ c
38
  /* User_heap_stack section, used to check that there is enough RAM left */
39
  ._user_heap_stack :
40
  {
41
    . = ALIGN(8);
42
    PROVIDE ( end = . );
43
    PROVIDE ( _end = . );
44
    . = . + _Min_Heap_Size;
45
    . = . + _Min_Stack_Size;
46
    . = ALIGN(8);
47
  } >RAM
48
~~~
49
50
その代わりに `>CCMRAM` に挿入します。
51
52
~~~ c
53
  .ccmram :
54
  {
55
    . = ALIGN(4);
56
    _sccmram = .;       /* create a global symbol at ccmram start */
57
    . = ALIGN(8);
58
    _user_heap_stack = .;
59
    PROVIDE ( end = . );
60
    PROVIDE ( _end = . );
61
    . = . + _Min_Heap_Size;
62
    . = . + _Min_Stack_Size;
63
    . = ALIGN(8);
64
    *(.ccmram)
65
    *(.ccmram*)
66
    
67
    . = ALIGN(4);
68
    _eccmram = .;       /* create a global symbol at ccmram end */
69
  } >CCMRAM
70
~~~
71
72
動作確認は、無限再帰の関数を作ってそれをmain()から呼び出してやることで行えます。
73
74
~~~ c
75
static int32_t
76
recurse(int32_t x)
77
{
78
    return recurse(x + 1);
79
}
80
81
int main()
82
{
83
    ...
84
    int32_t x = recurse(0);
85
    int32_t i;
86
    for (i = 0; i < x; i++) ;
87
    ...
88
~~~
89
90
## FreeRTOSのタスクのスタックオーバフロー検出
91
92
FreeRTOS自体にもスタックオーバフロー検出の仕組みが備わってはいます。しかし、いまいち信用ならないので、Memory Protection Unit(以降MPU)を使ってアクセス不能な領域を作ることで検出を行います。
93
94
デメリットは、スタック領域1つごとに32バイトの使用不可領域ができることです。
95
96
続く