Skip to main content

tg_linker/
app.rs

1/// 应用程序元数据。
2#[repr(C)]
3pub struct AppMeta {
4    base: u64,
5    step: u64,
6    count: u64,
7    first: u64,
8}
9
10impl AppMeta {
11    /// 定位应用程序元数据。
12    ///
13    /// 返回由链接脚本定义的应用程序元数据的静态引用。
14    #[inline]
15    pub fn locate() -> &'static Self {
16        extern "C" {
17            static apps: AppMeta;
18        }
19        // SAFETY: `apps` 是由链接脚本定义的静态符号,在程序运行期间始终有效。
20        // 它的内存布局与 AppMeta 结构体匹配(由 #[repr(C)] 保证)。
21        unsafe { &apps }
22    }
23
24    /// 遍历链接进来的应用程序。
25    #[inline]
26    pub fn iter(&'static self) -> AppIterator {
27        AppIterator { meta: self, i: 0 }
28    }
29}
30
31/// 应用程序迭代器。
32pub struct AppIterator {
33    meta: &'static AppMeta,
34    i: u64,
35}
36
37impl Iterator for AppIterator {
38    type Item = &'static [u8];
39
40    fn next(&mut self) -> Option<Self::Item> {
41        if self.i >= self.meta.count {
42            None
43        } else {
44            let i = self.i as usize;
45            self.i += 1;
46            // SAFETY: 以下操作基于链接脚本定义的应用程序布局:
47            // - `first` 之后紧跟着 count+1 个 usize,存储每个应用的位置和结尾
48            // - 如果 base != 0,则将应用拷贝到指定的基地址
49            // - 应用数据由链接器嵌入,在程序运行期间始终有效
50            unsafe {
51                let slice = core::slice::from_raw_parts(
52                    &self.meta.first as *const _ as *const usize,
53                    (self.meta.count + 1) as _,
54                );
55                let pos = slice[i];
56                let size = slice[i + 1] - pos;
57                let base = self.meta.base as usize + i * self.meta.step as usize;
58                if base != 0 {
59                    // SAFETY: pos 指向有效的应用数据,base 是调用者指定的目标地址,
60                    // 调用者负责确保 base 处有足够的内存空间
61                    core::ptr::copy_nonoverlapping::<u8>(pos as _, base as _, size);
62                    // 将目标区域剩余部分清零
63                    core::slice::from_raw_parts_mut(base as *mut u8, 0x20_0000)[size..].fill(0);
64                    Some(core::slice::from_raw_parts(base as _, size))
65                } else {
66                    Some(core::slice::from_raw_parts(pos as _, size))
67                }
68            }
69        }
70    }
71}