바뀜

3,691 바이트 추가됨 ,  2025년 12월 3일 (수)
새 문서: '''System V ABI'''(System V Application Binary Interface)는 유닉스 계열 운영체제에서 실행 파일 형식, 데이터 타입 크기, 함수 호출 규약 등을 정의하...
'''System V ABI'''(System V Application Binary Interface)는 유닉스 계열 운영체제에서 실행 파일 형식, 데이터 타입 크기, 함수 호출 규약 등을 정의하는 규격이다.

현대의 64비트 UNIX 계열 (Linux, *BSD) 시스템에서는 주로 '''amd64(x86-64) System V ABI'''가 사용되기에 이 문서는 '''amd64(x86-64) System V ABI'''를 중심으로 설명한다.

== amd64 System V ABI의 특징 ==

=== 데이터 모델 (LP64) ===

amd64 System V ABI에서는 다음과 같은 LP64 데이터 모델을 사용한다.

* <code>int</code> : 32비트
* <code>long</code>, <code>long long</code> : 64비트
* 포인터(<code>void *</code> 등) : 64비트

이는 C 코드에서 정수와 포인터 크기를 가정할 때 중요한 전제이다.

=== 함수 인자 전달 규칙 ===

정수형, 포인터형 등 대부분의 스칼라 인자는 다음 순서의 레지스터로 전달된다.

{| class="wikitable"
! 인자 번호 !! 사용 레지스터
|-
| 1번째 인자 || RDI
|-
| 2번째 인자 || RSI
|-
| 3번째 인자 || RDX
|-
| 4번째 인자 || RCX
|-
| 5번째 인자 || R8
|-
| 6번째 인자 || R9
|}

* 7번째 인자부터는 스택에 8바이트 단위로 저장된 뒤 전달된다.
* 부동소수점 인자(<code>float</code>, <code>double</code>)는 XMM0–XMM7 레지스터를 통해 전달되며, 정수 인자와는 별도로 순서가 관리된다.

스택은 함수 호출 시 16바이트 정렬(alignment)을 유지해야 하며, 컴파일러가 이를 맞추도록 코드를 생성한다.

=== 반환값 규칙 ===

* 대부분의 정수/포인터 반환값: RAX
* 128비트까지의 일부 정수/구조체 반환: RAX와 RDX 조합
* 부동소수점 반환값: XMM0

더 큰 구조체 반환 등 특수한 경우에는 호출자가 반환 버퍼를 준비하고 포인터를 넘기는 방식 등이 사용된다.

=== 레지스터 보존 규약 ===

amd64 System V ABI는 어떤 레지스터를 누가 보존해야 하는지도 정의한다.

* 호출자 저장(caller-saved): 함수 호출 시 덮어써져도 되므로, 필요한 경우 '''호출하는 쪽'''이 미리 저장해야 하는 레지스터
* 피호출자 저장(callee-saved): 함수가 종료될 때 원래 값이 유지되어야 하므로, '''호출되는 함수'''가 저장·복원해야 하는 레지스터

대표적인 규약은 다음과 같다.

{| class="wikitable"
! 구분 !! 레지스터
|-
| 호출자 저장 || RAX, RCX, RDX, RSI, RDI, R8, R9, R10, R11, XMM0–XMM15
|-
| 피호출자 저장 || RBX, RBP, R12, R13, R14, R15
|}

RSP(스택 포인터)는 호출 전후에 일관되게 유지되어야 한다.

== C 언어 예시 ==

다음 예시는 정수 인자가 어떻게 레지스터와 스택으로 전달되는지 보여준다.

<pre>
int foo(int a, int b, int c, int d, int e, int f, int g);

int caller(void) {
return foo(1, 2, 3, 4, 5, 6, 7);
}
</pre>

위 호출에서 <code>foo</code>는 amd64 System V ABI에 따라 다음과 같이 인자를 받는다.

* <code>a</code> → RDI (1번째 인자)
* <code>b</code> → RSI (2번째 인자)
* <code>c</code> → RDX (3번째 인자)
* <code>d</code> → RCX (4번째 인자)
* <code>e</code> → R8 (5번째 인자)
* <code>f</code> → R9 (6번째 인자)
* <code>g</code> → 스택 상의 슬롯 (7번째 인자)

<code>foo</code>가 <code>int</code>를 반환하면, 그 값은 RAX에 담겨 <code>caller</code>로 전달된다.

부동소수점 인자의 경우:

<rpe>
double add_double(double x, double y);

double caller2(void) {
return add_double(1.0, 2.0);
}
</pre>

* <code>x</code> → XMM0
* <code>y</code> → XMM1
* 반환값(<code>double</code>) → XMM0