c++11 undefined reference to `__dso_handle'



  • Hallo zusammen,
    ich habe über das Internet den Weg in euer Forum gefunden.

    Ich wollte in ein bestehendes C Projekt C++ Klassen einfügen.

    Die eigentliche Test Klasse ist sehr primitiv

    Header Datei Test_Cpp.hpp:

    namespace NFoo {
    
    class CFoo
    {
    public:
      CFoo();
    
      ~CFoo();
    
      uint32_t Get_value();
    private:
      uint32_t foo_dummy_value;
    };
    }  // namespace NFoo
    

    die passende Source Datei Test_Cpp.cpp

    static uint32_t foo_counter = 0;
    
    namespace NFoo
    {
    
    CFoo::CFoo()
    {
      foo_counter += 10;
      foo_dummy_value = foo_counter;
    }
    
    CFoo::~CFoo()
    {
      foo_counter -= 5;
      foo_dummy_value = foo_counter;
    }
    
    uint32_t CFoo::Get_value()
    {
      return foo_dummy_value;
    }
    
    }  // namespace NFoo
    

    die Klasse wird in einer weiteren Source Datei call_cpp_test.cpp aufgerufen

    void Run_Cpp_Tests()
     {
        NFoo::CFoo local_foo;
        volatile uint32_t foo_loc = local_foo.Get_value();
    
        NFoo::CFoo local_foo2;
        volatile uint32_t foo2_loc = local_foo2.Get_value();
      }
    

    Nach Verlassen der Funktion steht foo_counter auf 10. Dies ist korrekt!

    Wenn ich nun ein Globales Objekt von foo anlege bekomme ich die Fehlermeldung

    ../../lib/libfos_corefnct.a(run_cpp_test.cpp.obj): In function `__static_initialization_and_destruction_0':
    /run_cpp_test.cpp:55: undefined reference to `__dso_handle'
    /arm-none-eabi-gcc-4.8/bin/../lib/gcc/arm-none-eabi/4.8.4/../../../../arm-none-eabi/bin/ld.exe: ../../bin/3_zellen_2017.elf: hidden symbol `__dso_handle' isn't defined
    arm-none-eabi-gcc-4.8/bin/../lib/gcc/arm-none-eabi/4.8.4/../../../../arm-none-eabi/bin/ld.exe: final link failed: Bad value
    

    Mich verwirren 2 Punkte:

    1. zum einen: Warum wird ld.exe aufgerufen, ich dachte für C++ braucht es die g++.exe?
      2)Wenn ich den Destruktor von CFoo() entferne kompiliert zwar mein Code, aber der Konstruktor von dem globalen Objekt wird nie aufgerufen. Könnte dies eventuell mit dem oben genannten Fehler zusammenhängen?

    Habt ihr ne Vermutung woran dies liegen könnte?


  • Mod

    Klingt nach static initialization order fiasco. Auch bekannt als: Einer der vielen Gründe, warum globale Variablen böse sind.

    PS: Warum ld aufgerufen wird: g++ ruft das auf (oder genauer: eines der anderen Programme, die von g++ aufgerufen werden, wird das indirekt aufrufen). Schließlich gibt es keinen guten Grund dafür (und viele gute Gründe dagegen), wieso ein Compiler seinen eigenen Linker enthalten haben sollte, anstatt den Standardlinker des Systems zu benutzen.

    PPS: Wobei das eine etwas komische Äußerung für ein static initialization order fiasco wäre. Normalerweise sollte das erst zur Laufzeit explodieren. Ich habe aber auch noch nie selber solch ein Szenario gehabt, da ich aufpasse, nicht so zu programmieren. Jedenfalls hast du alle Zutaten für das Fiasko und selbst wenn du den Linkerfehler irgendwie beseitigst, wirst du damit Probleme bekommen.



  • This post is deleted!

  • Mod

    Nachtrag: Da du wohl für ARM cross-compilierst: Den Fehler mit dem __dso_handle findet man häufig in diesem Zusammenhang. Das ist dann eher ein Problem, wie genau du deinen Compiler/Linker bedienst. Wie genau sieht denn dein Aufruf aus?

    Das mögliche Fiasko zur Laufzeit besteht aber trotzdem, unabhängig von dem __dso_handle-Problem.



  • @SeppJ sagte in c++11 undefined reference to `__dso_handle':

    Klingt nach static initialization order fiasco. Auch bekannt als: Einer der vielen Gründe, warum globale Variablen böse sind.

    Mit dem Meyers Singleton löst sich das Problem in Wohlgefallen auf. Deshalb sollte man in C++ eben Singeltons nutzen.



  • @SeppJ sagte in c++11 undefined reference to `__dso_handle':

    Nachtrag: Da du wohl für ARM cross-compilierst: Den Fehler mit dem __dso_handle findet man häufig in diesem Zusammenhang. Das ist dann eher ein Problem, wie genau du deinen Compiler/Linker bedienst. Wie genau sieht denn dein Aufruf aus?

    Das mögliche Fiasko zur Laufzeit besteht aber trotzdem, unabhängig von dem __dso_handle-Problem.

    So aus dem Bauch heraus finde ich auch den Tripel arm-none-eabi im Zusammenhang mit "DSO" etwas auffällig.

    Nach meiner Interpretation ist das "Bare Metal"-Compiler für ein Embedded-System, kann das sein? Sonst würde ich eher sowas wie "arm-linux-eabi" erwarten. Auch dass direkt eine Datei mit .elf-Endung ausgegeben werden bestärkt mit hier ein wenig in dieser Annahme. Ist das vielleicht für irgendein Embedded-System, das mehr oder weniger fast direkt in deinen Code bootet?

    Für solche Zielsysteme müsste man schon etwas anders programmieren, als man das sonst gewohnt ist und eventuell sogar den Compiler-generierten Initialisierungscode explizit selbst aufrufen, wenn kein Betriebssystem das Programm mit irgendeinem bekannten Verfahren lädt und startet (habe mal aus Spass mithilfe des GCC alte DOS-MZ-Executables gestrickt, dort musste ich auch in meinem "Loader-Code" einige compiler-generiert Initialisierungsfunktionen direkt anspringen, damit solche Konstruktoren/Destruktoren aufgerufen wurden).

    DSOs sind natürlich auch eine Betriebbsystemfunktion (Dynamische Bibliotheken, ".dll", ".so" etc.). Ist es vielleicht möglich, dass das Zielsystem so etwas gar nicht unterstützt?

    Wenn ich raten müsste, würde ich sagen du solltest erstmal mal probieren, alle Bibliotheken zu linken (-static -static-libgcc -static-libstdc++) - vielleicht reicht das schon aus.

    Ansonsten recherchier mal in Foren zu der Hardware, für die du da programmieren willst. Da gibt es bestimmt irgendwo eine Anleitung, wie man Programme für das Zielsystem baut. Wie SeppJ schon erwähnte lässt sich das ziemlich sicher mit den richtigen Compiler/Linker-Flags lösen.



  • Hallo zusammen,
    vielen Dank für eure schnellen Antworten.

    Ja ich kompiliere Cross für einen Arm Cortex M4 (NXP K64) mit GCC 4.8 (ja ich weiß der ist etwas alt :O).
    Als Make System kommt CMAKE zum Einsatz.

    Ich weiß auch, dass es unschön ist im Konstruktor irgendwelche nicht Member Variablen zu verändern. Sowas mache ich sonst auch nicht. Es dient hier lediglich zur Überprüfung ob der Konstruktor aufgerufen wurde 🙂

    Ich habe bereits bei einem STM32 (auch ein Cortex M4) mit C++ gearbeitet. Dies hat dort wunderbar funktioniert. Ich würde mal vermuten, dass sich alle Cortex M4 ähneln (nur die Art der Peripherieanschlüsse ist natürlich Hersteller abhängig). Dies sollte aber vermutlich nichts mit den Systemfunktionen zu tun haben oder?

    Ich habe mal weitere libs hinzugefügt. Dies hat leider nichts gebracht 😮

    (Anmerkung: Der Übersichtlichkeit halber habe ich bereits alle Includes aus den Aufrufen entfernt)
    Mein C Compiler Aufruf schaut folgendermaßen aus:

    [ 96%] Building C object modules/cs/cmdface/CMakeFiles/cs_cmdface.dir/src/itcmdclnt.c.obj
    	cd dbg/modules/cs/cmdface && C:/git/fluegas/toolchains/arm-none-eabi-gcc-4.8/bin/arm-none-eabi-gcc.exe   -mcpu=cortex-m4 -mthumb -DCPU_MK64FN1M0VLL12 -DPLATFORM_CORTEXM4 -std=c11 -fomit-frame-pointer -ffunction-sections -fdata-sections  -Wall -Werror -fno-strict-aliasing -DeC_TARGET_ENV_EMBOS -DUSB_SUPPORT_HIGH_SPEED=0 -g -gdwarf-2 -DDEBUG=1 -DOS_LIBMODE_DP -O0 -gdwarf-2 -DDEBUG -g -o CMakeFiles/cs_cmdface.dir/src/itcmd.c.obj   -c modules/cs/cmdface/src/itcmd.c
    [ 96%] Building C object modules/cs/cmdface/CMakeFiles/cs_cmdface.dir/src/datapack_gas_desc.c.obj
    	cd /build/none/arm-cortex-m4/gcc-4.8/dbg/modules/cs/cmdface && toolchains/arm-none-eabi-gcc-4.8/bin/arm-none-eabi-gcc.exe   -mcpu=cortex-m4 -mthumb -DCPU_MK64FN1M0VLL12 -DPLATFORM_CORTEXM4 -std=c11 -fomit-frame-pointer -ffunction-sections -fdata-sections  -Wall -Werror -fno-strict-aliasing -DeC_TARGET_ENV_EMBOS -DUSB_SUPPORT_HIGH_SPEED=0 -g -gdwarf-2 -DDEBUG=1 -DOS_LIBMODE_DP -O0 -gdwarf-2 -DDEBUG -g -o CMakeFiles/cs_cmdface.dir/src/itcmdclnt.c.obj   -c C:/git/fluegas/t3xx_2017/modules/cs/cmdface/src/itcmdclnt.c
    	cd /build/none/arm-cortex-m4/gcc-4.8/dbg/modules/cs/cmdface && toolchains/arm-none-eabi-gcc-4.8/bin/arm-none-eabi-gcc.exe  - -mcpu=cortex-m4 -mthumb -DCPU_MK64FN1M0VLL12 -DPLATFORM_CORTEXM4 -std=c11 -fomit-frame-pointer -ffunction-sections -fdata-sections  -Wall -Werror -fno-strict-aliasing -DeC_TARGET_ENV_EMBOS -DUSB_SUPPORT_HIGH_SPEED=0 -g -gdwarf-2 -DDEBUG=1 -DOS_LIBMODE_DP -O0 -gdwarf-2 -DDEBUG -g -o CMakeFiles/cs_cmdface.dir/src/datapack_gas_desc.c.obj   -c C:/git/fluegas/t3xx_2017/modules/cs/cmdface/src/datapack_gas_desc.c
    

    Ein C++ Kompiler Aufruf sieht folgendermaßen aus

    [ 65%] Building CXX object modules/fos/corefnct/CMakeFiles/fos_corefnct.dir/src/test_cpp.cpp.obj
    	cd build/none/arm-cortex-m4/gcc-4.8/build_3_zellen_2017_app/dbg/modules/fos/corefnct && toolchains/arm-none-eabi-gcc-4.8/bin/arm-none-eabi-g++.exe    -mcpu=cortex-m4 -mthumb -DCPU_MK64FN1M0VLL12 -DPLATFORM_CORTEXM4 -std=c++11 -fomit-frame-pointer -ffunction-sections -fdata-sections  -Wall -fno-strict-aliasing -DUSB_SUPPORT_HIGH_SPEED=0 -g -gdwarf-2 -DDEBUG=1 -DOS_LIBMODE_DP -O0 -gdwarf-2 -std=c++11 -fpermissive -DDEBUG -g -o CMakeFiles/fos_corefnct.dir/src/test_cpp.cpp.obj -c C:/git/fluegas/t3xx_2017/modules/fos/corefnct/src/test_cpp.cpp
    [ 65%] Building CXX object modules/fos/corefnct/CMakeFiles/fos_corefnct.dir/src/run_cpp_test.cpp.obj
    	cd build/none/arm-cortex-m4/gcc-4.8/build_3_zellen_2017_app/dbg/modules/fos/corefnct && toolchains/arm-none-eabi-gcc-4.8/bin/arm-none-eabi-g++.exe    -mcpu=cortex-m4 -mthumb -DCPU_MK64FN1M0VLL12 -DPLATFORM_CORTEXM4 -std=c++11 -fomit-frame-pointer -ffunction-sections -fdata-sections  -Wall -fno-strict-aliasing -DUSB_SUPPORT_HIGH_SPEED=0 -g -gdwarf-2 -DDEBUG=1 -DOS_LIBMODE_DP -O0 -gdwarf-2 -std=c++11 -fpermissive -DDEBUG -g -o CMakeFiles/fos_corefnct.dir/src/run_cpp_test.cpp.obj -c C:/git/fluegas/t3xx_2017/modules/fos/corefnct/src/run_cpp_test.cpp
    [ 66%]
    

    Und zum Schluss der Linkeraufruf (mit den hinzugefügten Libs -static -static-libgcc -static-libstdc++)

    [100%] Linking CXX executable ../../bin/3_zellen_2017.elf
    	cd /build/none/arm-cortex-m4/gcc-4.8/build_3_zellen_2017_app/dbg/app/3_zellen_2017 && toolchains/arm-none-eabi-gcc-4.8/bin/arm-none-eabi-g++.exe  -mcpu=cortex-m4 -mthumb -DCPU_MK64FN1M0VLL12 -DPLATFORM_CORTEXM4 -std=c++11 -fomit-frame-pointer -ffunction-sections -fdata-sections  -Wall -fno-strict-aliasing -DUSB_SUPPORT_HIGH_SPEED=0 -g -gdwarf-2 -DDEBUG=1 -DOS_LIBMODE_DP -O0 -gdwarf-2 -std=c++11 -fpermissive -DDEBUG -g   -mthumb -T"linkerscript/ldscript_kinetis_k64_app.ld" -nostartfiles -static -static-libgcc -static-libstdc++ -Wl,--gc-sections -Wl,--no-warn-mismatch -Wl,-wrap=malloc -Wl,-wrap=calloc -Wl,-wrap=realloc -Wl,-wrap=free  @CMakeFiles/3_zellen_2017.dir/objects1.rsp  -o ../../bin/3_zellen_2017.elf  -LC:/git/fluegas/thirdparty/t3xx_2017/none/arm-cortex-m4/gcc-4.8/build_3_zellen_2017_app/embos/Lib -Wl,--start-group ../../lib/libapp_sms.a ../../lib/libembos_kinetis_k64.a ../../lib/libemfile_kinetis_k64.a ../../lib/libsdk_kinetis_k64.a ../../lib/libplattform_k64.a ../../lib/libmodule_hc.a -losT7LDP ../../lib/libemUSB_kinetis_k64.a -Wl,--start-group -Wl,--end-group
    ../../lib/libfos_corefnct.a(run_cpp_test.cpp.obj): In function `__static_initialization_and_destruction_0':
    corefnct/src/run_cpp_test.cpp:55: undefined reference to `__dso_handle'
    toolchains/arm-none-eabi-gcc-4.8/bin/../lib/gcc/arm-none-eabi/4.8.4/../../../../arm-none-eabi/bin/ld.exe: ../../bin/3_zellen_2017.elf: hidden symbol `__dso_handle' isn't defined
    toolchains/arm-none-eabi-gcc-4.8/bin/../lib/gcc/arm-none-eabi/4.8.4/../../../../arm-none-eabi/bin/ld.exe: final link failed: Bad value
    collect2.exe: error: ld returned 1 exit status
    jom: \none\arm-cortex-m4\gcc-4.8\build_3_zellen_2017_app\dbg\app/3_zellen_2017/CMakeFiles/3_zellen_2017.dir/build.make [bin\3_zellen_2017.elf] Error 1
    jom: \none\arm-cortex-m4\gcc-4.8\build_3_zellen_2017_app\dbg\CMakeFiles/Makefile2 [app\3_zellen_2017\CMakeFiles\3_zellen_2017.dir\all] Error 2
    jom: \arm-cortex-m4\gcc-4.8\build_3_zellen_2017_app\dbg\Makefile [all] Error 2
    "jom.exe all" terminated with exit code 2. Build might be incomplete.
    

    Hilft euch das weiter? Schonmal vielen Dank für eure vielen Antworten 🙂



  • Schau auch mal in ARM GCC.

    Und konkret bzgl. des __dso_handle habe ich noch folgenden SO-Beitrag gefunden: Where is __dso_handle defined?



  • @J-heni sagte in c++11 undefined reference to `__dso_handle':

    arm-none-eabi-g++.exe -mcpu=cortex-m4 -mthumb -DCPU_MK64FN1M0VLL12
    -DPLATFORM_CORTEXM4 -std=c++11 -fomit-frame-pointer -ffunction-sections
    -fdata-sections  -Wall -fno-strict-aliasing -DUSB_SUPPORT_HIGH_SPEED=0
    -g -gdwarf-2 -DDEBUG=1 -DOS_LIBMODE_DP -O0 -gdwarf-2 -std=c++11 -fpermissive
    -DDEBUG -g   -mthumb -T"linkerscript/ldscript_kinetis_k64_app.ld" -nostartfiles
    -static -static-libgcc -static-libstdc++ -Wl,--gc-sections -Wl,--no-warn-mismatch
    -Wl,-wrap=malloc -Wl,-wrap=calloc -Wl,-wrap=realloc -Wl,-wrap=free 
    @CMakeFiles/3_zellen_2017.dir/objects1.rsp  -o ../../bin/3_zellen_2017.elf 
    -LC:/git/fluegas/thirdparty/t3xx_2017/none/arm-cortex-m4/gcc-4.8/build_3_zellen_2017_app/embos/Lib
    -Wl,--start-group ../../lib/libapp_sms.a ../../lib/libembos_kinetis_k64.a ../../lib/libemfile_kinetis_k64.a
    ../../lib/libsdk_kinetis_k64.a ../../lib/libplattform_k64.a ../../lib/libmodule_hc.a -losT7LDP
    ../../lib/libemUSB_kinetis_k64.a -Wl,--start-group -Wl,--end-group
    

    Hilft euch das weiter? Schonmal vielen Dank für eure vielen Antworten 🙂

    Ja. Das hilft insofern weiter, als dass du hier definitiv im falschen Forum bist, es sei denn hier kennt sich zufällig jemand sehr gut mit exakt dieser Hardware und den Tools des Herstellers aus 😉

    -T"linkerscript/ldscript_kinetis_k64_app.ld" - das ist ein eigenes Linker-Script, und -nostartfiles schliesst explizit vom Compiler eingebetteten "Startup-Code" aus, der unter anderem dafür zuständig ist z.B. globale Konstruktoren/Destruktoren aufzurufen. D.h. es ist Aufgabe dieses Linker-Skripts eigenen Startup-Code in das Programm einzubauen, so dass dieser erstens ausgeführt wird und zweitens auch die vom Compiler generierten, internen Initialisierungsroutinen aufruft. Das ist schon sehr speziell und jenseits des "Standard-Kompilieren-und-Linken-mit-Betriebssystem", mit dem wohl die meisten hier im Forum zu tun haben.

    Du solltest dich an ein Forum speziell für deine Hardware wenden und/oder Dokumentation des Herstellers nochmal konsultieren und peinlich genau befolgen. Möglicherweise sind dort solche statisch initialisierten Variablen auch gar nicht vorgesehen. In diesem Fall würde ich das Programm vielleicht so umbauen, dass die Initialisierung globaler Objekte explizit am Anfang der main() durchgeführt wird. Das ist zwar nicht unbedingt sonderlich elegant, aber manchmal sind solche Krücken eben notwendig.



  • Hey vielen Dank.
    Das war in der tat ein guter Hinweis:
    Ich habe das nostartupfiles jetzt entfernt. Jetzt linkt er auch korrekt 🙂

    Falls es jemanden interessiert:
    Ich hatte danach noch ein weiteres Problem was ich lösen konnte: Leider wurden die statischen Konstruktoren nie aufgerufen.

    In meinem Startup Script sind die folgenden Schritte deifiniert:

    /**
    **===========================================================================
    **  Program - Reset_Handler
    **  Abstract: This code gets called after a reset event.
    **    1. Call system initialzation routine
    **    2. Copy .data section from ROM to RAM
    **    3. Clear .bss section (Zero init)
    **    4. Run static constructors
    **    5. Enter main
    **    6. Loop forever if returning from main
    **===========================================================================
    */
    

    Es hat sich herausgestellt das irgendjemand einfach den Teil (4) auskommentiert hat :O.
    Also Falls jemand ein Ähnliches Problem hat, dass die statischen Konstruktoren nicht auferufen werden, prüft euer startup script 🙂

    Vielen Dank aufjedenfall für eure schnelle Hilfe und Denkanstöße 🙂


Log in to reply