2016-11-17 6 views
6

構造体を返す2つのC関数を比較しました。私たちは、ABIレベルでは、大きな構造体が最初の関数引数としてポインタによって渡されることを知っています。実際に何が意味するのですか?

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

これらの機能については、x86_64 LinuxとWindowsのアセンブリをチェックしました。​​はvoid @fsret(%struct.S* sret %s)と宣言されています。

これら2つのバリエーションを比較すると、呼び出し側で違いはありません。しかし、関数の中では、​​は、最初の引数(構造体へのポインタ)をさらにRAXレジスタにコピーします。どうして?

+0

何(fsret()の言葉は[0] == 10){do_something場合は)( '行う場合。 } '?コンパイラはその場合に戻り値を必要とします(わかりません、ちょうどアイデア) –

答えて

4

理由はthisレビューの差分である:

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. 

ので、呼び出し先が呼び出し側から供給されたメモリを記入し、それは同様に渡されたポインタを返すことがあります。

この

は、値を戻し x86_64 R252システムV ABIドキュメント

によって確認された値を返すと、次の アルゴリズムに従って行われます。

  1. 分類分類と戻り値の型アルゴリズム。
  2. タイプは、クラスMEMORY (ndMarco:大きなものをIE)がある場合、呼び出し側は、戻り 値のためのスペースを提供し、それが関数の最初の の引数であるかのように%のRDIは、このストレージのアドレスを渡し、を。実際には、このアドレスは「隠された」最初の引数になります。 このストレージは、この引数以外の他の名前を使用して、呼び出し先が表示できるデータと重複してはなりません。 返信時に%raxには、%rdiの 呼び出し元によって渡されたアドレスが含まれます。
+1

偉大な答え!他のターゲットと同様の要件があるかどうか知っていますか? –

+0

@PawełBylica[o32およびeabi](http://www.brunocardoso.cc/blog/?p=27)、多くのABI文書はかなり貧弱です –

関連する問題