NatsuCamellia
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
      • Invitee
    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Versions and GitHub Sync Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
Invitee
Publish Note

Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

Your note will be visible on your profile and discoverable by anyone.
Your note is now live.
This note is visible on your profile and discoverable online.
Everyone on the web can find and read all notes of this public team.
See published notes
Unpublish note
Please check the box to agree to the Community Guidelines.
View profile
Engagement control
Commenting
Permission
Disabled Forbidden Owners Signed-in users Everyone
Enable
Permission
  • Forbidden
  • Owners
  • Signed-in users
  • Everyone
Suggest edit
Permission
Disabled Forbidden Owners Signed-in users Everyone
Enable
Permission
  • Forbidden
  • Owners
  • Signed-in users
Emoji Reply
Enable
Import from Dropbox Google Drive Gist Clipboard
   owned this note    owned this note      
Published Linked with GitHub
Subscribed
  • Any changes
    Be notified of any changes
  • Mention me
    Be notified of mention me
  • Unsubscribe
Subscribe
## 簡述 近年來 Rust 程式語言興起,憑藉其優秀的效能表現、記憶體安全以及開發者體驗在程式語言界取得一席之地。而在 Linux 核心中 Rust 也是近期的熱門話題,Linux 6.1 新增了 kernel crate,讓開發者可以用 Rust 開發核心,特別是驅動程式,在 Linux 6.15 有了第一個被加入 Linux 核心程式碼的 Rust 驅動程式。 另一方面,有部分研究在研究如何將 C 程式碼自動轉為 Rust 程式碼,最具規模的便是 [C2Rust](https://c2rust.com)。看到 C2Rust 我們不禁思考,以 C 語言寫成的 Linux 核心程式碼是否可以使用 C2Rust 轉為 Rust 程式碼?因此本篇研究嘗試使用 C2Rust 轉換部分 Linux 核心程式碼。 我們首先練習轉譯簡單的 hello world,接著嘗試 `lib/uuid.c`,最後嘗試轉換 [SeKVM](https://www.usenix.org/conference/usenixsecurity21/presentation/li-shih-wei) 。 結果發現核心程式碼中的 `<linux/kernel.h>` 中包含 C2Rust 無法轉譯的 C 語法,因此無法完成全自動轉換。 ## 環境設定 ### 參考資料 1. [Quick Start — The Linux Kernel documentation](https://docs.kernel.org/rust/quick-start.html) 2. [Rust version policy - Rust for Linux](https://rust-for-linux.com/rust-version-policy) ### 版本資訊 1. Linux 6.12 mainline 2. `rustc` & `cargo` 1.80.1(官方文件要求 1.78+) 3. `bindgen` 0.69.1 4. `clang` 18.1.3 ### 設定 Rust 工具鏈 在 `linux/` 目錄中 1. `rustup override set 1.80` 2. `rustup component add rust-src` 3. `cargo install --locked bindgen-cli --version 0.69.1` ### 啟用 Rust 支援 1. `make LLVM=1 defconfig` 2. `make LLVM=1 rustavailable`:確定成功再執行下一步 3. `scripts/config -e CONFIG_RUST` ### 編譯全部 為了方便之後測試,先完整編譯核心映像檔一次 `make LLVM=1 Image -j$(nproc)`。 ## 轉譯並執行 Hello World ### 第一步:插入 C 程式碼 因為 Linux 核心中的程式碼大多都較為複雜,沿襲資訊界傳統,我們從最簡單的 hello world 開始,在 Linux 開機時插入一個自訂訊息。 ```c= // lib/mytest.c #include <linux/kernel.h> #include <linux/init.h> void mytest_hello(void) { pr_info("Hello from mytest.c\n"); } ``` 修改 `lib/Makefile` 將我們的檔案插入核心中。 ```=38 buildid.o objpool.o union_find.o lib-y += mytest.o lib-$(CONFIG_PRINTK) += dump_stack.o ``` 最後到 `init/main.c` 中呼叫這個 hello world 函式。 ```c=1102 kcsan_init(); extern void mytest_hello(void); mytest_hello(); /* Do the rest non-__init'ed, we're now alive */ rest_init(); ``` 全部完成後我們先測試核心是否能夠如預期運作: 1. 編譯核心:`make LLVM=1 Image -j$(nproc)` 2. 啟動核心 3. 測試是否有印出訊息:`dmesg | grep mytest` ### 第二步:轉譯為 Rust 語言 我們首先取得 `mytest.c` 的編譯參數,讓 `c2rust` 知道如何轉換: ```sh rm lib/mytest.o intercept-build make LLVM=1 lib/mytest.o ``` 此時目錄下會產生 `compile_commands.json` 檔案,我們可以提供 `c2rust` 這個檔案來轉換程式碼: ```sh c2rust transpile compile_commands.json mv lib/mytest.rs lib/rmytest.rs ``` > [!Note] 為什麽要重新命名為 `rmytest.rs`? > 因為若我們在 Makefile 中加入 `mytest.o`,KBuild 會自動搜尋 `mytest.c` 或是 `mytest.rs` 編譯,如果我們同時擁有 `mytest.c` 與 `mytest.rs`,我們會不確定 Kbuild 選擇哪一個檔案編譯,所以這裡直接將檔案重新命名,對於 Rust 程式碼我們使用 `rmytest.o` 以和 `mytest.o` 做區隔。 接著是本專案的瓶頸,`c2rust` 會產生 `libc` 綁定而不是使用 `core::ffi`,因此需要修改 `lib/rmytest.rs`,將所有的 `libc` 替換為 `core::ffi`、註解掉 `compile_error!()` 巨集,以及為 `_printk()` 加上 unsafe 區塊。 ```rust #![allow( dead_code, mutable_transmutes, non_camel_case_types, non_snake_case, non_upper_case_globals, unused_assignments, unused_mut )] extern "C" { fn _printk(fmt: *const core::ffi::c_char, _: ...) -> core::ffi::c_int; } #[no_mangle] pub unsafe extern "C" fn mytest_hello() { ({ unsafe { _printk(b"\x016Hello from mytest.c\n\0" as *const u8 as *const core::ffi::c_char); } // compile_error!("Function call expression is not supposed to be used") }); } ``` 然後修改 `lib/Makefile`: ```=40 # lib-y += mytest.o lib-y += rmytest.o ``` 最後重新編譯核心即可。 ## 轉譯並執行 `lib/uuid.c` ### 第一步:轉換與編譯 我們首先取得 `lib/uuid.c` 的編譯參數,讓 `c2rust` 知道如何轉換: ```sh rm lib/uuid.o intercept-build make LLVM=1 lib/uuid.o ``` 此時目錄下會產生 `compile_commands.json` 檔案,我們可以提供 `c2rust` 這個檔案來轉換程式碼: ```sh c2rust transpile compile_commands.json mv lib/uuid.rs lib/ruuid.rs ``` 編輯 `lib/ruuid.rs` 檔案: 0. 可以選擇先使用 `rustfmt lib/ruuid.rs` 先格式化檔案 1. 將所有 `libc` 替換為 `core::ffi` 2. 為所有 unsafe 函式的本體套上 unsafe block 3. 註解掉與 `run_static_initializers` 相關的程式碼區塊,見下方轉換問題三 然後修改 `lib/Makefile`,把 `uuid.o` 替換為 `ruuid.o`。 最後重新編譯核心即可。 ### 第二步:測試 我們想要確定核心確實有使用轉換後的程式,因此在 `lib/ruuid.rs` 中加入: ```rust extern "C" { fn hex_to_bin(ch: core::ffi::c_uchar) -> core::ffi::c_int; static _ctype: [core::ffi::c_uchar; 0]; fn get_random_bytes(buf: *mut core::ffi::c_void, len: size_t); // 加入 _printk() fn _printk(fmt: *const core::ffi::c_char, _: ...) -> core::ffi::c_int; } ``` ```rust #[no_mangle] pub unsafe extern "C" fn uuid_gen(mut bu: *mut uuid_t) { unsafe { __uuid_gen_common(((*bu).b).as_mut_ptr()); (*bu) .b[6 as core::ffi::c_int as usize] = ((*bu).b[6 as core::ffi::c_int as usize] as core::ffi::c_int & 0xf as core::ffi::c_int | 0x40 as core::ffi::c_int) as __u8; // 加入 printk() _printk(b"\x016Generated Random UUID.\n\0" as *const u8 as *const core::ffi::c_char); } } ``` 重新編譯開機後,使用 `dmesg | grep Generated` 就會看到核心確實有使用這個程式。 ## 轉譯 SeKVM(沒有編譯進核心) [SeKVM](https://www.usenix.org/conference/usenixsecurity21/presentation/li-shih-wei) 採用模組化的寫法,我們期望它更容易被 C2Rust 轉譯,因此我們嘗試轉換這個核心模組。因為在 KrustVM 研究中將 SeKVM 移植到 Linux 5.15,且 KrustVM 是 SeKVM 的 Rust 語言實作,所以我們嘗試轉換 SeKVM 並與 KrustVM 比較。這裡使用的核心版本是 5.15,此時 KBuild 還不支援 Rust,所以本實驗沒有將其編譯進核心。 我們先從最簡單的程式碼開始轉換起,我選擇 SeKVM 中的 `BootAux.c`,詳細的實驗過程請見 [C2Rust on SeKVM:BootAux.c](/Q9tIBLzEQlyTstvpJWMKhw)。 > 從實驗的結果發現: > 1. C2Rust 產生的錯誤大部分來自於核心的標頭而不是 `hypsec.h` 中直接定義的內容,這表示 C2Rust 無法處理的程式碼大部分都存在於核心標頭中。 > 2. C2Rust 會先對 C 程式碼進行預處理,其中的 `#ifdef` 不會被保留在 Rust 程式碼中,從第三階段的結果可以看到 `BootAux.c` 中原本有兩種程式碼,但是轉換後只剩一種。 我們現在知道錯誤來自於核心標頭,因此進一步研究是哪部分的核心標頭讓 C2Rust 無法成功轉譯程式碼,詳細的實驗過程請見 [C2Rust 無法處理的核心標頭檔](/SDMcAZuSQSCo8gihRnnLug)。 > 實驗結果發現 GNU C 語法以及部分內嵌組合語言是 C2Rust 無法轉譯的程式碼,而此段程式碼存在於 `<linux/kernel.h>` 中,大量的核心程式碼都會直接或間接引用這個標頭檔,因此要自動轉譯 Linux 核心至 Rust 語言是困難的,更別說可能還有其他無法轉譯的程式碼。 `<linux/kernel.h>` 是核心中重要的標頭,我們猜測 RFL 與 KrustVM 都會使用到這個標頭,但是卻能夠順利運行,因此我們想要知道 RFL 與 KrustVM 是如何辦到的,詳細的實驗過程請見 [RFL 如何處理標頭問題](/CkM6Z66FQWWW3Lz7Ja7cVA)。 > 實驗發現 RFL 不需要處理這個問題,因為它直接透過 bindgen 使用 C 語言提供的功能。另外也探究了 SeKVM 的 Rust 版本 KrustVM 如何處理該問題,結果和 RFL 一樣,它直接呼叫 C 語言的 FFI 介面。因此 C2Rust 轉譯失敗的原因是它會嘗試轉譯直到最底層的所有程式,而 RFL 與 KrustVM 都將最底層交給 C 語言。 ## 注意事項 1. 使用 `intercept-build LLVM=1 make path/to/file.o` 時需要避免 Make 產生 nothing to do,否則 `compile_commands.json` 會輸出空白內容。解決方法是在執行前移除 `path/to/file.o`。 2. 使用 `c2rust transpile compile_commands.json` 時需要確保目標的 Rust 檔案不存在,否則 C2Rust 不會轉譯程式碼。 3. 產生 `compile_commands.json` 所使用的 Make 參數必須加上 `LLVM=1`,因為 `c2rust` 只接受 Clang 參數,不支援某些 GCC 參數。 ## 轉換問題 ### 1. C2Rust 無法將 libc 改為使用 core::ffi C2Rust 官方的文件過於老舊,其中沒有提到關於 `libc` 與 `core::ffi` 的設定,執行檔中附帶的說明也沒有這一方面的資訊。因為目前遇到的 `libc` 使用情境多為引用 C 語言的資料型態,所以目前的解法是手動將 `libc` 替換為 `core::ffi`。 ### 2. 轉換後的 unsafe 函式中會呼叫 unsafe 函式 這個問題會導致編譯失敗,因此需要手動在那些被呼叫的 unsafe 函式周圍包上 unsafe 區塊,當然一般而言需要更精細地處理,不過在這個情況我們只需要讓它運作即可。目前 C2Rust 文件也沒有這方面的資訊,因此當前的解法是為每個 unsafe 函式本體套上 unsafe 區塊。 ### 3. 連結 `.discard` 問題 `c2rust` 轉換 `lib/uuid.c` 時會產生如下程式碼: ```rust unsafe extern "C" fn run_static_initializers() { unsafe { __UNIQUE_ID___addressable_guid_null152 = &guid_null as *const guid_t as uintptr_t as *mut core::ffi::c_void; __UNIQUE_ID___addressable_uuid_null153 = &uuid_null as *const uuid_t as uintptr_t as *mut core::ffi::c_void; __UNIQUE_ID___addressable_generate_random_uuid154 = ::core::mem::transmute::< Option<unsafe extern "C" fn(*mut core::ffi::c_uchar) -> ()>, uintptr_t, >(Some( generate_random_uuid as unsafe extern "C" fn(*mut core::ffi::c_uchar) -> (), )) as *mut core::ffi::c_void; __UNIQUE_ID___addressable_generate_random_guid155 = ::core::mem::transmute::< Option<unsafe extern "C" fn(*mut core::ffi::c_uchar) -> ()>, uintptr_t, >(Some( generate_random_guid as unsafe extern "C" fn(*mut core::ffi::c_uchar) -> (), )) as *mut core::ffi::c_void; __UNIQUE_ID___addressable_guid_gen156 = ::core::mem::transmute::<Option<unsafe extern "C" fn(*mut guid_t) -> ()>, uintptr_t>( Some(guid_gen as unsafe extern "C" fn(*mut guid_t) -> ()), ) as *mut core::ffi::c_void; __UNIQUE_ID___addressable_uuid_gen157 = ::core::mem::transmute::<Option<unsafe extern "C" fn(*mut uuid_t) -> ()>, uintptr_t>( Some(uuid_gen as unsafe extern "C" fn(*mut uuid_t) -> ()), ) as *mut core::ffi::c_void; __UNIQUE_ID___addressable_uuid_is_valid158 = ::core::mem::transmute::< Option<unsafe extern "C" fn(*const core::ffi::c_char) -> bool_0>, uintptr_t, >(Some( uuid_is_valid as unsafe extern "C" fn(*const core::ffi::c_char) -> bool_0, )) as *mut core::ffi::c_void; __UNIQUE_ID___addressable_guid_parse159 = ::core::mem::transmute::< Option<unsafe extern "C" fn(*const core::ffi::c_char, *mut guid_t) -> core::ffi::c_int>, uintptr_t, >(Some( guid_parse as unsafe extern "C" fn(*const core::ffi::c_char, *mut guid_t) -> core::ffi::c_int, )) as *mut core::ffi::c_void; __UNIQUE_ID___addressable_uuid_parse160 = ::core::mem::transmute::< Option<unsafe extern "C" fn(*const core::ffi::c_char, *mut uuid_t) -> core::ffi::c_int>, uintptr_t, >(Some( uuid_parse as unsafe extern "C" fn(*const core::ffi::c_char, *mut uuid_t) -> core::ffi::c_int, )) as *mut core::ffi::c_void; } } #[used] #[cfg_attr(target_os = "linux", link_section = ".init_array")] #[cfg_attr(target_os = "windows", link_section = ".CRT$XIB")] #[cfg_attr(target_os = "macos", link_section = "__DATA,__mod_init_func")] static INIT_ARRAY: [unsafe extern "C" fn(); 1] = [run_static_initializers]; ``` 這些程式碼與 C 程式中的 `EXPORT_SYMBOL()` 有關,是為了讓 `kallsyms` 可以查詢函式記憶體位址等用途而存在,而最後的 `INIT_ARRAY` 會產生以下的連結錯誤: ``` ld.lld: error: relocation refers to a symbol in a discarded section: ruuid::__UNIQUE_ID___addressable_guid_null152 >>> defined in vmlinux.a(lib/ruuid.o) >>> referenced by ruuid.rs:273 (lib/ruuid.rs:273) >>> lib/ruuid.o:(ruuid::run_static_initializers) in archive vmlinux.a >>> referenced by ruuid.rs:273 (lib/ruuid.rs:273) >>> lib/ruuid.o:(ruuid::run_static_initializers) in archive vmlinux.a ... ``` 目前的解決方法是註解這些程式碼區塊,暫時不使用 `EXPORT_SYMBOL()` 功能。 ## 參考資料 - 其他轉譯器 - [NishanthSpShetty/crust: C/C++ to Rust transpiler](https://github.com/NishanthSpShetty/crust):功能不足(沒有函式指標),久未更新。 - [Rust — The Linux Kernel documentation](https://docs.kernel.org/rust/index.html):核心中 Rust 子模組文件。 - [Introduction - C2Rust Manual](https://c2rust.com/manual):C2Rust 手冊,過時沒什麼參考價值。 - [Transpiling A Kernel Module to Rust: The Good, the Bad and the Ugly :: Immunant, Inc](https://immunant.com/blog/2020/06/kernel_modules/):主要是轉換驅動程式而不是核心程式,不過也可以作為參考。 - [C2Rust Linux Kernel Module尝试【译】](https://retriever.hashnode.dev/c2rust-linux-kernel-module):上文翻譯版。 - 文獻論文 - [[2401.08264v1] Towards a Transpiler for C/C++ to Safer Rust](https://arxiv.org/abs/2401.08264v1):主要是轉譯 C++,沒有開源。 ## 補充資料 :::spoiler `lib/ruuid.rs` 完整程式碼 ```rust #![allow( dead_code, mutable_transmutes, non_camel_case_types, non_snake_case, non_upper_case_globals, unused_assignments, unused_mut )] extern "C" { fn hex_to_bin(ch: core::ffi::c_uchar) -> core::ffi::c_int; static _ctype: [core::ffi::c_uchar; 0]; fn get_random_bytes(buf: *mut core::ffi::c_void, len: size_t); fn _printk(fmt: *const core::ffi::c_char, _: ...) -> core::ffi::c_int; } pub type __u8 = core::ffi::c_uchar; pub type u8_0 = __u8; pub type C2RustUnnamed = core::ffi::c_uint; pub const true_0: C2RustUnnamed = 1; pub const false_0: C2RustUnnamed = 0; pub type __kernel_ulong_t = core::ffi::c_ulong; pub type __kernel_size_t = __kernel_ulong_t; pub type bool_0 = bool; pub type uintptr_t = core::ffi::c_ulong; pub type size_t = __kernel_size_t; #[derive(Copy, Clone)] #[repr(C)] pub struct guid_t { pub b: [__u8; 16], } #[derive(Copy, Clone)] #[repr(C)] pub struct uuid_t { pub b: [__u8; 16], } #[no_mangle] pub static mut guid_null: guid_t = guid_t { b: [0; 16] }; #[used] #[link_section = ".discard.addressable"] static mut __UNIQUE_ID___addressable_guid_null152: *mut core::ffi::c_void = 0 as *const core::ffi::c_void as *mut core::ffi::c_void; #[no_mangle] pub static mut uuid_null: uuid_t = uuid_t { b: [0; 16] }; #[used] #[link_section = ".discard.addressable"] static mut __UNIQUE_ID___addressable_uuid_null153: *mut core::ffi::c_void = 0 as *const core::ffi::c_void as *mut core::ffi::c_void; #[no_mangle] pub static mut guid_index: [u8_0; 16] = [ 3 as core::ffi::c_int as u8_0, 2 as core::ffi::c_int as u8_0, 1 as core::ffi::c_int as u8_0, 0 as core::ffi::c_int as u8_0, 5 as core::ffi::c_int as u8_0, 4 as core::ffi::c_int as u8_0, 7 as core::ffi::c_int as u8_0, 6 as core::ffi::c_int as u8_0, 8 as core::ffi::c_int as u8_0, 9 as core::ffi::c_int as u8_0, 10 as core::ffi::c_int as u8_0, 11 as core::ffi::c_int as u8_0, 12 as core::ffi::c_int as u8_0, 13 as core::ffi::c_int as u8_0, 14 as core::ffi::c_int as u8_0, 15 as core::ffi::c_int as u8_0, ]; #[no_mangle] pub static mut uuid_index: [u8_0; 16] = [ 0 as core::ffi::c_int as u8_0, 1 as core::ffi::c_int as u8_0, 2 as core::ffi::c_int as u8_0, 3 as core::ffi::c_int as u8_0, 4 as core::ffi::c_int as u8_0, 5 as core::ffi::c_int as u8_0, 6 as core::ffi::c_int as u8_0, 7 as core::ffi::c_int as u8_0, 8 as core::ffi::c_int as u8_0, 9 as core::ffi::c_int as u8_0, 10 as core::ffi::c_int as u8_0, 11 as core::ffi::c_int as u8_0, 12 as core::ffi::c_int as u8_0, 13 as core::ffi::c_int as u8_0, 14 as core::ffi::c_int as u8_0, 15 as core::ffi::c_int as u8_0, ]; #[no_mangle] pub unsafe extern "C" fn generate_random_uuid(mut uuid: *mut core::ffi::c_uchar) { unsafe { get_random_bytes( uuid as *mut core::ffi::c_void, 16 as core::ffi::c_int as size_t, ); *uuid.offset(6 as core::ffi::c_int as isize) = (*uuid.offset(6 as core::ffi::c_int as isize) as core::ffi::c_int & 0xf as core::ffi::c_int | 0x40 as core::ffi::c_int) as core::ffi::c_uchar; *uuid.offset(8 as core::ffi::c_int as isize) = (*uuid.offset(8 as core::ffi::c_int as isize) as core::ffi::c_int & 0x3f as core::ffi::c_int | 0x80 as core::ffi::c_int) as core::ffi::c_uchar; } } #[used] #[link_section = ".discard.addressable"] static mut __UNIQUE_ID___addressable_generate_random_uuid154: *mut core::ffi::c_void = 0 as *const core::ffi::c_void as *mut core::ffi::c_void; #[no_mangle] pub unsafe extern "C" fn generate_random_guid(mut guid: *mut core::ffi::c_uchar) { unsafe { get_random_bytes( guid as *mut core::ffi::c_void, 16 as core::ffi::c_int as size_t, ); *guid.offset(7 as core::ffi::c_int as isize) = (*guid.offset(7 as core::ffi::c_int as isize) as core::ffi::c_int & 0xf as core::ffi::c_int | 0x40 as core::ffi::c_int) as core::ffi::c_uchar; *guid.offset(8 as core::ffi::c_int as isize) = (*guid.offset(8 as core::ffi::c_int as isize) as core::ffi::c_int & 0x3f as core::ffi::c_int | 0x80 as core::ffi::c_int) as core::ffi::c_uchar; } } #[used] #[link_section = ".discard.addressable"] static mut __UNIQUE_ID___addressable_generate_random_guid155: *mut core::ffi::c_void = 0 as *const core::ffi::c_void as *mut core::ffi::c_void; unsafe extern "C" fn __uuid_gen_common(mut b: *mut __u8) { unsafe { get_random_bytes( b as *mut core::ffi::c_void, 16 as core::ffi::c_int as size_t, ); *b.offset(8 as core::ffi::c_int as isize) = (*b.offset(8 as core::ffi::c_int as isize) as core::ffi::c_int & 0x3f as core::ffi::c_int | 0x80 as core::ffi::c_int) as __u8; } } #[no_mangle] pub unsafe extern "C" fn guid_gen(mut lu: *mut guid_t) { unsafe { __uuid_gen_common(((*lu).b).as_mut_ptr()); (*lu).b[7 as core::ffi::c_int as usize] = ((*lu).b[7 as core::ffi::c_int as usize] as core::ffi::c_int & 0xf as core::ffi::c_int | 0x40 as core::ffi::c_int) as __u8; } } #[used] #[link_section = ".discard.addressable"] static mut __UNIQUE_ID___addressable_guid_gen156: *mut core::ffi::c_void = 0 as *const core::ffi::c_void as *mut core::ffi::c_void; #[no_mangle] pub unsafe extern "C" fn uuid_gen(mut bu: *mut uuid_t) { unsafe { __uuid_gen_common(((*bu).b).as_mut_ptr()); (*bu).b[6 as core::ffi::c_int as usize] = ((*bu).b[6 as core::ffi::c_int as usize] as core::ffi::c_int & 0xf as core::ffi::c_int | 0x40 as core::ffi::c_int) as __u8; _printk(b"\x016Generated Random UUID.\n\0" as *const u8 as *const core::ffi::c_char); } } #[used] #[link_section = ".discard.addressable"] static mut __UNIQUE_ID___addressable_uuid_gen157: *mut core::ffi::c_void = 0 as *const core::ffi::c_void as *mut core::ffi::c_void; #[no_mangle] pub unsafe extern "C" fn uuid_is_valid(mut uuid: *const core::ffi::c_char) -> bool_0 { unsafe { let mut i: core::ffi::c_uint = 0; i = 0 as core::ffi::c_int as core::ffi::c_uint; while i < 36 as core::ffi::c_int as core::ffi::c_uint { if i == 8 as core::ffi::c_int as core::ffi::c_uint || i == 13 as core::ffi::c_int as core::ffi::c_uint || i == 18 as core::ffi::c_int as core::ffi::c_uint || i == 23 as core::ffi::c_int as core::ffi::c_uint { if *uuid.offset(i as isize) as core::ffi::c_int != '-' as i32 { return false_0 as core::ffi::c_int != 0; } } else if !(*_ctype .as_ptr() .offset(*uuid.offset(i as isize) as core::ffi::c_uchar as core::ffi::c_int as isize) as core::ffi::c_int & (0x4 as core::ffi::c_int | 0x40 as core::ffi::c_int) != 0 as core::ffi::c_int) { return false_0 as core::ffi::c_int != 0; } i = i.wrapping_add(1); i; } return true_0 as core::ffi::c_int != 0; } } #[used] #[link_section = ".discard.addressable"] static mut __UNIQUE_ID___addressable_uuid_is_valid158: *mut core::ffi::c_void = 0 as *const core::ffi::c_void as *mut core::ffi::c_void; unsafe extern "C" fn __uuid_parse( mut uuid: *const core::ffi::c_char, mut b: *mut __u8, mut ei: *const u8_0, ) -> core::ffi::c_int { unsafe { static mut si: [u8_0; 16] = [ 0 as core::ffi::c_int as u8_0, 2 as core::ffi::c_int as u8_0, 4 as core::ffi::c_int as u8_0, 6 as core::ffi::c_int as u8_0, 9 as core::ffi::c_int as u8_0, 11 as core::ffi::c_int as u8_0, 14 as core::ffi::c_int as u8_0, 16 as core::ffi::c_int as u8_0, 19 as core::ffi::c_int as u8_0, 21 as core::ffi::c_int as u8_0, 24 as core::ffi::c_int as u8_0, 26 as core::ffi::c_int as u8_0, 28 as core::ffi::c_int as u8_0, 30 as core::ffi::c_int as u8_0, 32 as core::ffi::c_int as u8_0, 34 as core::ffi::c_int as u8_0, ]; let mut i: core::ffi::c_uint = 0; if !uuid_is_valid(uuid) { return -(22 as core::ffi::c_int); } i = 0 as core::ffi::c_int as core::ffi::c_uint; while i < 16 as core::ffi::c_int as core::ffi::c_uint { let mut hi: core::ffi::c_int = hex_to_bin( *uuid.offset((si[i as usize] as core::ffi::c_int + 0 as core::ffi::c_int) as isize) as core::ffi::c_uchar, ); let mut lo: core::ffi::c_int = hex_to_bin( *uuid.offset((si[i as usize] as core::ffi::c_int + 1 as core::ffi::c_int) as isize) as core::ffi::c_uchar, ); *b.offset(*ei.offset(i as isize) as isize) = (hi << 4 as core::ffi::c_int | lo) as __u8; i = i.wrapping_add(1); i; } return 0 as core::ffi::c_int; } } #[no_mangle] pub unsafe extern "C" fn guid_parse( mut uuid: *const core::ffi::c_char, mut u: *mut guid_t, ) -> core::ffi::c_int { unsafe { return __uuid_parse(uuid, ((*u).b).as_mut_ptr(), guid_index.as_ptr()); } } #[used] #[link_section = ".discard.addressable"] static mut __UNIQUE_ID___addressable_guid_parse159: *mut core::ffi::c_void = 0 as *const core::ffi::c_void as *mut core::ffi::c_void; #[no_mangle] pub unsafe extern "C" fn uuid_parse( mut uuid: *const core::ffi::c_char, mut u: *mut uuid_t, ) -> core::ffi::c_int { unsafe { return __uuid_parse(uuid, ((*u).b).as_mut_ptr(), uuid_index.as_ptr()); } } #[used] #[link_section = ".discard.addressable"] static mut __UNIQUE_ID___addressable_uuid_parse160: *mut core::ffi::c_void = 0 as *const core::ffi::c_void as *mut core::ffi::c_void; // unsafe extern "C" fn run_static_initializers() { // unsafe { // __UNIQUE_ID___addressable_guid_null152 = // &guid_null as *const guid_t as uintptr_t as *mut core::ffi::c_void; // __UNIQUE_ID___addressable_uuid_null153 = // &uuid_null as *const uuid_t as uintptr_t as *mut core::ffi::c_void; // __UNIQUE_ID___addressable_generate_random_uuid154 = ::core::mem::transmute::< // Option<unsafe extern "C" fn(*mut core::ffi::c_uchar) -> ()>, // uintptr_t, // >(Some( // generate_random_uuid as unsafe extern "C" fn(*mut core::ffi::c_uchar) -> (), // )) as *mut core::ffi::c_void; // __UNIQUE_ID___addressable_generate_random_guid155 = ::core::mem::transmute::< // Option<unsafe extern "C" fn(*mut core::ffi::c_uchar) -> ()>, // uintptr_t, // >(Some( // generate_random_guid as unsafe extern "C" fn(*mut core::ffi::c_uchar) -> (), // )) as *mut core::ffi::c_void; // __UNIQUE_ID___addressable_guid_gen156 = // ::core::mem::transmute::<Option<unsafe extern "C" fn(*mut guid_t) -> ()>, uintptr_t>( // Some(guid_gen as unsafe extern "C" fn(*mut guid_t) -> ()), // ) as *mut core::ffi::c_void; // __UNIQUE_ID___addressable_uuid_gen157 = // ::core::mem::transmute::<Option<unsafe extern "C" fn(*mut uuid_t) -> ()>, uintptr_t>( // Some(uuid_gen as unsafe extern "C" fn(*mut uuid_t) -> ()), // ) as *mut core::ffi::c_void; // __UNIQUE_ID___addressable_uuid_is_valid158 = ::core::mem::transmute::< // Option<unsafe extern "C" fn(*const core::ffi::c_char) -> bool_0>, // uintptr_t, // >(Some( // uuid_is_valid as unsafe extern "C" fn(*const core::ffi::c_char) -> bool_0, // )) as *mut core::ffi::c_void; // __UNIQUE_ID___addressable_guid_parse159 = ::core::mem::transmute::< // Option<unsafe extern "C" fn(*const core::ffi::c_char, *mut guid_t) -> core::ffi::c_int>, // uintptr_t, // >(Some( // guid_parse // as unsafe extern "C" fn(*const core::ffi::c_char, *mut guid_t) -> core::ffi::c_int, // )) as *mut core::ffi::c_void; // __UNIQUE_ID___addressable_uuid_parse160 = ::core::mem::transmute::< // Option<unsafe extern "C" fn(*const core::ffi::c_char, *mut uuid_t) -> core::ffi::c_int>, // uintptr_t, // >(Some( // uuid_parse // as unsafe extern "C" fn(*const core::ffi::c_char, *mut uuid_t) -> core::ffi::c_int, // )) as *mut core::ffi::c_void; // } // } // #[used] // #[cfg_attr(target_os = "linux", link_section = ".init_array")] // #[cfg_attr(target_os = "windows", link_section = ".CRT$XIB")] // #[cfg_attr(target_os = "macos", link_section = "__DATA,__mod_init_func")] // static INIT_ARRAY: [unsafe extern "C" fn(); 1] = [run_static_initializers]; ``` :::

Import from clipboard

Paste your markdown or webpage here...

Advanced permission required

Your current role can only read. Ask the system administrator to acquire write and comment permission.

This team is disabled

Sorry, this team is disabled. You can't edit this note.

This note is locked

Sorry, only owner can edit this note.

Reach the limit

Sorry, you've reached the max length this note can be.
Please reduce the content or divide it to more notes, thank you!

Import from Gist

Import from Snippet

or

Export to Snippet

Are you sure?

Do you really want to delete this note?
All users will lose their connection.

Create a note from template

Create a note from template

Oops...
This template has been removed or transferred.
Upgrade
All
  • All
  • Team
No template.

Create a template

Upgrade

Delete template

Do you really want to delete this template?
Turn this template into a regular note and keep its content, versions, and comments.

This page need refresh

You have an incompatible client version.
Refresh to update.
New version available!
See releases notes here
Refresh to enjoy new features.
Your user state has changed.
Refresh to load new user state.

Sign in

Forgot password

or

By clicking below, you agree to our terms of service.

Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
Wallet ( )
Connect another wallet

New to HackMD? Sign up

Help

  • English
  • 中文
  • Français
  • Deutsch
  • 日本語
  • Español
  • Català
  • Ελληνικά
  • Português
  • italiano
  • Türkçe
  • Русский
  • Nederlands
  • hrvatski jezik
  • język polski
  • Українська
  • हिन्दी
  • svenska
  • Esperanto
  • dansk

Documents

Help & Tutorial

How to use Book mode

Slide Example

API Docs

Edit in VSCode

Install browser extension

Contacts

Feedback

Discord

Send us email

Resources

Releases

Pricing

Blog

Policy

Terms

Privacy

Cheatsheet

Syntax Example Reference
# Header Header 基本排版
- Unordered List
  • Unordered List
1. Ordered List
  1. Ordered List
- [ ] Todo List
  • Todo List
> Blockquote
Blockquote
**Bold font** Bold font
*Italics font* Italics font
~~Strikethrough~~ Strikethrough
19^th^ 19th
H~2~O H2O
++Inserted text++ Inserted text
==Marked text== Marked text
[link text](https:// "title") Link
![image alt](https:// "title") Image
`Code` Code 在筆記中貼入程式碼
```javascript
var i = 0;
```
var i = 0;
:smile: :smile: Emoji list
{%youtube youtube_id %} Externals
$L^aT_eX$ LaTeX
:::info
This is a alert area.
:::

This is a alert area.

Versions and GitHub Sync
Get Full History Access

  • Edit version name
  • Delete

revision author avatar     named on  

More Less

Note content is identical to the latest version.
Compare
    Choose a version
    No search result
    Version not found
Sign in to link this note to GitHub
Learn more
This note is not linked with GitHub
 

Feedback

Submission failed, please try again

Thanks for your support.

On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

Please give us some advice and help us improve HackMD.

 

Thanks for your feedback

Remove version name

Do you want to remove this version name and description?

Transfer ownership

Transfer to
    Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

      Link with GitHub

      Please authorize HackMD on GitHub
      • Please sign in to GitHub and install the HackMD app on your GitHub repo.
      • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
      Learn more  Sign in to GitHub

      Push the note to GitHub Push to GitHub Pull a file from GitHub

        Authorize again
       

      Choose which file to push to

      Select repo
      Refresh Authorize more repos
      Select branch
      Select file
      Select branch
      Choose version(s) to push
      • Save a new version and push
      • Choose from existing versions
      Include title and tags
      Available push count

      Pull from GitHub

       
      File from GitHub
      File from HackMD

      GitHub Link Settings

      File linked

      Linked by
      File path
      Last synced branch
      Available push count

      Danger Zone

      Unlink
      You will no longer receive notification when GitHub file changes after unlink.

      Syncing

      Push failed

      Push successfully