Calling Conventions

Calling Conventions (callconv)

한국어 문서에서 '콜링 컨벤션(calling convention)'은 함수를 호출할 때 인자와 반환값을 어떻게 주고받을지, 스택과 레지스터를 어떤 식으로 쓸지 정하는 약속이에요. Zig에서는 기본적으로 타깃 플랫폼의 C ABI를 따르는데, 함수 단위로 이 약속을 직접 바꾸고 싶을 때 callconv 지정자를 씁니다.

출처: Zig Documentation

본문

callconv는 함수 타입에 호출 규약을 지정해요

함수를 선언할 때 매개변수 목록 뒤에 callconv(.이름) 형태로 붙이면, 그 함수가 어떤 호출 규약을 따를지 명시할 수 있어요. 실제로는 extern으로 외부 라이브러리 함수를 가져올 때 많이 쓰게 됩니다.

// The callconv specifier changes the calling convention of the function.
extern "kernel32" fn ExitProcess(exit_code: u32) callconv(.winapi) noreturn;
extern "c" fn atan2(a: f64, b: f64) f64;

위 코드에서 ExitProcess는 Windows API라서 .winapi 호출 규약을, atan2는 C 라이브러리 함수라서 기본 C ABI를 따릅니다.

exported 함수는 기본적으로 C ABI를 따라요

export 지정자가 붙은 함수는 생성된 오브젝트 파일에서 외부에 보이게 되는데, 동시에 호출 규약도 C ABI로 바뀝니다.

// The export specifier makes a function externally visible in the generated
// object file, and makes it use the C ABI.
export fn sub(a: i8, b: i8) i8 {
    return a - b;
}

외부에서 호출할 함수는 결국 C ABI를 쓴다는 뜻이에요. 그래서 별도로 callconv를 지정하지 않아도 exported 함수는 기본값으로 C calling convention을 사용합니다.

naked: 프롤로그와 에필로그가 없는 함수

.naked 호출 규약을 쓰면 함수가 prologue(함수 시작 시 스택 정리 코드)와 epilogue(반환 시 정리 코드)를 전혀 만들지 않아요. 어셈블리와 연동할 때 특히 유용합니다.

// The naked calling convention makes a function not have any function prologue or epilogue.
// This can be useful when integrating with assembly.
fn _start() callconv(.naked) noreturn {
    abort();
}

inline: 모든 호출 지점에서 인라인 강제

inline 키워드는 함수가 모든 호출 지점(call site)에서 인라인되도록 강제해요. 만약 인라인할 수 없는 함수라면 컴파일 타임 에러가 납니다.

// The inline calling convention forces a function to be inlined at all call sites.
// If the function cannot be inlined, it is a compile-time error.
inline fn shiftLeftOne(a: u32) u32 {
    return a << 1;
}

extern 함수와 C ABI

extern으로 선언된 함수는 정적 링크 시점(링크 타임)이나 동적 링크 시점(런타임)에 해석됩니다. extern 키워드 뒤의 큰따옴표 문자열은 그 함수를 제공하는 라이브러리 이름이에요 (예: "c"libc.so). 그리고 extern 함수가 구조체나 유니온을 값으로 주고받을 때는 C ABI를 따릅니다.

더 알아보기 (Learn more)

  • Functions — 함수 선언과 extern/export/pub 지정자, 함수 포인터에 대한 전체 설명
  • extern — 외부 라이브러리 함수 선언
  • @callCallModifier를 이용해 호출 방식(항상 인라인, 항상 테일콜 등)을 세밀하게 제어하는 빌트인