自制 x86-64 内核(46):mmap 文件映射

上一章实现了 TCP 服务端,这章来实现一个经典的内存管理功能:mmap 文件映射。 什么是 mmap 文件映射 mmap 把文件的一段内容映射到进程的虚拟地址空间。映射后可以像读内存一样读文件——不需要 read() 系统调用,直接解引用指针。 int fd = open("/bin/busybox", O_RDONLY); char *p = mmap(NULL, 4096, PROT_READ, MAP_PRIVATE, fd, 0); // p[0..3] 就是文件的前 4 字节(ELF magic: 7f 45 4c 46) 关键设计:VMA 和 Lazy 分配 mmap 不会立刻分配物理内存,而是登记一个 VMA(虚拟内存区域),等到进程真正访问这段地址时,才通过缺页异常按需读取文件内容并建立页表映射。 mmap(fd) → 注册 VMA(vaddr, len, inum, offset) → 返回虚拟地址 ↓ 进程访问该地址 #PF not-present → 找到 VMA → 分配物理页 → ext2_read(inum, offset, page) → 建立页表 → 重试指令 这就是操作系统课上说的"按需分页"(demand paging)。 实现步骤 1. 定义 VMA 结构 在 process_t 中加入 VMA 数组: ...

June 3, 2026 · 2 min · 大飞

从零写OS(三十):对齐 Linux syscall ABI,让 musl libc 能跑起来

musl libc 编译出来的程序会直接用 syscall 指令,传的是 Linux x86-64 标准调用号。我们之前的调用号是自己编的,如果不对齐,musl 程序一个 syscall 都跑不通。这一章把内核的 syscall 接口全面对齐 Linux ABI。 Linux x86-64 syscall 约定 Linux 的 x86-64 syscall 约定: 调用:rax=syscall号,rdi=a1,rsi=a2,rdx=a3,r10=a4,r8=a5,r9=a6 返回:rax(负数表示错误,如 -ENOENT = -2) CPU 自动保存:rcx=用户 rip,r11=用户 rflags 注意第 4 个参数是 r10,不是 rcx。原因是 syscall 指令会把用户 rip 存进 rcx,所以 r10 顶替了 rcx 的位置。这一点非常容易踩坑。 关键改动 1. syscall 号全部换成 Linux 标准 之前的调用号是自己定义的,现在全部换成 Linux 标准值: 功能 之前 现在 read 6 0 write 1 1 ✓ open 5 2 close 7 3 fork 3 57 exit 2 60 kill 12 62 write 碰巧没变,其他大部分都不一样。 ...

May 22, 2026 · 3 min · 大飞
京ICP备14031575号-3