mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
cxx: Add KConfig option for C++ exceptions, disable by default
Fixes https://github.com/espressif/esp-idf/issues/1072 (Additional 20KB is still used if C++ exception support is enabled in menuconfig.)
This commit is contained in:
parent
6f07e0797d
commit
9c7477ef34
14
Kconfig
14
Kconfig
@ -93,7 +93,19 @@ config OPTIMIZATION_ASSERTIONS_DISABLED
|
||||
|
||||
endchoice # assertions
|
||||
|
||||
endmenu # Optimization level
|
||||
config CXX_EXCEPTIONS
|
||||
bool "Enable C++ exceptions"
|
||||
default n
|
||||
help
|
||||
Enabling this option compiles all IDF C++ files with exception support enabled.
|
||||
|
||||
Disabling this option disables C++ exception support in all compiled files, and any libstdc++ code which throws
|
||||
an exception will abort instead.
|
||||
|
||||
Enabling this option currently adds an additional 20KB of heap overhead, and 4KB of additional heap is allocated
|
||||
the first time an exception is thrown in user code.
|
||||
|
||||
endmenu # Compiler Options
|
||||
|
||||
menu "Component config"
|
||||
source "$COMPONENT_KCONFIGS"
|
||||
|
@ -1,3 +1,11 @@
|
||||
# Mark __cxa_guard_dummy as undefined so that implementation of static guards
|
||||
# is taken from cxx_guards.o instead of libstdc++.a
|
||||
COMPONENT_ADD_LDFLAGS += -u __cxa_guard_dummy
|
||||
|
||||
ifndef CONFIG_CXX_EXCEPTIONS
|
||||
# If exceptions are disabled, ensure our fatal exception
|
||||
# hooks are preferentially linked over libstdc++ which
|
||||
# has full exception support
|
||||
COMPONENT_ADD_LDFLAGS += -u __cxx_fatal_exception
|
||||
endif
|
||||
|
||||
|
87
components/cxx/cxx_exception_stubs.cpp
Normal file
87
components/cxx/cxx_exception_stubs.cpp
Normal file
@ -0,0 +1,87 @@
|
||||
#include <cstdlib>
|
||||
#include <cstdio>
|
||||
#include <exception>
|
||||
#include <bits/functexcept.h>
|
||||
#include <sdkconfig.h>
|
||||
|
||||
#ifndef CONFIG_CXX_EXCEPTIONS
|
||||
|
||||
const char *FATAL_EXCEPTION = "Fatal C++ exception: ";
|
||||
|
||||
extern "C" void __cxx_fatal_exception(void)
|
||||
{
|
||||
abort();
|
||||
}
|
||||
|
||||
extern "C" void __cxx_fatal_exception_message(const char *msg)
|
||||
{
|
||||
printf("%s%s\n", FATAL_EXCEPTION, msg);
|
||||
abort();
|
||||
}
|
||||
|
||||
extern "C" void __cxx_fatal_exception_int(int i)
|
||||
{
|
||||
printf("%s (%d)\n", FATAL_EXCEPTION, i);
|
||||
abort();
|
||||
}
|
||||
|
||||
void std::__throw_bad_exception(void) __attribute__((alias("__cxx_fatal_exception")));
|
||||
|
||||
void std::__throw_bad_alloc(void) __attribute__((alias("__cxx_fatal_exception")));
|
||||
|
||||
void std::__throw_bad_cast(void) __attribute__((alias("__cxx_fatal_exception")));
|
||||
|
||||
void std::__throw_bad_typeid(void) __attribute__((alias("__cxx_fatal_exception")));
|
||||
|
||||
void std::__throw_logic_error(const char*) __attribute__((alias("__cxx_fatal_exception_message")));
|
||||
|
||||
void std::__throw_domain_error(const char*) __attribute__((alias("__cxx_fatal_exception_message")));
|
||||
|
||||
void std::__throw_invalid_argument(const char*) __attribute__((alias("__cxx_fatal_exception_message")));
|
||||
|
||||
void std::__throw_length_error(const char*) __attribute__((alias("__cxx_fatal_exception_message")));
|
||||
|
||||
void std::__throw_out_of_range(const char*) __attribute__((alias("__cxx_fatal_exception_message")));
|
||||
|
||||
void std::__throw_out_of_range_fmt(const char*, ...) __attribute__((alias("__cxx_fatal_exception_message")));
|
||||
|
||||
void std::__throw_runtime_error(const char*) __attribute__((alias("__cxx_fatal_exception_message")));
|
||||
|
||||
void std::__throw_range_error(const char*) __attribute__((alias("__cxx_fatal_exception_message")));
|
||||
|
||||
void std::__throw_overflow_error(const char*) __attribute__((alias("__cxx_fatal_exception_message")));
|
||||
|
||||
void std::__throw_underflow_error(const char*) __attribute__((alias("__cxx_fatal_exception_message")));
|
||||
|
||||
void std::__throw_ios_failure(const char*) __attribute__((alias("__cxx_fatal_exception_message")));
|
||||
|
||||
void std::__throw_system_error(int) __attribute__((alias("__cxx_fatal_exception_int")));
|
||||
|
||||
void std::__throw_bad_function_call(void) __attribute__((alias("__cxx_fatal_exception")));
|
||||
|
||||
void std::__throw_future_error(int) __attribute__((alias("__cxx_fatal_exception_int")));
|
||||
|
||||
|
||||
/* The following definitions are needed because libstdc++ is also compiled with
|
||||
__throw_exception_again defined to throw, and some other exception code in a few places.
|
||||
|
||||
This cause exception handler code to be emitted in the library even though it's mostly
|
||||
unreachable (as any libstdc++ "throw" will first call one of the above stubs, which will abort).
|
||||
|
||||
If these are left out, a bunch of unwanted exception handler code is linked.
|
||||
|
||||
Note: these function prototypes are not correct.
|
||||
*/
|
||||
|
||||
extern "C" void __cxa_allocate_exception(void) __attribute__((alias("__cxx_fatal_exception")));
|
||||
extern "C" void __cxa_begin_catch(void) __attribute__((alias("__cxx_fatal_exception")));
|
||||
extern "C" void __cxa_end_catch(void) __attribute__((alias("__cxx_fatal_exception")));
|
||||
extern "C" void __cxa_get_exception_ptr(void) __attribute__((alias("__cxx_fatal_exception")));
|
||||
extern "C" void __cxa_free_exception(void) __attribute__((alias("__cxx_fatal_exception")));
|
||||
extern "C" void __cxa_rethrow(void) __attribute__((alias("__cxx_fatal_exception")));
|
||||
extern "C" void __cxa_throw(void) __attribute__((alias("__cxx_fatal_exception")));
|
||||
extern "C" void __cxa_call_terminate(void) __attribute__((alias("__cxx_fatal_exception")));
|
||||
|
||||
bool std::uncaught_exception() __attribute__((alias("__cxx_fatal_exception")));
|
||||
|
||||
#endif // CONFIG_CXX_EXCEPTIONS
|
@ -188,8 +188,12 @@ TEST_CASE("before scheduler has started, static initializers work correctly", "[
|
||||
TEST_ASSERT_EQUAL(2, StaticInitTestBeforeScheduler::order);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CXX_EXCEPTIONS
|
||||
|
||||
TEST_CASE("c++ exceptions work", "[cxx]")
|
||||
{
|
||||
/* Note: This test currently trips the memory leak threshold
|
||||
as libunwind allocates ~4KB of data on first exception. */
|
||||
int thrown_value;
|
||||
try
|
||||
{
|
||||
@ -203,6 +207,8 @@ TEST_CASE("c++ exceptions work", "[cxx]")
|
||||
printf("OK?\n");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* These test cases pull a lot of code from libstdc++ and are disabled for now
|
||||
*/
|
||||
#if 0
|
||||
|
@ -379,8 +379,10 @@ void start_cpu1_default(void)
|
||||
|
||||
static void do_global_ctors(void)
|
||||
{
|
||||
#ifdef CONFIG_CXX_EXCEPTIONS
|
||||
static struct object ob;
|
||||
__register_frame_info( __eh_frame, &ob );
|
||||
#endif
|
||||
|
||||
void (**p)(void);
|
||||
for (p = &__init_array_end - 1; p >= &__init_array_start; --p) {
|
||||
|
@ -303,6 +303,12 @@ CXXFLAGS := $(strip \
|
||||
$(CXXFLAGS) \
|
||||
$(EXTRA_CXXFLAGS))
|
||||
|
||||
ifdef CONFIG_CXX_EXCEPTIONS
|
||||
CXXFLAGS += -fexceptions
|
||||
else
|
||||
CXXFLAGS += -fno-exceptions
|
||||
endif
|
||||
|
||||
export CFLAGS CPPFLAGS CXXFLAGS
|
||||
|
||||
# Set host compiler and binutils
|
||||
|
Loading…
Reference in New Issue
Block a user