애플리케이션 바이너리 인터페이스
애플리케이션 바이너리 인터페이스 (ABI)
크레이트를 컴파일하면 생기는 산출물의 ABI에 영향을 주는 기능들을 이 장에서 다뤄요. ABI가 뭔지 아직 어색하다면, 함수나 변수가 최종 바이너리에서 어떤 이름과 형태로 드러나고, 다른 바이너리나 라이브러리와 어떻게 연결되는지를 규정하는 약속이라고 보면 돼요.
함수를 내보낼 때 ABI를 지정하는 방법은 extern 함수에서, 외부 라이브러리를 링크할 때 ABI를 지정하는 방법은 외부 블록에서 각각 다뤄요.
출처: Rust Reference
본문
used 속성
used 속성은 크레이트 안에서 다른 어떤 아이템도 참조하지 않거나 사용하지 않더라도, 정적 아이템이 출력 오브젝트 파일(.o, .rlib 등, 최종 바이너리는 제외)에 남아 있도록 강제해요. 다만 링커가 이를 제거하는 건 여전히 자유예요.
예를 들어볼게요.
#![allow(unused)]
fn main() {
// lib.rs
// `#[used]` 덕분에 유지돼요.
#[used]
static S1: u8 = 0;
// 사용되지 않으므로 제거될 수 있어요.
#[allow(dead_code)]
static S2: u8 = 0;
// 공개적으로 접근 가능하기 때문에 유지돼요.
pub static S3: u8 = 0;
// 공개적으로 접근 가능한 함수가 참조하기 때문에 유지돼요.
static S4: u8 = 0;
#[unsafe(no_mangle)] pub fn f4() -> &'static u8 { &S4 }
// 오직 private하고 사용되지 않는(dead) 함수만 참조하므로 제거될 수 있어요.
static S5: u8 = 0;
#[allow(dead_code)]
fn f5() -> &'static u8 { &S5 }
}
실제로 오브젝트 파일에 어떤 심볼이 남는지 확인해볼게요. nm -C로 심볼 테이블을 보면 S1, S3, S4와 f4는 남고, S2와 S5는 빠져 있는 걸 볼 수 있어요.
$ rustc -O --emit=obj --crate-type=rlib lib.rs
$ LC_ALL=C nm -C lib.o
0000000000000000 R lib::S1
0000000000000000 R lib::S3
0000000000000000 r lib::S4
0000000000000000 T f4
used 속성은 MetaWord 문법을 사용해요. 또한 static 아이템에만 적용할 수 있고, 한 아이템에서 used의 첫 번째 사용만 효과가 있어요. 이후의 사용은 rustc가 린트로 경고해요.
no_mangle 속성
no_mangle 속성은 어떤 아이템에서든 표준 심볼 이름 맹글링(symbol name mangling)을 끌 수 있어요. 그 아이템의 심볼은 아이템 이름의 식별자가 되죠. 추가로, used 속성처럼 그 아이템이 생성된 라이브러리나 오브젝트 파일에서 공개적으로 내보내져요.
다만 이 속성은 안전하지 않아요(unsafe). 맹글링되지 않은 심볼이 같은 이름(또는 잘 알려진 심볼)을 가진 다른 심볼과 충돌하면 정의되지 않은 동작(undefined behavior)으로 이어질 수 있기 때문이에요.
#![allow(unused)]
fn main() {
#[unsafe(no_mangle)]
extern "C" fn foo() {}
}
2024 에디션 차이
2024 에디션 이전에는
no_mangle속성을unsafe한정 없이 사용해도 허용됐어요.
link_section 속성
link_section 속성은 함수나 정적 아이템의 내용이 배치될 오브젝트 파일의 섹션을 지정해요. 섹션 이름을 지정하기 위해 MetaNameValueStr 문법을 사용하죠.
#![allow(unused)]
fn main() {
#[cfg(target_os = "linux")] {
#[unsafe(no_mangle)]
#[unsafe(link_section = ".example_section")]
pub static VAR1: u32 = 1;
}
}
이 속성도 안전하지 않아요. 데이터나 코드가 예상하지 못한 메모리 섹션에 들어가게 할 수 있는데, 예를 들어 변경 가능한 데이터를 읽기 전용 영역에 넣을 수도 있거든요. 한 아이템에서 link_section의 첫 번째 사용만 효과가 있고, 이후 사용은 미래 호환성 경고(future-compatibility warning)로 린트돼요. 나중에는 오류가 될 수도 있어요.
2024 에디션 차이
2024 에디션 이전에는
link_section속성을unsafe한정 없이 사용해도 허용됐어요.
export_name 속성
export_name 속성은 함수나 정적 아이템에서 내보내질 심볼의 이름을 지정해요. 심볼 이름을 지정하기 위해 MetaNameValueStr 문법을 사용하죠.
#![allow(unused)]
fn main() {
#[unsafe(export_name = "exported_symbol_name")]
pub fn name_in_rust() { }
}
이 속성도 안전하지 않아요. 사용자 지정 이름을 가진 심볼이 같은 이름(또는 잘 알려진 심볼)을 가진 다른 심볼과 충돌하면 정의되지 않은 동작으로 이어질 수 있기 때문이에요. 한 아이템에서 export_name의 첫 번째 사용만 효과가 있고, 이후 사용은 미래 호환성 경고로 린트돼요.
2024 에디션 차이
2024 에디션 이전에는
export_name속성을unsafe한정 없이 사용해도 허용됐어요.
더 알아보기
- extern 함수: 함수를 내보낼 때 ABI를 지정하는 방법
- 외부 블록: 외부 라이브러리를 링크할 때 ABI를 지정하는 방법
- 맹글링과 심볼 이름에 대한 더 자세한 내용은
no_mangle,export_name속성 문서에서