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

1.使用库函数API触发一个系统调用

编写tim.c函数,使用time()获得tt变量之后,通过localtime()把tt变成struct tm这种结构 输出为可读的格式

#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:
",t->tm_year+1900,t->tm_mon,t->tm_mday,t->tm_hour,t->tm_min,t->tm_sec);
        return 0;
}      

2.C代码中嵌入汇编代码触发一个系统调用

常用的内嵌汇编常用的修饰限定符

 对于下面的代码,有如下解释:

"movl $0,%%ebx
	"表示把EBX寄存器清零
"movl $0xd,%%eax
	"表示把0xd放到了EAX寄存器里面,EXA寄存器用于传递系统调用号,d在十六进制里面表示13,所以系统调用号是13
"int $0x80
	"表示触发器系统调用陷入内核执行13号系统调用的内核处理函数
"movl %%eax,%0
	"系统调用有一个返回值,通过EAX寄存器返回,将EAX寄存器的值放到变量tt里面
#include<stdio.h>
#include<time.h>
int main(){
        time_t tt;
        struct tm *t;
        asm volatile(
                "movl $0,%%ebx
	"
                "movl $0xd,%%eax
	"
                "int $0x80
	"
                "movl %%eax,%0
	"
                :"=m"(tt)
                :
                :"eax","ebx"
        );
        t=localtime(&tt);
        printf("time:%d:%d:%d:%d:%d:%d:
",t->tm_year+1900,t->tm_mon+1,t->tm_mday,t->tm_hour,t->tm_min,t->tm_sec);
        return 0;
}

3.C语言调用rename系统调用

#include<stdio.h>
int main()
{
        int ret;
        char *oldname = "hello.c";
        char *newname = "newhello.c";
        ret = rename(oldname,newname);
        if(ret == 0)
        {
                printf("Rnamed successfuly
");
        }
        else{
                printf("Unable to rename the file
");
        }
        return 0;
}      

可以看到 改变后的文件夹里面已经没有hello.c 取代的则是newhello.c

 4.汇编语言调用rename系统调用

#include<stdio.h>
int main()
{
        int ret;
        char *oldname = "hello.c";
        char *newname = "newhello_20209312.c";
        asm volatile(
                "movl %2,%%ecx
	"
                "movl %1,%%ebx
	"
                "movl $0x26,%%eax
	"
                "int $0x80"
                :"=a"(ret)
                :"b"(oldname),"c"(newname)
        );
        if(ret == 0)
        {
                printf("Rnamed successfuly
");
        }
        else{
                printf("Unable to rename the file
");
        }
        return 0;
}   

#include <stdio.h>
int main()
{
    char* oldname="hello.c";
    char* newname="new1hello_9312.c";
    int ret;
    asm volatile(
        "movl %1,%%ebx
	"
        "movl %2,%%ecx
	"
        "movl $0x26,%%eax
	"
        "int $0x80
	"
        "movl %%eax,%0"
        :"=m"(ret)
        :"b"(oldname),"c"(newname)
        );
    if(ret==0)
        printf("Rename Successfully!
");
    else
        printf("Unable to rename the file!
");
    return 0;
}

上面的代码运行结果如下:

关于出现的两个error 处理结果是用-m32编译就好了

gcc rename_asm.c -o 20209312_test -m32

 5.总结

  在linux中,将程序的运行空间分为内核空间与用户空间(内核态和用户态),在逻辑上它们之间是相互隔离的,因此用户程序不能访问内核数据,也无法使用内核函数。当用户进程必须访问内核或使用某个内核函数时,就得使用系统调用(System Call)。在Linux中,系统调用是用户空间访问内核空间的唯一途径。

  系统调用就是一种特殊的接口。通过这个接口,用户可以访问内核空间。系统调用规定了用户进程进入内核的具体位置。

       系统调用是用户进程进入内核的接口层,它本身并非内核函数,但它是由内核函数实现,进入内核后,不同的系统调用会找到各自对应的内核函数,这些内核函数被称为系统调用的“服务例程”。比如系统调用getpid实际调用了服务例程为sys_getpid(),或者说系统调用getpid是服务例程sys_getpid()的“封装例程”。API和系统调用的区别

       具体步骤:用户进程-->系统调用-->内核-->返回用户空间。

系统调用就是为了解决上述问题而引入的,是提供给用户的“特殊接口”。

     系统调用规定用户进程进入内核空间的具体位置。

    1.程序运行空间从用户空间进入内核空间。

    2.处理完后再返回用户空间。

  系统调用的三层皮:API(应用程序接口),中断向量system_call,中断服务程序sys_xyz,内核实现了很多不同的系统调用,进程必须指明需要用哪个系统调用,这需要传递一些参数。其中的系统调用号,是使用eax寄存器传递。系统调用也需要输入输出参数,例如:实际的值、用户态进程地址空间的变量的地址、包含指向用户态函数的指针的数据结构的地址system_call是Linux中所有系统调用的入口点,每个系统调用至少有一个参数,即由eax传递的系统调用号。
原文地址:https://www.cnblogs.com/ZHANGwg11/p/13945162.html