操作系统课程设计3_系统调用

2023-11-07

一.实验目的

(1)学习怎样重新编译 Linux 内核

(2)理解、掌握 Linux 标准内核和发行版本内核的区别

二.实验内容

1、通过重新编译Linux来实现系统调用

2、通过增加模块来实现系统调用

三.实验步骤和结果

(一)通过重新编译内核进行系统调用

1.获取root权限(即管理员权限)

在终端输入下列指令:sudo su

注意:获取root权限需要用户输入密码(登陆密码),密码是看不见的,用户只需正确的输入密码即可,回车键结束

示意图如下:

 

2.准备工作

1)安装相关编译程序

sudo apt-get install build-essential kernel-package libncurses5-dev

选择第一项:

 

2)从外面将linux-5.5.8.tar拖入到了虚拟机桌面,将该压缩文件移入到/usr/src/文件夹中

 

3.进入/usr/src解压文件

cd /usr/src

sudo tar -xvf /usr/src/linux-5.5.8.tar.xz

解压完成!

 

4.进入解压出的文件目录

cd /usr/src/linux-5.5.8/kernel

 

5.安装vim

sudo apt-get install vim

 

6.打开sys.c加入函数

vim sys.c

在vim中, i进入编辑, esc退出编辑状态. G跳到末尾, gg进入开头。 :wq保存退出, :q不保存退出

在末尾加入函数

asmlinkage long sys_helloworld(void){

printk( "helloworld!");

    return 1;

}

 

7.添加声明

cd /usr/src/linux-5.5.8/arch/x86/include/asm/

vim syscalls.h

(插入asmlinkage long sys_helloworld(void);)

 

8.加一个系统调用的id

a、使用命令cd /usr/src/linux-5.5.8/arch/x86/entry/syscalls,进入/usr/src/linux-5.5.8/arch/x86/syscalls目录

b、使用命令vim syscall_64.tbl,打开文件syscall_64.tbl(该文件有一个系统调用列表,最前面的属性是id)

c、在里面添加自己的系统调用号(335  64  helloworld           sys_helloworld)

d、使用esc +:wq命令保存退出

 

9.配置内核

cd /usr/src/linux-5.5.8

编译内核和安装内核。

依次输入这四条语句

sudo make mrproper

sudo make clean

sudo make menuconfig  (并且在make menuconfig时,将那个General setup内的localversion修改成新的名称,比如我这里的myKernel)

根据自己处理器的最大线程数目来编译。

sudo make -j4 (我的电脑是4核4线程),线程越多编译越快!

配置内核界面:

 

开始编译,过程耗时两小时左右。

编译成功!

 

10、安装内核

编译后安装内核到系统中

sudo make modules_install  //安装模块

sudo make install  // 安装内核

模块安装完成!

内核安装完成!

 

11、重启虚拟机

将之前的工作保存后直接重启,重启后点击鼠标进入ubuntu并且迅速按住shift,长按!选择新内核。

 

 

12、验证系统调用是否成功

a、登陆虚拟机

b、用文本编辑器编辑一段代码hello.c,并保存至根目录下。

c、输入下列指令:

(1)gcc hello.c

(2)./a.out

返回值为1,系统调用实现成功!

 

(二)通过模块修改系统调用

1、在/usr/include/x86_64-linux-gnu/asm/unistd_64.h文件中查看系统调用序号

发现333号系统调用是空的,因此选取333作为新的系统调用号。

2、查看系统调用表的内存地址:为0xffffffffa6c002a0

3、编写模块文件:

module5.c

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/unistd.h>
#include <linux/sched.h>



MODULE_LICENSE("Dual BSD/GPL");

#define SYS_CALL_TABLE_ADDRESS 0xffffffffb18002a0  //sys_call_table对应的地址
#define NUM 333  //系统调用号为333
int orig_cr0;  //用来存储cr0寄存器原来的值
unsigned long *sys_call_table_my=0;

static int(*anything_saved)(void);  //定义一个函数指针,用来保存一个系统调用

static int clear_cr0(void) //使cr0寄存器的第17位设置为0(内核空间可写)
{
    unsigned int cr0=0;
    unsigned int ret;
    asm volatile("movq %%cr0,%%eax":"=a"(cr0));//将cr0寄存器的值移动到eax寄存器中,同时输出到cr0变量中
    ret=cr0;
    cr0&=0xfffeffff;//将cr0变量值中的第17位清0,将修改后的值写入cr0寄存器
    asm volatile("movq %%eax,%%cr0"::"a"(cr0));//将cr0变量的值作为输入,输入到寄存器eax中,同时移动到寄存器cr0中
    return ret;
}

static void setback_cr0(int val) //使cr0寄存器设置为内核不可写
{
    asm volatile("movq %%eax,%%cr0"::"a"(val));
}

asmlinkage long sys_mycall(void) //定义自己的系统调用
{   
    printk("模块系统调用-当前pid:%d,当前comm:%s\n",current->pid,current->comm);
    return current->pid;    
}
static int __init call_init(void)
{
    sys_call_table_my=(unsigned long*)(SYS_CALL_TABLE_ADDRESS);
    printk("call_init......\n");
    anything_saved=(int(*)(void))(sys_call_table_my[NUM]);//保存系统调用表中的NUM位置上的系统调用
    orig_cr0=clear_cr0();//使内核地址空间可写
    sys_call_table_my[NUM]=(unsigned long) &sys_mycall;//用自己的系统调用替换NUM位置上的系统调用
    setback_cr0(orig_cr0);//使内核地址空间不可写
    return 0;
}

static void __exit call_exit(void)
{
    printk("call_exit......\n");
    orig_cr0=clear_cr0();
    sys_call_table_my[NUM]=(unsigned long)anything_saved;//将系统调用恢复
    setback_cr0(orig_cr0);
}

module_init(call_init);
module_exit(call_exit);

MODULE_AUTHOR("25");
MODULE_VERSION("BETA 1.0");
MODULE_DESCRIPTION("a module for replace a syscall");

 

Makefile

4、执行make命令

5、载入模块,并用lsmod命令查看模块是否被加载

6、编写测试程序:

test.c

7、编译test.c,执行a.out,输出Hello,3011,系统调用成功!

四.实验问题分析

1、第一次编译就报了下面的错误,后来我想了想,可能是在添加系统调用id的时候出了错。因为当时添加系统调用的id的时候,我看到syscall_64.tbl里面的函数名都是__x64_sys_开头,所以误以为所有的函数名都要以这个格式来命名,现在弄明白了,不用管系统里的其他函数是什么样的,这里的函数名必须与sys.c里添加的函数以及syscall.h里的函数声明保持严格的一致,否则会报错。

2、第二次重新编译,前面的过程很顺利,最后一步进行系统调用的时候又出现了问题,返回值为-1,我通过上网查阅相关资料推测应该是系统调用找不到的原因。我又重新检查了一遍,才发现自己犯了粗心大意的错误,原来,最后的hello.c程序我在写的时候误将syscall(335)写成了syscall(333),系统调用的id错了,自然就找不到了。改过来之后,返回值为1,系统调用成功。

3、第二个小实验其实也并没有多难,但是做的过程并非一帆风顺,前前后后重做了十几次,因为每次加载模块的时候,都显示被杀死,而我想卸载的时候,又显示模块正在被使用,卸载不了,我通过lsmod查看时发现系统中有module5的存在,因此我推测,这个模块应该可以理解为被杀死的模块的尸体。想要卸载掉这个死模块,只能重启。

4、其中第一个问题是,查看系统调用序号的时候,我一开始是在unistd_32.h里查看的,然后找了个223来用,但后来发现,应该在unistd_64.h里找。

5、第二个问题也是实验成功之前一直困扰我一个小细节。就是每次重启之后,我一直都用的第一次查出来的系统调用表的内存地址,以为这个地址是恒定不变的。后来通过上网查资料,问同学才最终发现内存地址每次重启都会更新,这个才是导致我的模块一直被杀死的重要原因。

 

 

五.实验总结

本次实验,我学会了通过重新编译内核和修改模块两种方法来实现Linux系统调用,通过修改模块的方法来修改系统调用,更省时,也更能体现Linux内核的模块作用。在实验过程中我遇到了很多困难,但是在一步步的解决这些问题的同时,也在进一步的加深我对Linux系统调用的理解。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

操作系统课程设计3_系统调用 的相关文章

  • 进程如何知道它已收到信号

    如果我错了 请纠正我 以下是我对信号的理解 据我所知 信号生成 和信号传递有2个不同 事物 为了产生信号 操作系统只是在位数组中设置一个位 在过程控制中维护 工艺块 PCB 每一位 对应于特定信号 当设置一个位时 这意味着 该位对应的信号为
  • 在Linux中创建可执行文件

    我计划做的一件事是编写 非常简单的 Perl 脚本 并且我希望能够在不从终端显式调用 Perl 的情况下运行它们 我明白 要做到这一点 我需要授予他们执行权限 使用 chmod 执行此操作非常简单 但它似乎也是一个稍微费力的额外步骤 我想要
  • php56 - CentOS - Remi 仓库

    我刚刚在测试盒上安装了 php 5 6 正常的 cli php 解释器似乎不存在 gt php v bash php command not found gt php56 v PHP 5 6 13 cli built Sep 3 2015
  • 使用 terminfo 的终端颜色?

    我正在编写一个 C 类 允许在终端中使用颜色 我希望它适用于每个终端 在支持真彩色 24 位 的终端上打印 在支持它的终端上具有 256 色 6x6x6 其他都是基本的 16 种颜色 我曾经使用 termcap 编写过一次 C 函数 并且我
  • 路由是否会影响具有绑定源地址的套接字?

    假设我有两个网络接口 eth0有地址10 0 0 1 eth1有地址192 168 0 1 Using route or ip route add我已将其设置为路由 所有地址至eth0 1 2 3 4只为了eth1 所以数据包到1 2 3
  • 在bash中用其他文件过滤一个文件

    我有一个带有数字的文件 例如 cat file 31038467 32048169 33058564 34088662 35093964 31018168 31138061 31208369 31538163 31798862 和其他例如
  • python 可以检测它运行在哪个操作系统下吗?

    python 可以检测操作系统 然后为文件系统构建 if else 语句吗 我需要将 Fn 字符串中的 C CobaltRCX 替换为 FileSys 字符串 import os path csv from time import strf
  • 如何获取 bash 中从 Ping 接收到的数据包的百分比?

    当 ping 主机时 我希望输出仅显示收到的数据包 已发送 5 个 的百分比 我想我需要使用grep不知怎的 但我不知道如何 我是 bash 编程的新手 这是我所在的地方 ping c 5 q host grep grep 中应该包含什么
  • 如何清理 Runtime.exec() 中使用的用户输入?

    我需要通过命令行调用自定义脚本 这些脚本需要很少的参数并在 Linux 机器上调用 当前版本容易出现各种shell注入 如何清理用户给出的参数 参数包括登录名和路径 Unix 或 Windows 路径 用户应该能够输入任何可能的路径 该路径
  • 如何从命令行执行 PHP 代码?

    我想执行单个 PHP 语句 例如if function exists my func echo function exists 直接使用命令行 无需使用单独的 PHP 文件 这怎么可能 如果您要在命令行中执行 PHP 我建议您安装phpsh
  • OS X 对 /usr/local/lib 的权限被拒绝

    我正在寻找有关权限问题的任何建议 直觉 线索 答案 自从我切换到新的 Macbook Pro 以来 这个问题一直困扰着我 这就是困境 某些程序在安装期间复制 usr local lib 下的库 并且在运行这些程序时出现崩溃 我认为这与此文件
  • C/C++ with GCC:静态地将资源文件添加到可执行文件/库

    有人知道如何使用 GCC 将任何资源文件静态编译为可执行文件或共享库文件吗 例如 我想添加永远不会改变的图像文件 如果它们改变了 我无论如何都必须替换该文件 并且不希望它们位于文件系统中 如果这是可能的 我认为这是因为 Visual C f
  • Docker 容器可以访问 DNS,但无法解析主机

    我在运行 docker 容器时遇到一个有趣的问题 突然间 我无法从容器内解析 DNS 这是一个概要 一切都没有解决 apt get pip 一次性 ping 容器等正在运行docker run it dns 8 8 8 8 ubuntu p
  • Tk 初始化失败:无显示名称且无 $DISPLAY 环境变量

    我试图从 Ubuntu 终端调用 Centos 服务器上的工具 我收到以下错误 Tk 初始化失败 没有显示名称 也没有 DISPLAY 环境变量 请帮我解决这个问题 提前致谢 连接到你的 CentOS 机器ssh Y其中 每man ssh
  • 如何从 Linux 命令行打开 Sublime Text 2 文件到选项卡,而不是新窗口

    我有 ST2 设置 这样我就可以执行 sublime file txt 它将在 ST2 窗口中打开 但是我怎样才能让它在当前打开的窗口的新选项卡中打开呢 尝试 Sublime 命令行帮助 subl 帮助 Sublime Text 2 内部版
  • 有没有办法改变vim的默认模式

    有谁知道如何更改vim的默认模式 它的默认模式是命令模式 但是我可以将其更改为插入模式吗 只需将以下行添加到您的 vimrc 中 start Vim s default mode will be changed to Insert mode
  • 在 4.x 内核上的 64 位内存中查找系统调用表

    我正在尝试编写一个简单的内核模块来查找 Linux 中的 sys call table 但遇到了一些麻烦 我在这里找到了 32 位 Linux 的基本指南 https memset wordpress com 2011 03 18 sysc
  • mod_perl 无法看到 /tmp 中的文件

    我有一些 mod perl 代码试图访问 tmp 下的文件 但它抛出 没有这样的文件或目录 错误 我在代码中添加了一个 ls al tmp 来查看 Perl 在目录中看到的内容 它只给了我 和 drwxrwxrwt 2 root root
  • gnutls_handshake() 失败:握手失败 GIT

    一切都工作正常 但突然我收到错误 致命 无法访问 https 电子邮件受保护 cdn cgi l email protection name repo name git gnutls handshake 失败 握手失败 我在我的计算机和 E
  • 打破条件变量死锁

    我遇到这样的情况 线程 1 正在等待条件变量 A 该变量应该由线程 2 唤醒 现在线程 2 正在等待条件变量 B 该变量应该由线程 1 唤醒 在我使用的场景中条件变量 我无法避免这样的死锁情况 我检测到循环 死锁 并终止死锁参与者的线程之一

随机推荐

  • 技术博客能为你面试带来什么样的好处?

    作为一个老程序员 我看过的简历 面试过的程序员非常多 我直接说我的观点 写技术博客对面试中来说 有用 如果你有一个和岗位相关的的博客 Github 在我看来 这些能显得你这个人爱学习 爱总结分享 大厂里 很重视的一件事就是分享 分享经验 分
  • (18)语义分割--paddle--EISeg自动标注软件的使用和自己数据集的测试

    1 主要参考 1 使用过程 建议先看一下下面博主的视频 eiseg简单教学 哔哩哔哩 bilibili 2 软件使用 主要参考 百度飞浆EISeg高效交互式标注分割软件的使用教程 Leonard2021的博客 CSDN博客 安装eiseg
  • redis命令行操作五种数据类型

    这里写目录标题 1 redis有关key的操作命令 2 redis中关于string类型数据的操作命令 3 redis中关于list类型数据的操作命令 单key 多valu有序 4 redis中关于set类型数据的操作命令 单key 多va
  • 高数【连续、间断点】--猴博士爱讲课

    第二课 连续 间断点 函数连续不连续是要看区间的 1 3 证明f x 在某点连续 例一 试证明 f x
  • 蓝桥杯真题31日冲刺国一

    大家好 我是泡泡 接下来几天每天都有复习 目录 今日练习专题 一丶成绩统计 二丶既约分数 三丶最优包含 复习专题 一丶空间 二丶等差数列 三丶回文日期 四丶青蛙跳杯子 今日练习专题 一丶成绩统计 题目链接 成绩统计 蓝桥云课 lanqiao
  • 机器学习中如何选择分类器

    在机器学习中 分类器作用是在标记好类别的训练数据基础上判断一个新的观察样本所属的类别 分类器依据学习的方式可以分为非监督学习和监督学习 非监督学习顾名思义指的是给予分类器学习的样本但没有相对应类别标签 主要是寻找未标记数据中的隐藏结构 监督
  • C#实现的根据年月日计算星期几的函数

    算法如下 基姆拉尔森计算公式 W d 2 m 3 m 1 5 y y 4 y 100 y 400 mod 7 在公式中d表示日期中的日数 m表示月份数 y表示年数 注意 在公式中有个与其他公式不同的地方 把一月和二月看成是上一年的十三月和十
  • pandas 报警告:A value is trying to be set on a copy of a slice from a DataFrame

    pandas 报警告 A value is trying to be set on a copy of a slice from a DataFrame 我在抽取了原来DataFrame数据的几列后 对抽取后的数据进行赋值操作时弹出这个警告
  • 提取分割单引号 ‘ ‘ 之间的内容且不重复分割单引号 python

    分割两个单引号之间的内容 且不重复分割已使用的单引号 废话少说 直接上干货 import re result re findall string 将string替换为你需要分割的部分 示例代码 string jmp qword ptr ri
  • MySQL - Left Join和Inner Join的效率对比,以及优化

    最近在写代码的时候 遇到了需要多表连接的一个问题 初始sql类似于 select from a left join b on a id b aid left join c on c bid b id left join d on d cid
  • 什么是DI

    Spring致力于简化java企业级开发 促进代码松耦合 成功的关键在于依赖注入和AOP Spring通过应用上下文 Application Context 装载bean的定义并把他们组装起来 Spring应用上下文全权负责对象的创建和组装
  • python3发送邮件带附件,Python3.4 邮件发送(含带中文附件)详解

    import smtplib import os from email mime text import MIMEText from email mime multipart import MIMEMultipart from email
  • Xshell使用密钥登录Linux服务器

    1 使用如下命令生成密钥对 root xuegod130 ssh keygen Generating public private rsa key pair Enter file in which to save the key root
  • jsonp 实现跨域 同时也是一个 webflux 的demo 示例

    文章目录 核心原理 代码 html 服务端 java 为例子 服务端目录结构 核心原理 前端 使用js 创建 script 标签 将请求地址 放到其src 中 并将 script 标签追加到文档流 后端 根据约定好的 callback 字段
  • element-ui 首页布局

    效果 代码
  • [python]numpy 中的@运算

    运算其实等价于矩阵乘法 r location s y l location r location 1 np dot s y l location 与上面式子等价
  • java 保留字符串数字的位数,不够前面补0

    Test public void test this printToConsole autoGenericCode 10011 this printToConsole autoGenericCode 000 3 不够位数的在前面补0 保留c
  • 数模笔记——论文写作

    论文写作 各模块写作要点 数学建模论文的重要性 数学建模论文的写作是数学建模中重要的一个环节 数学建模的论文是参赛队工作的全面总结 也是评委评价建模成绩的主要依据 一篇好的论文应该逻辑清晰 在语言表述上清楚 数学符号标记清晰 对于读者或者评
  • 学习JavaScript以及React技术报告

    在学习JS中遇到的一些问题总结 1 我们需要在页面加载时能够通过javascript去动态操作html中的一些对象 对于这些操作 我们最好是在body中定义onload操作 然后在该操作中去完成这些任务 尽量避免在html中嵌入script
  • 操作系统课程设计3_系统调用

    一 实验目的 1 学习怎样重新编译 Linux 内核 2 理解 掌握 Linux 标准内核和发行版本内核的区别 二 实验内容 1 通过重新编译Linux来实现系统调用 2 通过增加模块来实现系统调用 三 实验步骤和结果 一 通过重新编译内核