FromNandの日記

自分的備忘録

構造体をポインタ渡し・値渡し・ポインタ返し・値返しする場合のアセンブラ出力について

ポインタ渡しとポインタ返しについては、普通の配列などと同様のコードが生成される。

値渡しについては、引数の部分に構造体のサイズ分のメモリが大胆に確保される。
つまり、4byteの変数と200byteのサイズの構造体を値渡しする場合、引数のサイズはなんと204byteにもなる。(隠れた引数が存在する場合は、もう少し大きくなるかもしれない。)
構造体のメモリを確保する方法は、値渡しする構造体のサイズが小さい場合はpush命令を使用することが多いが、サイズが大きすぎる場合はrep命令でバイト列コピーする場合が多い。
なぜなら、フィールドが多すぎる構造体をフィールド毎にコピーする処理をアセンブラで表現しようとすると、とんでもない量のインラインコードが生成される可能性があるからである。

値返しについては、引数の先頭に呼び出し元の構造体へのポインタを"こっそり"と付け加えることによって実現する。
例えば、呼び出し元の構造体のアドレスが0x2000である場合は、"func(1, 2, 3)"という呼び出しが例えば"func(0x2000, 1, 2, 3)"のように暗黙的に解釈される。
呼び出し先の関数(この場合は値返しをする関数であるfunc)は、コンパイラによって暗黙的に渡された0x2000というポインタを使って、そのメモリに構造体の値をコピーする。