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


    系统调用的三层机制

    用户态、内核态和中断

    用户态: 在低的执行级别下,代码能够掌控的范围有所限制,只能访问部分内存。

    内核态: 在高的执行级别下,代码可以执行特权指令,访问任意的物理内存。

    中断: 从用户态进入内核态的主要方式。

    • 硬件中断:在用户态进程执行时,硬件中断信号到来,进入内核态,就会执行这个中断对应的中断服务例程。
    • 软中断:在用户态进程执行过程中,调用了一个系统调用(一种特殊中断),进入内核态。

    系统调用概述

    系统调用的功能特性:

    • 把用户从底层的硬件编程中解放出来。操作系统为我们管理硬件,用户态进程不用直接与硬件设备打交道。
    • 极大地提高系统的安全性。如果用户态进程直接与硬件设备打交道,会产生安全隐患,可能引起系统崩溃。
    • 使用户程序具有可移植性。 用户程序与具体的硬件已经解耦合并用接口代替了,不会有紧密的关系,便于在不同系统间移植。

    系统调用3层机制:

    • 第一步,系统调用的库函数就是读者使用的操作系统提供的API,调用软中断向内核发出中断请求;
    • 第二步,CPU切换到内核态并开始执行一个system_call和系统调用内核函数,具体通过int $0x80触发系统调用的执行;
    • 第三步,进入内核,通过系统调用号将API函数和系统调用内核函数关联起来进行调用。

    参数传递方式:

    系统调用从用户态切换到内核态,在两种执行模式下使用不同的堆栈,通过比较特殊的寄存器传递参数。在x86-32中,EAX用于传递系统调用号,其余参数按顺序赋值给EBX,ECX,EDX,ESI,EDI和EBP,参数个数一般不超过6个。如果超过6个就把一个寄存器作为指针指向内存,通过内存传递更多的参数。

    使用库函数API和C代码中嵌入汇编代码触发同一个系统调用

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

    调用函数time()来获取当前系统时间

    #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;
    }
    

    执行结果

    内嵌汇编语法

    分类 限定符 描述
    通用寄存器 “a” 将输入变量放入eax
    - “b” 将输入变量放入ebx
    - “c” 将输入变量放入ecx
    - “d” 将输入变量放入edx
    - “s” 将输入变量放入esi
    - “D” 将输入变量放入edi
    - “q” 将输入变量放入eax,ebx ,ecx ,edx中的一个
    - “r” 将输入变量放入通用寄存器,也就是eax ,ebx,ecx,edx,esi,edi中的一个
    - “A” 把eax和edx,合成一个64位的寄存器(uselong longs)
    内存 “m” 内存变量
    - “o” 操作数为内存变量,但是其寻址方式是偏移量类型,也即是基址寻址,或者是基址加变址寻址
    - “V” 操作数为内存变量,但寻址方式不是偏移量类型
    - “.” 操作数为内存变量,但寻址方式为自动增量
    - “p” 操作数是一个合法的内存地址(指针)
    寄存器或内存 “g” 将输入变量放入eax,ebx,ecx,edx中的一个或者作为内存变量
    - “x” 操作数可以是任何类型
    立即数 “i” 0-31 之间的立即数(用于32位移位指令)
    - “J” 0-63 之间的立即数(用于64 位移位指令)
    - “N” 0-255 ,之间的立即数(用于out 指令)
    - “l” 立即数
    - “n” 立即数,有些系统不支持除字以外的立即数,这些系统应该使用“n”
    操作数类型 “=” 操作数在指令中是只写的(输出操作数)
    - “+” 操作数在指令中是读写类型的(输入输出操作数)
    浮点数 “f” 浮点数
    - “t” 第一个浮点寄存器
    - “u” 第二个浮点寄存器
    - “G” 标准的80387
    - “%” 该操作数可以和下一个操作数交换位置

    示例

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

    汇编代码分析

    asm volatile(
        "mov $0,%%ebx"           /*把EBX寄存器清零*/
        "mov $0xd,%%eax"     /*把0xd放到EAX寄存器中,EAX寄存器用于传递系统调用号*/
        "int $0x80"                          /*触发系统调用陷入内核执行13号系统调用的内核处理函数*/
        "mov %%eax,%0"/*通过EAX寄存器返回系统调用值*/
        :"=m"(tt)
        ); 
    

    含两个参数的系统调用

    汇编分析:

    asm volatile(
    			"movl %2,%%ecx"//将newname存入ECX寄存器
    			"movl %1,%%ebx"//将oldname存入EBX寄存器
    			"movl $0x26,%%eax"//系统调用号38 (16 进制是0x26)存入EAX寄存器
    			"int $0x80"//执行系统调用陷入内核态
    			:"=a"(ret)
    			:"b"(oldname),"c"(newname)
    		    );
    

    从运行结果可以看到9318.c文件被重命名为zhaoshu.c。

    遇到的问题

    课本中tim.c代码有错误,将t->tm_mda改为t->tm_mday;

    需要注意localtime函数使用0表示一月,因此输出结果与日常情况不符;

    linux 系统调用号表

  • 相关阅读:
    P2774 方格取数问题 题解
    golang文档(目录)
    下载安装
    微信小程序canvas画布新接口type为2D时wx.canvasToTempFilePath的参数差异
    【工具】让Mac能读取NTFS格式的移动硬盘
    codeforces 1562 E. Rescue Niwen! (dp)
    UVa1342 That Nice Euler Circuit (计算几何)
    ccpc2021 网络选拔赛 H. GCD on Sequence (线段树)
    codeforces 1558 D. Top-Notch Insertions (线段树+组合)
    codeforces 1561 E. Bottom-Tier Reversals (构造)
  • 原文地址:https://www.cnblogs.com/20209318zs/p/13942864.html
Copyright © 2020-2023  润新知