Warum verursacht die "leere" Schleife einen Busfehler beim Kompilieren des C-Programms mit clang -O2 auf macOS?

8

Ich bin auf macOS High Sierra.

%Vor%

Ich habe das folgende synthetisierte Programm.

%Vor%

Edit 2: Ich habe jetzt explizit mit clang in den folgenden Beispielen kompiliert.

Wenn ich das folgende C-Programm mit clang -O2 kompiliere und ausführe, erhalte ich einen Busfehler, wenn main() nop1() , nop2() , nop3() , aber nicht nop4() aufruft.

%Vor%

Beim Kompilieren ohne -O2 werden alle Versionen ohne Busfehler ausgeführt. Ich denke, der Optimierer transformiert nop3() in nop2() . Ich würde gerne verstehen, was den Busfehler in jedem Fall verursacht und warum die Verwendung einer statischen Variable in nop4() keinen Busfehler verursacht.

Dies ist meine Klangversion:

%Vor%

Ich habe auch mit gcc unter Linux getestet:

%Vor%

, und die Programme laufen gut für alle nop -Funktionen, sowohl mit als auch ohne -O2 .

Dies ist meine GCC-Version unter Linux.

%Vor%

Bearbeiten 4

Vielleicht ist die Ausgabe von otool einfacher zu analysieren. Zuerst mit -O2 .

%Vor%

Und ohne -O2 .

%Vor%

Bearbeiten Sie 3

Wie von @Olaf angefordert, füge ich die Assembly hinzu, die von clang -S generiert wurde.

%Vor%     
Karl Marklund 16.02.2018, 22:20
quelle

2 Antworten

6

Dies ist ein bekannter Fehler in LLVM. Das angezeigte Verhalten gilt für C ++, nicht jedoch für C.

Siehe Fehlerbericht # 965 zurück von 2006 hier .

In letzter Zeit tauchte dieses Problem wieder auf, weil Rust davon getroffen wurde .

Es gibt einen Patch mit einem Fix , der im November 2017 zusammengeführt wurde, aber ich bin nicht der, welcher Version er sein wird freigegeben in.

Siehe auch eine Diskussion in der Mailingliste hier .

>     
Ilya Popov 16.02.2018, 23:18
quelle
0

Es sieht so aus, als ob clang den Prolog der Funktion generiert und nichts anderes, wodurch die Ausführung auf ein anderes, nicht verwandtes Bit des Codes fallen kann. Auf meiner Maschine produziert es:

%Vor%

Der Busfehler wird durch die erste Anweisung add verursacht, da rax auf _main zeigt, und versucht, in den Nur-Lese-Speicher zu schreiben.

Interessanterweise ergibt das Platzieren von __asm__ volatile("nop\n"); als erste Zeile in nop1 korrektes Verhalten.

    
C_Elegans 16.02.2018 22:34
quelle

Tags und Links