Warum benötigt das GCC-kompilierte C-Programm den Abschnitt .eh_frame?

 C Programming >> C-Programmierung >  >> Tags >> GCC
Warum benötigt das GCC-kompilierte C-Programm den Abschnitt .eh_frame?


Test auf 32-Bit-x86-Linux mit gcc 4.6.3


Bei Verwendung von gcc um einen C zu kompilieren Programm und mit readelf Um die Abschnittsinformationen zu überprüfen,
kann ich den .eh_frame sehen Abschnitt und .eh_frame_hdr Abschnitte innen.


Hier ist zum Beispiel die Abschnittsinfo des Binärprogramms Perlbench .


readelf -S perlbench
There are 28 section headers, starting at offset 0x102e48:
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
[ 1] .interp PROGBITS 08048154 000154 000013 00 A 0 0 1
[ 2] .note.ABI-tag NOTE 08048168 000168 000020 00 A 0 0 4
[ 3] .note.gnu.build-i NOTE 08048188 000188 000024 00 A 0 0 4
[ 4] .gnu.hash GNU_HASH 080481ac 0001ac 000044 04 A 5 0 4
[ 5] .dynsym DYNSYM 080481f0 0001f0 0007b0 10 A 6 1 4
[ 6] .dynstr STRTAB 080489a0 0009a0 0003d6 00 A 0 0 1
[ 7] .gnu.version VERSYM 08048d76 000d76 0000f6 02 A 5 0 2
[ 8] .gnu.version_r VERNEED 08048e6c 000e6c 0000a0 00 A 6 2 4
[ 9] .rel.dyn REL 08048f0c 000f0c 000028 08 A 5 0 4
[10] .rel.plt REL 08048f34 000f34 000388 08 A 5 12 4
[11] .init PROGBITS 080492bc 0012bc 00002e 00 AX 0 0 4
[12] .plt PROGBITS 080492f0 0012f0 000720 04 AX 0 0 16
[13] .text PROGBITS 08049a10 001a10 0cf86c 00 AX 0 0 16
[14] .fini PROGBITS 0811927c 0d127c 00001a 00 AX 0 0 4
[15] .rodata PROGBITS 081192a0 0d12a0 017960 00 A 0 0 32
[16] .eh_frame_hdr PROGBITS 08130c00 0e8c00 003604 00 A 0 0 4
[17] .eh_frame PROGBITS 08134204 0ec204 01377c 00 A 0 0 4
[18] .ctors PROGBITS 08148f0c 0fff0c 000008 00 WA 0 0 4
[19] .dtors PROGBITS 08148f14 0fff14 000008 00 WA 0 0 4
[20] .jcr PROGBITS 08148f1c 0fff1c 000004 00 WA 0 0 4
[21] .dynamic DYNAMIC 08148f20 0fff20 0000d0 08 WA 6 0 4
[22] .got PROGBITS 08148ff0 0ffff0 000004 04 WA 0 0 4
[23] .got.plt PROGBITS 08148ff4 0ffff4 0001d0 04 WA 0 0 4
[24] .data PROGBITS 081491e0 1001e0 002b50 00 WA 0 0 32
[25] .bss NOBITS 0814bd40 102d30 002b60 00 WA 0 0 32
[26] .comment PROGBITS 00000000 102d30 00002a 01 MS 0 0 1
[27] .shstrtab STRTAB 00000000 102d5a 0000ec 00 0 0 1

Nach meinem Verständnis werden diese beiden Abschnitte zur Behandlung von Ausnahmen verwendet, sie erzeugen Tabellen, die beschreiben, wie der Stack abgewickelt wird.


Aber es ist für C++ Programm verwenden sie eh_frame und gcc_exception_table Abschnitte zum Verwalten von Ausnahmen, warum setzt der Compiler dann den eh_frame und eh_frame_hdr Abschnitte innerhalb von ELF kompiliert aus C Programm?


Antworten:


Zunächst einmal war der ursprüngliche Grund dafür größtenteils politischer Natur – die Leute, die die DWARF-basierte Abwicklung (.eh_frame ) wollte, dass es ein Feature ist, das immer vorhanden ist, damit es für die Implementierung aller möglichen Dinge außer C++-Ausnahmen verwendet werden kann, einschließlich:



  • backtrace()

  • __attribute__((__cleanup__(f)))

  • __builtin_return_address(n) , für n>0

  • pthread_cleanup_push , implementiert im Sinne von __attribute__((__cleanup__(f)))

  • ...


Wenn Sie jedoch keines dieser Dinge benötigen, .eh_frame ist so etwas wie eine 15-30 %ige Steigerung auf .text Größe ohne Nutzen. Sie können die Generierung von .eh_frame deaktivieren mit -fno-asynchronous-unwind-tables für einzelne Übersetzungseinheiten, und dies eliminiert größtenteils die Kosten für die Größe, obwohl Sie noch einige übrig haben, die von crtbegin.o kommen usw. Sie können nicht entfernen Sie sie mit dem strip Befehl später; seit .eh_frame ist ein Abschnitt, der sich im geladenen Teil des Programms befindet (das ist der springende Punkt). Wenn Sie ihn entfernen, wird die Binärdatei so modifiziert, dass sie zur Laufzeit beschädigt wird. Unter https://sourceware.org/bugzilla/show_bug.cgi?id=14037 finden Sie ein Beispiel dafür, wie Dinge kaputt gehen können.


Beachten Sie, dass DWARF-Tabellen auch zum Debuggen verwendet werden, aber zu diesem Zweck müssen sie sich nicht im ladbaren Teil des Programms befinden. Mit -fno-asynchronous-unwind-tables wird das Debuggen nicht unterbrechen, da -g wird ebenfalls an den Compiler übergeben, die Tabellen werden trotzdem generiert; Sie werden einfach in einem separaten, nicht ladbaren, entfernbaren Abschnitt der Binärdatei .debug_frame gespeichert .