2016-11-17 13 views
6

Porównałem funkcje 2 C zwracające struct. Wiemy, że na poziomie ABI duże struktury będą przekazywane przez wskaźnik jako pierwszy argument funkcji.Co właściwie oznacza ten sret?

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; 
} 

Dla tych funkcji sprawdziłem złożenie dla x86_64 Linux i Windows. Numer fsret jest zadeklarowany jako void @fsret(%struct.S* sret %s).

Porównując te dwa warianty, nie ma różnicy po stronie odbiorcy. Jednak wewnątrz funkcji fsret dodatkowo kopiuje swój pierwszy argument (wskaźnik do struktury) do rejestru RAX. Czemu?

+0

co jeśli nie 'if (fsret() słowa [0] == 10). {Do_something(); } '? kompilator potrzebuje wartości zwracanej w tym przypadku (nie jestem pewien, tylko pomysł) –

Odpowiedz

4

Przyczyna leży w this przeglądarki 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. 

więc wywoływany musi wypełnić pamięć dostarczonego przez dzwoniącego i powrócić wskaźnik, który został przeszedł również.

Potwierdza dokumencie x86_64 r252 System V ABI

Zwrot wartości przekazujących wartości odbywa się zgodnie z następującą algorytmu:

  1. klasyfikować typu zwrotny z klasyfikacją algorytm.
  2. Jeśli typ ma klasy PAMIĘĆ (ndMarco: czyli wielkie rzeczy), potem rozmówca zapewnia miejsce dla wartości powrotu i przekazuje adres tej pamięci w% RDI, jakby to była pierwsza argument funkcji . W efekcie adres ten staje się "ukrytym" pierwszym argumentem. Ta pamięć nie może nakładać się na żadne dane widoczne dla adresata poprzez inne nazwy niż ten argument. Po powrocie% rax będzie zawierać adres, który został przekazany przez wywołującego w% rdi.
+1

Świetna odpowiedź! Czy wiesz, czy istnieją podobne wymagania dla innych celów? –

+0

@ PawełBylica [o32 i eabi] (http://www.brunocardoso.cc/blog/?p=27), wiele dokumentacji ABI jest raczej słabych –