linux内核编程入门篇_linux内核编程入门

linux内核编程入门篇_linux内核编程入门Linux内核编程实战经验谈李艳彬01-7-27上午10:45:17当前,在国产自主版权的操作系统这面大旗

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE稳定放心使用

Linux内核编程实战经验谈

李艳彬

01-7-27 上午 10:45:17


当前,在国产自主版权的操作系统这面大旗的倡导下,IT界掀起了一浪高过一浪的Linux编程热潮。Linux以其源码开放、配置灵活等不可多得的优越性吸引着越来越多的编程爱好者深入Linux的内核开发。笔者近来实践过一个Linux的实时化改造课题任务,积累了一点Linux内核编程的实战经验,在这里想就编译内核、增加系统调用等方面的问题和感兴趣的爱好者共做切磋。
编译内核
在Linux编程的实践中,经常会遇到编译内核的问题。为什么要编译内核呢?其一,可以定制内核模块。Linux引入了“动态载入模块”的概念,使用户可以把驱动程序以及非必要的内核功能代码编译成“模块”,由系统在需要时动态载入,不需要时自动卸载,从而提高了系统的效率和灵活性。其二,可以定制系统功能。当添加某种设备时、增加系统功能时、系统暴露出缺陷需要打“补丁”时,当新版内核出现准备用来升级时,编译内核是不可避免的。而且,编译内核正是Linux独有的“系统级DIY”的魅力所在!
好,现在就让我们一起开始——编译内核!
(1)安装源码
首先要确定自己Linux系统是否已安装了内核源码:
# rpm -q kernel-source
kernel_source-2.2.5-16
如果证实没有安装,则需要找来安装盘或从网上下载kernel-source-2.2.5-15.i386.rpm并安装:
# rpm -Uhv kernel-source-2.2.5-15.i386.rpm
如果是升级到新版本,则需要找来升级包(linux-2.2.16.tar.gz),自己解压安装:
# cd /usr/src
进入源码目录。
# rm -rf linux
删除以前的链接。
# tar xzvf linux-2.2.16.tar.gz
解压升级包。
# ln -s linux-2.2.16 linux
重建目录链接。
(2)配置内核
进入内核源码所在目录:
# cd /usr/src/linux
先清除多余的(一般是以前编译生成的)文件:
# make mrproper
开始配置内核(如果对各选项不是很熟悉的话,建议按回车键):
# make config
(3)编译内核
清除以前生成的目标文件及其他文件:
# make clean
理顺各文件之间的依存关系:
# make dep
编译压缩的内核:
# make bzImage
编译模块:
# make modules-install
(4)装新内核
将新内核文件复制到用于存放启动文件的 /boot目录:
# cp /usr/src/linux/System.map /boot/System.new
# cp /usr/src/linux/arch/i386/boot/bzImage /boot/vmlinuz.new
进入启动目录:
# cd /boot
给新内核建立链接:
# rm System.map
# ln -s System.new System.map
# rm vmlinuz
# ln -s vmlinuz.new vmlinuz
编辑LILO的配置文件/etc/lilo.conf ,使LILO能启动新内核:
# vi /etc/lilo.conf
在文件末加入以下部分:(后两行内容要与旧内核相应行保持一致)
image=/boot/vmlinuz.new
lable=new
root=/dev/hda3
read-only
重写LILO的启动扇区,使改动生效:
# lilo
(5)重启系统
# reboot
当重启后出现 lilo: 提示时输入新内核的标号(按TAB键可显示所有的标号):
lilo: new
OK!!boot new……
…..
一切运行正常,新内核引导成功!
以上步骤在pentium Ⅲ/64M/20G、Red Hat Linux 6.0(2.2.5-15)机上测试通过。
增加系统调用
在实际编程中,尤其是当我们需要增加或完善系统功能的时候,我们经常会用到系统调用函数。系统调用函数通常由用户进程在用户态下调用,内核通过system_call 函数响应系统调用产生的软中断,在正确访问核心栈、系统调用开关表之后陷入到操作系统内核中进行处理。
系统调用是用户进程由用户态切换到核心态的一种常见方式。利用编写系统调用函数来直接调用了部分操作系统内核代码,也是Linux内核编程者必修之功。下面笔者以在Linux中创建一个名为print_info的系统调用函数为例,来说明如何为内核增加系统调用。
需要以下几个基本步骤:
1、编写系统调用函数
编辑sys.c文件:
# cd /usr/src/linux/kernel
# vi sys.c
在文件的最后增加一个系统调用函数:
asmlinkage int sys_print_info(int testflag)
{
printk(” Its my syscall function!n”);
return 0;
}
该函数有一个int型入口参数testflag,并返回整数0。
2、修改与系统调用号相关的文件
编辑入口表文件:
# cd /usr/src/linux/arch/i386/kernel
# vi entry.S
把函数的入口地址加到sys_call_table表中:
arch/i386/kernel/entry.S中的最后几行源代码修改前为:
……
.long SYMBOL_NAME(sys_sendfile)
.long SYMBOL_NAME(sys_ni_syscall) /* streams1 */
.long SYMBOL_NAME(sys_ni_syscall) /* streams2 */
.long SYMBOL_NAME(sys_vfork) /* 190 */
rept NR_syscalls-190
.long SYMBOL_NAME(sys_ni_syscall)
.endr
修改后为:
……
.long SYMBOL_NAME(sys_sendfile)
.long SYMBOL_NAME(sys_ni_syscall) /* streams1 */
.long SYMBOL_NAME(sys_ni_syscall) /* streams2 */
.long SYMBOL_NAME(sys_vfork) /* 190 */
.long SYMBOL_NAME(sys_print_info) /* added by I */
.rept NR_syscalls-191
.endr
修改相应的头文件:
# cd /usr/src/linux/include/asm
# vi unistd.h
把增加的sys_call_table表项所对应的向量,在include/asm/unistd.h中进行必要申明,以供用户进程和其他系统进程查询或调用。
#define __NR_putpmsg 189
#define __NR_vfork 190
#define __NR_print_info 191 /* added by I */
3、编译内核,再重启动
4、测试
编写用户测试程序(test.c):
# vi test.c
#include
#include
extern int errno;
_syscall1(int,print_info,int,testflag)
main()
{
int i;
i= print_info(0);
if(i==0)
printf(“i=%d , syscall success!n”,i);
}
如果要在用户程序中使用系统调用函数,那么在主函数main前必须申明调用_syscall,其中1 表示该系统调用只有一个入口参数,第一个int 表示系统调用的返回值为整型,print_info为系统调用函数名,第二个int 表示入口参数的类型为整型,testflag为入口参数名。
编译测试程序:
# gcc -o test test.c
执行测试程序:
# ./test
Its my syscall function!
i=0, syscall success!
ok!!!增加系统调用函数成功!
以上步骤在pentium Ⅲ/64M/20G、Red Hat Linux 6.0(2.2.5-15)机上测试通过。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/184684.html原文链接:https://javaforall.net

(0)
上一篇 2022年10月8日 上午8:00
下一篇 2022年10月8日 上午8:16


相关推荐

  • Java数组初始化数值

    Java数组初始化数值初始化变量 publicstatic String args int numbers newint 8 实际上 上面的代码的目的就是做了一个数组的初始化 这个初始化的作用就是开辟了该长度的存储空间 这个概念我们经常会混淆 这里还是希望大家有个印象 数组初始化完后 并没有存储实际的值 int 类型的数据默认值是 0 所以如果没有完成数组的赋值 那么 int 数组的每一个值都是 0 String 类型的数据默认值是 null 所以没有赋值 那么 Stri

    2025年11月12日
    5
  • linux文件的创建与扫描,Linux系统quotacheck命令:扫描文件系统并建立Quota记录文件…

    linux文件的创建与扫描,Linux系统quotacheck命令:扫描文件系统并建立Quota记录文件…其实,磁盘配额(Quota)就是通过分析整个文件系统中每个用户和群组拥有的文件总数和总容量,再将这些数据记录在文件系统中的最顶层目录中,然后在此记录文件中使用各个用户和群组的配额限制值去规范磁盘使用量的。因此,建立Quota的记录文件是非常有必要的。扫描文件系统(必须含有挂载参数usrquota和grpquota)并建立Quota记录文件,可以使用quotacheck命令。此命令…

    2025年7月24日
    5
  • GenshinPlayerQuery_qeriuwjhrf

    GenshinPlayerQuery_qeriuwjhrf百度百科:https://baike.baidu.com/item/qeephp/8328612?fr=aladdin 官方地址:http://www.qeephp.cn/app/index.php 下载地址:https://github.com/firzen/QeePHP 文档快速入门:http://qeephp.cn/docs/qeephp-quic…

    2025年6月18日
    7
  • 完全背包问题(详细解答)

    完全背包问题(详细解答)首先完全背包问题需要01背包问题做铺垫,如果读者01背包问题没有解决,一定要理解之后,在看完全背包问题,包括01背包的优化!这里是01背包这里是01背包的全部优化好,我们开始完全背包!完全背包定义有N种物品和一个容量为V的背包,每种物品都有无限件可用。第i种物品的体积是v[i],价值是val[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。从定义中可以看出,与01背包的区别01背包最多只能拿一件物品,完全背包则不然,只要空间够多,一种物品我可以拿n件!01

    2022年6月15日
    33
  • idea连接数据库报错 Server returns invalid timezone. Need to set‘serverTimezone’property

    idea连接数据库报错 Server returns invalid timezone. Need to set‘serverTimezone’propertyidea 连接数据库报错 Serverreturn Needtoset serverTimezo property 原因是 MySQL 驱动中默认时区是 UTC 与本地时间 中国 相差八个小时 所以链接不上 点击 Settimezone1 在框中填写 GMT 保存即可 或填写 Asia Shanghai 2 也可以在 url 后添加 serverTimezo GMTPS GMT GreenwichMea 格林威治标准时间 UTC

    2026年3月26日
    2
  • 初识ABP vNext(5):ABP扩展实体

    初识ABP vNext(5):ABP扩展实体

    2020年11月20日
    186

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号