course2610-lab9- 系统调用实验

1. 什么是系统调用

操作系统为用户态运行的进程与硬件设备(如 CPU、磁盘、打印机等等)进行交互提供了一组接口。
在应用程序和硬件之间设置这样一个接口层具有很多优点,

  • 首先,这使得编程更加容易,把用户从学习硬件设备的低级编程特性中解放出来。
  • 其次,极大地提高了系统的安全性,内核在要满足某个请求之前就可以在接口级检查这种请求的正确性。
  • 最后,更重要的是,这些接口使得程序更具有可移植性,因为只要不同操作系统所提供的一组接口相同,那么在这些操作系统之上就可以正确地编译和执行相同的程序。

这组接口就是所谓的“系统调用”。

1.1 fork() 系统调用

在 Linux 系统中,如何创建一个进程,就是通过调用系统调用 fork(),fork() 创建一个新进程,fork() 本身就是分叉的意思,也就是当执行 fork() 以后,一个新的进程就诞生了,也就是父子进程都存在了,执行流就一分为二,fork() 给父进程返回子进程的 pid,给子进程返回 0, 如图所示:

在这里插入图片描述

  1. fork 系统调用头文件:<unistd.h>;

  2. fork 系统调用的原型:pid_t fork();

  3. fork 系统调用的返回值:pid_t 是进程描述符类型,本质就是一个 int。如果 fork() 函数执行失败,返回一个负数(<0);如果 fork() 调用执行成功,返回两个值:0 和所创建子进程的 ID。

  4. fork 系统调用的功能:以当前进程作为父进程创建出一个新的子进程,并且将父进程的所有资源拷贝给子进程,这样子进程作为父进程的一个副本存在。父子进程几乎是完全相同的,但子进程与父进程的 ID 不同。

#include<stdlib.h>
#include<stdio.h>
#include<unistd.h>


int main(void)
{
    
    
  pid_t pid;  // 定义一个pid 类型的变量, 存放进程号;
  printf("Before fork ... \n");

  /* 调用fork()系统调用, 创建一个子进程 */
  switch(pid = fork()){
    
    
  
  /*  fork() 失败,返回一个负值; */
  case -1:
      printf("fork call fail \n");
      fflush(stdout);
      exit(1); // 调用失败,退出;

   // 子进程调用fork(), 返回0;
   case 0:
      printf("I am child. \n");
      printf("The pid of child is:%d \n", getpid());
      printf("the pid of child's parent is: %d \n",getppid());
      printf("child exiting ... \n");
      exit(0); // 子进程退出;

   // 父进程调用fork(), 会返回子进程的进程号;
   default:
       printf("I am father. \n");
       printf("the pid of parent is: %d \n", getpid());
       printf("the pid of parent's child is %d \n", pid); 
  }
  printf("After fork, program exiting... \n");
  exit(0); // 父进程退出;

}

进行编译, 链接, 运行,并反汇编

1. gcc -S hello.c -o hello.s  // 编译;
2. // 汇编 :  gcc -c hello.s -o hello.o;
3.  // 链接 : gcc hello.c -o hello
4.  // 装载可执行文件,并执行  ./hello;
 ./lab_fork 
Before fork ... 
I am father. 
the pid of parent is: 9718 
the pid of parent's child is 9719 
After fork, program exiting... 
I am child. 
The pid of child is:9719 
the pid of child's parent is: 9718 
child exiting ...

2.在执行 fork() 时系统进入到什么态? Fork()调用,创建一个子进程

  1. fork() 的执行流,分析 getpid() 的执行流。
 getpid函数头文件:#include <unistd.h>; 
 getpid函数原型:int _getpid(void); 
 getpid函数返回值:程序进入到子进程,并获得子进程的进程号,通过getpid返回当前进程识别码 
getpid函数说明:getpid函数用来取得当前进程的进程识别码,
程序利用getpid创建临时文件,从而避免临时文件出现进程拥塞等问题

4.fork() 的执行对你有什么启发?
Fork函数通过系统调用创建一个子进程,
而子进程可以做父进程完全相同的事,
但是传入的ID或者变量不同,
那么两个进程也可以做不同的事,这相当于父进程克隆了自己;

将汇编生成的目标文件, 反汇编成 inel 的汇编格式
objdump -d hello.o -Mintel

~/Documents/course_2610/lab9_fork$ objdump -d lab9.o

lab9.o:     file format elf64-x86-64


Disassembly of section .text:

0000000000000000 <main>:
   0:	55                   	push   %rbp
   1:	48 89 e5             	mov    %rsp,%rbp
   4:	48 83 ec 10          	sub    $0x10,%rsp
   8:	48 8d 3d 00 00 00 00 	lea    0x0(%rip),%rdi        # f <main+0xf>
   f:	e8 00 00 00 00       	callq  14 <main+0x14>
  14:	e8 00 00 00 00       	callq  19 <main+0x19>
  19:	89 45 fc             	mov    %eax,-0x4(%rbp)
  1c:	8b 45 fc             	mov    -0x4(%rbp),%eax
  1f:	83 f8 ff             	cmp    $0xffffffff,%eax
  22:	74 06                	je     2a <main+0x2a>
  24:	85 c0                	test   %eax,%eax
  26:	74 27                	je     4f <main+0x4f>
  28:	eb 77                	jmp    a1 <main+0xa1>
  2a:	48 8d 3d 00 00 00 00 	lea    0x0(%rip),%rdi        # 31 <main+0x31>
  31:	e8 00 00 00 00       	callq  36 <main+0x36>

2. 添加系统调用的方式

添加系统调用的方式有两种,
一种是重新编译内核,
一种是编写内核模块,请参看Linux 添加系统调用的两种方法;

https://www.cnblogs.com/wangzahngjun/p/4992045.html;

3. 系统调用日志收集系统

系统调用是用户程序与系统打交道的唯一入口,因此对系统调用的安全调用直接关系到系统的安全,但对系统管理员来说,某些操作却会给系统管理带来麻烦,比如一个用户恶意地不断调用 fork() 将导致系统负载增加,所以如果我们能收集到是谁调用了一些有危险的系统调用,以及调用系统调用的时间和其他信息,将有助于系统管理员进行事后追踪,从而提高系统的安全性。

本实例收集 Linux 系统运行时系统调用被执行的信息,也就是实时获取系统调用日志,这些日志信息将以可读的形式实时地返回到用户空间,以便做为系统管理或者系统安全分析时的参考数据。

本实例需要完成以下几个基本功能:

第一:记录系统调用日志,将其写入缓冲区(内核中),以便用户读取;

第二:建立新的系统调用,以便将内核缓冲中的系统调用日志返回到用户空间。

第三:循环利用系统调用,以便能动态实时返回系统调用的日志。

系统调用的实现需要调用内核中的函数,因此,内核版本不同,其内核函数名可能稍有差异,以下实验使用的内核版本为 5.0 平台。内核源代码的默认目录为 /usr/src/linux。

请在学堂在线观看视频,并动手实践。

动手实践-添加系统调用(系统调用日志收集系统

Linux 内核 3.x 的版本,可参看:

Linux 系统调用日志收集程序_x86_64 环境 3.14 版本内核

提示:此实验要重新编译内核,需要在本地完成。

猜你喜欢

转载自blog.csdn.net/chumingqian/article/details/124643341
今日推荐