17373309郑贺 L42 2019-10-24 13:48:21 系统调用
499 0

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

系统调用

实验3 系统调用

实验目的

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

实验步骤

1. 在源代码中添加系统调用入口

  • 需要修改的文件有:sys.hunistd.hsystem_call.sMakefile
  • 首先在 include/unistd.h 中添加系统调用编号 __NR_iam__NR_whoami
#define __NR_iam 72
#define __NR_whoami 73
copy

图片描述

  • include/linux/sys.h 中声明系统调用。
extern int sys_iam();
extern int sys_whoami();
  
fn_ptr sys_call_table[] = { ..., sys_iam, sys_whoami };
copy

图片描述

  • kernel/system_call.s 中修改系统调用数量。
nr_system_calls = 74
copy

图片描述

  • kernel/Makefile 中添加 who.c 的编译选项。
OBJS = ... who.o
  
who.s who.o: who.c ../include/linux/kernel.h ../include/unistd.h
copy

图片描述 图片描述

2. 编写系统调用的实现 who.c

#include <linux/kernel.h>
#include <errno.h>
#include <asm/segment.h>
  
char username[24], buf[24];
  
int sys_iam(const char* name) {
    int i, flag;
    for (i = 0, flag = 0; i < 24; i++) {
        buf[i] = get_fs_byte(&name[i]);
        if (buf[i] == '\0') {
            flag = 1;
            break;
        }
    }
    if (!flag) {
        return -(EINVAL);
    }
    else {
        i = 0;
        while (buf[i] != '\0') {
            username[i] = buf[i];
            i++;
        }
        username[i] = '\0';
    }
    return i;
}
  
int sys_whoami(char* name, unsigned int size) {
    int i, flag;
    for (i = 0, flag = 0; i < size; i++) {
        if (username[i] == '\0') {
            flag = 1;
            break;
        }
        else {
            put_fs_byte(username[i], &name[i]);
        }
    }
    if (!flag) {
        if (size != 0) {
            put_fs_byte('\0', &name[size - 1]);
        }
        return -(EINVAL);
    }
    return i;
}
copy

图片描述

3. 编写测试程序 iam.cwhoami.c

  • 编写 iam.c 测试系统调用 iam()
#define __LIBRARY__
#include "unistd.h"
#include "errno.h"
#include <stdio.h>
  
_syscall1(int, iam, const char*, name);
_syscall2(int, whoami, char*, name, unsigned int, size);
  
int main(int argc, char** argv) {
    int n;
    if (argc < 2) {
        printf("Usage: %s [name]\n", argv[0]);
        return 0;
    }
    n = iam(argv[1]);
    return 0;
}
copy

图片描述

  • 编写 whoami.c 测试系统调用 whoami()
#define __LIBRARY__
#include "unistd.h"
#include "errno.h"
#include <stdio.h>
  
char name[24];
  
_syscall1(int, iam, const char*, name);
_syscall2(int, whoami, char*, name, unsigned int, size);
  
int main() {
    int n;
    n = whoami(name, 24);
    printf("%s\n", name);
    return 0;
}
copy

图片描述

4. 编译修改后的内核并将测试代码 iam.cwhoami.ctestlab2.ctestlab2.sh 复制到虚拟机中,以及修改后的 unistd.c

cd linux-0.11
make
cd ..
sudo ./mount-hdc
sudo cp iam.c ./hdc
sudo cp whoami.c ./hdc
sudo cp /home/teacher/testlab2.c ./hdc
sudo cp /home/teacher/testlab2.sh ./hdc
sudo cp ./linux-0.11/include/unistd.h ./hdc/usr/include
sudo umount hdc
copy

图片描述

5. 运行虚拟机,编译测试程序并执行

  • 启动虚拟机
./run
copy
cd /
gcc -o iam iam.c -Wall
gcc -o whoami whoami.c -Wall
gcc -o testlab2 testlab2.c -Wall
testlab2
testlab2.sh
copy

图片描述

实验结果

运行 testlab2testlab2.sh,结果如下。

图片描述

可以看到,运行结果完全正确,系统调用成功。

实验总结

本次实验,我认识了系统调用接口,对系统调用的过程有了深入了解,可以自己添加、删除、修改系统调用接口,能控制系统调用的过程,学习到了新的调试内核的方式(printk() 函数),为后续实验做准备。

思考题

  1. Linux 0.11 使用 ebx、ecx、edx 寄存器传递参数,因此最多传递3个参数。扩大此限制的办法是,可以增加传参使用的寄存器,或者传递参数列表的指针等。
  2. 首先在 include/unistd.h 中加入 __NR_foo 的调用编号定义,然后在 include/linux/sys.h 中加入函数声明 extern void sys_foo(); 和入口表项 fn_ptr sys_call_table[] = { ..., sys_foo }; ,再在 kernel/system_call.s 中修改系统调用的数量,最后添加 foo.c 实现 sys_foo() 函数并在 Makefile 中添加此文件的编译选项(OBJS 中的 foo.ofoo.s foo.o 的依赖规则)。
最新评论
暂无评论~