16151091_李楠 L26 2019-10-26 14:54:38 系统调用
410 0

“操作系统与Linux内核导读(北京航空航天大学)”实验报告

系统调用

实验目标

  • 建立对系统调用接口的深入认识;
  • 掌握系统调用的基本过程;
  • 能完成系统调用的全面控制;
  • 为后续实验做准备。

此次实验的基本内容是:在 Linux 0.11 上添加两个系统调用,并编写两个简单的应用程序测试它们。

(1)iam() 第一个系统调用是 iam(),其原型为:

int iam(const char * name);
copy

完成的功能是将字符串参数 name 的内容拷贝到内核中保存下来。要求 name 的长度不能超过 23 个字符。返回值是拷贝的字符数。如果 name 的字符个数超过了 23,则返回 “-1”,并置 errno 为 EINVAL。

在 kernal/who.c 中实现此系统调用。

(2)whoami() 第二个系统调用是 whoami(),其原型为:

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

它将内核中由 iam() 保存的名字拷贝到 name 指向的用户地址空间中,同时确保不会对 name 越界访存(name 的大小由 size 说明)。返回值是拷贝的字符数。如果 size 小于需要的空间,则返回“-1”,并置 errno 为 EINVAL。

也是在 kernal/who.c 中实现。

(3)测试程序 运行添加过新系统调用的 Linux 0.11,在其环境下编写两个测试程序 iam.c 和 whoami.c。最终的运行结果是:

$ ./iam lizhijun

$ ./whoami

lizhijun 
copy

实验内容与结果

修改 include/unistd.h

添加

#define __NR_iam 72
#define __NR_whoami 73
copy

图片描述

修改 /include/linux/sys.h

添加

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

在sys_call_table[]中添加

sys_iam,sys_whoami
copy

图片描述 ####修改/kernel/system_call.s 把nr_system_call的值从72改成74

nr_system_calls = 74
copy

图片描述

修改/kernel/Makefile

(1)第一处

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
copy

改为:

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
copy

添加了 who.o。 图片描述 (2)第二处

### 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
copy

改为:

### 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
copy

添加了 who.s who.o: who.c ../include/linux/kernel.h ../include/unistd.h。 图片描述

添加kernel/who.c文件

#define __LIBRARY__
#include <asm/segment.h>
#include <errno.h>
#include <unistd.h>
#include<linux/kernel.h>
char username[64] =  {0};

int sys_iam(char *name)
{
    int i;
    for(i=0; get_fs_byte(name+i)!='\0'; i++);
    if(i>23)
        return -EINVAL;
    for(i=0; (username[i]=get_fs_byte(name+i))!='\0'; i++);
    return i;
}

int sys_whoami(char *name, unsigned int size)
{
    int i;
    for(i=0; username[i] != '\0'; i++);
    if(i>size)
        return -EINVAL;
    for(i=0; username[i] != '\0'; i++)  
        put_fs_byte(username[i], name+i);
    return i;
}
copy

图片描述

运行oslab目录下的mount-hdc,挂载虚拟硬盘

cd ~/oslab
sudo ./mount-hdc
cd hdc/usr/root
copy

添加iam.c

#define __LIBRARY__
#include <unistd.h>
_syscall1(int,iam,char *,name)

int main(int argc, char *argv[])
{
    if(argc<=1)
        return -1;
    if(iam(argv[1])==-1)
        return -1;
    return 0;
}
copy

添加 whoami.c

#define __LIBRARY__
#include <unistd.h>
#include <stdio.h>
_syscall2(int,whoami,char *,name,unsigned int,size)

int main(int argc, char *argv[])
{
    char name[24];
    if(whoami(name, 23)==-1)
        return -1;
    printf("%s\n", name);
    return 0;
}
copy

拷贝testlab2.c和testlab2.sh

cp /home/teacher/testlab2.c .
cp /home/teacher/testlab2.sh .
chmod +x testlab2.sh
./testlab2.sh
copy

替换部分库文件

sudo cp ~/oslab/linux-0.11/include/linux/sys.h ~/oslab/hdc/usr/include/linux/sys.h 
sudo cp ~/oslab/linux-0.11/include/unistd.h ~/oslab/hdc/usr/include/unistd.h
copy

卸载hdc

cd ~/oslab
sudo umount hdc
copy

编译与运行

cd linux-0.11
make
../run
copy

图片描述 编译c文件

gcc -o iam iam.c -Wall
gcc -o whoami whoami.c -Wall
gcc -o testlab2 testlab2.c -Wall
copy

运行 图片描述 运行testlab2和testlab.sh 图片描述

总结与收获

通过实验进一步了解了系统调用接口,对于理论知识有了更深入的理解。 ##问题回答 ####从 Linux 0.11 现在的机制看,它的系统调用最多能传递几个参数?你能想出办法来扩大这个限制吗? 最多能传递3个参数,通过ebx、ecx、edx3个寄存器。 可以通过定义结构体,将参数存入结构体中,只需要传入结构体的大小和入口地址即可。 ####用文字简要描述向 Linux 0.11 添加一个系统调用 foo() 的步骤。

  1. 在在include/unistd.h中定义宏__NR_foo
  2. 在include/linux/sys.h中添加函数声明extern void sys_foo(),在系统调用入口表fn_ptr末端添加元素sys_foo
  3. 修改kernel/system_call.s中的nr_system_calls加1
  4. 修改kernel/Makefile,在OBJS中加入foo.o,并添加生成foo.s、foo.o的依赖规则
  5. 添加kernel/foo.c文件,实现sys_foo()函数
最新评论
暂无评论~