2014-10-10 6 views
26

Test è da 32 bit x86 Linux con gcc 4.6.3Perché il programma C compilato da GCC ha bisogno della sezione .eh_frame?

Quando si utilizza gcc di compilare un programma C e utilizzando readelf di controllare la sezione info, posso vedere la sezione .eh_frame e .eh_frame_hdr sezioni interne.

Ad esempio, ecco le informazioni sulla sezione del programma binario 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 

Nella mia comprensione, queste due sezioni sono utilizzati per la gestione delle eccezioni, si producono le tabelle che descrivono come per rilassarsi pila.

Ma è per C++ programma, usano eh_frame e gcc_exception_table sezioni per gestire le eccezioni, allora perché compilatore mettere le eh_frame e eh_frame_hdr sezioni all'interno ELF compilati da C programma?

+4

x86-64 ABI richiede ".eh frame" ovunque esatto. Questo è stato aggiunto per consentire lo sbobinamento dello stack ovunque poiché è necessario in tutto il sistema in alcune occasioni, come negli strumenti di profilazione. GCC quindi su default x86_64 alla generazione di frame EH e tenta di renderlo ovunque esatto, mentre sulla maggior parte degli altri ABI è impostato di default sulla generazione di frame EH solo quando è necessario il frame EH ed è preciso solo nei punti del programma che potrebbero attivare EH e quindi rilassarsi. – askmish

+0

Sospetto che 'gcc' li usi anche per implementare' __attribute __ ((cleanup (..))) '. – gsg

+0

possibile duplicato di [Qual è l'uso della sezione .eh \ _frame nei programmi C?] (Http://stackoverflow.com/questions/21351099/whats-the-use-of-the-eh-frame-section-in -c-programmi) –

risposta

38

Prima di tutto, il motivo originale per questo era in gran parte politico: le persone che hanno aggiunto lo sbobinamento basato su DWARF (.eh_frame) volevano che fosse una funzione sempre presente in modo che potesse essere utilizzata per implementare tutti i tipi di cose diverse da solo C++ eccezioni, tra cui:

  • backtrace()
  • __attribute__((__cleanup__(f)))
  • __builtin_return_address(n), per n>0
  • pthread_cleanup_push, imp lemented in termini di __attribute__((__cleanup__(f)))
  • ...

Tuttavia, se non avete bisogno di nessuna di queste cose, .eh_frame è qualcosa di simile a un aumento del 15-30% per .text dimensioni senza alcun beneficio. È possibile disabilitare la generazione diper le singole unità di traduzione e questo elimina principalmente il costo delle dimensioni, sebbene ne rimangano ancora alcune che arrivano dallo crtbegin.o, ecc. non è possibile eliminarle successivamente con il comando strip; poiché .eh_frame è una sezione che risiede nella parte caricata del programma (questo è l'intero punto), la sua rimozione modifica il file binario in modo da interromperlo in fase di runtime. Vedi https://sourceware.org/bugzilla/show_bug.cgi?id=14037 per un esempio di come le cose possono rompersi.

Si noti che le tabelle DWARF vengono utilizzate anche per il debug, ma a tale scopo non è necessario che si trovino nella parte caricabile del programma. L'utilizzo di -fno-asynchronous-unwind-tables non interromperà il debug, poiché fino al -g viene passato anche al compilatore, le tabelle vengono ancora generate; vengono semplicemente archiviati in una sezione separata, non caricabile e sganciabile del file binario, .debug_frame.

+2

Una piccola correzione: 'crtbegin.o' non contiene CFI, almeno su RedHat e Ubuntu. Gli avanzi verrebbero molto probabilmente dal CFI per '__libc_csu_init' e' __libc_csu_fini'. Quelle non sono in 'crtbegin.o', ma piuttosto nella parte non condivisa di GLIBC' libc_nonshared.a' –

+0

@HristoIliev: ho sperimentato di ottenere '.eh_frame' nell'output quando non si utilizza glibc, quindi ci deve essere un po ' venendo anche da qualche altra parte. Ho pensato che fosse "crtbegin.o" ma potrei sbagliarmi. –

+0

Cosa intendi con '' Non * non puoi * spogliarli con il comando 'strip'? '' Penso che possa essere spogliato senza rischi (e l'eseguibile diventerà più piccolo) se nessuna delle caratteristiche sopra descritte è usata nell'eseguibile . Ho ragione? – pts