UEFI에서 제한된 std 사용

27979 단어 uefirusttianocore
여러분, 안녕하세요; 마지막으로post UEFI에 대한 Rust 지원을 추가하기 위한 개발 환경을 설정했습니다. 이 게시물에서는 x86_64 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_strpathunix 대신 windows 또는 unsupported 모듈을 가리킵니다. 이는 unsupported가 이에 대한 정의를 제공하지 않기 때문입니다. cmath 유닉스 모듈 API는 compiler-builtins에서 제공할 수 있으므로 작동해야 합니다. 그러나 os_strpath는 현재로서는 단순히 자리 표시자입니다.

환경 모듈 구현



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_stdsrc/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 참조). 이제 할당 작업을 수행하고 이 코드에서 모든 배열을 벡터로 바꾸겠습니다.

좋은 웹페이지 즐겨찾기