Linux下实现一个系统调用

环境:

环境: cenos7

kernel: 3.10.0-862.el7.x86_64

gcc: gcc version 4.8.5 20150623 (Red Hat 4.8.5-36) (GCC)

新版内核: linux-5.2-rc2

 

准备:

  • 安装相关软件:
yum install make automake vim perl openssl* elfutils-libelf- curl gcc wget flex git build-essential ncurses-devel xz-utils libssl-dev bc flex libelf-dev bison elfutils-libelf-devel -y
 
  • 下载内核源码并解压:

tar -xf linux-5.2-rc2.tar.gz

 

编写系统调用:

 

  •   新增系统调用表条目:

 cp syscall_64.tbl syscall_64.tbl.backup

 linux-5.2-rc2/arch/x86/entry/syscalls/syscall_64.tbl 新增下面一条

 +  434        common     iadd_test        __x64_sys_iadd_test
 
其中434为新增的调用号
 
  • 增加函数声明

 
 linux-5.2-rc2/include/linux/syscalls.h:新增一行
 asmlinkage long sys_iadd_test(int one, int two);
 
  • 新增系统调用定义

kernel/linux-5.2-rc2/fs/iadd_test.c
#include <linux/printk.h>
#include <linux/syscalls.h>
#include "internal.h"

long do_iadd(const int one, const int two )
{
long sum = 0L;
sum = one + two;
return sum;
}

SYSCALL_DEFINE2(iadd_test, const int, one, const int, two)
{
printk("call iaddtest...");
return do_iadd(one, two);
}
  • 修改Makfile

增加iadd_test.o

 9 obj-y :=        open.o read_write.o file_table.o super.o \
10                 char_dev.o stat.o exec.o pipe.o namei.o fcntl.o \
11                 ioctl.o readdir.o select.o dcache.o inode.o \
12                 attr.o bad_inode.o file.o filesystems.o namespace.o \
13                 seq_file.o xattr.o libfs.o fs-writeback.o \
14                 pnode.o splice.o sync.o utimes.o d_path.o \
15                 stack.o fs_struct.o statfs.o fs_pin.o nsfs.o \
16                 fs_types.o fs_context.o fs_parser.o fsopen.o iadd_test.o
17

编译内核:

  • 更新相关头文件

        /linux-5.2-rc2/arch/x86/include/generated/uapi/asm

 
cd /usr/include/asm
cp unistd_64.h  unistd_64.h.backup
cd linux-5.2-rc2/arch/x86/include/generated/uapi/asm 
cp /unistd_64.h /usr/include/asm/unistd_64.h
# 进入linux-5.2-rc2,将当前内核配置信息拷贝过来
cp /boot/config-3.10.0-862.el7.x86_64 .config
# 配置内核,这里没有修改
make menuconfig    
# 清除暂存文档,编译核心,模组
make -j 4 clean bzImage modules
# 安装模组
make modules_install
# 安装核心
make install
# 生成开机菜单
grub2-mkconfig -o /boot/grub2/grub.cfg
# 重启验证
reboot
# 查看内核版本是否更新
uname -r
 

 验证:

  编写测试程序验证

      1 #define _GNU_SOURCE
      2 #include <stdio.h>
      3 #include <linux/kernel.h>
      4 #include <sys/syscall.h>
      5 #include <unistd.h>
      6
      7 long iadd_test(const int one, const int two)
      8 {
      9         return  syscall(__NR_iadd_test, one, two);
     10 }
     11 int main()
     12 {
     13
     14         printf("sum = %ld\n", iadd_test(1,1));
     15         printf("sum = %ld\n", iadd_test(100,100));
     16         printf("sum = %ld\n", iadd_test(1000,1000));
     17         return 0;
     18 }


[root@centosgpt syscall]# gcc test.c -o test [root@centosgpt syscall]# ./test sum = 2 sum = 200 sum = 2000

 

问题:

  1. 内核编译很慢, 可以根据实际情况调整 make -j 4 clean bzImage modules,支持多个核心同时编译。
  2. 验证程序开始编写时, 直接使用iadd_test函数名, 这里编写的是系统调用, 不像用户态编写的库可以方便引用,需要通过glibc syscall 进行系统调用。 
 
极客时间 刘超《趣谈Linux操作系统》的课堂作业, 练习后整理了相关知识点。

另外,编译一次内核时间太长了。:(

 

参考:

How to Compile & Install Linux Kernel 5.0 on CentOS7/RHEL7

鸟哥私房菜 第24章

Linux系统添加系统调用

centos 7 增加系统调用

Adding a Hello World System Call to Linux Kernel

 

Be First to Comment

发表回复