Do czego służą dyrektywy CFI w narzędziu Gnu Assembler (GAS)?

118

Nie wydaje się być dyrektywa .CFI po każdym wierszu, a także nie są szerokie odmian winorośli z tych ex., .cfi_startproc, .cfi_endprocEtc .. więcej tutaj .

    .file   "temp.c"
    .text
.globl main
    .type   main, @function
main:
.LFB0:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    movq    %rsp, %rbp
    .cfi_offset 6, -16
    .cfi_def_cfa_register 6
    movl    $0, %eax
    leave
    ret
    .cfi_endproc
.LFE0:
    .size   main, .-main
.globl func
    .type   func, @function
func:
.LFB1:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    movq    %rsp, %rbp
    .cfi_offset 6, -16
    .cfi_def_cfa_register 6
    movl    %edi, -4(%rbp)
    movl    %esi, %eax
    movb    %al, -8(%rbp)
    leave
    ret
    .cfi_endproc
.LFE1:
    .size   func, .-func
    .ident  "GCC: (Ubuntu 4.4.1-4ubuntu9) 4.4.1"
    .section    .note.GNU-stack,"",@progbits

Nie zrozumiałem ich celu.

pazury
źródło
3
opis cfiinstrukcji GNU AS tutaj
Paschalis
powiązane: Jak usunąć „szum” z wyjścia zespołu GCC / clang? , jeśli chcesz tylko instrukcje bez dyrektyw. Dobrym sposobem jest umieszczenie kodu na gcc.godbolt.org, aby zobaczyć ładne przefiltrowane wyjście asm z różnych wersji różnych kompilatorów (w tym innych niż x86), z podświetleniem kolorów w celu dopasowania wierszy źródłowych do bloków asm.
Peter Cordes,

Odpowiedzi:

70

Mam wrażenie, że to skrót od Call Frame Information i jest rozszerzeniem GNU AS do zarządzania ramkami wywołań. Od DeveloperWorks :

W przypadku niektórych architektur obsługa wyjątków musi być zarządzana za pomocą dyrektyw Call Frame Information. Te dyrektywy są używane w zestawie do bezpośredniej obsługi wyjątków. Te dyrektywy są dostępne w systemie Linux on POWER, jeśli z jakiegoś powodu (na przykład przenośność podstawy kodu) informacje dotyczące obsługi wyjątków wygenerowane przez GCC są niewystarczające.

Wygląda na to, że są one generowane na niektórych platformach w zależności od potrzeby obsługi wyjątków.

Jeśli chcesz je wyłączyć, zapoznaj się z odpowiedzią Davida .

Społeczność
źródło
5
Czy możesz też powiedzieć słowo o .LFB0, .LFB1, .LFE0, .LFE1
pazurach
@claws - To są etykiety generowane przez kompilator (jak widać na :). Zobacz stackoverflow.com/a/15285058/4294399
Calculuswhiz
144

Aby je wyłączyć, użyj opcji gcc

-fno-asynchronous-unwind-tables

-fno-dwarf2-cfi-asm może być również potrzebny.

David Watson
źródło
12
-fno-dwarf2-cfi-asmmoże być również potrzebny
technozaur
Jeśli wyłączasz go dla wyjścia asm w postaci czytelnej dla człowieka, zobacz Jak usunąć „szum” z wyjścia zespołu GCC / clang? inne przydatne opcje i sztuczki.
Peter Cordes
30

Dyrektywy CFI służą do debugowania. Pozwala debugerowi rozwinąć stos. Na przykład: jeśli procedura A wywołuje procedurę B, która następnie wywołuje wspólną procedurę C. Procedura C kończy się niepowodzeniem. Teraz chcesz wiedzieć, kto faktycznie dzwonił do C, a następnie możesz chcieć wiedzieć, kto dzwonił do B.

Debugger może rozwinąć ten stos za pomocą wskaźnika stosu (% rsp) i zarejestrować% rbp, jednak musi wiedzieć, jak je znaleźć. I tu właśnie pojawiają się dyrektywy CFI.

movq    %rsp, %rbp
.cfi_def_cfa_register 6

więc ostatnia linia tutaj mówi, że "Adres ramki wywołania" jest teraz w rejestrze 6 (% rbp)

Graham Stott
źródło
2
Myślę jednak, że obsługa wyjątków cfi powinna być częstsza niż debugowanie.
osgx
6
Właściwie CFA oznacza „kanoniczny adres ramki”. Zobacz tutaj .
Cameron,
1
Dyrektywy CFI pozwalają na rozwijanie stosu nawet dla kodu skompilowanego za pomocą -fomit-frame-pointer, jako alternatywa dla RBP (który jest domyślnie włączony z gcc lub clang -O1i wyższymi). Jest używany przez obsługę wyjątków C ++, a także debuggery / profilery. W kodzie z tradycyjnymi wskaźnikami ramek RBP bieżąca wartość RBP zawsze wskazuje na zapisaną wartość RBP, która wskazuje na poprzednią, tworząc połączoną listę. W takim przypadku nie ma potrzeby korzystania z CFI. (Chociaż w funkcjach, które używają wskaźnika ramki, CFI cfa_register unika potrzeby większej ilości metadanych dla każdej zmiany RSP, jak to pokazujesz.)
Peter Cordes
2

Aby je wyłączyć, g ++ potrzebuje -fno-exceptionsrazem z wymienionymi wcześniej -fno-asynchronous-unwind-tables, pod warunkiem, że nie używasz wyjątków.

iw4h
źródło