2015年4月24日 星期五

bare metal programming for stm32f4 - discovery: c++ exception handling(0)

我很希望可以告訴你 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_frame)
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 帳號。