いずれかが呼び出し先によって使用されている場合は、呼び出し元による指示caller saved registers (rax rdx rcx rsi rdi r8 r9 r10 r11)の前に保存し、後で復元する必要があることを学びました。call
以下の例を通して、
int read();
void print(int i);
int main()
{
int a = read();
int b = read();
int c = read();
int d = read();
int e = read();
int f = read();
int g = read();
print(a);
print(b);
print(c);
print(d);
print(e);
print(f);
print(g);
}
ノート
変数
a - gはすべてcallee saved registers (rbp rsp rbx r12 r13 r14 r15). また、スタック メモリのアドレス指定にはどちらかを使用する必要があるため、rbpまたはの両方を使用することはできません。rspreadとprintは、外部のコンパイル ユニットからのものです。したがって、現在のコンパイル単位をコンパイルするとき、具体的には関数のレジスタ割り当て中に、呼び出し元の保存レジスタの使用について実際にはわかりませんmain。
Godboltでは、-O3次のようにコンパイルされます
main:
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbp
pushq %rbx
subq $24, %rsp # spill here
call read()
movl %eax, 12(%rsp) # spill here
call read()
movl %eax, %ebx
call read()
movl %eax, %r15d
call read()
movl %eax, %r14d
call read()
movl %eax, %r13d
call read()
movl %eax, %r12d
call read()
movl 12(%rsp), %edi
movl %eax, %ebp
call print(int)
movl %ebx, %edi
call print(int)
movl %r15d, %edi
call print(int)
movl %r14d, %edi
call print(int)
movl %r13d, %edi
call print(int)
movl %r12d, %edi
call print(int)
movl %ebp, %edi
call print(int)
addq $24, %rsp
xorl %eax, %eax
popq %rbx
popq %rbp
popq %r12
popq %r13
popq %r14
popq %r15
ret
ノート
変数
aは にスピルされ12(%rsp)ます。これらはまったく使用されないため、スピルを行う必要はありません
caller saved registers。これは、ここではより効率的であることが判明しています。
私の質問
caller saved registers使用しない場合は、をこぼすことに対処する必要がないように見えます。したがって、いつ使用する必要がありcaller saved registersますか?のような呼び出し先の場合、レジスタの使用法がわからないため、 ? の流出をどのように行う必要があり
readますか?printcaller saved registers
ありがとう