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 | 続く |