(一)了解應(yīng)用程序如何調(diào)用系統(tǒng)調(diào)用
在通常情況下,調(diào)用系統(tǒng)調(diào)用和調(diào)用一個(gè)普通的自定義函數(shù)在代碼上并沒(méi)有什么區(qū)別,但調(diào)用后發(fā)生的事情有很大不同。調(diào)用自定義函數(shù)是通過(guò)call指令直接跳轉(zhuǎn)到該函數(shù)的地址,繼續(xù)運(yùn)行。而調(diào)用系統(tǒng)調(diào)用,是調(diào)用系統(tǒng)庫(kù)中為該系統(tǒng)調(diào)用編寫(xiě)的一個(gè)接口函數(shù),叫API(Application Programming Interface)(它對(duì)應(yīng)一個(gè)宏_syscallx,在unistd.h中)。API并不能完成系統(tǒng)調(diào)用的真正功能,它要做的是去調(diào)用真正的系統(tǒng)調(diào)用,過(guò)程是:
- 把系統(tǒng)調(diào)用的編號(hào)存入EAX
- 把函數(shù)參數(shù)存入其它通用寄存器
- 觸發(fā)0x80號(hào)中斷(int 0x80)
- 接下來(lái)就是內(nèi)核的中斷處理了,自動(dòng)調(diào)用函數(shù)system_call(在kernel/system_call.s中),到sys_call_table找到系統(tǒng)調(diào)用號(hào)對(duì)用的系統(tǒng)調(diào)用sys_xxx,執(zhí)行它。
閱讀文件lib/close.c、fs/open.c、kernel/system_call.s、include/unistd.h、include/linux/sys.h,找出系統(tǒng)調(diào)用close與這些文件之間的關(guān)系,清晰close系統(tǒng)調(diào)用的過(guò)程;
參照系統(tǒng)調(diào)用close,在上面一系列文件中添加或修改系統(tǒng)調(diào)用iam和whoami相關(guān)的內(nèi)容(系統(tǒng)調(diào)用號(hào)、系統(tǒng)調(diào)用表、系統(tǒng)調(diào)用總數(shù)等);
創(chuàng)建who.c文件,在其中分別編寫(xiě)包含具體實(shí)現(xiàn)細(xì)節(jié)的sys_iam()和sys_whoami()函數(shù);
修改Makefile,以便在執(zhí)行make命令時(shí)可以編譯who.c文件;
編譯linux內(nèi)核,運(yùn)行bochs;
編寫(xiě)測(cè)試程序iam.c和whoiam.c;
此次實(shí)驗(yàn)需要修改unistd.h sys.h system_call.s makefile,并編寫(xiě)who.c iam.c whoami.c
(1)修改linux-0.11/include/linux/sys.h
根據(jù)Linux調(diào)用系統(tǒng)調(diào)用的過(guò)程,需要把 iam()與whoami()兩個(gè)函數(shù)加到全局變量,和中斷函數(shù)表中就可以了,中斷被調(diào)用的時(shí)候,先查找中斷向量表,找到相應(yīng)的函數(shù)名,調(diào)用其函數(shù)。
分別添加聲明到最下面和數(shù)組中
extern int sys_setup();
extern int sys_exit();
extern int sys_fork();
extern int sys_read();
extern int sys_write();
extern int sys_open();
extern int sys_close();
extern int sys_waitpid();
extern int sys_creat();
extern int sys_link();
extern int sys_unlink();
extern int sys_execve();
extern int sys_chdir();
extern int sys_time();
extern int sys_mknod();
extern int sys_chmod();
extern int sys_chown();
extern int sys_break();
extern int sys_stat();
extern int sys_lseek();
extern int sys_getpid();
extern int sys_mount();
extern int sys_umount();
extern int sys_setuid();
extern int sys_getuid();
extern int sys_stime();
extern int sys_ptrace();
extern int sys_alarm();
extern int sys_fstat();
extern int sys_pause();
extern int sys_utime();
extern int sys_stty();
extern int sys_gtty();
extern int sys_access();
extern int sys_nice();
extern int sys_ftime();
extern int sys_sync();
extern int sys_kill();
extern int sys_rename();
extern int sys_mkdir();
extern int sys_rmdir();
extern int sys_dup();
extern int sys_pipe();
extern int sys_times();
extern int sys_prof();
extern int sys_brk();
extern int sys_setgid();
extern int sys_getgid();
extern int sys_signal();
extern int sys_geteuid();
extern int sys_getegid();
extern int sys_acct();
extern int sys_phys();
extern int sys_lock();
extern int sys_ioctl();
extern int sys_fcntl();
extern int sys_mpx();
extern int sys_setpgid();
extern int sys_ulimit();
extern int sys_uname();
extern int sys_umask();
extern int sys_chroot();
extern int sys_ustat();
extern int sys_dup2();
extern int sys_getppid();
extern int sys_getpgrp();
extern int sys_setsid();
extern int sys_sigaction();
extern int sys_sgetmask();
extern int sys_ssetmask();
extern int sys_setreuid();
extern int sys_setregid();
extern int sys_iam();//需要新增的地方
extern int sys_whoami();
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 };//記得在中斷向量表的最后填上系統(tǒng)調(diào)用
(2) 修改系統(tǒng)調(diào)用數(shù):
system_call.s 在 linux-0.11/kernel 中
需要把nr_system_calls 由72改為 74 表示了中斷函數(shù)的個(gè)數(shù)。
sa_handler = 0
sa_mask = 4
sa_flags = 8
sa_restorer = 12
nr_system_calls = 74
(3)新增系統(tǒng)調(diào)用 號(hào):
unistd.h 不能直接在oslab直接直接修改,
而需要在虛擬機(jī)中修改,
在oslab中有一個(gè)mount-hdc腳本
運(yùn)行sudo ./mount-hdc 可以把虛擬機(jī)硬盤(pán)掛載在oslab/hdc 目錄下。
(這個(gè)也可以實(shí)現(xiàn)文件共享)
在hdc/usr/include 目錄下修改unistd.h
卡在這兩天的路過(guò).
#define __NR_setup 0 /* used only by init, to get system going */
#define __NR_exit 1
#define __NR_fork 2
#define __NR_read 3
#define __NR_write 4
#define __NR_open 5
#define __NR_close 6
#define __NR_waitpid 7
#define __NR_creat 8
#define __NR_link 9
#define __NR_unlink 10
#define __NR_execve 11
#define __NR_chdir 12
#define __NR_time 13
#define __NR_mknod 14
#define __NR_chmod 15
#define __NR_chown 16
#define __NR_break 17
#define __NR_stat 18
#define __NR_lseek 19
#define __NR_getpid 20
#define __NR_mount 21
#define __NR_umount 22
#define __NR_setuid 23
#define __NR_getuid 24
#define __NR_stime 25
#define __NR_ptrace 26
#define __NR_alarm 27
#define __NR_fstat 28
#define __NR_pause 29
#define __NR_utime 30
#define __NR_stty 31
#define __NR_gtty 32
#define __NR_access 33
#define __NR_nice 34
#define __NR_ftime 35
#define __NR_sync 36
#define __NR_kill 37
#define __NR_rename 38
#define __NR_mkdir 39
#define __NR_rmdir 40
#define __NR_dup 41
#define __NR_pipe 42
#define __NR_times 43
#define __NR_prof 44
#define __NR_brk 45
#define __NR_setgid 46
#define __NR_getgid 47
#define __NR_signal 48
#define __NR_geteuid 49
#define __NR_getegid 50
#define __NR_acct 51
#define __NR_phys 52
#define __NR_lock 53
#define __NR_ioctl 54
#define __NR_fcntl 55
#define __NR_mpx 56
#define __NR_setpgid 57
#define __NR_ulimit 58
#define __NR_uname 59
#define __NR_umask 60
#define __NR_chroot 61
#define __NR_ustat 62
#define __NR_dup2 63
#define __NR_getppid 64
#define __NR_getpgrp 65
#define __NR_setsid 66
#define __NR_sigaction 67
#define __NR_sgetmask 68
#define __NR_ssetmask 69
#define __NR_setreuid 70
#define __NR_setregid 71 /*Linux system_call total 72*/
#define __NR_iam 72 /*new system_call 72 and 73*/
#define __NR_whoami 73
(4)新增who.c文件,實(shí)現(xiàn)系統(tǒng)調(diào)用的函數(shù):
將完成的who.c文件放入linux-0.01/kernel 目錄下
#include <string.h>
#include <errno.h>
#include <asm/segment.h>
char msg[24];
int sys_iam(const char * name)
{
char tep[26];
int i = 0;
for(; i < 26; i++)
{
tep[i] = get_fs_byte(name+i);
if(tep[i] == '\0') break;
}
if (i > 23) return -(EINVAL);
strcpy(msg, tep);
return i;
}
int sys_whoami(char * name, unsigned int size)
{
int len = 0;
for (;msg[len] != '\0'; len++);
if (len > size)
{
return -(EINVAL);
}
int i = 0;
for(i = 0; i < size; i++)
{
put_fs_byte(msg[i], name+i);
if(msg[i] == '\0') break;
}
return i;
}
(5) 修改Makefile 文件
讓我們添加的kernel/who.c可以和其它Linux代碼編譯鏈接到一起,必須要修改Makefile文件
Makefile在代碼樹(shù)中有很多,分別負(fù)責(zé)不同模塊的編譯工作。我們要修改的是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
Makefile修改后,和往常一樣“make all”就能自動(dòng)把who.c加入到內(nèi)核中了
make all
編譯系統(tǒng)
(6) 新增iam.c 跟whoami.c文件以測(cè)試是否添加系統(tǒng)調(diào)用成功:
iam.c
#define __LIBRARY__
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
_syscall1(int,iam,const char*,name)
int main(int argc,char* argv[])
{
iam(argv[1]);
return 0;
}
whoami.c
#define __LIBRARY__
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
_syscall2(int, whoami, char*, name, unsigned int, size);
int main(int argc, char ** argv)
{
char t[30];
whoami(t, 30);
printf("%s\n", t);
return 0;
}
注:這兩個(gè)C文件是需要在 你修改過(guò)的linux 0.11版本上編譯的,如果嫌在 0.11 里面用vi 寫(xiě)代碼太煩,可以在虛擬機(jī)中寫(xiě)好, 在oslab中運(yùn)行
sudo ./mount-hdc
可以把虛擬機(jī)硬盤(pán)掛載在oslab/hdc 目錄下。
然后再將文件復(fù)制到 oslab/hdc/user/root/下
/user/root/ 就是你的linux 0.11 開(kāi)機(jī)后所在目錄
好了, 寫(xiě)完了,運(yùn)行run
cd /home/fgx/oslab
./run
運(yùn)行系統(tǒng)
(7)編譯 iam.c 跟 whoami.c
gcc -o iam iam.c
gcc -o whoami whoami.c
運(yùn)行一波,驚喜來(lái)啦~
