이 코드를 실행하게 되면 println 매크로를 제공하는 표준 라이브러리를 링크하지 않게 되어 에러를 낸다.
Panic 시 호출되는 함수 구현
컴파일러는 panic이 일어날 경우 panic_handler 속성이 적용된 함수가 호출되도록 합니다. 표준 라이브러리는 panic시 호출되는 함수가 제공되지만, no_std 환경에서는 우리 panic 시에 호출 될 함수를 직접 설정해야함 ```Rust use core::panic::PanicInfo;
### ***PanicInfo*** 인자
> 패닉 일어난 파일명, 패닉 일어난 코드 줄번호, 전달된 메시지 를 가진 구조체
위 panic 함수는 절대 반환하지 않기때문에 ***never*** 타입! 을 반환
### ***eh_personality*** Language Item
Language item이란?
컴파일러가 내부적으로 요구하는 특별한 함수 및 타입
> ex) ***Copy*** trait는 어떤 타입들이 [copy semantics]()를 가지는지 컴파일러에게 알려줌.
> Copy trait 구현코드에 ***#[lang="copy"]*** 속성을 이용하여 language item으로 선언을 확인할수있다.
임의로 구현한 Language item 유의 사항
- language item 구현 코드는 매우 자주 변경되어 불안정
- 컴파일러가 타입 체크를 하지않음
-> 따라서 language item 오류를 고치는 방법 ***eh_personality*** language item
***eh_personality*** Language item : Stack unwinding 구현하는 함수
Stack unwinding 해제하는 방법
```toml
[profile.dev]
panic = "abort"
[profile.release]
panic = "abort"
Start 속성
Rust 표준 라이브러리를 링크하는 파일의 실행 과정
crt0(C runtime zero)에서 실행이 시작됨
start language item으로 지정된 Rust 런타임 실행 시작 함수를 호출한다.
Rust 런타임 초기화 후 main 함수가 호출
현재 freestanding 파일은 Rust 런타임과 crt0에 접근할 수 없기에 직접 실행 시작 지점을 지정해야함.
#![no_std]#![no_main]usecore::panic::PanicInfo;/// 패닉이 일어날 경우, 이 함수가 호출됩니다.#[panic_handler]fnpanic(_info:&PanicInfo)->!{loop{}}// name mangling 해제, Rust 컴파일러가 `_start` 함수를 만들도록 함#[no_mangle]// Rust 함수 호출 규약이 아닌 C 함수 호출 규약사용pubextern"C"fn_start()->!{loop{}}/*
! 리턴 타입 : diverging function.
시작지점 함수는 운영체제 or 부트로더에 의해 호출.종료시 exit 시스템콜로 종료
*/
#[no_mangle] 속성 : name mangling 해제, Rust 컴파일러가 _start 함수를 만들도록 함
#[no_mangle] 속성 없으면 실제 함수 이름을 이상한 이름으로 바꿔 생성
링커 오류
위 코드는 링커에 C 런타임 링크 하지말라 해야함
Bare Metal 시스템 목표로 빌드
target triple: 여러 시스템 환경들을 표현하기 위함
rustup target add thumbv7em-none-eabihf
링커 인자
링커에 특정 인자들을 추가하여 오류를 해결하는 방법
링커 인자 #### Linux ``` error: linking with `cc` failed: exit code: 1 | = note: "cc" […] = note: /usr/lib/gcc/../x86_64-linux-gnu/Scrt1.o: In function `_start': (.text+0x12): undefined reference to `__libc_csu_fini' /usr/lib/gcc/../x86_64-linux-gnu/Scrt1.o: In function `_start': (.text+0x19): undefined reference to `__libc_csu_init' /usr/lib/gcc/../x86_64-linux-gnu/Scrt1.o: In function `_start': (.text+0x25): undefined reference to `__libc_start_main' collect2: error: ld returned 1 exit status ``` 기본적으로 C런타임 실행 루틴 내에 `_start` 함수가 있음. 하지만 `no_std` 속성 사용하여 `libc`를 링크 하지않으므로 에러가 난다. 해결하는 방법은 `--nostartfiles`추가한다 ```Shell cargo rustc -- -C link-arg=nostartfiles ``` #### Windows ``` error: linking with `link.exe` failed: exit code: 1561 | = note: "C:\\Program Files (x86)\\…\\link.exe" […] = note: LINK : fatal error LNK1561: entry point must be defined ``` `entry point must be defined` : 링커가 실행 시작지점을 찾을 수 없다. Windows의 경우 기본 실행 시작 지점 이름이 subsystem에 따라 다름 - `CONSOLE` 서브시스템의 경우 링커가 mainCRTStartup - `WINDOWS` 서브시스템의 경우 링커가 WinMainCRTStartUp ```Shell cargo rustc -- -C link-args="/ENTRY:_start /SUBSYSTEM:{subsystem}" ## {subsystem}은 console | windows 로 하면된다 ``` #### macOS 1. 실행 시작 지점 함수 기본값 설정 ``` error: linking with `cc` failed: exit code: 1 | = note: "cc" […] = note: ld: entry point (_main) undefined. for architecture aarch64 clang: error: linker command failed with exit code 1 […] ``` 링커가 실행 시작 지점 함수의 기본값 `main`을 찾지 못했다 는 메시지 - macOS에서는 모든 함수들의 이름 맨 앞에 `_` 문자가 앞에 붙음(무슨 이유인지 모름) 따라서 실행 시작 지점 함수 이름을 `_start`로 새롭게 지정하자 ```Shell cargo rustc -- -C link-args="-e __start" ``` `-e`인자 : 실행시작지점 함수이름 설정 macOS에서는 모든 함수 이름앞에 추가로 `_`문자가 붙으므로 하나 더 추가함 2. static 링크 실행파일 만들기 - macOS는 기본적으로 모든 프로그램이 `libSystem`라이브러리를 링크하도록 요구함 따라서 `-static`인자를 추가해야함 ```Shell cargo rustc -- -C link-args="-e __start -static" ``` 3. crt0 링크 해제하기 - macOS에서 기본적으로 `crt0`를 링크하도록함 ```Shell cargo rustc -- -C link-args="-e __start -static -nostartfiles" ``` #### 플랫폼 별 빌드 명령어들을 하나로 통합하기 위에서 살펴본 대로 호스트 플랫폼 별로 상이한 빌드 명령어가 필요한데, `.cargo/config.toml` 이라는 파일을 만들고 플랫폼 마다 필요한 상이한 인자들을 명시하여 여러 빌드 명령어들을 하나로 통합할 수 있다. ```toml # in .cargo/config.toml [target.'cfg(target_os = "linux")'] rustflags = ["-C", "link-arg=-nostartfiles"] [target.'cfg(target_os = "windows")'] rustflags = ["-C", "link-args=/ENTRY:_start /SUBSYSTEM:console"] [target.'cfg(target_os = "macos")'] rustflags = ["-C", "link-args=-e __start -static -nostartfiles"] ```