◼ 함수 호출 규약이란?
- 함수의 호출 및 반환에 대한 약속
- 함수를 호출할 때는 반환된 이후를 위해 스택 프레임과 반환주소를 저장해야 한다.
- 또한, 호출자(caller)는 피호출자(callee)가 요구하는 인자를 전달해줘야 하며, 피호출자의 실행이 종료될 때는 반환 값을 전달받아야 한다.
◼ 함수 호출 규약의 종류
컴파일러는 지원하는 호출 규약 중, CPU 아키텍처에 적합한 것을 선택한다.
CPU의 아키텍처가 같아도, 컴파일러가 다르면 적용하는 호출규약이 다를 수 있다.
x86 아키텍처는 레지스터 수가 적으므로, 스택으로 인자를 전달하는 규약을 사용하는 반면,
x86-64 아키텍처에서는 레지스터가 많으므로 적은 수의 인자는 레지스터만 사용하고, 안자가 많을 때만 스택을 사용한다.

◼ x86 호출 규약: cdecl
C Declaration
gcc에서 x86 바이너리를 컴파일할 때 사용하는 규약
- x86 아키텍처는 레지스터 수가 적으므로, 스택을 통해 인자를 전달한다.
- 또한, 인자를 전달하기 위해 사용한 스택을 caller가 정리 하는 특징이 있다.
- 스택을 통해 인자를 정리할 때는, 마지막 인자부터 첫 번째 인자까지 거꾸로 스택에 push한다.
void __attribute__((cdecl)) callee(int a1, int a2){
}
void caller(){
callee(1, 2);
}
위의 코드를 어셈블리어로 컴파일한 후 확인!
💡 컴파일의 정확한 의미
어떤 언어로 작성된 소스코드를 다른 언어의 목적 토드로 번역하는 것

- cdecl 함수 호출 처리 순서
- caller가 전달할 argument를 stack에 push
- callee prolog
- callee epilog
- caller가 call과정에서 사용한 stack 정리
◼ x86-64 호출 규약: SYSV
x86-64 바이너리를 컴파일할 때 사용하는 규약
◼ 특징
- 6개의 인자를 rdi,rsi,rdx,rcx,r8,r9에 순서대로 저장하여 전달
더 많은 인자 전달시 스택 사용
- caller에서 인자 전달에 사용된 스택 정리
- 함수의 반환 값은 rax로 전달
◼ SYSV 상세 분석
callee 함수 호출 전 후

스택프레임 저장
push rbp
: caller의 rbp 저장 => callee에서 반환될 때 sfp를 꺼내어 caller의 스택 프레임으로 돌아갈 수 있다.
스택프레임 할당
mov rbp, rsp
- 이 예제에서 callee 는 지역 변수를 사용하지 않으므로, 새로운 스택 프레임을 만들지 않는다.