Включение исключений C ++ в загрузчике ARM с нуля

В целях обучения я пытаюсь получить полную поддержку C ++ на ARM MCU (STM32F407ZE). Я изо всех сил пытаюсь заставить работать исключения, следовательно, несу этот вопрос:

Как получить исключения C ++ для загрузчика с голым железом ARM?

Чтобы немного расширить вопрос:
Я понимаю, что исключение, такое как выход из функции, требует разматывания стека. Тот факт, что выход из функции работает «из коробки», а обработка исключений — нет, заставляет меня думать, что компилятор добавляет раскручивание функций-выхода, но не может делать это для исключений.

Итак, подвопрос 1: Правильна ли эта предпосылка? Действительно ли мне нужно реализовать / интегрировать библиотеку раскручивания для обработки исключений?

В моем поверхностном понимании раскручивания, в стеке есть рамка, и раскручивание «просто» должно вызвать деструктор для каждого его объекта и, наконец, перейти к заданному catch,

Подвопрос 2: Как библиотека раскрутки выполняет эту задачу? Какая стратегия используется? (в пределах, подходящих для SO ответа)

В своих поисках я обнаружил много объяснений, что такое раскручивание, но очень мало, как заставить его работать. Наиболее близким является:

GCC arm-none-eabi (Codesourcery) и исключения C ++


Проект

1) Первым шагом, но с некоторыми трудностями, было включение MCU и связь через JTAG.

Это просто контекстная информация, пожалуйста, не помечайте вопрос не по теме только из-за этой картинки. Вместо этого перейдите к шагу 2.

Я знаю, что доступны тестовые доски, но это учебный проект, чтобы лучше понять все «волшебство» за сценой. Итак, я получил чип-сокет, макетную плату и настроил схему минимального включения питания:

введите описание изображения здесь

Примечание: JTAG выполняется через GPIO малины-пи.
Примечание 2: я использую OpenOCD для связи с чипом.

2) Вторым шагом было сделать минимальное программное обеспечение для мигания желтого светодиода.
Используя arm-none-eabi-g ++ в качестве компилятора и компоновщика, код на c ++ был прост, но мое понимание сценария компоновщика все еще несколько размыто.

3) Включить обработку исключений (пока не работает).

Для этой цели, следующая информация, где это полезно:

Однако для простой обработки исключений это кажется слишком сложным, и прежде чем приступить к реализации / интеграции библиотеки раскручивания, я хотел бы убедиться, что я иду в правильном направлении.
Я бы не хотел, чтобы через 2 недели ушло: «Ох, кстати, вам просто нужно добавить опцию« -xx »в компилятор, и она работает»

main.cpp

auto reset_handler() noexcept ->void;
auto main() -> int;

int global_variable_test=50;

extern "C"{

#include "stm32f4xx.h"#include "stm32f4xx_rcc.h"#include "stm32f4xx_gpio.h"void assert_failed(uint8_t* file, uint32_t line){}
void hardFaultHandler( unsigned int * hardFaultArgs);

// vector table
#define SRAM_SIZE 128*1024
#define SRAM_END        (SRAM_BASE + SRAM_SIZE)
unsigned long *vector_table[] __attribute__((section(".vector_table"))) =
{
(unsigned long *)SRAM_END,   // initial stack pointer
(unsigned long *)reset_handler,        // main as Reset_Handler
};
}auto reset_handler() noexcept -> void
{
// Setup execution

// Call the main function
int ret = main();

// never finish
while(true);
}class A
{
public:
int b;

auto cppFunc()-> void
{
throw (int)4;
}
};

auto main() -> int
{
// Initializing led GPIO
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG, ENABLE);
GPIO_InitTypeDef GPIO_InitDef;

GPIO_InitDef.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14;
GPIO_InitDef.GPIO_OType = GPIO_OType_PP;
GPIO_InitDef.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitDef.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitDef.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_Init(GPIOG, &GPIO_InitDef);

// Testing normal blinking
int loopNum = 500000;
for (int i=0; i<5; ++i)
{
loopNum = 100000;
GPIO_SetBits(GPIOG, GPIO_Pin_13 | GPIO_Pin_14);
for (int i = 0; i < loopNum; i++) continue; //active waiting!

loopNum = 800000;
GPIO_ResetBits(GPIOG, GPIO_Pin_13 | GPIO_Pin_14);
for (int i=0; i<loopNum; i++) continue; //active waiting!
}

// Try exceptions handling
try
{
A a;
a.cppFunc();
}
catch(...){}return 0;
}

Makefile

CPP_C = arm-none-eabi-g++
C_C = arm-none-eabi-g++
LD = arm-none-eabi-g++
COPY = arm-none-eabi-objcopy

LKR_SCRIPT = -Tstm32_minimal.ld

INCLUDE = -I. -I./stm32f4xx/CMSIS/Device/ST/STM32F4xx/Include -I./stm32f4xx/CMSIS/Include -I./stm32f4xx/STM32F4xx_StdPeriph_Driver/inc -I./stm32f4xx/Utilities/STM32_EVAL/STM3240_41_G_EVAL -I./stm32f4xx/Utilities/STM32_EVAL/Common
C_FLAGS  = -c -fexceptions -fno-common -O0 -g -mcpu=cortex-m4 -mthumb -DSTM32F40XX -DUSE_FULL_ASSERT -DUSE_STDPERIPH_DRIVER $(INCLUDE)
CPP_FLAGS  = -std=c++11 -c $(C_FLAGS)
LFLAGS  = -specs=nosys.specs -nostartfiles -nostdlib $(LKR_SCRIPT)
CPFLAGS = -Obinary

all: main.bin

main.o: main.cpp
$(CPP_C) $(CPP_FLAGS) -o main.o main.cpp

stm32f4xx_gpio.o: stm32f4xx_gpio.c
$(C_C) $(C_FLAGS) -o stm32f4xx_gpio.o stm32f4xx_gpio.c

stm32f4xx_rcc.o: stm32f4xx_rcc.c
$(C_C) $(C_FLAGS) -o stm32f4xx_rcc.o stm32f4xx_rcc.c

main.elf: main.o stm32f4xx_gpio.o stm32f4xx_rcc.o
$(LD) $(LFLAGS) -o main.elf main.o stm32f4xx_gpio.o stm32f4xx_rcc.o

main.bin: main.elf
$(COPY) $(CPFLAGS) main.elf main.bin

clean:
rm -rf *.o *.elf *.bin

write:
./write_bin.sh main.elf

Сценарий компоновщика: stm32_minimal.ld

/* memory layout for an STM32F407 */
MEMORY
{
FLASH (rx)  : ORIGIN = 0x08000000, LENGTH = 512K
SRAM (rwx)  : ORIGIN = 0x20000000, LENGTH = 128K
}

/* output sections */
SECTIONS
{
/* program code into FLASH */
.text :
{
*(.vector_table)    /* Vector table */
*(.text)            /* Program code */
*(.data)
/**(.eh_frame)*/
} >FLASH

.ARM.exidx :            /* Required for unwinding the stack? */
{
__exidx_start = .;
* (.ARM.exidx* .gnu.linkonce.armexidx.*)
__exidx_end   = .;
} > FLASH

PROVIDE ( end = . );

}

1

Решение

Задача ещё не решена.

Другие решения

Других решений пока нет …