快捷搜索:

您的位置:澳门新葡4473网站 > 澳门新葡4473网站 > Linux系统调用原理

Linux系统调用原理

发布时间:2019-12-23 05:56编辑:澳门新葡4473网站浏览(125)

    操作系统通过系统调用为运维于其上的经过提供服务。

    当顾客态进度发起二个连串调用, CPU 将切换成 内核态 并起始实施贰个 内核函数 。 内核函数担负响应应用程序的渴求,比方操作文件、举行互连网通信可能申请内部存款和储蓄器能源等。

    原稿地址:https://learn-linux.readthedocs.io
    玩转Linux旧群已满,请加新群:278378501。
    款待关怀大家的众生号:小菜学编制程序 (coding-fan)

    举二个最简易的例子,应用进度供给输出生机勃勃行文字,需求调用 write 那么些系统调用:

    #include <string.h>
    #include <unistd.h>
    
    int main(int argc, char *argv[])
    {
        char *msg = "Hello, world!n";
        write(1, msg, strlen(msg));
    
        return 0;
    }
    

    注解

    读者或者会有个别难题——输出文本不是用 printf 等函数吗?

    确实是。 printf 是更加高档案的次序的库函数,建设布局在系统调用之上,完结数据格式化等功效。 由此,本质上或然系统调用起决定性功效。

    调用流程

    那么,在应用程序内,调用一个连串调用的流程是哪些的呢?

    我们以一个若是的系统调用 xyz 为例,介绍叁遍系统调用的持有环节。

    图片 1

    如上海教室,系统调用奉行的流水生产线如下:

    1. 应用程序 代码调用系统调用( xyz 卡塔尔,该函数是三个装进系统调用的 库函数 ;
    2. 库函数 ( xyz 卡塔尔国担负盘算向根底传递的参数,并触发 软中断 以切换成基本;
    3. CPU 被 软中断 打断后,执行 停顿管理函数 ,即 系统调用场理函数 ( system_call);
    4. 系统调用项理函数 调用 系统调用服务例程 ( sys_xyz 卡塔尔(قطر‎,真正起初拍卖该系统调用;

    施行态切换

    应用程序 ( application program )与 库函数 ( libc )之间, 系统调用场理函数 ( system call handler )与 系统调用服务例程 ( system call service routine 卡塔尔之间, 均是平日函数调用,应该轻便明白。 而 库函数 与 系统调用项理函数 之间,由于涉及客商态与内核态的切换,要复杂一些。

    Linux 通过 软中断 实现从 用户态 到 内核态 的切换。 用户态 与 内核态 是单独的实践流,因而在切换时,供给未雨计划粮草先行 执行栈 并保存 寄存器 。

    基本完结了点不清不如的系统调用(提供不一样效率卡塔尔国,而 系统调用途理函数 独有叁个。 因而,客商进程必需传递三个参数用于区分,那便是 系统调用号 ( system call number )。 在 Linux 中, 系统调用号 平常经过 eax 寄存器 来传递。

    小结起来, 进行态切换 进度如下:

    1. 应用程序 在 用户态 思考好调用参数,实施 int 指令触发 软中断 ,中断号为 0x80 ;
    2. CPU 被软中断打断后,试行相应的 停顿处理函数 ,这时候便已步向 内核态 ;
    3. 系统调用项理函数 准备 基本施行栈 ,并保存全部 寄存器 (经常用汇编语言实现卡塔尔;
    4. 系统调用场理函数 根据 系统调用号 调用对应的 C 函数—— 系统调用服务例程 ;
    5. 系统调用项理函数 准备 返回值 并从 内核栈 中恢复 寄存器 ;
    6. 系统调用场理函数 执行 ret 指令切换回 用户态 ;

    编制程序实践

    上边,通过多少个粗略的前后相继,看看应用程序如何在 用户态 计划参数并因而 int 指令触发 软中断 以陷入 内核态 执行 系统调用 :

    .section .rodata
    
    msg:
        .ascii "Hello, world!n"
    
    .section .text
    
    .global _start
    
    _start:
        # call SYS_WRITE
        movl $4, %eax
        # push arguments
        movl $1, %ebx
        movl $msg, %ecx
        movl $14, %edx
        int $0x80
    
        # Call SYS_EXIT
        movl $1, %eax
        # push arguments
        movl $0, %ebx
        # initiate
        int $0x80
    

    那是一个汇编语言程序,程序入口在 *_start* 标签之后。

    第 12 行,准备 系统调用号 :将常数 4 放进 寄存器 eax 。 系统调用号 4 代表 系统调用 SYS_write , 大家将通过该系统调用向职业输出写入叁个字符串。

    第 14-16 行, 希图系统调用参数:第二个参数放进 寄存器 ebx ,第三个参数放进 ecx , 由此及彼。

    write 系统调用供给 3 个参数:

    • 文本呈报符 ,标准输出文件陈述符为 1 ;
    • 写入内容(缓冲区卡塔尔(قطر‎地址;
    • 写入内容长度(字节数卡塔尔;

    第 17 行,执行 int 指令触发软中断 0x80 ,程序将沦为内核态并由基本执行系统调用。 系统调用施行完成后,内核将担当切换回客商态,应用程序继续实施之后的吩咐( 从 20 行开始 )。

    第 20-24 行,调用 exit 系统调用,以便退出程序。

    注解

    在意到,这里不可不显式调用 exit 系统调用退出程序。 不然,程序将世袭往下施行,末了蒙受 段错误segmentation fault )!

    读者可能很愕然——在写 C 语言只怕其余程序时,那一个调用并非必得的!

    那是因为 C 库( libc 卡塔尔国已经帮您把脏活累活都干了。

    接下去,大家编写翻译并执行这一个汇编语言程序:

    $ ls
    hello_world-int.S
    $ as -o hello_world-int.o hello_world-int.S
    $ ls
    hello_world-int.o  hello_world-int.S
    $ ld -o hello_world-int hello_world-int.o
    $ ls
    hello_world-int  hello_world-int.o  hello_world-int.S
    $ ./hello_world-int
    Hello, world!
    

    其实,将 系统调用号 和 调用参数 放进正确的 寄存器 并触及正确的 软中断 是个再度的细节。 C 库已经把这脏累活给干了——试试 syscall 函数吧!

    #include <string.h>
    #include <sys/syscall.h>
    #include <unistd.h>
    
    int main(int argc, char *argv[])
    {
        char *msg = "Hello, world!n";
        syscall(SYS_write, 1, msg, strlen(msg));
    
        return 0;
    }
    

    下一步

    订阅更新,获取更加的多读书质感,请关切大家的 Wechat公众号 :

    图片 2

    参考文献

    1. Serg Iakovlev
    2. write(2) - Linux manual page
    3. syscall(2) - Linux manual page
    4. _exit(2) - Linux manual page

    图片 3

    本文由澳门新葡4473网站发布于澳门新葡4473网站,转载请注明出处:Linux系统调用原理

    关键词:

上一篇:没有了

下一篇:没有了