mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
Merge branch 'origin/feature/prevent_unwind_code_linking_4.0' into 'release/v4.0'
[C++]: prevent unwind code linking (backport 4.0) See merge request espressif/esp-idf!13806
This commit is contained in:
commit
12704ae528
@ -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")
|
||||
|
@ -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 =
|
||||
|
@ -6,79 +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();
|
||||
}
|
||||
|
||||
#if !GCC_NOT_5_2_0
|
||||
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_va")));
|
||||
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")));
|
||||
#endif
|
||||
extern "C" void __wrap___register_frame_info (const void *begin, struct object *ob)
|
||||
{
|
||||
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_table_bases (void *begin, struct object *ob, void *tbase, void *dbase)
|
||||
{
|
||||
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 (void *begin, struct object *ob)
|
||||
{
|
||||
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 __wrap___register_frame (void *begin)
|
||||
__attribute__((alias("abort_expect_void")));
|
||||
|
||||
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_table (void *begin)
|
||||
__attribute__((alias("abort_expect_void")));
|
||||
|
||||
bool std::uncaught_exception() __attribute__((alias("__cxx_fatal_exception_bool")));
|
||||
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
|
||||
|
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 | ESP32-C3 |
|
||||
| ----------------- | ----- | -------- |
|
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.defaults
Normal file
2
tools/test_apps/system/cxx_no_except/sdkconfig.defaults
Normal file
@ -0,0 +1,2 @@
|
||||
CONFIG_IDF_TARGET="esp32"
|
||||
CONFIG_COMPILER_CXX_EXCEPTIONS=n
|
Loading…
Reference in New Issue
Block a user