Le test est sur Linux x86 32 bits avec gcc
4.6.3
Lorsque vous utilisez gcc
pour compiler un programme C
et que vous utilisez readelf
pour vérifier les informations de la section, je peux voir la section .eh_frame
Et .eh_frame_hdr
sections à l'intérieur.
Par exemple, voici la section info du programme binaire 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
À ma connaissance, ces deux sections sont utilisées pour gérer les exceptions, elles produisent des tableaux qui décrivent comment dérouler la pile.
Mais c'est pour le programme C++
, Ils utilisent les sections eh_frame
Et gcc_exception_table
Pour gérer les exceptions, alors pourquoi le compilateur met les eh_frame
Et eh_frame_hdr
sections à l'intérieur de ELF
compilées à partir du programme C
?
Tout d'abord, la raison initiale de cela était largement politique - les personnes qui ont ajouté le déroulement basé sur DWARF (.eh_frame
) Voulaient que ce soit une fonctionnalité qui soit toujours là afin qu'il puisse être utilisé pour implémenter toutes sortes de choses autres que de simples exceptions C++, notamment:
backtrace()
__attribute__((__cleanup__(f)))
__builtin_return_address(n)
, pour n>0
pthread_cleanup_Push
, Implémenté en termes de __attribute__((__cleanup__(f)))
Cependant, si vous n'avez besoin d'aucune de ces choses, .eh_frame
Est quelque chose comme une augmentation de 15-30% à la taille de .text
Sans aucun avantage. Vous pouvez désactiver la génération de .eh_frame
Avec -fno-asynchronous-unwind-tables
Pour les unités de traduction individuelles, et cela élimine principalement le coût de taille, bien qu'il vous en reste encore quelques-uns provenant de crtbegin.o
, Etc. Vous ne pouvez pas les supprimer plus tard avec la commande strip
; puisque .eh_frame
est une section qui vit dans la partie chargée du programme (c'est le point entier), le supprimer modifie le binaire de manière à le casser lors de l'exécution. Voir https://sourceware.org/bugzilla/show_bug.cgi?id=14037 pour un exemple de la façon dont les choses peuvent se briser.
Notez que les tables DWARF sont également utilisées pour le débogage, mais à cette fin, elles n'ont pas besoin d'être dans la partie chargeable du programme. L'utilisation de -fno-asynchronous-unwind-tables
N'interrompra pas le débogage, car tant que -g
Est également transmis au compilateur, les tables sont toujours générées; ils sont simplement stockés dans une section séparée, non chargeable et supprimable du binaire, .debug_frame
.