内核编程三:Library and system call APIs

在Linux内核开发中,**库(Library)系统调用API(System Call API)**是两个重要的概念,它们共同构成了用户空间和内核空间之间的交互机制。


1. Library(库)

库是**用户空间(user space)**提供的一组函数封装,通常由标准C库(glibc)或其他库(如musl、uClibc)提供,主要用于简化系统调用的使用。例如:

  • printf → 最终调用 write 系统调用
  • malloc → 依赖 brkmmap 系统调用
  • fopen → 封装 open 系统调用

特点

  • 封装复杂性:库函数一般会对系统调用进行封装,使其更易于使用。
  • 性能优化:一些库函数会进行缓存、批量操作等优化,减少系统调用的开销。
  • 可移植性:库函数可以在不同操作系统上提供相同接口,而底层的系统调用可能不同。

示例

1. printf 调用的过程
#include <stdio.h>

int main() {
    printf("Hello, world!\n");
    return 0;
}

调用链

  1. printf("Hello, world!\n")
  2. fprintf(stdout, "Hello, world!\n")
  3. write(1, "Hello, world!\n", 14) ⬅ 实际调用 write 系统调用

2. System Call API(系统调用)

系统调用是用户态进程和内核通信的唯一合法方式,它提供了访问硬件和内核资源的接口。系统调用是通过 int 0x80(x86 32位)、syscall 指令(x86_64)、svc(ARM)等方式切换到内核态。

常见系统调用

类别示例系统调用
进程管理forkexecveexit
文件系统openreadwriteclose
内存管理mmapbrk
设备管理ioctlreadwrite
进程通信pipeshmgetmmap
网络通信socketbindlistenaccept

示例

1. 使用 write 系统调用
#include <unistd.h>

int main() {
    write(1, "Hello, world!\n", 14);
    return 0;
}
  • write(int fd, const void *buf, size_t count) 是一个系统调用,fd=1 代表 stdout

用户态 -> 内核态 调用路径

  1. write 用户态封装(glibc)
  2. syscall(SYS_write, 1, "Hello, world!\n", 14);
  3. 内核中的 sys_write() 处理
  4. 调用 vfs_write()
  5. 调用 file->f_op->write()(具体的文件系统实现)
  6. 数据最终写入设备(比如标准输出)

3. Library vs System Call API 的关系

对比点Library(库)System Call API(系统调用)
作用提供封装、优化提供用户态访问内核资源的接口
执行位置用户态内核态
性能可能包含缓存优化直接进入内核,开销较高
可移植性跨平台封装依赖内核实现

示例:malloc vs brk

  • malloc()glibc 提供的库函数,它内部可能使用:
    • brk()(调整堆内存)
    • mmap()(大块内存分配)
  • brk()mmap() 是真正的系统调用,它们直接操作内存分配
#include <stdlib.h>

int main() {
    void *ptr = malloc(1024);  // 实际上可能调用 brk() 或 mmap()
    free(ptr);
    return 0;
}

4. 内核开发中的系统调用

在内核开发中,我们可以扩展系统调用,比如添加一个新的 sys_hello 系统调用。

示例:添加 sys_hello 系统调用

  1. 修改内核源码(sys_hello.c)
    1. #include <linux/kernel.h>
      #include <linux/syscalls.h>
      
      SYSCALL_DEFINE0(hello) {
          printk(KERN_INFO "Hello from kernel!\n");
          return 0;
      }
      
  2. 注册系统调用
    1. arch/x86/entry/syscalls/syscall_64.tbl 添加:
      1. 548     common   sys_hello
        
    2. 在 include/linux/syscalls.h 声明:
      1. asmlinkage long sys_hello(void);
        
  3. 用户态调用
    1. #include <unistd.h>
      #include <sys/syscall.h>
      
      #define SYS_hello 548
      
      int main() {
          syscall(SYS_hello);
          return 0;
      }
      

5. 结论

  • 库函数(Library) 是用户空间的封装,简化系统调用的使用。
  • 系统调用(System Call API) 是内核提供的接口,是用户态访问硬件的唯一方式。
  • 库函数和系统调用的关系:库函数可以调用多个系统调用,提高性能和可用性,但最终还是依赖内核的系统调用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值