热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

linux0.11_系统调用

系统调用系统调用的过程voidsched_init(void){set_system_gate(0x80,&system_call);注册}system_call:c

系统调用


系统调用的过程

void sched_init(void)
{...set_system_gate(0x80,&system_call); //注册
}system_call:cmpl $nr_system_calls-1,%eaxja bad_sys_callpush %dspush %espush %fspushl %edxpushl %ecx # push %ebx,%ecx,%edx as parameterspushl %ebx # to the system callmovl $0x10,%edx # set up ds,es to kernel spacemov %dx,%dsmov %dx,%esmovl $0x17,%edx # fs points to local data spacemov %dx,%fs //***call sys_call_table(,%eax,4)pushl %eaxmovl current,%eaxcmpl $0,state(%eax) # statejne reschedulecmpl $0,counter(%eax) # counterje reschedule
ret_from_sys_call:movl current,%eax # task[0] cannot have signalscmpl task,%eaxje 3fcmpw $0x0f,CS(%esp) # was old code segment supervisor ?jne 3fcmpw $0x17,OLDSS(%esp) # was stack segment = 0x17 ?jne 3fmovl signal(%eax),%ebxmovl blocked(%eax),%ecxnotl %ecxandl %ebx,%ecxbsfl %ecx,%ecxje 3fbtrl %ecx,%ebxmovl %ebx,signal(%eax)incl %ecxpushl %ecxcall do_signalpopl %eax
3: popl %eaxpopl %ebxpopl %ecxpopl %edxpop %fspop %espop %dsiret//这是sys_call_table的表,根据传入eax的值找到对于的函数,
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_iam, sys_whoami };

添加系统调用


  • 在kernal 的 makefile中增加文件

    diff --git a/linux-0.11/kernel/Makefile b/linux-0.11/kernel/Makefile
    index 0afa1dc..2ae5152 100644
    --- a/linux-0.11/kernel/Makefile
    +++ b/linux-0.11/kernel/Makefile
    @@ -26,7 +26,7 @@ CPP =gcc-3.4 -E -nostdinc -I../includeOBJS = 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
    + signal.o mktime.o who.okernel.o: $(OBJS)$(LD) -m elf_i386 -r -o kernel.o $(OBJS)
    @@ -48,6 +48,11 @@ dep:(cd blk_drv; make dep)### Dependencies:
    +who.s who.o: who.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.hexit.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 \

  • 编写在kernal中编写who.c文件,

    #include
    #include #include #define NAMELEN 23char username[NAMELEN+1];int sys_iam(const char *name)
    {unsigned int namelen &#61; 0;int i &#61; 0;int res &#61; -1;//printk("Now we in kernel&#39;s sys_iam\n");while (get_fs_byte(name&#43;namelen) !&#61; &#39;\0&#39;)namelen&#43;&#43;;if (namelen <&#61; NAMELEN) {//printk("All %d user space&#39;s chars to be copied to the kernel\n", namelen);//printk("Copying from user to kernel...\n");for(i &#61; 0; i < namelen; i&#43;&#43;) {username[i] &#61; get_fs_byte(name&#43;i);}//printk("Done!\n");username[i] &#61; &#39;\0&#39;;//printk("%s\n", username);res &#61; namelen;} else {printk("Error, the user space&#39;s name&#39;s length is %d longer than 23!\n", namelen);res &#61; -(EINVAL);}return res;
    }int sys_whoami(char *name, unsigned int size)
    {unsigned int namelen &#61; 0;int i &#61; 0;int res &#61; -1;//printk("Now we in kernel&#39;s sys_whoami\n");while(username[namelen] !&#61; &#39;\0&#39;)namelen&#43;&#43;;if (namelen < size) {//printk("All %d kernel&#39;s chars to be copied to user space\n", namelen);//printk("Copying from kernel to user...\n");for (i &#61; 0; i < namelen; i&#43;&#43;) {put_fs_byte(username[i], name&#43;i);}//printk("Done!\n");put_fs_byte(&#39;\0&#39;, name&#43;i);res &#61; namelen;} else {printk("Error, the kernel&#39;s name&#39;s length is longer than %d\n", size);res &#61; -(EINVAL);}return res;
    }

  • 修改几个宏

    jewinh&#64;ubuntu:~/oslab/linux-0.11$ git diff
    diff --git a/linux-0.11/include/linux/sys.h b/linux-0.11/include/linux/sys.h
    index c538fc1..1d1ef15 100644
    --- a/linux-0.11/include/linux/sys.h
    &#43;&#43;&#43; b/linux-0.11/include/linux/sys.h
    &#64;&#64; -70,6 &#43;70,8 &#64;&#64; extern int sys_sgetmask();extern int sys_ssetmask();extern int sys_setreuid();extern int sys_setregid();
    &#43;extern int sys_iam();
    &#43;extern int sys_whoami();fn_ptr sys_call_table[] &#61; { sys_setup, sys_exit, sys_fork, sys_read,sys_write, sys_open, sys_close, sys_waitpid, sys_creat, sys_link,
    &#64;&#64; -83,4 &#43;85,4 &#64;&#64; 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 };
    &#43;sys_setreuid,sys_setregid, sys_iam, sys_whoami };
    diff --git a/linux-0.11/include/unistd.h b/linux-0.11/include/unistd.h
    index bf71dcb..43af333 100644
    --- a/linux-0.11/include/unistd.h
    &#43;&#43;&#43; b/linux-0.11/include/unistd.h
    &#64;&#64; -129,6 &#43;129,8 &#64;&#64;#define __NR_ssetmask 69#define __NR_setreuid 70#define __NR_setregid 71
    &#43;#define __NR_iam 72
    &#43;#define __NR_whoami 73#define _syscall0(type,name) \type name(void) \
    diff --git a/linux-0.11/kernel/system_call.s b/linux-0.11/kernel/system_call.s
    index 05891e1..8b096d6 100644
    --- a/linux-0.11/kernel/system_call.s
    &#43;&#43;&#43; b/linux-0.11/kernel/system_call.s
    &#64;&#64; -58,7 &#43;58,7 &#64;&#64; sa_mask &#61; 4sa_flags &#61; 8sa_restorer &#61; 12-nr_system_calls &#61; 72
    &#43;nr_system_calls &#61; 74 # origin is 72, now add sys_iam and sys_whoami


应用编写

通过上面操作&#xff0c;我们的内核已经有了两个系统调用的函数。

下面&#xff0c;我们在应用层去调用系统的函数。

iam.c

#define __LIBRARY__
#include
#include _syscall1(int, iam, const char*, name)#define NAMELEN 100
char name[NAMELEN];int main(int argc, char *argv[])
{int res;int namelen &#61; 0;if (2 <&#61; argc) {//参数多于2个while ((name[namelen] &#61; argv[1][namelen]) !&#61; &#39;\0&#39;) //放到name中&#xff0c;namelen&#43;&#43;; printf("iam.c: %s, %d\n", name, namelen);res &#61; iam(name);//把name传入。调用sys_iamerrno &#61; EINVAL; //返回参数无效。return res;}
}

#define _syscall1(type,name,atype,a) \
type name(atype a) \
{ \
long __res; \
__asm__ volatile ("int $0x80" \: "&#61;a" (__res) \: "0" (__NR_##name),"b" ((long)(a))); \
if (__res >&#61; 0) \return (type) __res; \
errno &#61; -__res; \
return -1; \
}
int iam(char * name)
{long __res; \__asm__ volatile ("int $0x80" \: "&#61;a" (__res) \: "0" (__NR_iam),"b" ((long)(name))); \if (__res >&#61; 0) \return (type) __res; \errno &#61; -__res; \return -1; \
}

int sys_iam(const char *name) 做了什么&#xff1f;

通过get_fs_byte把用户空间的内容拷贝到内核空间。

在system_call中&#xff0c;fs&#61;0x17 是本地数据空间。

通过从寄存器中读出东西&#xff0c;回写到内核空间来完成&#xff0c;最终保存到who.c 中的 char username[NAMELEN&#43;1];

int sys_whoami(char *name, unsigned int size) 反过来&#xff0c;从内核空间把username的内容拷贝回来&#xff0c;

static inline unsigned char get_fs_byte(const char * addr)
{unsigned register char _v;__asm__ ("movb %%fs:%1,%0":"&#61;r" (_v):"m" (*addr));return _v;
}static inline void put_fs_byte(char val,char *addr)
{
__asm__ ("movb %0,%%fs:%1"::"r" (val),"m" (*addr));
}

linux0.11中的编译&#xff1a;

gcc -o iam iam.c -Wall

测试用例

注意用例3&#xff0c;当输入太长时&#xff0c;iam不会修改username的内容&#xff0c;因此还是跟第二次修改之后的内容一致。

#/bin/shstring1&#61;"Sunner"
string2&#61;"Richard Stallman"
string3&#61;"This is a very very long string!"score1&#61;10
score2&#61;10
score3&#61;10expected1&#61;"Sunner"
expected2&#61;"Richard Stallman"
expected3&#61;"Richard Stallman"echo Testing string:$string1
./iam "$string1"
result&#61;&#96;./whoami&#96;
if [ "$result" &#61; "$expected1" ]; thenecho PASS.
elsescore1&#61;0echo FAILED.
fi
score&#61;$score1echo Testing string:$string2
./iam "$string2"
result&#61;&#96;./whoami&#96;
if [ "$result" &#61; "$expected2" ]; thenecho PASS.
elsescore2&#61;0echo FAILED.
fi
score&#61;$score&#43;$score2echo Testing string:$string3
./iam "$string3"
result&#61;&#96;./whoami&#96;
if [ "$result" &#61; "$expected3" ]; thenecho PASS.
elsescore3&#61;0echo FAILED.
fi
score&#61;$score&#43;$score3let "totalscore&#61;$score"
echo Score: $score &#61; $totalscore%

总结

我们通过系统调用实现了一个库函数&#xff0c;这个库函数可以实现往内核的某个内存写入一些东西&#xff0c;然后从内核中再把这个东西读出来。


推荐阅读
  • 本文讨论了clone的fork与pthread_create创建线程的不同之处。进程是一个指令执行流及其执行环境,其执行环境是一个系统资源的集合。在调用系统调用fork创建一个进程时,子进程只是完全复制父进程的资源,这样得到的子进程独立于父进程,具有良好的并发性。但是二者之间的通讯需要通过专门的通讯机制,另外通过fork创建子进程系统开销很大。因此,在某些情况下,使用clone或pthread_create创建线程可能更加高效。 ... [详细]
  • 电话号码的字母组合解题思路和代码示例
    本文介绍了力扣题目《电话号码的字母组合》的解题思路和代码示例。通过使用哈希表和递归求解的方法,可以将给定的电话号码转换为对应的字母组合。详细的解题思路和代码示例可以帮助读者更好地理解和实现该题目。 ... [详细]
  • 在Docker中,将主机目录挂载到容器中作为volume使用时,常常会遇到文件权限问题。这是因为容器内外的UID不同所导致的。本文介绍了解决这个问题的方法,包括使用gosu和suexec工具以及在Dockerfile中配置volume的权限。通过这些方法,可以避免在使用Docker时出现无写权限的情况。 ... [详细]
  • 本文介绍了深入浅出Linux设备驱动编程的重要性,以及两种加载和删除Linux内核模块的方法。通过一个内核模块的例子,展示了模块的编译和加载过程,并讨论了模块对内核大小的控制。深入理解Linux设备驱动编程对于开发者来说非常重要。 ... [详细]
  • 本文详细介绍了git常用命令及其操作方法,包括查看、添加、提交、删除、找回等操作,以及如何重置修改文件、抛弃工作区修改、将工作文件提交到本地暂存区、从版本库中删除文件等。同时还介绍了如何从暂存区恢复到工作文件、恢复最近一次提交过的状态,以及如何合并多个操作等。 ... [详细]
  • 本文介绍了一道经典的状态压缩题目——关灯问题2,并提供了解决该问题的算法思路。通过使用二进制表示灯的状态,并枚举所有可能的状态,可以求解出最少按按钮的次数,从而将所有灯关掉。本文还对状压和位运算进行了解释,并指出了该方法的适用性和局限性。 ... [详细]
  • python中安装并使用redis相关的知识
    本文介绍了在python中安装并使用redis的相关知识,包括redis的数据缓存系统和支持的数据类型,以及在pycharm中安装redis模块和常用的字符串操作。 ... [详细]
  • linux进阶50——无锁CAS
    1.概念比较并交换(compareandswap,CAS),是原⼦操作的⼀种,可⽤于在多线程编程中实现不被打断的数据交换操作࿰ ... [详细]
  • 本文主要介绍了gym102222KVertex Covers(高维前缀和,meet in the middle)相关的知识,包括题意、思路和解题代码。题目给定一张n点m边的图,点带点权,定义点覆盖的权值为点权之积,要求所有点覆盖的权值之和膜qn小于等于36。文章详细介绍了解题思路,通过将图分成两个点数接近的点集L和R,并分别枚举子集S和T,判断S和T能否覆盖所有内部的边。文章还提到了使用位运算加速判断覆盖和推导T'的方法。最后给出了解题的代码。 ... [详细]
  • #define_CRT_SECURE_NO_WARNINGS#includelist.h#includevoidSListInit(PNode*pHead ... [详细]
  • Introduction(简介)Forbeingapowerfulobject-orientedprogramminglanguage,Cisuseda ... [详细]
  • Thisworkcameoutofthediscussioninhttps://github.com/typesafehub/config/issues/272 ... [详细]
  • [转载]从零开始学习OpenGL ES之四 – 光效
    继续我们的iPhoneOpenGLES之旅,我们将讨论光效。目前,我们没有加入任何光效。幸运的是,OpenGL在没有设置光效的情况下仍然可 ... [详细]
  • 详解 Python 的二元算术运算,为什么说减法只是语法糖?[Python常见问题]
    原题|UnravellingbinaryarithmeticoperationsinPython作者|BrettCannon译者|豌豆花下猫(“Python猫 ... [详细]
  • QuestionThereareatotalofncoursesyouhavetotake,labeledfrom0ton-1.Somecoursesmayhaveprerequi ... [详细]
author-avatar
fanersai_668
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有