0

いずれかが呼び出し先によって使用されている場合は、呼び出し元による指示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);
}

ノート

  1. 変数a - gはすべてcallee saved registers (rbp rsp rbx r12 r13 r14 r15). また、スタック メモリのアドレス指定にはどちらかを使用する必要があるため、rbpまたはの両方を使用することはできません。rsp

  2. readprintは、外部のコンパイル ユニットからのものです。したがって、現在のコンパイル単位をコンパイルするとき、具体的には関数のレジスタ割り当て中に、呼び出し元の保存レジスタの使用について実際にはわかりません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

ノート

  1. 変数aは にスピルされ12(%rsp)ます。

  2. これらはまったく使用されないため、スピルを行う必要はありませんcaller saved registers。これは、ここではより効率的であることが判明しています。

私の質問

  1. caller saved registers使用しない場合は、をこぼすことに対処する必要がないように見えます。したがって、いつ使用する必要がありcaller saved registersますか?

  2. のような呼び出し先の場合、レジスタの使用法がわからないため、 ? の流出をどのように行う必要がありreadますか?printcaller saved registers

ありがとう

4

2 に答える 2