2013-09-07 24 views
8

Chciałbym wiedzieć, jak GCC implementuje obsługę wyjątków dla programów w C++. Nie mogłem znaleźć łatwego do zrozumienia i czytelnego artykułu w sieci (chociaż istnieje wiele takich artykułów dla Visual C++). Wiem tylko, że implementacja GCC jest nazywana obsługą wyjątków DWARF.GCC C++ Implementacja obsługi wyjątków

NapisaĹ,em małe C++ programu i translacji go do zespołu z poleceniem:

g ++ main.cpp -S -masm = Intel -fno-dwarf2-CFi-ASM

Pliki main.cpp i main.s są tutaj podane. Czy ktokolwiek mógłby wyjaśnić zawartość pliku main.s, w szczególności sekcje .gcc_except_table i .eh_frame linia po linii? (Mój OS jest Ubuntu 13.04 32-bitowy.) Dzięki!

main.cpp:

void f() 
{ 
    throw 1; 
} 

int main() 
{ 
    int j; 
    try { 
     f(); 
    } catch (int i) { 
     j = i; 
    } 
    return 0; 
} 

main.s:

.file "main.cpp" 
.intel_syntax noprefix 
.text 
.globl _Z1fv 
.type _Z1fv, @function 
_Z1fv: 
.LFB0: 
    push ebp 
.LCFI0: 
    mov ebp, esp 
.LCFI1: 
    sub esp, 24 
    mov DWORD PTR [esp], 4 
    call __cxa_allocate_exception 
    mov DWORD PTR [eax], 1 
    mov DWORD PTR [esp+8], 0 
    mov DWORD PTR [esp+4], OFFSET FLAT:_ZTIi 
    mov DWORD PTR [esp], eax 
    call __cxa_throw 
.LFE0: 
    .size _Z1fv, .-_Z1fv 
    .globl main 
    .type main, @function 
main: 
.LFB1: 
    push ebp 
.LCFI2: 
    mov ebp, esp 
.LCFI3: 
    and esp, -16 
    sub esp, 32 
.LEHB0: 
    call _Z1fv 
.LEHE0: 
.L7: 
    mov eax, 0 
    jmp .L9 
.L8: 
    cmp edx, 1 
    je .L6 
    mov DWORD PTR [esp], eax 
.LEHB1: 
    call _Unwind_Resume 
.LEHE1: 
.L6: 
    mov DWORD PTR [esp], eax 
    call __cxa_begin_catch 
    mov eax, DWORD PTR [eax] 
    mov DWORD PTR [esp+24], eax 
    mov eax, DWORD PTR [esp+24] 
    mov DWORD PTR [esp+28], eax 
    call __cxa_end_catch 
    jmp .L7 
.L9: 
    leave 
.LCFI4: 
    ret 
.LFE1: 
    .globl __gxx_personality_v0 
    .section .gcc_except_table,"a",@progbits 
    .align 4 
.LLSDA1: 
    .byte 0xff 
    .byte 0 
    .uleb128 .LLSDATT1-.LLSDATTD1 
.LLSDATTD1: 
    .byte 0x1 
    .uleb128 .LLSDACSE1-.LLSDACSB1 
.LLSDACSB1: 
    .uleb128 .LEHB0-.LFB1 
    .uleb128 .LEHE0-.LEHB0 
    .uleb128 .L8-.LFB1 
    .uleb128 0x1 
    .uleb128 .LEHB1-.LFB1 
    .uleb128 .LEHE1-.LEHB1 
    .uleb128 0 
    .uleb128 0 
.LLSDACSE1: 
    .byte 0x1 
    .byte 0 
    .align 4 
    .long _ZTIi 
.LLSDATT1: 
    .text 
    .size main, .-main 
    .section .eh_frame,"a",@progbits 
.Lframe1: 
    .long .LECIE1-.LSCIE1 
.LSCIE1: 
    .long 0 
    .byte 0x1 
    .string "zPL" 
    .uleb128 0x1 
    .sleb128 -4 
    .byte 0x8 
    .uleb128 0x6 
    .byte 0 
    .long __gxx_personality_v0 
    .byte 0 
    .byte 0xc 
    .uleb128 0x4 
    .uleb128 0x4 
    .byte 0x88 
    .uleb128 0x1 
    .align 4 
.LECIE1: 
.LSFDE1: 
    .long .LEFDE1-.LASFDE1 
.LASFDE1: 
    .long .LASFDE1-.Lframe1 
    .long .LFB0 
    .long .LFE0-.LFB0 
    .uleb128 0x4 
    .long 0 
    .byte 0x4 
    .long .LCFI0-.LFB0 
    .byte 0xe 
    .uleb128 0x8 
    .byte 0x85 
    .uleb128 0x2 
    .byte 0x4 
    .long .LCFI1-.LCFI0 
    .byte 0xd 
    .uleb128 0x5 
    .align 4 
.LEFDE1: 
.LSFDE3: 
    .long .LEFDE3-.LASFDE3 
.LASFDE3: 
    .long .LASFDE3-.Lframe1 
    .long .LFB1 
    .long .LFE1-.LFB1 
    .uleb128 0x4 
    .long .LLSDA1 
    .byte 0x4 
    .long .LCFI2-.LFB1 
    .byte 0xe 
    .uleb128 0x8 
    .byte 0x85 
    .uleb128 0x2 
    .byte 0x4 
    .long .LCFI3-.LCFI2 
    .byte 0xd 
    .uleb128 0x5 
    .byte 0x4 
    .long .LCFI4-.LCFI3 
    .byte 0xc5 
    .byte 0xc 
    .uleb128 0x4 
    .uleb128 0x4 
    .align 4 
.LEFDE3: 
    .ident "GCC: (Ubuntu/Linaro 4.7.3-1ubuntu1) 4.7.3" 
    .section .note.GNU-stack,"",@progbits 
+3

GCC wykorzystuje Itanium ABI, który [opisującą jak obsługiwane są wyjątki] (http://mentorembedded.github.io/cxx-abi/abi-eh.html#cxx-throw). –

+1

powyższy link jest martwy. @KerrekSB – FaceBro

+1

@FaceBro: OK, może https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html –

Odpowiedz

5

.eh_frame Układ został krótko opisany w LSB documentation. Ian Lance Taylor (autor złotego linkera) również napisał kilka postów na blogu: on .eh_frame i .gcc_except_table layout.

Aby uzyskać bardziej podobny do opisu opis, sprawdź mój Recon 2012 slides (zacznij od 37 lub więcej).

EDIT: Oto skomentowane struktury z twojej próbki. Po pierwsze, .eh_table (pominięciu niektórych elementów dla jasności):

.Lframe1:      # start of CFI 1 
    .long .LECIE1-.LSCIE1 # length of CIE 1 data 
.LSCIE1:      # start of CIE 1 data 
    .long 0     # CIE id 
    .byte 0x1    # Version 
    .string "zPL"    # augmentation string: 
           # z: has augmentation data 
           # P: has personality routine pointer 
           # L: has LSDA pointer 
    .uleb128 0x1    # code alignment factor 
    .sleb128 -4    # data alignment factor 
    .byte 0x8    # return address register no. 
    .uleb128 0x6    # augmentation data length (z) 
    .byte 0     # personality routine pointer encoding (P): DW_EH_PE_ptr|DW_EH_PE_absptr 
    .long __gxx_personality_v0 # personality routine pointer (P) 
    .byte 0     # LSDA pointer encoding: DW_EH_PE_ptr|DW_EH_PE_absptr 
    .byte 0xc    # Initial CFI Instructions 
    [...] 
    .align 4 
.LECIE1:      # end of CIE 1 
    [...] 

.LSFDE3:      # start of FDE 3 
    .long .LEFDE3-.LASFDE3 # length of FDE 3 
.LASFDE3:      # start of FDE 3 data 
    .long .LASFDE3-.Lframe1 # Distance to parent CIE from here 
    .long .LFB1    # initial location     
    .long .LFE1-.LFB1  # range length      
    .uleb128 0x4    # Augmentation data length (z)  
    .long .LLSDA1   # LSDA pointer (L)     
    .byte 0x4    # CFI instructions     
    .long .LCFI2-.LFB1 
    [...] 
    .align 4 
.LEFDE3:      # end of FDE 3 

Następnie LSDA (obszar dane specyficzne dla języka) odwołuje FDE 3:

.LLSDA1:       # LSDA 1 
    .byte 0xff     # LPStart encoding: DW_EH_PE_omit 
    .byte 0      # TType encoding: DW_EH_PE_ptr|DW_EH_PE_absptr 
    .uleb128 .LLSDATT1-.LLSDATTD1 # TType offset 
.LLSDATTD1:      # LSDA 1 action table 
    .byte 0x1     # call site encoding: DW_EH_PE_uleb128|DW_EH_PE_absptr 
    .uleb128 .LLSDACSE1-.LLSDACSB1 # call site table length 
.LLSDACSB1:      # LSDA 1 call site entries 
    .uleb128 .LEHB0-.LFB1   # call site 0 start 
    .uleb128 .LEHE0-.LEHB0   # call site 0 length 
    .uleb128 .L8-.LFB1    # call site 0 landing pad 
    .uleb128 0x1     # call site 0 action (1=action 1) 
    .uleb128 .LEHB1-.LFB1   # call site 1 start 
    .uleb128 .LEHE1-.LEHB1   # call site 1 length 
    .uleb128 0      # call site 1 landing pad 
    .uleb128 0      # call site 1 action (0=no action) 
.LLSDACSE1:      # LSDA 1 action table entries 
    .byte 0x1     # action 1 filter (1=T1 typeinfo) 
    .byte 0      # displacement to next action (0=end of chain) 
    .align 4 
    .long _ZTIi     # T1 typeinfo ("typeinfo for int") 
.LLSDATT1:       # LSDA 1 TTBase 
14

Itanium ABI (oba gcc szczęk oraz szereg innych, poniżej), że określenie obsługę wyjątków powinien być zgodny z Zero-Cost strategy.

Idea strategii zerowej ceny polega na przepychaniu wszystkich wyjątków w tabelach bocznych, które nie są przechowywane na ścieżce wykonywania głównego programu (a tym samym nie powodują zniszczenia pamięci podręcznej instrukcji). Tabele te są indeksowane według punktu programu.

Ponadto, informacje DWARF (które są informacjami debugowania naprawdę) są używane do rozwijania stosu. Ta funkcja jest zwykle dostarczana jako biblioteka, na przykład libunwind, na przykład kod źródłowy jest choksem złożenia (a zatem bardzo specyficznym dla platformy).

Zalety:

  • 0-koszt wprowadzania try/catch bloku (tak szybko, jakby nie było wcale)
  • 0-koszt posiadania throw oświadczenie w funkcji (tak długo, jak to jest nie podjęta)

Wada:

  • Powolny w przypadku wyjątku (10x wolniej niż strategii if), ponieważ stoliki nie są zazwyczaj w pamięci podręcznej, a następnie są drogie obliczeń do uruchomienia wiedzieć, które catch klauzula faktycznie zestawienia (na podstawie RTTI)

It jest bardzo popularnym narzędziem strategii na platformach 32-bitowych i 64-bitowych dla wszystkich głównych kompilatorów ... z wyjątkiem 32 bitów MSVC (o ile dobrze pamiętam).