Wofür werden CFI-Direktiven in Gnu Assembler (GAS) verwendet?

118

Es scheint nach jeder Zeile eine .CFI-Direktive zu geben, und es gibt auch eine große Vielfalt dieser Beispiele .cfi_startproc, .cfi_endprocusw., mehr hier .

    .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

Ich habe den Zweck dieser nicht verstanden.

Krallen
quelle
3
Beschreibung der cfiAnweisungen von GNU AS hier
Paschalis
Verwandte Themen: Wie entferne ich „Rauschen“ von der Ausgabe der GCC / Clang-Baugruppe? , wenn Sie nur die Anweisungen ohne die Anweisungen wollen. Ein guter Weg ist, Ihren Code auf gcc.godbolt.org zu platzieren , um eine schöne gefilterte asm-Ausgabe von verschiedenen Versionen verschiedener Compiler (einschließlich Nicht-x86) mit farblicher Hervorhebung zu sehen, um Quellzeilen mit asm-Blöcken abzugleichen.
Peter Cordes

Antworten:

70

Ich habe das Gefühl, es steht für Call Frame Information und ist eine GNU AS-Erweiterung zum Verwalten von Anrufrahmen. Von DeveloperWorks :

Bei einigen Architekturen muss die Ausnahmebehandlung mit Call Frame Information-Anweisungen verwaltet werden. Diese Anweisungen werden in der Assembly verwendet, um die Ausnahmebehandlung zu steuern. Diese Anweisungen sind unter Linux unter POWER verfügbar, wenn aus irgendeinem Grund (z. B. Portabilität der Codebasis) die vom GCC generierten Informationen zur Ausnahmebehandlung nicht ausreichen.

Es sieht so aus, als würden diese auf einigen Plattformen generiert, je nachdem, ob eine Ausnahmebehandlung erforderlich ist.

Wenn Sie diese deaktivieren möchten, lesen Sie bitte Davids Antwort .

Gemeinschaft
quelle
5
Können Sie auch ein Wort über .LFB0, .LFB1, .LFE0, .LFE1
Krallen
@claws - Dies sind vom Compiler generierte Labels (wie Sie aus dem sehen können :). Siehe stackoverflow.com/a/15285058/4294399
Calculuswhiz
144

Um diese zu deaktivieren, verwenden Sie die Option gcc

-fno-asynchronous-unwind-tables

-fno-dwarf2-cfi-asm kann auch benötigt werden.

David Watson
quelle
12
-fno-dwarf2-cfi-asmkann auch benötigt werden
Technosaurus
Wenn Sie es für die vom Menschen lesbare ASM-Ausgabe deaktivieren, lesen Sie Wie entferne ich "Rauschen" von der Ausgabe der GCC / Clang-Baugruppe? für andere nützliche Optionen und Tricks.
Peter Cordes
30

Die CFI-Anweisungen werden zum Debuggen verwendet. Es ermöglicht dem Debugger, einen Stapel abzuwickeln. Beispiel: Wenn Prozedur A Prozedur B aufruft, die dann eine allgemeine Prozedur C aufruft. Prozedur C schlägt fehl. Sie möchten jetzt wissen, wer tatsächlich C angerufen hat, und dann möchten Sie möglicherweise wissen, wer B angerufen hat.

Ein Debugger kann diesen Stapel mithilfe des Stapelzeigers (% rsp) abwickeln und% rbp registrieren. Er muss jedoch wissen, wie er sie findet. Hier kommen die CFI-Richtlinien ins Spiel.

movq    %rsp, %rbp
.cfi_def_cfa_register 6

Die letzte Zeile hier sagt also, dass sich die "Call Frame Address" jetzt in Register 6 befindet (% rbp).

Graham Stott
quelle
2
Aber die Verwendung von cfi bei der Ausnahmebehandlung sollte häufiger sein als das Debuggen, denke ich.
Osgx
6
Eigentlich steht CFA für "Canonical Frame Address". Siehe hier .
Cameron
1
CFI-Direktiven ermöglichen das Abwickeln von Stapeln auch für Code, mit dem kompiliert wurde -fomit-frame-pointer, als Alternative zu RBP (das standardmäßig mit gcc oder clang -O1und höher aktiviert ist ). Es wird sowohl von der C ++ - Ausnahmebehandlung als auch von Debuggern / Profilern verwendet. In Code mit herkömmlichen RBP-Frame-Zeigern zeigt der aktuelle RBP-Wert immer auf einen gespeicherten RBP-Wert, und dieser zeigt auf den vorherigen und bildet eine verknüpfte Liste. In diesem Fall ist kein CFI erforderlich. (Obwohl in Funktionen, die einen Frame-Zeiger verwenden, CFI cfa_register vermeidet, dass für jede RSP-Änderung mehr Metadaten benötigt werden, wie Sie anzeigen.)
Peter Cordes
2

Um diese zu deaktivieren, benötigt g ++ -fno-exceptionszusammen mit den zuvor genannten -fno-asynchronous-unwind-tables, sofern Sie keine Ausnahmen verwenden.

iw4h
quelle