我很希望可以告訴你 c++ exception handle 是怎麼做的, 不過很遺憾, 我還沒搞懂, c++ exception handling 實在太複雜。如果你以為這篇是要講這個, 我很抱歉。
這篇只是要提怎麼 compile 使用了 c++ exception handling 的程式碼, 只能 compile, exception handling 應該是不能正常運作的。你一定會疑惑這有什麼難的嗎? 在 os 之下沒有問題, 不過這是 bare metal 程式, 也就是在作業系統之前的程式。
new_section.cpp
1 __attribute__((section("s1")))
2 int new_s1(int i)
3 {
4 const char* s="i am s1";
5 int a=5, b=6, c;
6 c = a + b;
7 return c;
8 }
9
10 int throw_test()
11 {
12 int i=0;
13 i+=2;
14 try
15 {
16 if (5 > 0)
17 {
18 throw "something wrong...";
19 }
20 }
21 catch (const char* message)
22 {
23 "got it";
24 }
25 return i;
26 }
一旦程式碼加入了 eh (compile 不要使用 -fno-exceptions -fno-rtti), c++ compiler 就會加入某些程式碼 (link 了 libgcc 下的 library), 一開始會看到這個錯誤訊息:
/usr/lib/gcc/arm-none-eabi/4.8/libgcc.a(unwind-arm.o): In function `get_eit_entry':
/build/gcc-arm-none-eabi-DEMfr1/gcc-arm-none-eabi-11/build/arm-none-eabi/libgcc/../../../gcc-4.8.3/libgcc/unwind-arm-common.inc:221: undefined reference to `__exidx_end'
/build/gcc-arm-none-eabi-DEMfr1/gcc-arm-none-eabi-11/build/arm-none-eabi/libgcc/../../../gcc-4.8.3/libgcc/unwind-arm-common.inc:221: undefined reference to `__exidx_start'
所以補上了 stm32.ld L31 ~39, 如果沒有加上 (NOLOAD), .eh_frame, objcopy 的 bin 檔 mycpp.bin 會有 536,870,912 (0x20000000, 500 MB)
-rwxr-xr-x 1 descent descent 536873732 Apr 23 14:36 mycpp.bin
那個 0x20000000 不是巧合, 是 sram 開頭位址。
stm32.ld
1 /*
2 MEMORY
3 {
4 FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 128K
5 SRAM (rwx) : ORIGIN = 0x20000000, LENGTH = 20K
6 }
7 */
8
9 /* Specify the memory areas */
10 /* form: STM32F4-Discovery_FW_V1.1.0/Project/Peripheral_Examples/IO_Toggle/TrueSTUDIO/IO_Toggle/stm32_flash.ld */
11 MEMORY
12 {
13 FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 1024K
14 SRAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K
15 MEMORY_B1 (rx) : ORIGIN = 0x60000000, LENGTH = 0K
16 }
17
18
19 SECTIONS
20 {
21 .text :
22 {
23 KEEP(*(.isr_vector .isr_vector.*))
24 *(.text .text.*)
25 *(.rodata .rodata*)
26 _etext = .;
27 } > FLASH
28
29
30
31 /*
32 .ARM.exidx (NOLOAD) :
33 */
34 arm (NOLOAD ) :
35 {
36 __exidx_start = .;
37 *(.ARM* .gnu.linkonce.armexidx.* .eh_fram e )
38 __exidx_end = .;
39 } > SRAM
40 s1 (NOLOAD) :
41 {
42 s1_begin = .;
43 *(s1)
44 s1_end = .;
45 } > SRAM
46
47 .data : AT (_etext)
48 {
49 _data = .;
50 *(.data .data.*)
51 _edata = .;
52 } > SRAM
53 .bss(NOLOAD) :
54 {
55 _bss = .;
56 *(.bss .bss.*)
57 *(COMMON)
58 . = ALIGN(4);
59 _ebss = .;
60 } > SRAM
61
62
63
64
65 .stackarea(NOLOAD) :
66 {
67 . = ALIGN(8);
68 *(.stackarea .stackares.*)
69 . = ALIGN(8);
70 } > SRAM
71
72 . = ALIGN(4);
73 _end = .;
74 }
這些奇怪的 section 似乎是從 binutils 來的, 感覺是為了支援 c++ eh。
binutils-2.25/bfd/elf32-arm.c
1 bfd/elf32-arm.c:14750: return (CONST_STRNEQ (name, ELF_STRING_ARM_unwind)
2 bfd/elf32-arm.c:14751: || CONST_STRNEQ (name, ELF_STRING_ARM_unwind_once));
3 gas/config/tc-arm.c:21158: prefix = ELF_STRING_ARM_unwind;
4 gas/config/tc-arm.c:21159: prefix_once = ELF_STRING_ARM_unwind_once;
5 gas/config/tc-arm.c:21164: prefix = ELF_STRING_ARM_unwind_info;
6 gas/config/tc-arm.c:21165: prefix_once = ELF_STRING_ARM_unwind_info_once;
7 include/elf/arm.h:328:#define ELF_STRING_ARM_unwind ".ARM.exidx"
8 include/elf/arm.h:329:#define ELF_STRING_ARM_unwind_info ".ARM.extab"
9 include/elf/arm.h:330:#define ELF_STRING_ARM_unwind_once ".gnu.linkonce.armexidx."
10 include/elf/arm.h:331:#define ELF_STRING_ARM_unwind_info_once ".gnu.linkonce.armextab."
git@github.com:descent/stm32f4_prog.git
git commit 7a90d6f327e04851c1922960396624f41ffd5a21
path: stm32f4_prog/cpp
make result
1
2 descent@debianlinux:cpp$ make
3 arm-none-eabi-g++ -fno-common -O0 -g -mcpu=cortex-m3 -mthumb -fno-exceptions -fno-rtti -fomit-frame-pointer -c mycpp.cpp
4 arm-none-eabi-g++ -fno-common -O0 -g -mcpu=cortex-m3 -mthumb -fomit-frame-pointer -c new_section.cpp
5 new_section.cpp:25:82: warning: missing terminating ' character
6 /usr/lib/gcc/arm-none-eabi/4.8/libgcc.a(unwind-arm.o): In function `get_eit_entry':
7 ^
8 new_section.cpp:26:169: warning: missing terminating ' character
9 /build/gcc-arm-none-eabi-DEMfr1/gcc-arm-none-eabi-11/build/arm-none-eabi/libgcc/../../../gcc-4.8.3/libgcc/unwind-arm-common.inc:221: undefined reference to `__exidx_end'
10 ^
11 new_section.cpp:27:171: warning: missing terminating ' character
12 /build/gcc-arm-none-eabi-DEMfr1/gcc-arm-none-eabi-11/build/arm-none-eabi/libgcc/../../../gcc-4.8.3/libgcc/unwind-arm-common.inc:221: undefined reference to `__exidx_start'
13 ^
14 arm-none-eabi-g++ -Wl,-T./stm32.ld -nostartfiles -fomit-frame-pointer -o mycpp.elf mycpp.o new_section.o
15 arm-none-eabi-objcopy -O binary mycpp.elf mycpp.bin
之前不是提到不能使用 c++ eh (exception handling) 嗎? 為什麼又要用了呢? 為了使用 std::vector, 我自己寫的程式碼可以不用 eh, 但是我沒辦法控制標準程式庫的寫法, 所以才會遇到這個問題。
常看到介紹 bare metal 的程式大多是 c 語言, 由於對 c++ 的喜愛, 我偏好使用 c++, 若能成功的使用 std::vector, 那應該會很美好吧! 那我成功的使用了 std::vector 了嗎? 下一篇告訴你。
ref:
在沒有 Frame Pointer 的情況下進行 Stack Unwind (這篇文章提到的名詞和本文高度相關)
沒有留言:
張貼留言
使用 google 的 reCAPTCHA 驗證碼, 總算可以輕鬆留言了。
我實在受不了 spam 了, 又不想讓大家的眼睛花掉, 只好放棄匿名留言。這是沒辦法中的辦法了。留言的朋友需要有 google 帳號。