如何为单体式OS内核与用户应用配置不同global_allocator
问题根源
用户态应用的全局分配器静态变量ALLOCATOR被链接到了内核的地址空间范围内,当用户态代码尝试访问该地址时,因用户态无内核空间访问权限触发页错误。本质是用户态应用的编译/链接配置未与内核完全隔离,导致符号地址重叠。
解决方案
1. 为用户态创建独立的目标配置文件
在项目根目录或user目录下创建用户态专属目标文件(如x86_64-myos-user.json),明确用户态内存布局,与内核地址空间完全隔离:
{ "llvm-target": "x86_64-unknown-none", "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128", "arch": "x86_64", "target-endian": "little", "target-pointer-width": "64", "target-c-int-width": "32", "os": "none", "executables": true, "linker-flavor": "ld.lld", "linker": "rust-lld", "panic-strategy": "abort", "disable-redzone": true, "features": "-mmx,-sse,+soft-float" }
2. 修改用户态链接脚本(user/arch/link.ld)
确保所有段(.text/.data/.bss等)映射到用户态合法地址,避开内核的<32MiB空间:
ENTRY(start) MEMORY { USER (rxw) : ORIGIN = 0x02000000, LENGTH = 96M // 从32MB起始,完全避开内核空间 } SECTIONS { .text : { *(.text.entry) *(.text .text.*) } > USER .rodata : { *(.rodata .rodata.*) } > USER .data : { *(.data .data.*) } > USER .bss : { *(.bss .bss.*) *(COMMON) } > USER }
3. 配置用户态Cargo环境
在user目录下创建.cargo/config.toml,指定专属目标与链接脚本:
[build] target = "x86_64-myos-user.json" [target.x86_64-myos-user] rustflags = [ "-C", "link-arg=-Tarch/link.ld", "-C", "relocation-model=static", "-C", "code-model=small", ]
4. 修正用户态分配器实现
确保分配器适配用户态环境:内核的LockedHeap可能依赖内核态同步原语,用户态需替换为用户态安全的实现(单线程可直接去掉锁):
#![no_std] #![no_main] use alloc::alloc::GlobalAlloc; use linked_list_allocator::Heap; struct UserHeap(Heap); unsafe impl GlobalAlloc for UserHeap { unsafe fn alloc(&self, layout: core::alloc::Layout) -> *mut u8 { self.0.allocate(layout).unwrap_or(core::ptr::null_mut()) } unsafe fn dealloc(&self, ptr: *mut u8, layout: core::alloc::Layout) { self.0.deallocate(ptr, layout) } } #[global_allocator] static ALLOCATOR: UserHeap = UserHeap(Heap::empty()); #[no_mangle] pub extern "C" fn start() -> ! { let mem_size = 3 * Page::SIZE; let mem = syscall::mmap(mem_size); // 确保返回用户态合法地址 unsafe { ALLOCATOR.0.init(mem, mem_size); } let v = vec![1, 2, 3]; loop {} }
5. 独立编译用户态应用
在工作区Cargo.toml中声明用户应用成员:
[workspace] members = [ ".", "user/bin/app1", "user/bin/app2", ]
进入user目录执行cargo build --target x86_64-myos-user,将生成的可执行文件用objcopy处理为扁平二进制后放入initrd。
验证步骤
用nm工具查看用户应用符号表,确认ALLOCATOR地址处于用户态指定的内存区间(如32MB以上),而非内核的<32MiB空间。
内容的提问来源于stack exchange,提问作者ebeneEinHalb
相关产品推荐
相关产品推荐

