[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
pull/6974/head
Jakob Hasse 2021-02-07 16:51:52 +08:00
rodzic 2554d8956a
commit 2552c7ba0f
9 zmienionych plików z 246 dodań i 36 usunięć

Wyświetl plik

@ -3,14 +3,58 @@ idf_component_register(SRCS "cxx_exception_stubs.cpp"
# Make sure that pthread is in component list
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} INTERFACE "-u __cxa_guard_dummy")
# Force pthread to also appear later than stdc++ in link line
add_library(stdcpp_pthread INTERFACE)
# Force libpthread to appear later than libstdc++ in link line since libstdc++ depends on libpthread.
# 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(cxx cxx COMPONENT_LIB)
add_library(stdcpp_pthread INTERFACE)
target_link_libraries(stdcpp_pthread INTERFACE stdc++ $<TARGET_FILE:${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)
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u __cxx_fatal_exception")

Wyświetl plik

@ -6,7 +6,12 @@ ifndef CONFIG_COMPILER_CXX_EXCEPTIONS
# If exceptions are disabled, ensure our fatal exception
# hooks are preferentially linked over libstdc++ which
# 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
endif
endif # CONFIG_COMPILER_CXX_EXCEPTIONS
COMPONENT_ADD_INCLUDEDIRS =

Wyświetl plik

@ -6,58 +6,178 @@
#ifndef CONFIG_COMPILER_CXX_EXCEPTIONS
const char *FATAL_EXCEPTION = "Fatal C++ exception: ";
extern "C" void __cxx_fatal_exception(void)
extern "C" void abort_expect_void(const void *context)
{
abort();
}
extern "C" bool __cxx_fatal_exception_bool(void)
extern "C" void *abort_expect_void_and_return(const void *context)
{
__cxx_fatal_exception();
return false;
abort();
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();
}
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();
}
/* 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.
extern "C" void __wrap___register_frame_info (const void *begin, struct object *ob)
{
abort();
}
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).
extern "C" void __wrap___register_frame_info_table_bases (void *begin, struct object *ob, void *tbase, void *dbase)
{
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 __cxa_allocate_dependent_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_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")));
extern "C" void __wrap___register_frame (void *begin)
__attribute__((alias("abort_expect_void")));
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

Wyświetl plik

@ -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)

Wyświetl plik

@ -0,0 +1,2 @@
| Supported Targets | ESP32 | ESP32-C3 |
| ----------------- | ----- | -------- |

Wyświetl plik

@ -0,0 +1,2 @@
idf_component_register(SRCS "main.cpp"
INCLUDE_DIRS ".")

Wyświetl plik

@ -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;
}

Wyświetl plik

@ -0,0 +1,2 @@
CONFIG_IDF_TARGET="esp32c3"
CONFIG_COMPILER_CXX_EXCEPTIONS=n

Wyświetl plik

@ -0,0 +1,2 @@
CONFIG_IDF_TARGET="esp32"
CONFIG_COMPILER_CXX_EXCEPTIONS=n