热门标签 | 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;然后从内核中再把这个东西读出来。


推荐阅读
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社区 版权所有