From c00db75f8595e1ba249b2309a7bdb04ed25db039 Mon Sep 17 00:00:00 2001 From: Khalil Estell Date: Mon, 11 Mar 2024 12:38:13 -0700 Subject: [PATCH] :bug: ACTUALLY Fix undefined references in GCC The error looks like this: ``` arm-none-eabi/picolibc/arm-none-eabi/lib/thumb/v7e-m+fp/hard/libc.a(libc_stdlib_abort.c.o): in function `abort': newlib/libc/stdlib/abort.c:63: undefined reference to `_exit' arm-none-eabi/lib/thumb/v7e-m+fp/hard/libstdc++.a(vterminate.o): in function `__gnu_cxx::__verbose_terminate_handler()': vterminate.cc:(.text._ZN9__gnu_cxx27__verbose_terminate_handlerEv+0xf4): undefined reference to `_impure_ptr' arm-none-eabi/picolibc/arm-none-eabi/lib/thumb/v7e-m+fp/hard/libc.a(libc_signal_signal.c.o): in function `raise': newlib/libc/signal/signal.c:151: undefined reference to `_exit' ``` The solution, have conan add these flags to the link stage of the binary: ``` -Wl,--whole-archive -Wl,--no-whole-archive ``` The GCC linker will find unknown symbols and resolve them by searching the .a archive files. If it doesn't find one, then it complains. Here is the problem. Because we never call any of these functions, the linker never searches for them. Then at final link stage, it finds some symbols like abort() that calls _exit(), realizes it never saw it in any of our code, then yells at us. Now I'm not sure why it doesn't try to find `_exit` through `abort`. But with `whole-archive` it forces all of the symbols to be in the symbol table to be added to the linker's symbol list ensuring that they are available for resolution. :arrow_up: to 1.0.0 because I want to get the full benefit of semver version control --- .github/workflows/1.0.0.yml | 11 +++++++++ conanfile.py | 7 +++++- include/libhal-exceptions/control.hpp | 2 +- src/builtin/gcc/impl.cpp | 2 +- src/control.cpp | 32 ++++----------------------- 5 files changed, 23 insertions(+), 31 deletions(-) create mode 100644 .github/workflows/1.0.0.yml diff --git a/.github/workflows/1.0.0.yml b/.github/workflows/1.0.0.yml new file mode 100644 index 0000000..a17e5d5 --- /dev/null +++ b/.github/workflows/1.0.0.yml @@ -0,0 +1,11 @@ +name: 🚀 Deploy 1.0.0 + +on: + workflow_dispatch: + +jobs: + deploy: + uses: libhal/ci/.github/workflows/deploy_all.yml@5.x.y + with: + version: 1.0.0 + secrets: inherit diff --git a/conanfile.py b/conanfile.py index 4d3761c..4408c89 100644 --- a/conanfile.py +++ b/conanfile.py @@ -108,8 +108,9 @@ def package(self): cmake.install() def package_info(self): - self.cpp_info.libs = ["libhal-exceptions"] self.cpp_info.set_property("cmake_target_name", "libhal::exceptions") + lib_path = os.path.join(self.package_folder, + 'lib', 'liblibhal-exceptions.a') # Keep this for now, will update this for the runtime select if self._is_arm_cortex: @@ -117,4 +118,8 @@ def package_info(self): "-Wl,--wrap=__cxa_allocate_exception", "-Wl,--wrap=__cxa_free_exception", "-Wl,--wrap=__cxa_call_unexpected", + # Ensure that all symbols are added to the linker's symbol table + "-Wl,--whole-archive", + lib_path, + "-Wl,--no-whole-archive", ] diff --git a/include/libhal-exceptions/control.hpp b/include/libhal-exceptions/control.hpp index 9b65505..520517d 100644 --- a/include/libhal-exceptions/control.hpp +++ b/include/libhal-exceptions/control.hpp @@ -116,4 +116,4 @@ class single_thread_exception_allocator : public exception_allocator std::array m_buffer{}; bool m_allocated = false; }; -} // namespace hal \ No newline at end of file +} // namespace hal diff --git a/src/builtin/gcc/impl.cpp b/src/builtin/gcc/impl.cpp index c3b0593..5defa56 100644 --- a/src/builtin/gcc/impl.cpp +++ b/src/builtin/gcc/impl.cpp @@ -30,7 +30,7 @@ extern "C" std::terminate(); } - void* __wrap___cxa_allocate_exception(unsigned int p_size) // NOLINT + void* __wrap___cxa_allocate_exception(unsigned int p_size) noexcept // NOLINT { // Size of the GCC exception object header is 128 bytes. Will have to update // this if the size of the EO increases. 😅 diff --git a/src/control.cpp b/src/control.cpp index ac101af..bb1917b 100644 --- a/src/control.cpp +++ b/src/control.cpp @@ -20,28 +20,6 @@ namespace __cxxabiv1 { // NOLINT std::terminate_handler __terminate_handler = +[]() { // NOLINT - // So you may be wondering what this code is doing here? Its actually a - // bit of weird circular logic. So the linker will garbage collect any - // functions that are not used in your code. If you somehow have an - // application without any exceptions thrown, the exception code will be - // eliminated. This would be great, but due the fact that our build system - // adds the `-Wl,--wrap=symbol` to the compiler to swap the function - // implementations, this results in the compiler yelling at the user that - // they are missing a wrapped function. In order to prevent the compiler - // from throwing away this function and then turning around demanding that - // we supply it, we simply need to call throw somewhere in the code. That - // will force it to link in the original implementations which will be - // swapped out with our wrapped implementations. - // - // Use a volatile bool that is always set to false to ensure that the - // "throw 5" is NEVER called. - // - // This location was choosen because it always links in for GCC. - volatile bool force_exceptions_to_link = false; - if (force_exceptions_to_link) { - throw 5; - } - while (true) { continue; } @@ -63,11 +41,9 @@ std::terminate_handler get_terminate() noexcept } // TODO(#11): Add macro to IFDEF this out if the user want to save 256 bytes. -using default_single_thread_exception_allocator = - single_thread_exception_allocator<256>; - -default_single_thread_exception_allocator default_allocator{}; -exception_allocator* __exception_allocator = &default_allocator; // NOLINT +using default_exception_allocator = single_thread_exception_allocator<256>; +default_exception_allocator __default_allocator{}; +exception_allocator* __exception_allocator = &__default_allocator; void set_exception_allocator(exception_allocator& p_allocator) noexcept { @@ -78,4 +54,4 @@ exception_allocator* get_exception_allocator() noexcept { return __exception_allocator; } -} // namespace hal \ No newline at end of file +} // namespace hal