2020-2021-1 20209326 《Linux内核原理与分析》第五周作业

[toc] 一、实验内容:使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用

###1. 13号系统调用time
编写time.c

#include<stdio.h>
#include<time.h>
int main()
{
        time_t tt;
        struct tm *t;
        tt=time(NULL);
        t=localtime(&tt);
        printf("time:%d:%d:%d:%d:%d:%d\n",t->tm_year+1900,t->tm_mon,t->tm_mday,t->tm_hour,t->tm_min,t->tm_sec);
        return 0;
}

经过编译执行:

问题:月份比当前月份提前一个月,经查阅ctime中的tm结构体,发现月份从0开始计月。

修改参数,得到正确输出。

内嵌汇编形式调用:

#include<stdio.h>
#include<time.h>

int main(){
        time_t tt;
        struct tm *t;
        asm volatile(
                "mov $0,%%ebx;\n\t"
                "mov $0xd,%%eax;\n\t"
                "int $0x80;\n\t"
                "mov %%eax,%0;\n\t"
                :"=m"(tt)
        );
        t = localtime(&tt);
        printf("time:%d:%d:%d:%d:%d:%d\n",t->tm_year+1900,t->tm_mon+1,t->tm_mday,t->tm_hour,t->tm_min,t->tm_sec);
        return 0;
}

出现段错误

经参考李明帅同学的博客在汇编代码后添加,代表“eax”“ebx”两个寄存器会被改变,最后执行顺利!

		:
		:"eax","ebx"

###2. 8号系统调用creat
函数原型,参数中file为文件名,__mode表示权限。

#include<fcntl.h>
#include<sys/types.h>
#include<sys/stat.h>
int creat (const char *__file, mode_t __mode)

编写creat.c

#include<fcntl.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<stdio.h>
int main(){
        char *pachname="20209326";
        int mode =0777;
        int fd=creat(pachname,mode);
        if(fd==0)
                printf("create failed!\n");
        else
                printf("create successful!\n");
}

经过编译执行:

内嵌汇编形式调用:

#include<fcntl.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<stdio.h>
int main(){
        char *pachname="20209326";
        int mode =0777;
        int fd;
        asm volatile(
                "movl %2,%%ecx\n\t"        //将权限mode值赋值给ecx寄存器
                "movl %1,%%ebx\n\t"        //将文件名pachname值赋值给ebx寄存器
                "movl $0x8,%%eax\n\t"      //creat系统调用号为8
                "int $0x80"                //启动中断
                :"=a"(fd)                  //输出成功与否
                :"b"(pachname),"c"(mode)   //输入文件名和权限
        );
        if(fd==0)
                printf("create failed!\n");
        else
                printf("create successful!\n");
}

经过编译执行:

问题:文件的权限与输入的不一致?
经查阅博客,此处设定的mode的值并不是文件最终的权限,文件最终的权限是按照mode & ~umask得到的,所以如果想按照mode的值设置文件权限,需要在建立文件之前将umask的值设置为0000。加一句umask(0000),即可。

二、总结

1.Intel x86 CPU定义了4种不同的执行级别0、1、2、3,数字越小特权越高。Linux系统采用了其中的0、3两个特权级别,分别对应内核态和用户态。内核态下可以访问所有的地址空间,但是在用户态下只能访问0x00000000-0xbfffffff的地址空间,0xc0000000以上的地址空间只能在内核态下访问。
2.中断处理是从用户态进入内核态的主要方式。硬件中断或是由调用系统调用(Trap)引起中断,陷入内核态。从用户态切换到内核态,将用户态寄存器的上下文保存起来,同时将内核态寄存器的值放入当前CPU中。
3.Linux下系统调用通过int 0x80中断完成。int指令触发中断机制会在堆栈上保存一些寄存器的值,会保存用户态栈顶地址、当时的状态字、当时的CS:EIP的值。
4.libc函数库内部定义的一些API内部就使用了系统调用的封装历程。每个系统调用对应一个系统调用的封装例程。
5.系统调用的3层机制:xyz();system_call;sys_xyz()。
6.用户进程必须指明需要哪一个系统调用,使用EAX寄存器传递一个名为系统调用号的参数。系统调用从用户态切换到内核态时使用的不同的堆栈,所以参数的传递无法通过参数压栈的方式进行传递。参数按照顺序赋值给EBX ECX EDX ESI EDI EBP 参数的个数不能超过6个寄存器。如果参数过多,就把寄存器作为指针指向内存,以传递更多的参数。

posted @ 2020-11-04 16:54  20209326  阅读(87)  评论(0编辑  收藏  举报