long P(long x, long y) {
long u = Q(y);
long v = Q(x);
return u + v;
}
P :
// 먼저 두 레지스터의 값을 스택에 저장한다.
pushq %rbp // save %rbp. x를 보관한다.
pushq %rbx // save %rbx. Q(y)를 보관한다.
subq $8, %rsp // allign stack frame
movq %rdi, %rbp // save x
movq %rsi, %rdi // move y to first argument
call Q
movq %rax, %rbx // save result. Q 호출의 결과를 %rbx에 저장한다.
movq %rbp, %rdi // move x to first argument
call Q
addq %rbx, %rax // add saved Q(y) to Q(x)
addq $8, %rsp // deallocate last part of stack
// 두 피호출자-저장 레지스터의 값을 스택에서 pop해와서 복원한다. (역순임을 주의하자!!)
popq %rbx // restore %rbx
popq %rbp // restore %rbp
ret
long call_incr2(long x) {
long v1 = 351;
long v2 = increment(&v1, 100);
return x + v2;
}
call_incr2 :
pushq %rbx // save %rbx. 먼저 레지스터 값을 스택에 저장
subq $16, %rsp // 2 frame 공간을 만든다
movq %rdi, %rbx // %rbx에 x값 저장. (%rdi는 1st argument register)
movq $351, 8(%rsp) // 아까 frame 공간 만들었던 위쪽에 351 저장
// 1st, 2nd argument register에 값을 넣어서 call 준비
movl $100, %esi // %esi에 100 저장
leaq 8(%rsp), %rdi // %rdi에 351 저장 (%rdi는 1st argument register)
call increment
addq %rbx, %rax // %rax(increment함수의 결과값)과 x 더해서 다시 %rax에 저장
// 다시
addq $16, %rsp // 2 frame 공간 없애
popq %rbx // pop으로 복원
long rfact(long n) {
long result;
if (n <= 1)
result = 1;
else
result = n * rfact(n-1);
return result;
}
rfact :
// 여기도 마찬가지로, %rbx 레지스터 사용하기 위해 일단 stack에 push해서 저장시켜둔다.
pushq %rbx
movq %rdi, %rbx // %rbx에 n을 저장한다. (%rdi는 1st argument register)
movl $1, %eax // %eax에 1 저장 (result = 1)
cmpq $1, %rdi // n : 1 비교
jle .L35 // 1 ≤ n이면 L35로 jump
leaq -1(%rdi), %rdi // n = n-1
call rfact
imulq %rbx, %rax // %rax(rfact의 return값) = %rax * n
.L35:
popq %rbx // 다시 popq해서 저장해두었던 값 restore. restore %rbx
ret
cmpq에서는 레지스터 순서를 바꿔서 비교한다는 걸 주의하자!!
long pcount_r(unsigned long x) {
if (x == 0)
return 0;
else
return (x&1) + pcount_r(x>>1);
}
pcount_r :
movl $0, %eax // %eax에 먼저 0을 저장해둔다. recursive 안들어가면 바로 return 0이니까
testq %rdi, %rdi // compare x : 0
jne .L8 // not equal이면 L8로 jump
rep ret
.L8 :
pushq %rbx // %rbx 쓰려고 일단 스택에 저장시킴
movq %rdi, %rbx // %rbx에 x 저장
// 함수 호출하기 전 1st argument 만져줌
shrq %rdi // x = x >> 1
call pcount_r
andl $1, %ebx // x = x & 1
addq %rbx, %rax // %rax(pcount_r의 결과값) + x&1 더해서 %rax에 저장
popq %rbx // restore %rbx
ret