Rust, main 함수 이전의 숨겨진 세계
Rust의 `main` 함수 이전 초기화 과정에 대한 심층 분석이 진행 중임
운영체제별 시스템 콜(System Call) 접근 방식과 C 런타임의 역할이 논의됨
Linux, macOS, Windows, BSD 등 다양한 환경에서의 ABI 안정성 경계가 비교됨
`_start` 및 `_WinMainCRTStartup`과 같은 진입점 함수와 링커 스크립트의 중요성이 강조됨
운영체제별 시스템 콜(System Call) 인터페이스
커뮤니티에서는 macOS의 `libSystem.dylib`와 Windows의 `ntdll.dll`이 시스템 콜 접근을 위한 ABI 안정성 경계 역할을 한다고 설명합니다. 특히 Linux가 안정적인 시스템 콜 번호를 제공하는 것과 달리, 다른 OS들은 동적 라이브러리 형태의 인터페이스를 통해 커널과 통신하는 방식을 사용한다고 지적합니다. Go 언어가 이러한 환경에서 C 런타임을 우회하려다 겪었던 어려움도 언급되며, 이는 운영체제별 저수준 인터페이스의 복잡성을 보여줍니다.
Rust 런타임 초기화와 'main' 이전 생명주기
논의에서는 Rust의 `main` 함수 실행 전에 발생하는 초기화 과정의 중요성을 강조합니다. 여기에는 패닉(Panic) 처리 및 언와인딩(Unwinding) 인프라 설정, C 스타일 프로그램 인자를 Rust의 `std::env::args` 인터페이스로 변환하는 작업 등이 포함됩니다. 특히 Windows에서는 MS-DOS 스타일 명령 문자열을 POSIX 스타일 `argv` 배열로 파싱하는 C 런타임의 역할이 언급되며, 이는 크로스 플랫폼 개발 시 고려해야 할 저수준 동작을 시사합니다.
링커(Linker)와 실행 파일 진입점(`_start`)
Linux 환경에서 ELF 실행 파일의 진입점은 링커 헤더의 `e_entry` 필드에 의해 결정되며, `_start`는 GCC의 관례적인 심볼 이름임을 명확히 합니다. 반면 Windows PE 헤더의 `AddressOfEntryPoint`는 `_WinMainCRTStartup`과 같은 함수를 가리킵니다. 이러한 진입점(Entry Point) 메커니즘은 C 런타임이 자체적으로 초기화할 기회를 제공하며, 최소 크기 실행 파일 제작 연구를 통해 PE 헤더의 세부 사항을 학습할 수 있다는 점이 흥미롭습니다.
임베디드 Rust와 초기화 커스터마이징
임베디드 환경(`no_std`, `no_alloc`)에서의 Rust 개발 경험이 공유되었습니다. 이 환경에서는 `main` 함수가 일반 함수와 같으며, 초기화 과정이 개발자에게 상당 부분 위임됩니다. `linktime` 크레이트와 같은 도구들이 링커 집계(Linker Aggregation)를 통해 보일러플레이트 코드를 줄여주는 유용성을 언급하며, 개발자가 직접 linker script를 설정하여 `.init_array` 섹션을 관리하는 방식에 대한 논의도 이어졌습니다.
BSD 시스템의 ABI 안정성 논쟁
초기 논의에서 BSD 계열 시스템의 `libc`가 ABI 안정성 경계라는 주장이 있었으나, 이후 FreeBSD와 NetBSD의 경우 시스템 콜의 ABI 안정성에 대한 혼란스러운 정보가 많았음이 밝혀졌습니다. Go 1.16 버전부터 OpenBSD에서 libc를 사용하게 된 점은 이러한 환경의 복잡성을 반영합니다. 시스템 콜 인터페이스의 안정성에 대한 명확한 문서화 부족이 개발자들에게 혼란을 야기할 수 있음을 시사합니다.