美文网首页
Linux0.11源码学习--系统调用

Linux0.11源码学习--系统调用

作者: 郭江伟 | 来源:发表于2022-04-04 22:09 被阅读0次

系统调用介绍

  1. 系统调用原理
    系统中的程序类型及状态
    操作系统中的状态分为管态(核心态)和目态(用户态)。特权指令:一类只能在核心态下运行而不能在用户态下运行的特殊指令。不同的操作系统特权指令会有所差异,但是一般来说主要是和硬件相关的一些指令。访管指令:本身是一条特殊的指令,但不是特权指令。(trap指令)。基本功能:“自愿进管”,能引起访管异常。
    用户程序只在用户态下运行,有时需要访问系统核心功能,这时通过系统调用接口使用系统调用。
  2. 系统功能调用
    系统功能调用:就是用户在程序中使用“访管指令”调用由操作系统提供的子功能集合。其中每一个系统子功能称为一个系统调用命令,也叫广义指令。
  3. 系统调用的核心
    用户程序包含一段int 0x80的代码(通常由库函数提供)
    操作系统写中断处理获取想调程序的编号
    操作系统根据编号执行相应代码


    系统调用处理过程

系统调用源码

理解系统调用重点在于理解int 80中断和中断向量表。
这里以open系统调用来解释系统调用的源码。

  1. 发起int 80中断
    open系统调用的源码在lib/open.c 文件中,源码如下:
/*
 *  linux/lib/open.c
 *
 *  (C) 1991  Linus Torvalds
 */

#define __LIBRARY__
#include <unistd.h>
#include <stdarg.h>

int open(const char * filename, int flag, ...)
{
    register int res;
    va_list arg;

    va_start(arg,flag);
////c语言调用汇编,第一个参数是返回值,第二个参数是响应函数在系统调用表中的位置,第三个参数为文件名,第四个参数是打开的mode,
// %0 - eax(返回的描述符或出错码);%1 - eax(系统中断调用功能号__NR_open);
// %2 - ebx(文件名 filename);%3 - ecx(打开文件标志 flag);%4 - edx(后随参数文件属性 mode)

    __asm__("int $0x80"    //系统中断号,这个中断号表示系统调用
        :"=a" (res)              
        :"0" (__NR_open),"b" (filename),"c" (flag),
        "d" (va_arg(arg,int)));
    if (res>=0)
        return res;
    errno = -res;
    return -1;
}

查看0x80中断定义
0x80中断在kernel/sched.c中定义,代码如下:

void sched_init(void)
{
..........省略不相关代码
    set_system_gate(0x80,&system_call);   ///这里定义了0x80中断的入口(系统门) 
} 

set_system_gate 是个宏,在 include/asm/system.h 中定义为:
可以看出来0x80 是中断描述符中的下标号15 是中断类型,3是运行特权级,addr是中断入口函数

#define set_system_gate(n,addr) \
    _set_gate(&idt[n],15,3,addr)

接下来看 system_call。该函数纯汇编打造,定义在 kernel/system_call.s 中:

nr_system_calls = 72  ///定义当前Linux有多少系统调用,其实就是include/linux/sys.h 中sys_call_table数组的长度
  1. 查找中断向量表
    __NR_open 定义在unistd.h中

define __NR_open 5

显然,sys_call_table 一定是一个函数指针数组的起始地址,它定义在 include/linux/sys.h 中:
这里只挑选跟open系统调用有关的代码:

extern int sys_open();

fn_ptr sys_call_table[] = { sys_setup, sys_exit, sys_fork, sys_read,
sys_write, sys_open, sys_close, sys_waitpid, sys_creat, sys_link,
sys_unlink, sys_execve, sys_chdir, sys_time, sys_mknod, sys_chmod,
sys_chown, sys_break, sys_stat, sys_lseek, sys_getpid, sys_mount,
sys_umount, sys_setuid, sys_getuid, sys_stime, sys_ptrace, sys_alarm,
sys_fstat, sys_pause, sys_utime, sys_stty, sys_gtty, sys_access,
sys_nice, sys_ftime, sys_sync, sys_kill, sys_rename, sys_mkdir,
sys_rmdir, sys_dup, sys_pipe, sys_times, sys_prof, sys_brk, sys_setgid,
sys_getgid, sys_signal, sys_geteuid, sys_getegid, sys_acct, sys_phys,
sys_lock, sys_ioctl, sys_fcntl, sys_mpx, sys_setpgid, sys_ulimit,
sys_uname, sys_umask, sys_chroot, sys_ustat, sys_dup2, sys_getppid,
sys_getpgrp, sys_setsid, sys_sigaction, sys_sgetmask, sys_ssetmask,
sys_setreuid,sys_setregid };

可以看到sys_open 在数组下标5的位置
linux-0.11\fs\open.c 实现了文件系统的sys_open

添加自己的系统调用

案例介绍

  1. 在include/unistd.h 添加自定义系统调用宏
    __NR_whoami 和 __NR_iam
#define __NR_whoami     72
#define __NR_iam        73
  1. 修改kernel/system_call.s
nr_system_calls = 74  ///原始值为72,我们添加两个系统调用,需要将数组改为74
  1. 修改include/linux/sys.h
    添加如下代码
extern int sys_whoami();
extern int sys_iam();

将数组修改为

fn_ptr sys_call_table[] = { sys_setup, sys_exit, sys_fork, sys_read,
sys_write, sys_open, sys_close, sys_waitpid, sys_creat, sys_link,
sys_unlink, sys_execve, sys_chdir, sys_time, sys_mknod, sys_chmod,
sys_chown, sys_break, sys_stat, sys_lseek, sys_getpid, sys_mount,
sys_umount, sys_setuid, sys_getuid, sys_stime, sys_ptrace, sys_alarm,
sys_fstat, sys_pause, sys_utime, sys_stty, sys_gtty, sys_access,
sys_nice, sys_ftime, sys_sync, sys_kill, sys_rename, sys_mkdir,
sys_rmdir, sys_dup, sys_pipe, sys_times, sys_prof, sys_brk, sys_setgid,
sys_getgid, sys_signal, sys_geteuid, sys_getegid, sys_acct, sys_phys,
sys_lock, sys_ioctl, sys_fcntl, sys_mpx, sys_setpgid, sys_ulimit,
sys_uname, sys_umask, sys_chroot, sys_ustat, sys_dup2, sys_getppid,
sys_getpgrp, sys_setsid, sys_sigaction, sys_sgetmask, sys_ssetmask,
sys_setreuid,sys_setregid,sys_whoami, sys_iam};
  1. 模仿open.c 编写kernel/who.c
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <utime.h>
#include <sys/stat.h>

#include <linux/sched.h>
#include <linux/tty.h>
#include <linux/kernel.h>
#include <asm/segment.h>
#define MAXLEN 23 
struct {
char name[MAXLEN ];
int  len;
} myName;

int sys_whoami(char *name,int len){
if(myName.len> len) return -1;
for(int i=0;i<myName.len;i++){
put_fs_byte( myName.name[i],name++);
}
return 0;
}
int sys_iam(char* name){
 
for(int i =0;i<MAXLEN ;i++){
char ch = get_fs_byte(name);
if(ch=='\0') break;
myName.name[i] = ch ;
myName.len++;
}
return 0;
}
  1. 修改makefile
    [root@localhost linux-0.11]# vi kernel/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
    修改为:
    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:

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
修改为:

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

  1. 编写用户程序 testiam.c
#define __LIBRARY__
#include <unistd.h>
_syscall1(int,iam,char *,name)
int main(int arg1,char* arg[]){
const char * a=arg[1];
char  aa[40];
int ii;
printf("string:%s\n",a);
ii=iam(a);
return(0);
}
  1. 编写用户程序 testwhoami.c
#define __LIBRARY__
#include <unistd.h>
_syscall2(int,whoami,char *,name,unsigned int, size)
int main(int arg1,char* arg[]){
char  aa[40];
whoami(aa,40);
printf("whoami=%s\n",aa);
return(0);
}

编译运行后效果如下:


效果展示

相关文章

网友评论

      本文标题:Linux0.11源码学习--系统调用

      本文链接:https://www.haomeiwen.com/subject/ibdhsrtx.html