int 0x80
mov __NR_write, %eax
mov fd, %ebx
mov buff, %ecx
mov count, %edx
eax存放系统调用号, ebx, ecx, edx存放携带的参数
1 include/unistd.h 中添加新增的两个宏 __NR_iam, __NR_iam
2 kernel/system_call.s 中将nr_system_calls(表示系统调用总数)改为74(新增两个,原来72)
3 在include/linux/sys.h中对sys_call_table进行添加sys_iam, sys_whoami 同时在文件中加上extern int sys_whoami(); extern int sys_iam();
注意:第一步的宏添加需要先在oslab下要通过mount方法完成对linux0.11中文件的编辑
sudo ./mount-hdc
这样再hdc文件夹下会生成对应的linux0.11的文件系统,从而可以修改其中文件亦或是实现文件传递。我们需要进入hdc/usr/include/unistd.h内添加宏(这样才行,不然不能正常编译链接)
当修改完成后记得卸载
sudo ./umount hdc
添加 printk() 调试who.c的时候,注意printk打印字符串时,直接printk(buf)即可,无需printk("%s")!!!
接下来我们分析我们最终完成的iam.c文件的执行
// iam.c
#include
#define __LIBRARY__
#include
#include
_syscall1(int, iam, const char*, name);
int main(int argc, char **argv)
{
int num = iam(argv[1]);
printf("%d\n", num);
return 0;
}
首先,会对_syscall1(int, iam, const char*, name);在#include
// 展开后对内嵌汇编翻译,大致意思如下
int 0x80
mov %eax, __NR__iam
mov %ebx, name
解释执行int 0x80, 通过查找IDT表中的0x80对应表项,跳到system_call函数去执行。
注意:通过IDT表我们找到的对应CS,此时的CS段选择子,最后两位是0,也即代表此时进入内核态!
通过call _sys_call_table(, %eax, 4) )(%eax即__NR__iam即72) 找到我们真正需要调用的内核函数(sys_call_table是某一个函数表的起始地址),我们之前已经完成:
#define __NR__iam 72,
以及添加sys_iam到sys_call_table中
所以此时sys_call_table(, 4*_NR__iam), 则找到对应的sys iam()内核函数,真正执行iam的功能,sys_iam()也是我们自己实现好的
#include
#include
#include
char msg[23]; //storage area
// we assume '\0' is also a byte
int sys_iam(const char* name)
{
char temp[30];
char *p = name;
int i;
for (i = 0; i < 30; i ++)
{
temp[i] = get_fs_byte(name+i);
if (temp[i] == '\0') break;
}
int len = i + 1;
if (len > 23) return -1;
strcpy(msg, temp);
return len;
}
int sys_whoami(char* name, unsigned int size)
{
char temp[30];
int i;
for (i = 0; i < 30; i ++)
{
temp[i] = msg[i];
if (temp[i] == '\0') break;
}
int len = i + 1;
if (len > size) return -1;
for (i = 0; i < len; i ++)
{
put_fs_byte(temp[i], name+i);
}
return len;
}
注意:get_fs_byte()是内核从用户态获取字符,put_fs_byte()则是将内核字符传输到用户态。这两个函数帮助我们在用户态和内核态之间传递数据。
这样,我们就完成了从用户态iam.c对iam()系统调用的全过程啦!
其实关键就是Int 0x80进入中断,通过该中断跳转到中断处理程序,从而进入内核,找到对应的内核实现函数。