2017-01-30 1 views
24

Es gibt einen merkwürdigen Unterschied zwischen Assemblies eines kleinen Programms, wenn es als C-Programm oder als C++ - Programm kompiliert wird (für Linux x86-64)).Unterschiede in der Initialisierung des EAX-Registers beim Aufruf einer Funktion in C und C++

Der Code in Frage:

int fun(); 
int main(){ 
    return fun(); 
} 

es als C-Programm kompiliert (mit gcc -O2) ergibt:

main: 
    xorl %eax, %eax 
    jmp fun 

Aber es als C++ kompiliert - Programm (mit g++ -02) ergibt:

main: 
    jmp _Z3funv 

Ich finde es verwirrend, dass die C-Version den Rückgabewert initialisiert e der Hauptfunktion mit 0 (xorl %eax, %eax).

Welche Eigenschaft der C-Sprache ist für diese Notwendigkeit verantwortlich?

Edit: Es ist wahr, dass für int fun(void); die Initialisierung des eax-Registers ist.

Wenn es kein Prototyp fun überhaupt ist, d.h .:

int main(){ 
    return fun(); 
} 

dann der C-Compiler nullt die EAX-Register erneut.

+0

Es könnte sein, dass der Optimierer eine andere Optimierungsstrategie für c und C++ hat. – Alex

+0

Quirk des Optimierers? Was macht es ohne Optimierung? –

+0

Wie erhalten Sie die Funktionsnamen, die in den Disassemblies angezeigt werden? 'objdump -d' gibt mir nur Zahlen in den jmp-Anweisungen. – PSkocik

Antwort

39

In C int fun(); kann eine beliebige Anzahl von Argumenten nehmen, so dass es sogar eine varargs Funktion sein kann. In C++ bedeutet es jedoch, dass es keine Argumente benötigt.

Die x86-64 sysv abi-Konvention fordert, dass das Register AL die Anzahl der SSE-Register enthalten muss, die beim Aufruf einer varargs-Funktion verwendet werden. Natürlich gibt es kein Argument, also wird es auf Null gesetzt. Der Einfachheit halber entschied sich der Compiler dafür, die gesamte eax auf Null zu setzen. Deklarieren Sie Ihren Prototyp als int fun(void); und die xor soll verschwinden.

+0

Nun bin ich auf folgendes gestoßen: In ISO C muss die Variadic-Funktion eine feste/benannt haben Argument (siehe zum Beispiel http://stackoverflow.com/questions/11811828/is-it-possible-to-create-ac-varargs-function-with-no-arguments), so eigentlich Compiler sollte wissen, dass 'Spaß' ist keine variadische Funktion, da keine festen Parameter vorhanden sind. Weißt du, warum gcc sowieso "al"? – ead

+0

Weil 'int fun()' diese Information nicht liefert. Es könnte alles sein, einschließlich "int fun (x, ...)", was variadisch ist. – Jester

+0

Vielleicht verstehe ich etwas nicht. Ich denke, dass der Compiler die Funktionssignatur (wenn keine Parameterspezifikation vorliegt) von seiner Verwendung ableitet. Wenn 'fun' also als' fun (5) 'verwendet würde, könnte das zwei Dinge bedeuten' fun (int x) 'oder' fun (int x, ...) '. 'Fun()' könnte jedoch nur 'fun (void)' bedeuten, weil 'fun (...)' in ISO C nicht gültig ist. Aus dieser Nullstellung sollte also 'al' nicht zwingend sein. Habe ich falsch verstanden? – ead

4

Offensichtlich ist es eine defensive Maßnahme, die für Situationen entwickelt wurde, in denen prototyplose fun Funktion tatsächlich eine variadic Funktion ist, wie von @ Jester's Antwort erklärt.

Beachten Sie jedoch, dass diese Erklärung kein Wasser aus der Sicht der Standard-C-Sprache enthält.

Seit dem Beginn der genormten Zeiten (C89/90) C-Sprache explizit alle variadic Funktionen erforderlich, um mit Prototyp vor dem Zeitpunkt des Aufrufs deklariert werden. Das Aufrufen einer nicht-prototypisierten variadischen Funktion löst ein undefiniertes Verhalten in Standard C aus. Formal müssen Compiler also nicht die Möglichkeit in Betracht ziehen, dass fun variabel ist - wenn dies der Fall ist, wäre das Verhalten sowieso undefiniert. Außerdem

, wie @John Bollinger in den Kommentaren erwähnt, gemäß der C-Standard, einem nicht-Prototyps int fun() Erklärung tatsächlich schließt weiteren variadische Prototyps Erklärungen fun. I.e. Eine Variadic-Funktion kann nicht rechtlich als ()-Funktion vorbezeichnet werden. Das wäre ein weiterer Grund, warum die obige Nicht-Prototyp-Deklaration ausreicht, damit der Compiler davon ausgehen kann, dass fun nicht variabel sein kann.

Dies könnte tatsächlich eine Legacy-Funktion sein, die entworfen wurde, um Vor-Standard-C-Code zu unterstützen, bei dem die Vordefinition von Variadic-Funktionen mit Prototypen nicht erforderlich war.

+0

Ich denke [Codys Kommentar] (https://stackoverflow.com/questions/41945951/differences-in-the-initialization-of-the-axs-register-when-calling-a-function-in#comment76316514_41946081) als Antwort zu Johns ist die Antwort: Als Erweiterung zu den ISO C-Regeln gibt der GNU-Dialekt von C nicht heraus, eine variadic Funktion nach einer 'int fun(); -Deklaration zu definieren. –

Verwandte Themen