2016-11-17 4 views
6

Ich habe 2 C-Funktionen verglichen, die eine Struktur zurückgeben. Wir wissen, dass große Strukturen auf ABI-Ebene als Zeiger auf das erste Funktionsargument übergeben werden.Was bedeutet eigentlich?

struct S { 
    int words[8]; 
}; 

struct S fsret() { 
    struct S s; 
    s.words[0] = 1; 
    return s; 
} 

void fout(struct S* s) { 
    s->words[0] = 1; 
} 

Für diese Funktionen habe ich die Assembly für x86_64 Linux und Windows überprüft. Die fsret ist als void @fsret(%struct.S* sret %s) deklariert.

Beim Vergleich dieser beiden Varianten gibt es keinen Unterschied auf der Callee-Seite. Innerhalb der Funktionen kopiert das fsret jedoch zusätzlich sein erstes Argument (den Zeiger auf die Struktur) in das RAX-Register. Warum?

+0

was, wenn Sie tun 'if (fsret() Worte [0] == 10.) {Do_something(); } '? der Compiler benötigt in diesem Fall einen Rückgabewert (nicht sicher, nur eine Idee) –

Antwort

4

Der Grund liegt in this Bewertung diff:

if (Subtarget->is64Bit() || Subtarget->isTargetKnownWindowsMSVC()) { 
    for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { 
    // The x86-64 ABIs require that for returning structs by value we copy 
    // the sret argument into %rax/%eax (depending on ABI) for the return. 
    // Win32 requires us to put the sret argument to %eax as well. 
    // Save the argument into a virtual register so that we can access it 
    // from the return points. 

so hat der Angerufene den Speicher durch die Anrufer geliefert zu füllen und die Zeiger zurück, die es auch übergeben wurde.

Dies wird durch das x86_64 R252 System V ABI Dokument bestätigt

Wertezurückführen des von Werten zurückkehren wird nach folgendem Algorithmus durchgeführt:

  1. Klassifizieren des Rückgabetyp mit der Klassifikation Algorithmus.
  2. Wenn der Typ hat Klasse MEMORY (ndMarco: dh große Sachen), dann wird der Anrufer bietet Platz für die Rückkehr Wert und übergibt die Adresse dieses Speichers in% rdi, als ob es das erste Argument an die Funktion war . In der Tat wird diese Adresse ein "verstecktes" erstes Argument. Dieser Speicher darf keine Daten überlappen, die für den Aufgerufenen über andere Namen als dieses Argument sichtbar sind. Bei Rückgabe enthält% rax die Adresse, die vom Aufrufer in% rdi übergeben wurde.
+1

Tolle Antwort! Weißt du, ob es ähnliche Anforderungen für andere Ziele gibt? –

+0

@ PawełBylica [o32 und eabi] (http://www.brunocardoso.cc/blog/?p=27), viele ABI-Dokumentationen sind eher schlecht –

Verwandte Themen