raspberrypi / pico-sdk

BSD 3-Clause "New" or "Revised" License
3.76k stars 938 forks source link

Undefined reference to __dso_handle when building with PICO_NO_FLASH #1368

Open tobias-groeger opened 1 year ago

tobias-groeger commented 1 year ago

When building an executable with PICO_NO_FLASH while using a static std::vector the build fails with a linker error:

/usr/lib/gcc/arm-none-eabi/12.2.0/../../../../arm-none-eabi/bin/ld: /usr/lib/gcc/arm-none-eabi/12.2.0/../../../../arm-none-eabi/lib/thumb/v6-m/nofp/libstdc++.a(eh_globals.o): in function `_GLOBAL__sub_I___cxa_get_globals_fast':
/build/arm-none-eabi-gcc/src/gcc-12.2.0/libstdc++-v3/libsupc++/eh_globals.cc:178: undefined reference to `__dso_handle'
/usr/lib/gcc/arm-none-eabi/12.2.0/../../../../arm-none-eabi/bin/ld: /usr/lib/gcc/arm-none-eabi/12.2.0/../../../../arm-none-eabi/lib/thumb/v6-m/nofp/libc.a(libc_a-fini.o): in function `__libc_fini_array':
/build/arm-none-eabi-newlib/src/build-newlib/arm-none-eabi/thumb/v6-m/nofp/newlib/../../../../../../newlib-4.3.0.20230120/newlib/libc/misc/fini.c:36: undefined reference to `_fini'
/usr/lib/gcc/arm-none-eabi/12.2.0/../../../../arm-none-eabi/bin/ld: picopp_include_all.elf: hidden symbol `__dso_handle' isn't defined
/usr/lib/gcc/arm-none-eabi/12.2.0/../../../../arm-none-eabi/bin/ld: final link failed: bad value
collect2: error: ld returned 1 exit status

I am using gcc 12.2.0.

This does not happen when building the same application without PICO_NO_FLASH. This is because inside $PICO_SDK_PATH/src/rp2_common/pico_standard_link/CMakeLists.txt:79 the compile option -nostartfiles is set iff PICO_NO_FLASH is set to 1.

At the same time manually defining the missing symbols works as well.

void* __dso_handle = 0;
void* _fini = 0;

I am not sure what exactly these symbols do or whether they are actually needed so any help is appreciated. Is this a bug in the pico-sdk or do I have any mistakes on my side.


To reproduce, a basic example where this error occurs is:

#include <vector>

void
test()
{
    static std::vector<int> vec;
    vec.push_back(0);
}

int
main()
{
    return 0;
}
crash8229 commented 1 year ago

It does seem related to the -nostartfiles option.

I took a look at src/rp2_common/pico_standard_link/CMakeLists.txt in my local Pico SDK (develop branch). The option that causes the -nostartfiles option to be set is PICO_CXX_ENABLE_EXCEPTIONS being set to 0. Setting this to 1 allows my project to build with no further modifications. This change to the CMakeLists.txt in the SDK was made after the 1.5.0 release, so this currently only applies to those using the develop branch. https://github.com/raspberrypi/pico-sdk/blob/62201a83e2693ea165fdc7669b4ab2f3b4f43c36/src/rp2_common/pico_standard_link/CMakeLists.txt#L77-L81

kilograham commented 1 year ago

are you saying the change after 1.5.0 fixes it or breaks it?

crash8229 commented 1 year ago

Neither, just the conditions that cause the issue changed between 1.5.0 and develop.

For 1.5.0 and prior, PICO_NO_FLASH being set to 1 would cause the -nostartfiles option to be set. https://github.com/raspberrypi/pico-sdk/blob/2ccab115de0d42d31d6611cca19ef0cd0d2ccaa7/src/rp2_common/pico_standard_link/CMakeLists.txt#L77-L79

In the develop branch, that section was modified to set -nostartfiles if PICO_C_COMPILER_IS_GNU is true and PICO_CXX_ENABLE_EXCEPTIONS is false (I believe this might be the default). PICO_NO_FLASH no longer affects the setting of the -nostartfiles option. https://github.com/raspberrypi/pico-sdk/blob/62201a83e2693ea165fdc7669b4ab2f3b4f43c36/src/rp2_common/pico_standard_link/CMakeLists.txt#L77-L81

I was trying to find a way around the issue without defining __dso_handle and _fini as that felt wrong to me.

tobias-groeger commented 1 year ago

As far as I know PICO_CXX_ENABLE_EXCEPTIONS is the default (at least for the 1.5.0 release). I don't think always setting this is a good solution as some people (me included) would like to continue building their projects without exceptions enabled.

From what I understand from the C++ Itanium ABI the __dso_handle symbol is responsible for destruction of static (or gobal) objects upon dynamic object unloading. Do we actually need this behaviour? On a Pico the only time we would need to destruct these objects is when we exit our program which stops the processor anyway. So maybe globally defining these symbols as 0 might actually be a valid strategy. Or maybe we can somehow disable this behaviour?

crash8229 commented 1 year ago

You are probably right. I was setting PICO_CXX_ENABLE_EXCEPTIONS to 0 on my project before I changed it to 1 to workaround this issue. I agree that setting PICO_CXX_ENABLE_EXCEPTIONS to 1 should not be the permanent solution.

I am not knowledgeable in the behavior of __dso_handle or _fini to weigh in on whether defining them as 0 is the right call.

kilograham commented 1 year ago

Ok, i am reverting (for 1.5.1) the behavior to (what is still for you broken) preexisting behavior of looking at PICO_NO_FLASH, as it seems C++ using various standard c++ libs is now broken.

kilograham commented 3 months ago

can you recheck on SDK 2.0.0

tobias-groeger commented 3 months ago

I am still having the same problem on SDK 2.0.0.

kilograham commented 3 months ago

thx