• 例说linux内核与应用数据通信(一):加入一个系统调用


    【版权声明:尊重原创。转载请保留出处:blog.csdn.net/shallnet,文章仅供学习交流,请勿用于商业用途】
            应用不能訪问内核的内存空间。为了应用和内核交互信息,内核提供一组接口,通过这组接口。应用能够发送请求,内核能够响应处理该请求,这组接口就是系统调用。
    关于内核系统调用的实现查看本博客中这篇文章:
    http://blog.csdn.net/shallnet/article/details/47113753
    本文章以x86-32为例:
    $ uname -a
    Linux localhost 2.6.32 #1 SMP Sat Jun 13 23:55:06 CST 2015 i686 i686 i386 GNU/Linux
    第一步,在系统调用表中加入一个表项。表中为每个有效的系统调用指定了惟一的系统调用号。系统调用表位于arch/x86/kernel/syscall_table_32.S文件里,在该文件里最后一行加入自己的系统调用表项。例如以下:
            ......
            .long sys_preadv
            .long sys_pwritev
            .long sys_rt_tgsigqueueinfo     /* 335 */
            .long sys_perf_event_open
            .long sys_shallnet
    尽管没有明白指定编号,但该系统调用已经按次序分配了337这个系统调用号,接下来就应该加入系统调用号。
    第二步,加入系统调用号。在Linux中,每一个系统调用被赋予一个系统调用号。

    这样。通过这个独一无二的号就能够关联系统调用。当用户空间的进程运行一个系统调用的时候,这个系统调用号就被用来指明究竟是要运行哪个系统调用。在文件arch/sh/include/asm/unistd_32.h该列表中加入一行#define __NR_shallnet   337

    ......
    #define __NR_inotify_init1 332
    #define __NR_preadv 333
    #define __NR_pwritev 334
    #define __NR_rt_tgsigqueueinfo 335
    #define __NR_perf_event_open 336
    
    #define __NR_shallnet   337
    
    //#define NR_syscalls 337
    #define NR_syscalls 338
    ......
    
    
    在内核源文件里该行为#define NR_syscalls 337,在系统调用运行的过程中。system_call()函数会依据该值来对用户态进程的有效性进行检查。假设这个号大于或等于NR_syscalls,系统调用处理程序终止。所以应该将原来的#define NR_syscalls 337改动为#define NR_syscalls 338。

    第三步,实现shallnet系统调用。在文件kernel/sys.c最后加入例如以下函数:
    SYSCALL_DEFINE0(shallnet)SYSCALL_DEFINE1(shallnet, int, arg)
    {
            printk(KERN_ALERT"My blog address: "http://blog.csdn.net/shallnet"");
            return arg + arg;
    }
    第四步,又一次编译内核。依次运行:
    make oldconfig
    make bzImage
    make modules
    make modules_install
    make install
    第五步,又一次启动系统然后进入刚新编译的系统,编写測试代码例如以下:
    #include <stdio.h>
    #include <unistd.h>
    #include <sys/syscall.h>
    
    #define __NR_shallnet 337
    
    int main(int argc, const char *argv[])
    {
        int     ret;
    
        ret = syscall(337, 99);
    
        printf("shallnet() return: %d
    ", ret);
        return 0;
    }
    编译运行该程序例如以下:
    $ ./target_bin
    shallnet() return: 198
    
    $ demsg
    ......
    My blog address: "http://blog.csdn.net/shallnet"
    能够看到我们新加的系统调用运行成功了。

    可见建立一个新的系统调用还是非常easy的,可是不提倡这么做,系统调用须要一个系统调用号,须要改动内核代码,改动之后须要又一次编译内核。

    linux系统应当尽量避免每出现一个新的抽象就增加一个新的系统调用,通常有其它的方法能够取代系统调用,比方说实现一个设备节点等。



  • 相关阅读:
    JAVA不可变类(immutable)机制与String的不可变性
    如何高效学习
    [细品java]ThreadLocal源码学习
    Spring 入门知识点笔记整理
    spring远程服务知识梳理
    Spring Security 入门详解
    Selenium 安装 geckdriver Firefox 对应关系 历史版本下载
    Redhat linux 下 Jmeter 非GUI界面执行压力测试
    Spring Boot 进程守护 修改启动端口号 Spring Boot 监听端口被占用无法启动
    Redhat Linux 部署maven环境
  • 原文地址:https://www.cnblogs.com/liguangsunls/p/7067367.html
Copyright © 2020-2023  润新知