操作系统实验——系统调用

一、什么是系统调用

  • 接口:连接两个东西、信号转换、屏蔽细节……

  • 图形界面:消息框架程序+消息处理程序。

  • 命令:一个用c语言写的程序

  • 操作系统接口:接口表示为函数调用,又由系统提供,所以称为系统调用。

  • POSIX:

    分类 POSIX定义 含义
    任务管理 fork 创建一个进程
    excel 运行一个可执行程序
    pthread_create 创建一个线程
    文件系统 open 打开一个文件或目录
    EACCES 返回值,表示没有权限
    mode_t st_mode 文件头结构:文件属性

二、应用程序如何调用系统调用

​ 在通常情况下,调用系统调用和调用一个普通的自定义函数在代码上并没有什么区别,到那时调用之后发生的事情有很大的不同。

  • 调用自定义函数是通过call指令直接跳转到该函数的地址,继续运行。
  • 而调用系统调用,是调用系统库中为该系统调用编写的一个接口函数,叫API(Application Programming Interface)。API并不能完成系统调用的真正功能,它要做的是去调用真正的系统调用,过程是:
    1. 应用程序调用函数库(API);
    2. API将系统调用号存入EAX,然后通过中断调用使系统进入内核态;
    3. 内核中的中断处理函数根据系统调用号,调用对应的内核函数(系统调用);
    4. 系统调用完成相应功能,将返回值存入EAX,返回到中断处理函数;
    5. 中断处理函数返回到API中。
    6. API将EAX返回给应用程序。

三、实验报告

实验目的:

  • 添加系统调用iam(),原型为:

    int iam(const char * name);
    
  • 第二个系统调用是whoami(),原型为:

    int whoami(char* name, unsigned int size);
    

实验步骤:

  1. 既然我们知道了系统调用的原型,那么就先来编写这两个函数,再~/work/oslab/linux-0.11/kernel下编写who.c程序,实现这两个函数:

    #define __LIBRARY__
    #include 
    #include 
    #include 
    #include 
    
    char string_buf[64]={
           0};
    
    int sys_iam(const char* name)
    {
           
      printk("debug:iam is called successfully\n");
      int i =0;
      char char_buf;
      while((char_buf=get_fs_byte(name+i)) != '\0' && i<63)
      {
           
    	string_buf[i]=char_buf;
    	i++;
      }
      string_buf[i]='\0';
      
      if(i>23)
      {
           
    	errno=EINVAL;
    	return -1;
      }
      else
      {
           
    	return i;
      }
    }
    
    int sys_whoami(char* name,unsigned int size)
    {
           
    	int i=0;
    	char char_buf;
    	
    	while(i < 23)
    	{
           
    		char_buf=string_buf[i];
    		put_fs_byte(char_buf,name+i);
    		i++;
    	}
    	
    	put_fs_byte("\0",name+i);
    	
    	if(string_buf[i] != '\0')
    	{
           
    	  errno = EINVAL;
    	  return -1;
    	}
    	else
    	{
           
    		return i;
    	}
    
    }
    
  2. 我们已经知道进系统调用时,应用程序调用的是系统函数库,所以我们需要编写关于这两个函数 的系统API。在0.11的lib目录下,已经有一些实现的API,我们可以仿照的创建iam.c:

    #define __LIBRARY__
    #include 
    
    _syscall1(int,iam,const char*,name);
    

    再创建whoami.c

    #define __LIBRARY__
    #include 
    
    _syscall2(int,whoami,char*,name,unsigned int,size);
    
  3. 添加系统调用时需要修改include/unistd.h文件,使其包含__NR_whoami__NR_iam。修改unistd.h文件,第一处修改是添加两行:

    define __NR_setregid	71
    define __NR_iam			72
    define __NR_whoami		73
    

    第二处修改是文件的最后:

    pid_t getpgrp(void);
    pid_t setsid(void);
    int iam(const char* name);
    int whoami(char* name,unsigned int size);
    #endif
    
  4. 然后再修改~/work/oslab/linux-0.11/include/linux/sys.h,添加:

    extern int sys_iam();
    extern int sys_whoami();
    

    在文件的最后添加:

    sys_setregid,sys_iam,sys_whoami
    
  5. 由于我们添加了系统调用,所以必须修改kernel/system_call.s,其中第61行中,将72改为74,代表系统调用总数。

    nr_system_calls = 74
    
  6. 修改``kernal/MakeFile`文件:

    OBJS  = sched.o system_call.o traps.o asm.o fork.o \
            panic.o printk.o vsprintf.o sys.o exit.o \
            signal.o mktime.o who.o
    
    ### Dependencies:
    who.s who.o: who.c ../include/linux/kernel.h ../include/unistd.h
    exit.s exit.o: exit.c ../include/errno.h ../include/signal.h \
      ../include/sys/types.h ../include/sys/wait.h ../include/linux/sched.h \
      ../include/linux/head.h ../include/linux/fs.h ../include/linux/mm.h \
      ../include/linux/kernel.h ../include/linux/tty.h ../include/termios.h \
      ../include/asm/segment.h
    
  7. 在应用程序中,必须要有:

    #define __LIBRARY__                    /* 有它,_syscall1等才有效。详见unistd.h */
    #include                 /* 有它,编译器才能获知自定义的系统调用的编号 */
    _syscall1(int, iam, const char*, name);        /* iam()在用户空间的接口函数 */
    _syscall2(int, whoami,char*,name,unsigned int,size);    /* whoami()在用户空间的接口函数 */
    
  8. 编写应用程序:

    • user_iam.c

      #define __LIBRARY__
      #include  
      #include 
      #include  
      #include 
      _syscall1(int, iam, const char*, name);
       
      int main(int argc, char *argv[])
      {
               
          iam(argv[1]);
       
          return 0;
      }
      
    • user_whoami.c

      #define __LIBRARY__
      #include  
      #include 
      #include  
      #include 
      #include 
       
      _syscall2(int, whoami,char *,name,unsigned int,size);
       
      int main(int argc, char *argv[])
      {
               
          char username[64] = {
               0};
          whoami(username, 24);
          printf("%s\n", username);
          return 0;
      }
      
  9. 编写测试脚本

    #!/bin/bash
    gcc use_iam.c -o iam
    gcc use_whoami.c -o whoami
    ./iam Lizhijun
    ./whoami              
    
  10. 注意:一定要将use_iam.c、use_whoami.c、和test.sh上传到linux0.11文件系统的同一文件夹下,然后执行。

注意:可能会报错如下:

操作系统实验——系统调用_第1张图片

原因是找不到系统调用好,但是明明改了的,这时需要在当前的Linux 0.11系统中,进入/usr/include,修改unistd.h,添加这两个系统调用。

运行:
操作系统实验——系统调用_第2张图片

你可能感兴趣的:(操作系统)