UEFI에서 제한된 std 사용
no_std
hello_world 프로그램부터 시작하겠습니다.표준에 UEFI용 env 모듈 추가
UEFI 모듈 추가
먼저
uefi
아래에 library/std/src/sys
모듈을 추가합니다. 이를 위해 새 파일library/std/src/sys/uefi/mod.rs
을 생성합니다. env
모듈 이외의 모든 항목은 지원되지 않는 모듈을 가리킵니다. library/std/src/sys/uefi/mod.rs
의 내용은 다음과 같습니다.//! Platform-specific extensions to `std` for UEFI platforms.
//!
//! Provides access to platform-level information on UEFI platforms, and
//! exposes Unix-specific functions that would otherwise be inappropriate as
//! part of the core `std` library.
//!
//! It exposes more ways to deal with platform-specific strings ([`OsStr`],
//! [`OsString`]), allows to set permissions more granularly, extract low-level
//! file descriptors from files and sockets, and has platform-specific helpers
//! for spawning processes.
//!
//! [`OsStr`]: crate::ffi::OsStr
//! [`OsString`]: crate::ffi::OsString
#![deny(unsafe_op_in_unsafe_fn)]
#[path = "../unsupported/alloc.rs"]
pub mod alloc;
#[path = "../unsupported/args.rs"]
pub mod args;
#[path = "../unix/cmath.rs"]
pub mod cmath;
pub mod env;
#[path = "../unsupported/fs.rs"]
pub mod fs;
#[path = "../unsupported/io.rs"]
pub mod io;
#[path = "../unsupported/locks/mod.rs"]
pub mod locks;
#[path = "../unsupported/net.rs"]
pub mod net;
#[path = "../unsupported/os.rs"]
pub mod os;
#[path = "../windows/os_str.rs"]
pub mod os_str;
#[path = "../unix/path.rs"]
pub mod path;
#[path = "../unsupported/pipe.rs"]
pub mod pipe;
#[path = "../unsupported/process.rs"]
pub mod process;
#[path = "../unsupported/stdio.rs"]
pub mod stdio;
#[path = "../unsupported/thread.rs"]
pub mod thread;
#[path = "../unsupported/thread_local_key.rs"]
pub mod thread_local_key;
#[path = "../unsupported/time.rs"]
pub mod time;
#[path = "../unsupported/common.rs"]
#[deny(unsafe_op_in_unsafe_fn)]
mod common;
pub use common::*;
보시다시피
cmath
, os_str
및 path
는 unix
대신 windows
또는 unsupported
모듈을 가리킵니다. 이는 unsupported
가 이에 대한 정의를 제공하지 않기 때문입니다. cmath
유닉스 모듈 API는 compiler-builtins
에서 제공할 수 있으므로 작동해야 합니다. 그러나 os_str
및 path
는 현재로서는 단순히 자리 표시자입니다.환경 모듈 구현
env 모듈은 매우 기본적이며 이에 대한 몇 가지 상수를 정의하기만 하면 됩니다. 다음은
library/std/src/sys/uefi/env.rs
의 내용입니다.pub mod os {
pub const FAMILY: &str = "";
pub const OS: &str = "";
pub const DLL_PREFIX: &str = "";
pub const DLL_SUFFIX: &str = "";
pub const DLL_EXTENSION: &str = "";
pub const EXE_SUFFIX: &str = ".efi";
pub const EXE_EXTENSION: &str = "efi";
}
UEFI 모듈 콘텐츠 내보내기
library/std/sys/mod.rs
에 다음 줄을 추가하면 됩니다. } else if #[cfg(target_family = "wasm")] {
mod wasm;
pub use self::wasm::*;
+ } else if #[cfg(target_os = "uefi")] {
+ mod uefi;
+ pub use self::uefi::*;
} else if #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] {
mod sgx;
pub use self::sgx::*;
이제
env
모듈이 구현되었습니다. 이러한 상수는 std::env::consts
아래에 노출됩니다.새로운 툴체인 구축
이제 툴체인을 다시 빌드해야 합니다.
./x.py build --stage 1
이제 stage1이 이 새 도구 체인을 가리켜야 합니다.
이제 이러한 상수를 매우 원시적인 방식으로 UEFI에 인쇄하려고 합니다(io, 문자열 등이 아직 구현되지 않았으므로).
std로 hello_world 컴파일
먼저
no_std
속성과 panic_handler
속성을 src/main.rs
에서 제거합니다. 그런 다음 다음 내용으로 업데이트.cargo/config.toml
합니다.[unstable]
build-std = ["std", "compiler_builtins"]
build-std-features = ["compiler-builtins-mem"]
지금 프로젝트를 컴파일하려고 하면 다음 오류가 발생합니다.
error[E0463]: can't find crate for `panic_abort`
error[E0658]: use of unstable library feature 'restricted_std'
|
= help: add `#![feature(restricted_std)]` to the crate attributes to enable
Some errors have detailed explanations: E0463, E0658.
For more information about an error, try `rustc --explain E0463`.
error: could not compile `hello_world` due to 2 previous errors
첫 번째 오류는 bug in build-std 입니다. panic_abort와 panic_unwind를 처리하는 방법을 모르기 때문에 크레이트를 사용하지 않아 위의 오류가 발생합니다.
panic_abort
에 .cargo/config.toml
를 추가하여 수정할 수 있습니다.두 번째 오류는
restricted_std
에 src/main.rs
기능을 추가하여 수정할 수 있습니다.지금 구축을 시도하고 ........ 실패합니다. 다음과 같은 오류가 발생합니다.
error: linking with `rust-lld` failed: exit status: 1
|
= note: "rust-lld" "-flavor" "link" "/NOLOGO" "/entry:efi_main" "/subsystem:efi_application" "/var/home/ayush/Documents/Programming/Rust/uefi/hello_world/target/target/debug/deps/hello_world-bf96c91d419b97ff.3aumljakx58twtt1.rcgu.o" "/var/home/ayush/Documents/Programming/Rust/uefi/hello_world/target/target/debug/deps/hello_world-bf96c91d419b97ff.11wx9iybsb4s2x54.rcgu.o" "/LIBPATH:/var/home/ayush/Documents/Programming/Rust/uefi/hello_world/target/target/debug/deps" "/LIBPATH:/var/home/ayush/Documents/Programming/Rust/uefi/hello_world/target/debug/deps" "/LIBPATH:/var/home/ayush/Documents/Programming/Rust/rust/build/x86_64-unknown-linux-gnu/stage1/lib/rustlib/target/lib" "/var/home/ayush/Documents/Programming/Rust/uefi/hello_world/target/target/debug/deps/libr_efi-44f0e2c98ca397ed.rlib" "/var/home/ayush/Documents/Programming/Rust/uefi/hello_world/target/target/debug/deps/libstd-0f82fcd1446bb823.rlib" "/var/home/ayush/Documents/Programming/Rust/uefi/hello_world/target/target/debug/deps/libpanic_abort-6267bb336da2fa77.rlib" "/var/home/ayush/Documents/Programming/Rust/uefi/hello_world/target/target/debug/deps/librustc_demangle-12ba4dfb1ce0974e.rlib" "/var/home/ayush/Documents/Programming/Rust/uefi/hello_world/target/target/debug/deps/libstd_detect-af3466d26b0b584c.rlib" "/var/home/ayush/Documents/Programming/Rust/uefi/hello_world/target/target/debug/deps/libhashbrown-282ed18a03cc159e.rlib" "/var/home/ayush/Documents/Programming/Rust/uefi/hello_world/target/target/debug/deps/librustc_std_workspace_alloc-d47af0fe9b191470.rlib" "/var/home/ayush/Documents/Programming/Rust/uefi/hello_world/target/target/debug/deps/libunwind-8ad628841136827a.rlib" "/var/home/ayush/Documents/Programming/Rust/uefi/hello_world/target/target/debug/deps/libcfg_if-f793ff480fd551b6.rlib" "/var/home/ayush/Documents/Programming/Rust/uefi/hello_world/target/target/debug/deps/liblibc-249d18e9ef84acfd.rlib" "/var/home/ayush/Documents/Programming/Rust/uefi/hello_world/target/target/debug/deps/liballoc-4b1b3794d0343e8a.rlib" "/var/home/ayush/Documents/Programming/Rust/uefi/hello_world/target/target/debug/deps/librustc_std_workspace_core-3a7d1ce70363f171.rlib" "/var/home/ayush/Documents/Programming/Rust/uefi/hello_world/target/target/debug/deps/libcore-73e7a0474be04fb7.rlib" "/var/home/ayush/Documents/Programming/Rust/uefi/hello_world/target/target/debug/deps/libcompiler_builtins-4f95060227077e02.rlib" "/NXCOMPAT" "/LIBPATH:/var/home/ayush/Documents/Programming/Rust/rust/build/x86_64-unknown-linux-gnu/stage1/lib/rustlib/target/lib" "/OUT:/var/home/ayush/Documents/Programming/Rust/uefi/hello_world/target/target/debug/deps/hello_world-bf96c91d419b97ff.efi" "/OPT:REF,NOICF" "/DEBUG" "/NODEFAULTLIB"
= note: rust-lld: error: undefined symbol: __CxxFrameHandler3
>>> referenced by libstd-0f82fcd1446bb823.rlib(std-0f82fcd1446bb823.std.ea9c30f6-cgu.2.rcgu.o):(.xdata)
>>> referenced by libstd-0f82fcd1446bb823.rlib(std-0f82fcd1446bb823.std.ea9c30f6-cgu.2.rcgu.o):(.xdata)
error: could not compile `hello_world` due to previous error
이 오류는 약간 이상합니다. 지금은
__CxxFrameHandler3
의 빈 구현을 제공하여 빌드를 수정할 수 있지만 더 많은 연구가 필요합니다. src/main.rs
에 다음 줄을 추가해야 합니다.#[no_mangle]
pub extern "C" fn __CxxFrameHandler3() {}
이제 응용 프로그램이 제대로 빌드되고 실행됩니다.
EXE_EXTENSION 상수 인쇄
이제 EXE_EXTENSION을 콘솔에 출력합니다. 아직 io와 문자열이 구현되지 않았기 때문에
u16
배열을 사용하여 기본 방식으로 수행해야 합니다. 최종src/main.rs
은 다음과 같습니다.#![no_main]
#![feature(restricted_std)]
use r_efi::efi;
use std::env::consts;
#[no_mangle]
pub extern "C" fn __CxxFrameHandler3() {}
fn print_efi(s: &[u16], st: *mut efi::SystemTable) -> Result<(), r_efi::base::Status> {
let r = unsafe { ((*(*st).con_out).output_string)((*st).con_out, s.as_ptr() as *mut efi::Char16) };
if r.is_error() {
Err(r)
} else {
Ok(())
}
}
fn print_newline(st: *mut efi::SystemTable) -> Result<(), r_efi::base::Status> {
let mut s = [0;2];
create_const_uefi_str("\n", &mut s);
print_efi(&s, st)
}
fn create_const_uefi_str(const_str: &str, uefi_array: &mut [u16]) {
let mut i = 0;
for v in const_str.bytes() {
uefi_array[i] = v as u16;
i += 1;
}
uefi_array[i] = 0x0000u16;
}
fn print_env_constants(st: *mut efi::SystemTable) -> Result<(), r_efi::base::Status> {
let mut exe_extension_heading = [0; 16];
create_const_uefi_str("exe_extension: ", &mut exe_extension_heading);
print_efi(&exe_extension_heading, st)?;
let mut exe_extension = [0; 5];
create_const_uefi_str(consts::EXE_EXTENSION, &mut exe_extension);
print_efi(&exe_extension, st)?;
print_newline(st)
}
#[export_name = "efi_main"]
pub extern "C" fn main(_h: efi::Handle, st: *mut efi::SystemTable) -> efi::Status {
let r = print_env_constants(st);
if let Err(x) = r {
return x;
}
efi::Status::SUCCESS
}
다음은 qemu에서 실행되는 프로그램입니다.
이것으로 우리는 UEFI에 대한 새로운
std
를 사용하고 있습니다.편집하다
__CxxFrameHandler3
공백 구현은 더 이상 master
분기에 필요하지 않습니다. 이전에는 v1.61.0 태그를 기반으로 변경했습니다. 하지만 지금부터는 직접 마스터 작업을 하려고 합니다.결론
기술적으로 우리는 현재
std
를 사용하고 있습니다(아직 구현되지는 않았지만). 이제 할당부터 시작하여 std
의 일부를 천천히 구현하기 시작합니다. 또한 기존의 Rustmain
함수 대신 일반 Rustefi_main
함수를 사용할 수 있는 방법을 찾고 싶었습니다. 그러나 이것은 여전히 가능해 보이지 않습니다(#29633 참조). 이제 할당 작업을 수행하고 이 코드에서 모든 배열을 벡터로 바꾸겠습니다.
Reference
이 문제에 관하여(UEFI에서 제한된 std 사용), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/ayush1325/use-restricted-std-in-uefi-2epg텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)