Welche Funktionen fügt gcc dem Linux-ELF hinzu?

Lesezeit: 4 Minuten

Benutzeravatar von Victor Polevoy
Victor Polevoy

Beim Verlinken eines hello-world-ähnlichen Programms in c (oder asm) mit gcc Es fügt der ausführbaren Objektdatei des Ergebnisses einige Dinge hinzu. Ich kenne nur Laufzeit-Dynamic-Linker und _start Einstiegspunkt, aber welcher Art sind diese zusätzlichen Funktionen?

00000000004003f0 t deregister_tm_clones
0000000000400430 t register_tm_clones
0000000000400470 t __do_global_dtors_aux
0000000000400490 t frame_dummy
00000000004004e0 T __libc_csu_init
0000000000400550 T __libc_csu_fini
0000000000400554 T _fini
0000000000600668 t __frame_dummy_init_array_entry
0000000000600668 t __init_array_start
0000000000600670 t __do_global_dtors_aux_fini_array_entry
0000000000600670 t __init_array_end

Was sind sie und wozu? Ist es irgendwo beschrieben? Googeln hilft nicht.

  • Sehen Start des Linux x86-Programms von Patrick Horgan Beachten Sie, dass reiner Asm-Code ohne libc diese nicht hinzufügt, da sie von libc stammen.

    – Narr

    23. Januar 2016 um 16:51 Uhr


  • @Jester sieht sehr gut aus, danke! Wenn es etwas enthält, was ich gefragt habe, können Sie mit diesen Informationen antworten (natürlich mit einigen Informationen von dort).

    – Victor Polevoy

    23. Januar 2016 um 16:52 Uhr

Benutzeravatar von John Hascall
John Hascal

Die meisten davon sind verschiedene Methoden, um Code vor oder nach dem “Haupt” -Programm selbst auszuführen, und die meisten leben darin crtstuff.c ( https://github.com/gcc-mirror/gcc/blob/master/libgcc/crtstuff.c ). Sie existieren, um Funktionen verschiedener C-ähnlicher Programmiersprachen zu unterstützen, aber sie können auch in C aufgerufen werden. Es scheint vielleicht zu kompliziert zu sein, da einige davon Altlasten darstellen und einige die Variationen darstellen, die erforderlich sind, um die verschiedenen Architekturen zu unterstützen, auf denen GCC ausgeführt wird.

Aus Ihrer Liste, eins nach dem anderen (oder zwei nach zwei):

00000000004003f0 t deregister_tm_clones
0000000000400430 t register_tm_clones

Transaktionsspeicher sollen das Programmieren mit Threads vereinfachen. Es ist eine Alternative zur sperrenbasierten Synchronisierung. Diese Routinen zerstören bzw. richten eine Tabelle ein, die von der Bibliothek (libitm) verwendet wird, die diese Funktionen unterstützt. Mehr Infos zu TM hier https://gcc.gnu.org/wiki/TransactionalMemory und hier http://pmarlier.free.fr/gcc-tm-tut.html

0000000000400470 t __do_global_dtors_aux

Führt alle globalen Destruktoren beim Beenden des Programms auf Systemen aus, auf denen .fini_array ist nicht verfügbar.

0000000000400490 t frame_dummy

Diese Funktion lebt in der .init Sektion. Es ist definiert als void frame_dummy ( void ) und sein ganzer Sinn im Leben besteht darin, anzurufen __register_frame_info_bases was Argumente hat. Anscheinend Aufrufe von Funktionen mit Argumenten aus der .init Abschnitt kann unzuverlässig sein, daher diese Funktion so __register_frame_info_bases wird nicht direkt von der angerufen .init section. Das .eh_frame info-Basen werden für die Ausnahmebehandlung und ähnliche Funktionen verwendet (z. B. Funktionen, die mit deklariert sind __attribute__((cleanup(..)))).

00000000004004e0 T __libc_csu_init
0000000000400550 T __libc_csu_fini

Diese führen alle Initialisierer und Finalisierer auf Programmebene aus (ähnlich wie Konstruktoren/Destruktoren für Ihr gesamtes Programm). Wenn Sie Funktionen definieren wie:

void __attribute__ ((constructor)) mefirst () {
    /* ... do something here ... */
}

void __attribute__ ((destructor)) melast () {
    /* ... do something here ... */
}

Sie werden vorher und nachher angerufen main() bzw. durch diese Routinen. Siehe auch https://gcc.gnu.org/onlinedocs/gccint/Initialization.html

0000000000400554 T _fini

Dies ist eine inzwischen veraltete Möglichkeit, einen Destruktor auf Programmebene (eigentlich auf Objektdateiebene) auszuführen (einige Informationen dazu finden Sie in man dlclose). Die entsprechende obsolete Funktion für Konstruktoren ist __init.

0000000000600668 t __frame_dummy_init_array_entry
0000000000600668 t __init_array_start

Diese markieren das Ende und den Beginn der .init_array Abschnitt, der Zeiger auf alle Initialisierer auf Programmebene enthält (siehe __libc_csu_init Oben).

0000000000600670 t __do_global_dtors_aux_fini_array_entry
0000000000600670 t __init_array_end

Diese markieren das Ende und den Beginn der .fini_array Abschnitt, der Verweise auf alle Finalizer auf Programmebene enthält (siehe __libc_csu_fini Oben).

[EDIT] Einige zusätzliche Anmerkungen:

  • Die Verbindung
    http://dbp-consulting.com/tutorials/debugging/linuxProgramStartup.html (Wayback-Maschine)
    aus Jesters Fragekommentar enthält ein schönes Diagramm und ein kleines Beispielprogramm, das die Gesamtreihenfolge dieser Dinge veranschaulicht und wie man auf einige dieser Funktionen von C aus zugreift.

  • Die Begriffe ‘ctors‘ und ‘dtors‘ sind Abkürzungen für ‘Konstrukteure‘ und ‘Destruktoren‘ beziehungsweise.

  • Der Unterschied zwischen globalen Konstruktoren/Destruktoren und Objektdatei-Konstruktoren/Destruktoren wird am deutlichsten, wenn Ihr Programm aus mehreren Objektdateien aufgebaut ist.

  • Die mit „T‘ (__libc_csu_init, __libc_csu_fini, _fini) sind “global” (von außen sichtbar), der Rest (gekennzeichnet mit ‘t‘) sind nicht.

  • Könnten Sie einige Ergänzungen vornehmen, um zu verdeutlichen, was ist global destructors program-level initializers and finalizers, bitte? Dies würde die Antwort meiner Meinung nach fertiger aussehen lassen.

    – Victor Polevoy

    8. Dezember 2016 um 9:19 Uhr

  • Pro geteilt Objektdatei, nicht pro Objektdatei.

    – o11c

    9. Mai 2017 um 19:02 Uhr

1386750cookie-checkWelche Funktionen fügt gcc dem Linux-ELF hinzu?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy