익명 사용자
로그인하지 않음
계정 만들기
로그인
youngwiki
검색
Procedure call 문서 원본 보기
youngwiki
이름공간
문서
토론
더 보기
더 보기
문서 행위
읽기
원본 보기
역사
←
Procedure call
문서 편집 권한이 없습니다. 다음 이유를 확인해주세요:
요청한 명령은 다음 권한을 가진 사용자에게 제한됩니다:
사용자
.
문서의 원본을 보거나 복사할 수 있습니다.
상위 문서: [[Assembly]] ==개요== 함수 f가 함수 g를 호출할 때, f는 caller에 해당하고, g는 callee에 해당한다. caller와 callee는 정상적으로 작동하기 위해 다음 정보들을 알아야 한다. * Callee는 사용할 매개변수가 어디에 저장되어 있는지 알아야 한다.(보통 스택, 레지스터에 저장) * Callee는 return address가 어디에 저장되어 있는지 알아야 한다.(보통 스택에 저장) * Caller는 return value가 어디에 저장되어 있는지 알아야 한다. 이때 caller와 caller는 같은 레지스터를 사용하고 있으므로, '''calling convention'''이 존재하여 매개변수, 반환값, return address 등을 어디에 저장할 지를 약속한다. ==Procedure Control Flow== Procedure control flow의 주축을 이루는 명령어는 ret'''와 call이다. 이때 두 명령어를 구현하는 데에는 메모리의 스택 자료구조가 사용된다. ===Function call=== 함수 호출에는 '''<code>call Dest</code>''' 명령어가 사용된다. 이는 현재에서 '''지정된 함수 주소(Dest)로 jump하며, 돌아올 주소(스택 포인터)를 스택에 저장'''한다. 이는 다음과 같은 순서로 작동한다: # 현재 명령어의 바로 다음 주솟값(return address)을 스택에 push한다. #* call 명령의 크기는 5bytes 크기이므로 %rip+5 (call 명령의 다음 주소)를 스택에 저장한다. # Dest가 가리키는 주소로 jump한다. #* 프로그램 카운터<ref>프로그램 카운터(%rip)다음에 실행될 명령어의 주소를 저장한다.</ref>로 사용되는 %rip에 지정된 함수 주소(Dest)를 저장한다. 이때 스택에 추가적으로 return address를 저장하므로 %rsp(스택 포인터)의 값은 8 감소한다. ===Function Return=== Call 명령어를 통해 호출된 함수의 실행이 끝나면, '''<code>ret</code>''' 명령어를 사용해 '''원래의 주소(return address)로 복귀'''해야 한다. 이는 다음과 같은 방식으로 작동한다: # 스택에서 값을 pop하고, return address를 얻는다. 이때 %rsp의 값은 8 증가한다. # %rip에 return address를 할당하고, 이를 통해 return address로 jump한다. 즉, <code>ret</code>는 <code>pop %rip</code>과 동일한 효과이다. ==x86-64 Return Values== x86-64 시스템에서 기본적인 규칙은 함수가 종료된 뒤의 '''반환값은 %rax에 저장'''된다는 것이다. 이때 caller와 callee는 각각 주의할 점이 존재한다. * Caller 주의점: Callee를 호출하기 전에 %rax의 값을 먼저 백업해두어야 한다. * Callee 주의점: 반환값을 %rax에 저장하되, 해당 값이 8byte를 초과할 경우, 포인터를 대신 반환해야 한다. ===Caller/Callee save=== 함수는 인자 외에도 다양한 임시 값이나 변수들을 register에 저장해 사용한다. 하지만 '''caller/callee save'''라는 개념이 없다면, register를 이용한 변수들의 사용에 상당한 제약이 생긴다. 왜냐하면 어떤 함수에서 %rbx를 사용하고자 할 때, 해당 레지스터는 이전에 호출된 함수에서 이미 덮어쓰기되어 있을 수 있기 때문이다. '''Caller/Callee save'''는 caller에서 사용된 register를 보존하여 callee에서 자유롭게 register들을 사용할 수 있도록 하는 개념이다. 이 개념을 구현하기 위해서 register는 '''caller-saved register'''와 '''callee-saved register'''로 나누어진다. ===Caller-saved registers=== Caller-saved register는 '''caller 측에서 백업/복원에 대한 책임이 있는 register'''이다. 이는 caller 함수가 register 값을 메모리에 백업한 후, callee 함수가 시작/종료된 후 메모리에 백업된 값을 이용해서 register를 복원하여 구현된다. 이를 통해서 '''callee가 caller-saved register들을 자유롭게 사용할 수 있도록 보장'''한다. 이때 caller-saved register들에는 %rdi, %rsi, %rdx, %rcx, %r8 ~ %r11가 있다. ===Callee-saved registers=== Callee-saved register는 '''callee 측에서 백업/복원 책임이 있는 register'''이다. 이는 callee 함수가 해당 register들을 사용하고자 할 때 백업해둔 후, callee 함수가 해당 register 사용을 완료한 후 해당 register의 값을 복원하여 구현된다. 즉 '''callee가 자유롭게 사용하되, 스스로 복구해야 하는 레지스터'''이다. Callee-saved register들에는 %rbx, %r12 ~ %r14이 있다. __예제 코드에는 callee 함수인 multistore에서 사용되는 %rbx를 caller 함수에서 보존하는 것을 보여준다. %rbx register는 callee-saved이지만,__ ==Stack based languages== Stack 기반 언어(Stack based language)는 말 그대로 스택을 기반으로 하는 언어이다. 이러한 언어는 재귀 함수를 지원하며, 여러 번 같은 함수를 호출할 수 있으므로, '''각 호출마다 상태(지역 변수, return address 등)를 스택에서 따로 관리하고 저장'''해야 한다. 이때 스택은 함수 실행 상태를 저장하는 '''frame들의 집합으로 구성'''된다. 이때 stack frame에는 다음과 같은 내용이 저장된다. * '''return address''': callee 함수가 반환된 후 다시 돌아갈 명령어 주소 * '''local variables''': 해당 함수 내에서 사용되는 지역 변수들(register에 모두 저장할 수 없을 정도로 많으면 사용) * '''Caller saved registers''': Caller의 레지스터를 백업 * '''Callee saved registers''': Callee측이 레지스터를 사용하기 전에 백업(필요할 경우) 이때 함수가 호출된 직후 frame이 생성되며, 해당 함수가 return되기 직전에 frame이 제거된다. 또한, '''%rsp는 현재 스택의 top을 가리키는 레지스터'''이다. === ==[[Function call in Assembly]]== 자세한 내용은 [[Function call in Assembly]] 문서를 참조하십시오. ==[[Memory management]]== 자세한 내용은 [[Memory management]] 문서를 참조하십시오. ==각주== [[분류:컴퓨터 시스템]]
Procedure call
문서로 돌아갑니다.
둘러보기
둘러보기
대문
최근 바뀜
임의의 문서로
미디어위키 도움말
위키 도구
위키 도구
특수 문서 목록
문서 도구
문서 도구
사용자 문서 도구
더 보기
여기를 가리키는 문서
가리키는 글의 최근 바뀜
문서 정보
문서 기록