## 簡述
近年來 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];
```
:::