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

系统调用介绍

  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);
}

编译运行后效果如下:


效果展示
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,590评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,808评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,151评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,779评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,773评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,656评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,022评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,678评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,038评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,756评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,411评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,005评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,973评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,053评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,495评论 2 343

推荐阅读更多精彩内容