mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
[C++]: wrapper functions around unwind code
* Replaced all C++ exception related functions with wrappers if -fno-exception is used. This prevents linking of the corresponding code in libgcc. The code size will decrease by around 7-9 KB when building with -fno-exception. * added no except test app Closes https://github.com/espressif/esp-idf/pull/5380 Closes https://github.com/espressif/esp-idf/issues/5363 Closes https://github.com/espressif/esp-idf/issues/5224 Closes IDFGH-3153 Closes IDF-2577
This commit is contained in:
parent
71cf821659
commit
dd08575c29
@ -3,14 +3,58 @@ idf_component_register(SRCS "cxx_exception_stubs.cpp"
|
|||||||
# Make sure that pthread is in component list
|
# Make sure that pthread is in component list
|
||||||
PRIV_REQUIRES pthread)
|
PRIV_REQUIRES pthread)
|
||||||
|
|
||||||
|
if(NOT CONFIG_CXX_EXCEPTIONS)
|
||||||
|
set(WRAP_FUNCTIONS
|
||||||
|
_Unwind_SetEnableExceptionFdeSorting
|
||||||
|
__register_frame_info_bases
|
||||||
|
__register_frame_info
|
||||||
|
__register_frame
|
||||||
|
__register_frame_info_table_bases
|
||||||
|
__register_frame_info_table
|
||||||
|
__register_frame_table
|
||||||
|
__deregister_frame_info_bases
|
||||||
|
__deregister_frame_info
|
||||||
|
_Unwind_Find_FDE
|
||||||
|
_Unwind_GetGR
|
||||||
|
_Unwind_GetCFA
|
||||||
|
_Unwind_GetIP
|
||||||
|
_Unwind_GetIPInfo
|
||||||
|
_Unwind_GetRegionStart
|
||||||
|
_Unwind_GetDataRelBase
|
||||||
|
_Unwind_GetTextRelBase
|
||||||
|
_Unwind_SetIP
|
||||||
|
_Unwind_SetGR
|
||||||
|
_Unwind_GetLanguageSpecificData
|
||||||
|
_Unwind_FindEnclosingFunction
|
||||||
|
_Unwind_Resume
|
||||||
|
_Unwind_RaiseException
|
||||||
|
_Unwind_DeleteException
|
||||||
|
_Unwind_ForcedUnwind
|
||||||
|
_Unwind_Resume_or_Rethrow
|
||||||
|
_Unwind_Backtrace
|
||||||
|
__cxa_call_unexpected
|
||||||
|
__gxx_personality_v0)
|
||||||
|
|
||||||
|
foreach(wrap ${WRAP_FUNCTIONS})
|
||||||
|
target_link_libraries(${COMPONENT_LIB} INTERFACE "-Wl,--wrap=${wrap}")
|
||||||
|
endforeach()
|
||||||
|
endif()
|
||||||
|
|
||||||
target_link_libraries(${COMPONENT_LIB} PUBLIC stdc++ gcc)
|
target_link_libraries(${COMPONENT_LIB} PUBLIC stdc++ gcc)
|
||||||
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u __cxa_guard_dummy")
|
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u __cxa_guard_dummy")
|
||||||
|
|
||||||
# Force pthread to also appear later than stdc++ in link line
|
# Force libpthread to appear later than libstdc++ in link line since libstdc++ depends on libpthread.
|
||||||
add_library(stdcpp_pthread INTERFACE)
|
# Furthermore, force libcxx to appear later than libgcc because some libgcc unwind code is wrapped, if C++
|
||||||
|
# exceptions are disabled. libcxx (this component) provides the unwind code wrappers.
|
||||||
|
# This is to prevent linking of libgcc's unwind code which considerably increases the binary size.
|
||||||
idf_component_get_property(pthread pthread COMPONENT_LIB)
|
idf_component_get_property(pthread pthread COMPONENT_LIB)
|
||||||
|
idf_component_get_property(cxx cxx COMPONENT_LIB)
|
||||||
|
add_library(stdcpp_pthread INTERFACE)
|
||||||
target_link_libraries(stdcpp_pthread INTERFACE stdc++ $<TARGET_FILE:${pthread}>)
|
target_link_libraries(stdcpp_pthread INTERFACE stdc++ $<TARGET_FILE:${pthread}>)
|
||||||
target_link_libraries(${COMPONENT_LIB} PUBLIC stdcpp_pthread)
|
target_link_libraries(${COMPONENT_LIB} PUBLIC stdcpp_pthread)
|
||||||
|
add_library(libgcc_cxx INTERFACE)
|
||||||
|
target_link_libraries(libgcc_cxx INTERFACE gcc $<TARGET_FILE:${cxx}>)
|
||||||
|
target_link_libraries(${COMPONENT_LIB} PUBLIC libgcc_cxx)
|
||||||
|
|
||||||
if(NOT CONFIG_COMPILER_CXX_EXCEPTIONS)
|
if(NOT CONFIG_COMPILER_CXX_EXCEPTIONS)
|
||||||
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u __cxx_fatal_exception")
|
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u __cxx_fatal_exception")
|
||||||
|
@ -6,7 +6,12 @@ ifndef CONFIG_COMPILER_CXX_EXCEPTIONS
|
|||||||
# If exceptions are disabled, ensure our fatal exception
|
# If exceptions are disabled, ensure our fatal exception
|
||||||
# hooks are preferentially linked over libstdc++ which
|
# hooks are preferentially linked over libstdc++ which
|
||||||
# has full exception support
|
# has full exception support
|
||||||
|
WRAP_FUNCTIONS = _Unwind_SetEnableExceptionFdeSorting __register_frame_info_bases __register_frame_info __register_frame __register_frame_info_table_bases __register_frame_info_table __register_frame_table __deregister_frame_info_bases __deregister_frame_info _Unwind_Find_FDE _Unwind_GetGR _Unwind_GetCFA _Unwind_GetIP _Unwind_GetIPInfo _Unwind_GetRegionStart _Unwind_GetDataRelBase _Unwind_GetTextRelBase _Unwind_SetIP _Unwind_SetGR _Unwind_GetLanguageSpecificData _Unwind_FindEnclosingFunction _Unwind_Resume _Unwind_RaiseException _Unwind_DeleteException _Unwind_ForcedUnwind _Unwind_Resume_or_Rethrow _Unwind_Backtrace __cxa_call_unexpected __gxx_personality_v0
|
||||||
|
WRAP_ARGUMENT := -Wl,--wrap=
|
||||||
|
|
||||||
|
COMPONENT_ADD_LDFLAGS = -l$(COMPONENT_NAME) $(addprefix $(WRAP_ARGUMENT),$(WRAP_FUNCTIONS))
|
||||||
COMPONENT_ADD_LDFLAGS += -u __cxx_fatal_exception
|
COMPONENT_ADD_LDFLAGS += -u __cxx_fatal_exception
|
||||||
endif
|
|
||||||
|
endif # CONFIG_COMPILER_CXX_EXCEPTIONS
|
||||||
|
|
||||||
COMPONENT_ADD_INCLUDEDIRS =
|
COMPONENT_ADD_INCLUDEDIRS =
|
||||||
|
@ -6,58 +6,178 @@
|
|||||||
|
|
||||||
#ifndef CONFIG_COMPILER_CXX_EXCEPTIONS
|
#ifndef CONFIG_COMPILER_CXX_EXCEPTIONS
|
||||||
|
|
||||||
const char *FATAL_EXCEPTION = "Fatal C++ exception: ";
|
extern "C" void abort_expect_void(const void *context)
|
||||||
|
|
||||||
extern "C" void __cxx_fatal_exception(void)
|
|
||||||
{
|
{
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" bool __cxx_fatal_exception_bool(void)
|
extern "C" void *abort_expect_void_and_return(const void *context)
|
||||||
{
|
{
|
||||||
__cxx_fatal_exception();
|
abort();
|
||||||
return false;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void __cxx_fatal_exception_message(const char *msg)
|
extern "C" void *forward_abort_uw_ctx(struct _Unwind_Context *context)
|
||||||
|
{
|
||||||
|
return abort_expect_void_and_return((void*) context);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static T abort_return()
|
||||||
|
{
|
||||||
|
abort();
|
||||||
|
return static_cast<T>(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// unwind-dw2-fde.o
|
||||||
|
extern "C" void __wrap__Unwind_SetEnableExceptionFdeSorting(unsigned char enable)
|
||||||
{
|
{
|
||||||
printf("%s%s\n", FATAL_EXCEPTION, msg);
|
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void __cxx_fatal_exception_message_va(const char *msg, ...)
|
extern "C" void __wrap___register_frame_info_bases (const void *begin, struct object *ob, void *tbase, void *dbase)
|
||||||
{
|
{
|
||||||
__cxx_fatal_exception_message(msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" void __cxx_fatal_exception_int(int i)
|
|
||||||
{
|
|
||||||
printf("%s (%d)\n", FATAL_EXCEPTION, i);
|
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The following definitions are needed because libstdc++ is also compiled with
|
extern "C" void __wrap___register_frame_info (const void *begin, struct object *ob)
|
||||||
__throw_exception_again defined to throw, and some other exception code in a few places.
|
{
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
This cause exception handler code to be emitted in the library even though it's mostly
|
extern "C" void __wrap___register_frame_info_table_bases (void *begin, struct object *ob, void *tbase, void *dbase)
|
||||||
unreachable (as any libstdc++ "throw" will first call one of the above stubs, which will abort).
|
{
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
If these are left out, a bunch of unwanted exception handler code is linked.
|
extern "C" void __wrap___register_frame_info_table (void *begin, struct object *ob)
|
||||||
|
{
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
Note: these function prototypes are not correct.
|
|
||||||
*/
|
|
||||||
|
|
||||||
extern "C" void __cxa_allocate_exception(void) __attribute__((alias("__cxx_fatal_exception")));
|
extern "C" void __wrap___register_frame (void *begin)
|
||||||
extern "C" void __cxa_allocate_dependent_exception(void) __attribute__((alias("__cxx_fatal_exception")));
|
__attribute__((alias("abort_expect_void")));
|
||||||
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_free_dependent_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_bool")));
|
extern "C" void __wrap___register_frame_table (void *begin)
|
||||||
|
__attribute__((alias("abort_expect_void")));
|
||||||
|
|
||||||
|
extern "C" void *__wrap___deregister_frame_info_bases (const void *begin)
|
||||||
|
__attribute__((alias("abort_expect_void_and_return")));
|
||||||
|
|
||||||
|
extern "C" void *__wrap___deregister_frame_info (const void *begin)
|
||||||
|
__attribute__((alias("abort_expect_void_and_return")));
|
||||||
|
|
||||||
|
extern "C" void __wrap___deregister_frame (void *begin)
|
||||||
|
__attribute__((alias("abort_expect_void")));
|
||||||
|
|
||||||
|
typedef void* fde;
|
||||||
|
|
||||||
|
extern "C" const fde * __wrap__Unwind_Find_FDE (void *pc, struct dwarf_eh_bases *bases)
|
||||||
|
{
|
||||||
|
return abort_return<fde*>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// unwind-dw2.o (riscv), unwind-dw2-xtensa.o (xtensa)
|
||||||
|
typedef void* _Unwind_Ptr;
|
||||||
|
typedef int _Unwind_Word;
|
||||||
|
|
||||||
|
extern "C" _Unwind_Word __wrap__Unwind_GetGR (struct _Unwind_Context *context, int index)
|
||||||
|
{
|
||||||
|
return abort_return<_Unwind_Word>();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" _Unwind_Word __wrap__Unwind_GetCFA (struct _Unwind_Context *context)
|
||||||
|
{
|
||||||
|
return abort_return<_Unwind_Word>();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void __wrap__Unwind_SetIP (struct _Unwind_Context *context, _Unwind_Ptr val)
|
||||||
|
{
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void __wrap__Unwind_SetGR (struct _Unwind_Context *context, int index, _Unwind_Word val)
|
||||||
|
{
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" _Unwind_Ptr __wrap__Unwind_GetIPInfo (struct _Unwind_Context *context, int *ip_before_insn)
|
||||||
|
{
|
||||||
|
return abort_return<_Unwind_Ptr>();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" _Unwind_Ptr __wrap__Unwind_GetIP (struct _Unwind_Context *context)
|
||||||
|
__attribute__((alias("forward_abort_uw_ctx")));
|
||||||
|
|
||||||
|
extern "C" _Unwind_Ptr __wrap__Unwind_GetRegionStart (struct _Unwind_Context *context)
|
||||||
|
__attribute__((alias("forward_abort_uw_ctx")));
|
||||||
|
|
||||||
|
extern "C" _Unwind_Ptr __wrap__Unwind_GetDataRelBase (struct _Unwind_Context *context)
|
||||||
|
__attribute__((alias("forward_abort_uw_ctx")));
|
||||||
|
|
||||||
|
extern "C" _Unwind_Ptr __wrap__Unwind_GetTextRelBase (struct _Unwind_Context *context)
|
||||||
|
__attribute__((alias("forward_abort_uw_ctx")));
|
||||||
|
|
||||||
|
extern "C" void *__wrap__Unwind_GetLanguageSpecificData (struct _Unwind_Context *context)
|
||||||
|
__attribute__((alias("forward_abort_uw_ctx")));
|
||||||
|
|
||||||
|
extern "C" void *__wrap__Unwind_FindEnclosingFunction (void *pc)
|
||||||
|
__attribute__((alias("abort_expect_void_and_return")));
|
||||||
|
|
||||||
|
struct frame_state *__frame_state_for (void *pc_target, struct frame_state *state_in)
|
||||||
|
{
|
||||||
|
return abort_return<struct frame_state *>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// unwind.inc
|
||||||
|
typedef int _Unwind_Reason_Code;
|
||||||
|
typedef int _Unwind_Action;
|
||||||
|
typedef int _Unwind_Exception_Class;
|
||||||
|
typedef int* _Unwind_Trace_Fn;
|
||||||
|
typedef int* _Unwind_Stop_Fn;
|
||||||
|
|
||||||
|
extern "C" void __wrap__Unwind_Resume (struct _Unwind_Exception *exc)
|
||||||
|
{
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void __wrap__Unwind_DeleteException (struct _Unwind_Exception *exc)
|
||||||
|
{
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extern "C" _Unwind_Reason_Code __wrap__Unwind_RaiseException(struct _Unwind_Exception *exc)
|
||||||
|
{
|
||||||
|
return abort_return<_Unwind_Reason_Code>();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" _Unwind_Reason_Code __wrap__Unwind_Resume_or_Rethrow (struct _Unwind_Exception *exc)
|
||||||
|
__attribute__((alias("__wrap__Unwind_RaiseException")));
|
||||||
|
|
||||||
|
extern "C" _Unwind_Reason_Code __wrap__Unwind_ForcedUnwind (struct _Unwind_Exception *exc,
|
||||||
|
_Unwind_Stop_Fn stop, void * stop_argument)
|
||||||
|
{
|
||||||
|
return abort_return<_Unwind_Reason_Code>();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" _Unwind_Reason_Code __wrap__Unwind_Backtrace(_Unwind_Trace_Fn trace, void * trace_argument)
|
||||||
|
{
|
||||||
|
return abort_return<_Unwind_Reason_Code>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// eh_personality.o
|
||||||
|
extern "C" void __wrap___cxa_call_unexpected (void *exc_obj_in)
|
||||||
|
__attribute__((alias("abort_expect_void")));
|
||||||
|
|
||||||
|
extern "C" _Unwind_Reason_Code __wrap___gxx_personality_v0 (int version,
|
||||||
|
_Unwind_Action actions,
|
||||||
|
_Unwind_Exception_Class exception_class,
|
||||||
|
struct _Unwind_Exception *ue_header,
|
||||||
|
struct _Unwind_Context *context)
|
||||||
|
{
|
||||||
|
return abort_return<_Unwind_Reason_Code>();
|
||||||
|
}
|
||||||
|
|
||||||
#endif // CONFIG_COMPILER_CXX_EXCEPTIONS
|
#endif // CONFIG_COMPILER_CXX_EXCEPTIONS
|
||||||
|
6
tools/test_apps/system/cxx_no_except/CMakeLists.txt
Normal file
6
tools/test_apps/system/cxx_no_except/CMakeLists.txt
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
# The following lines of boilerplate have to be in your project's CMakeLists
|
||||||
|
# in this exact order for cmake to work correctly
|
||||||
|
cmake_minimum_required(VERSION 3.5)
|
||||||
|
|
||||||
|
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||||
|
project(cxx_no_except)
|
2
tools/test_apps/system/cxx_no_except/README.md
Normal file
2
tools/test_apps/system/cxx_no_except/README.md
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
| Supported Targets | ESP32 |
|
||||||
|
| ----------------- | ----- |
|
2
tools/test_apps/system/cxx_no_except/main/CMakeLists.txt
Normal file
2
tools/test_apps/system/cxx_no_except/main/CMakeLists.txt
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
idf_component_register(SRCS "main.cpp"
|
||||||
|
INCLUDE_DIRS ".")
|
27
tools/test_apps/system/cxx_no_except/main/main.cpp
Normal file
27
tools/test_apps/system/cxx_no_except/main/main.cpp
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
No except example.
|
||||||
|
|
||||||
|
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, this
|
||||||
|
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "esp_system.h"
|
||||||
|
#include <new>
|
||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/task.h"
|
||||||
|
|
||||||
|
extern "C" void app_main()
|
||||||
|
{
|
||||||
|
char *char_array = new (std::nothrow) char [47];
|
||||||
|
|
||||||
|
for (int i = 10; i >= 0; i--) {
|
||||||
|
char_array[i] = i;
|
||||||
|
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||||
|
}
|
||||||
|
esp_restart();
|
||||||
|
|
||||||
|
delete [] char_array;
|
||||||
|
}
|
2
tools/test_apps/system/cxx_no_except/sdkconfig.ci.xtensa
Normal file
2
tools/test_apps/system/cxx_no_except/sdkconfig.ci.xtensa
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
CONFIG_IDF_TARGET="esp32"
|
||||||
|
CONFIG_COMPILER_CXX_EXCEPTIONS=n
|
Loading…
Reference in New Issue
Block a user