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

操作系统通过系统调用为运营于其上的进程提供劳务。

享有的程序员在写程序的时候都离不开通过库函数的措施和系统调用打交道

安大大 + 原创小说转发请表明出处 + 《Linux操作系统一分配析》MOOC课程

当用户态进程发起几个系列调用, CPU 将切换成 内核态 并开首履行多个 内核函数 。
内核函数负责响应应用程序的须要,例如操作文件、进行互联网通信或许申请内部存款和储蓄器能源等。

当用户态进程发起3个种类调用, CPU 将切换来 内核态 并初始实施三个内核函数 。
内核函数负责响应应用程序的渴求,例如操作文件、实行互联网通信大概申请内存财富等。

哪些是用户态和内核态?(从CPU指令级其余角度)

用户态、内核态和刹车处理进度

程序员通过库函数的法门和系统调用打交道,库函数把系统调用给封装起来了。
诚如现代CPU都有两种分歧的下令执行级别

在高执行级别下,代码能够进行特权指令,访问任意的物理地址,这种CPU执行级别就对应着内核态

而在对应的低级别实施情状下,代码的掌握控制范围会合临限制。只能在对应级别允许的限量内活动
♦ 举例:intel x86
CPU有三种不一致的实施级别0-3,Linux只利用了里面包车型客车0级和3级分别来代表内核态和用户态


原稿地址:https://learn-linux.readthedocs.io
玩转Linux旧群已满,请加新群:278378501。
迎接关心我们的群众号:小菜学编制程序 (coding-fan)

举二个最简便易行的例证,应用进度需求输出一行文字,供给调用 write
那个系统调用:

诚如现代CPU都有二种差异的指令执行级别,什么样的主次可以推行什么样的通令
在高执行级别下,代码可以推行特权指令,访问随便的情理地址,那时CPU执行级别就对应着内核态
而在对应的低级别实施意况下,代码的掌握控制范围会碰到限制。只可以在对应级别允许的界定内运动
举例:intel x86
CPU有多种分裂的举办级别0-3,Linux只行使了里面包车型客车0级3级独家来表示内核态用户态

缘何有权力级其他分开

提防程序员违规访问系统只怕是其它国资本源而使得系统崩溃

举二个最简便的例子,应用进度须求输出一行文字,要求调用 write 这么些连串调用:

【澳门金沙国际】详解linux系统调用原理,Linux系统调用原理。hello_world.c

如何区分用户态和内核态?(从进度地址空间的角度)

Linux中怎么差异用户态和内核态:

♦ cs寄存器的最低两位注明了脚下代码的特权级
♦ CPU每条指令的读取都以由此cs:eip那五个寄存器:
在那之中cs是代码段采纳寄存器,eip是偏移量寄存器。
♦ 上述判断由硬件完结
♦ 一般的话在Linux中,地址空间是多个鲜明的注解:
0xc0000000上述的地点空间只能在内核态下访问,0x00000000-0xbfffffff的地址空间在二种情形下都得以访问
瞩目:那里所说的地点空间是逻辑地址而不是情理地址

在内核态时,cs和eip能够是任意的地方


#include <string.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
    char *msg = "Hello, world!\n";
    write(1, msg, strlen(msg));

    return 0;
}
#include <string.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
 char *msg = "Hello, world!\n";
 write(1, msg, strlen(msg));

 return 0;
}

cs寄存器的最低两位申明了当下代码的特权级
CPU每条指令的读取都是通过cs:eip那八个寄存器:
      其中  cs是代码段选用寄存器,eip是偏移量寄存器
上述判断由硬件完毕

暂停处理是从用户态进入内核态重要的措施

用户态进入内核态一般的话都以用中断来触发的,恐怕是硬件中断。也说不定是用户态程序运维当中调用了系统调用进入了内核态(trap)。系统调用是一种很是的中断。

♦ 寄存器上下文
– 从用户态切换成内核态时
• 必须保留用户态的寄存器上下文,同时内核态相应的值放到CPU中
• 要保存哪些?
• 保存在何地?
♦ 中断/int指令会在仓库上保留一些寄存器的值
– 如:用户态栈顶地址、当时的状态字、当时的cs:eip的值

注解

读者可能会略微难题——输出文本不是用 printf 等函数吗?

确实是。 printf 是更高层次的库函数,建立在系统调用之上,实现多少格式化等功效。
因而,本质上或许系统调用起决定性作用。

注解

在三15人x86的机械上,有4G的经过地址空间(逻辑地址),在内核态的时候全都可以访问,在用户态的时候,只可以访问0x00000000-0xbfffffff的地点空间。也便是说0xc0000000以上的地址空间只还好内核态下访问

停顿产生后第叁件事就是保留现场 SAVE_ALL

敬再现场 正是进入暂停程序,保存供给运用的寄存器的多寡
还原现场 就是退出中断程序,复苏保存寄存器的数目

调用流程

那么,在应用程序内,调用贰个系统调用的流程是什么的啊?

大家以三个假设的种类调用 xyz 为例,介绍3次系统调用的享有环节。

澳门金沙国际 1

如上航海用体育场面,系统调用执行的流程如下:

  1. 应用程序 代码调用系统调用( xyz ),该函数是三个包裹系统调用的 库函数 ;
  2. 库函数 ( xyz )负责准备向基础传递的参数,并触发 软中断 以切换成基本;
  3. CPU 被 软中断 打断后,执行 暂停处理函数 ,即 系统调用处理函数 ( system_call);
  4. 系统调用处理函数 调用 系统调用服务例程 ( sys_xyz ),真正先导拍卖该系统调用;

读者或然会略带难题——输出文本不是用 printf 等函数吗?

暂停处理是从用户态进入内核态首要的章程

停顿处理达成前最终一件事是还原现场 RESTORE_ALL

澳门金沙国际 2

施行态切换

应用程序 ( 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 指令切换回 用户态 ;

当真是。 printf
是更高层次的库函数,建立在系统调用之上,完毕多少格式化等功用。
由此,本质上照旧系统调用起决定性功能。

当从用户态切换到内核态的时候,必须用户态的寄存器上下文物保护存起来,同时安装内核态的寄存器内容
停顿/int指令会在库房上保留一些寄存器的值
      如:用户态栈顶地址、当时的状态字、当时的 cs:eip 的值
还要设置内核态的栈顶地址、内核态的状态字,中断处理程序的输入地址 cs:eip
的值(对于系统调用来讲,它是指向system_call函数)

暂停处理的全体经过

澳门金沙国际 3


编制程序实践

上边,通过2个简短的先后,看看应用程序如何在 用户态 准备参数并经过 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;
}

调用流程

暂停/int指令发出后首先件事正是保卫安全现场

系统调用概述

以体系调用为例,看看中断服务实际是怎么实施的:

系统调用的意义

  • 操作系统为用户态进度与硬件设备进行互相提供了一组接口——系统调用
  • 把用户从底部的硬件编制程序中解放出来
  • 小幅的增强了系统的安全性
  • 使用户程序具有可移植性

下一步

订阅更新,获取越多学学材质,请关怀大家的 微信公众号 :

澳门金沙国际 4

那么,在应用程序内,调用二个系统调用的流程是怎么样的吗?

保卫安全现场正是进入暂停程序保存须要接纳的寄存器的多寡

操作系统提供的API和系统调用的关联

行使编制程序接口(application program interface, API) 和体系调用是见仁见智的

  • API只是二个函数定义
  • 系统调用通过软中断(trap)向基础发出三个肯定的乞求
    Libc库定义的有个别API引用了包装例程(wrapper
    routine,唯一目标便是宣布种类调用)
  • 相似种种系统调用对应2个装进例程
  • 库再用那些包裹例程定义出给用户的API
    不是各样API都对应1个一定的系列调用。
  • API只怕直接提供用户态的劳务,如部分数学函数
  • 1个独立的API或许调用多少个系统调用
  • 今非昔比的API大概调用了同一个种类调用
    返回值
  • 绝大部分装进例程重返3个整数,其值的意义依赖于相应的系列调用
  • -1在多数情况下表示内核不能够满意进度的伸手
  • Libc中定义的errno变量(error number)包蕴特定的出错码
    应用程序、封装例程、系统调用处理程序及系统调用服务例程之间的涉及

澳门金沙国际 5

左手是用户态User Mode,左侧是内核态Kernel
Mode,最左侧api:xyz()封装了二个系统调用,那些种类调用会触发一个0x80的中止。0x80以其中断向量就对应着system_call这么些基本代码的进口源点。那些基础代码里大概有SAVE_ALL,sys_xyz()中断服务程序,在暂停服务程序执行完后,恐怕ret_from_sys_call,在return的历程中只怕产生进度调度,那是二个进程调度的机会。假若没有发出系统调度,就会iret,再回到到用户态接着执行。
系统调用的三层皮:xyz(api)、system_call(中断向量)和sys_xyz


参考文献

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

澳门金沙国际 6

大家以二个比方的系统调用 xyz 为例,介绍1回系统调用的装有环节。

当进入到中断处理程序后,一伊始就实施SAVE_ALL,把别的的一对寄存器的值push到根本堆栈里面去

当用户态进度调用一个系统调用时,CPU切换成内核态并初始实施多少个内核函数。
  • 在Linux中是因此执行int
    $0x80来实行系统调用的,那条汇编指令发出向量为128的编程至极
    系统调用号讲xyz和sys_xyz关联起来了

澳门金沙国际 7

澳门金沙国际 8

传参:

基本完结了诸多例外的系统调用,进程必须指明必要哪些系统调用,那亟需传递3个名为系统调用号的参数
-使用eax寄存器

如上海体育场地,系统调用执行的流水生产线如下:

SAVE_ALL

系统调用的参数字传送递方法

  • 应用程序 代码调用系统调用( xyz ),该函数是二个卷入系统调用的 库函数
  • 库函数 ( xyz )负责准备向基础传递的参数,并触发 软中断 以切换来根本;
  • CPU 被 软中断 打断后,执行 中断处理函数 ,即 系统调用处理函数 (
    system_call );
  • 系统调用处理函数 调用 系统调用服务例程 ( sys_xyz
    ),真正伊始拍卖该体系调用;

暂停处理终结前最终一件事是恢复生机现场

系统调用也亟需输入输出参数,例如:
  • 实质上的值
  • 用户态进程地址空间的变量的地方
  • 居然是带有指向用户态函数的指针的数据结构的地点

假若是函数调用的时候,它能够把函数压栈的不二法门来传递。而用户态到内核态的函数字传送递的形式:

实施态切换

回复现场便是脱离中断程序苏醒寄存器的数目

system_call是linux中颇具系统调用的入口点,各类系统调用至少有3个参数,即由eax传递的种类调用号
  • 2个应用程序调用fork()封装例程,那么在执行int
    $0x80事先就把eax寄存器的值置为2(即__NR_fork)。
  • 这一个寄存器的装置是libc库中的封装例程实行的,由此用户一般不珍爱系统调用号
  • 进入sys_call之后,立时将eax的值压入内核堆栈

•寄存器传递参数具有如下限制:
•1)每一种参数的长短无法超越寄存器的长短,即三1几人
•2)在系统调用号(eax)之外,参数的个数不能够超越陆个(ebx,ecx,edx,esi,edi,ebp)
•超过四个怎么办?
即使超过七个,某三个寄存器作为叁个指南针指向一块内部存款和储蓄器,进入到内核态以往,它能够访问具有的内部存款和储蓄器空间,能够通过那块内部存款和储蓄器来传递数据。


行使程序 ( application program )与 库函数 ( libc )之间,
系统调用处理函数 ( system call handler )与 系统调用服务例程 ( system
call service routine )之间, 均是见惯司空函数调用,应该简单明白。 而 库函数
与 系统调用处理函数 之间,由于涉及用户态与内核态的切换,要复杂一些。

当刹车处理程序结束以往,它会RESTORE_ALL,把保存的用户态的寄存器再pop出来到当前的CPU里面,最终iret,iret指令与中断信号(包含int指令)发生时CPU做的动作刚好相反

应用库函数API来收获系统当下日子

简易的系统调用time,来获得当前系统的日子:

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

int main()
{
    time_t tt;// tt只是int型的数值 
    struct tm *t;// tm为了输出的时候变成可读的 
    tt = time(NULL);//time系统调用,返回值赋给tt//使用了time这个库函数,api 
    t = localtime(&tt);//把tt改成t这种格式的,即tm格式
    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;   
} 

澳门金沙国际 9

Paste_Image.png

澳门金沙国际 10

选拔库函数的章程比较不难,上边使用汇编的章程:

Linux 通过 软中断 完结从 用户态 到 内核态 的切换。 用户态 与 内核态
是单独的执行流,因而在切换时,须求忧盛危明 执行栈 并保存 寄存器 。

澳门金沙国际 11

用汇编情势触发系统调用获取系统当下时刻

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

int main()
{
    time_t tt;
    struct tm *t;
    asm volatile(
        "mov $0,%%ebx\n\t"//把ebx清零 
        "mov $0xd,%%eax\n\t"//把0xd(13)放到eax里,eax是用来传递系统调用号的 
        "int $0x80\n\t"
        "mov %%eax,%0\n\t"//通过eax返回值 
        :"=m"(tt) 
    ); 
    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;   
} 

澳门金沙国际 12

澳门金沙国际 13

能够观察实行的成效是截然一致的。用户态进度向内核态传递了二个种类调用号。在那段汇编代码里,先是给ebx传参数,然后给eax传体系调用号,int指令,系统调用执行完后重返结果eax,那就水到渠成了系统调用。

系统调用号的定义在 /usr/include/asm/unistd.h 文件中

基本实现了无数两样的系统调用(提供分歧效用),而 系统调用处理函数
唯有1个。 由此,用户进度必须传递2个参数用于区分,这正是 系统调用号 (
system call number )。 在 Linux 中, 系统调用号 一般经过 eax 寄存器
来传递。

RESTORE_ALL

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

暂停处理的一体化进度

  • 应用程序 在 用户态 准备好调用参数,执行 int 指令触发 软中断
    ,中断号为 0x80 ;
  • CPU 被软中断打断后,执行相应的 中断处理函数 ,这时便已进入 内核态 ;
  • 系统调用处理函数 准备 内核执行栈 ,并保存全部 寄存器
    (一般用汇编语言达成);
  • 系统调用处理函数 依据 系统调用号 调用对应的 C 函数——
    系统调用服务例程 ;
  • 系统调用处理函数 准备 重回值 并从 内核栈 中平复 寄存器 ;
  • 系统调用处理函数 执行 ret 指令切换回 用户态 ;

interrupt(ex:int 0x80)
save cs:eip/ss:esp/eflags(current) to kernel stack, then load
cs:eip(entry of a specific ISR) and ss:esp(point to kernel stack)
SAVE_ALL
….  // 内核代码,完结人中学断服务,爆发进度调度
RESTORE_ALL
iret
pop cs:eip/ss:esp/eflags from kernel stack

编制程序实践

SAVE_ALL….借使产生了经过调度,那么当前的景观都会一时保留在系统里面,当下贰遍爆发进程调度切换回当前经过的时候,就会跟着把它实施完,RESTORE_ALL….

下边,通过三个简单的程序,看看应用程序怎么着在 用户态 准备参数并经过 int
指令触发 软中断 以陷入 内核态 执行 系统调用 :

以连串调用为例,看中断具体是怎么执行的

hello_world-int.S

系统调用通过软中断向基础发出3个明了的乞请,是操作系统为用户态进程与硬件装备进行交互提供的一组接口

.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

封装例程 (wrapper
routine),唯一目标就是揭破种类调用,让程序员在写代码的时候不须要用汇编指令来触发3个种类调用,而是径直调用1个函数就可以触发1个系统调用

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

选拔编制程序接口(application program interface, API)
只是一个函数定义。一般各种系统调用对应2个包裹例程,库再用这一个包裹例程定义出给用户的API。但并不是每一种API都对应1个特定的系统调用,API大概一向提供用户态的劳动,例如有个别数学函数。三个单身的API恐怕调用多少个体系调用,分化的API恐怕调用了同一个系统调用

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

澳门金沙国际 14

第 14-16 行, 准备系统调用参数:第一个参数放进 寄存器 ebx
,第3个参数放进 ecx , 以此类推。

应用程序、封装例程、系统调用处理程序及系统调用服务例程之间的关系

write 系统调用须要 3 个参数:

User Mode 用户态      Kernel Mode 内核态

  • 文件讲述符 ,标准输出文件讲述符为 1 ;
  • 写入内容(缓冲区)地址;
  • 写入内容长度(字节数);

xyz()函数,是系统调用对应的API,那么些应用程序编制程序接口里面封装了三个类别调用,这一个系统调用会触发多个int
0x80的刹车,0x80这个中断向量对应着system_call以此基本代码的源点,那几个基础代码里面会有SAVE_ALL,然后实施到sys_xyz()中断服务程序,进入程序里面处理,在刹车服务程序执行完之后会ret_from_sys_call,在return的经过中大概会发出经过调度(这是三个进程调度的火候),若是没有经过调度,就会iret,回到用户态接着执行

第 17 行,执行 int 指令触发软中断 0x80
,程序将陷入内核态并由基础执行系统调用。
系统调用执行实现后,内核将负责切换回用户态,应用程序继续执行之后的一声令下(
从 20 行开端 )。

Summary

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

系统调用的三层皮:API、中断向量对应的system_call、中断服务程序sys_xyz

注解
瞩目到,那里不可不显式调用 exit 系统调用退出程序。
不然,程序将持续往下实施,最后蒙受段错误( segmentation fault )!

读者或然很奇异——作者在写 C 语言依旧其余程序时,这些调用并不是必须的!

那是因为 C 库( libc )已经帮你把脏活累活都干了。

当用户态进度调用1个连串调用时,CPU切换来内核态并初叶实践二个内核函数,在Linux中是透过进行int
$0x80
来推行系统调用的,那条汇编指令发出向量为128的编制程序卓殊。(IntelPentium II中引入了sysenter指令(火速系统调用),2.6业已支撑)

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

水源完毕了见惯不惊不等的系统调用,进度必须指明必要哪些系统调用,那供给传递1个名为系统调用号的参数,使用eax寄存器(系统调用号将xyz()和sys_xyz()关联起来了)

$ 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 函数吧!

系统调用的参数传递方法

hello_world-syscall.c

平常函数调用的时候,能够选取把参数压栈的点子传递参数。不过从用户态到内核态,怎么传递参数呢?

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

system_call是linux中有所系统调用的入口点,每一个系统调用至少有3个参数,即由eax传递的连串调用号

你恐怕感兴趣的稿子:

  • Python下调用Linux的Shell命令的不二法门
  • 采纳Golang怎样调用Linux命令详解
  • Linux makefile
    和shell文件相互调用实例详解
  • 浅谈在linux
    kernel中打字与印刷函数调用的仓库的艺术
  • 详解Linux驱动中,probe函数什么时候被调用
  • 三种方法达成Linux系统调用
  • 举例来说讲解Linux系统下Python调用系统Shell的法子
  • Python在Windows和在Linux下调用动态链接库的学科
  • Linux下编写Lua扩张so文件和调用方法实例
  • Linux下行使python调用top命令获得CPU利用率
  • Java调用linux
    shell脚本的办法

二个应用程序调用fork()封装例程,那么在推行int
$0x80事先就把eax寄存器的值置为2(即__NR_fork)
那些寄存器的安装是libc库中的封装例程实行的,因而用户一般不关怀系统调用号
进入sys_call之后,立时将eax的值压入内核堆栈

寄存器传递参数具有如下限制:
1)每种参数的尺寸不可能跨越寄存器的尺寸,即33位
2)在系统调用号(eax)之外,参数的个数无法超越五个(ebx,
ecx,edx,esi,edi,ebp)
抢先四个怎么做?

要是当先伍个,就把某一个寄存器作为八个指针,指向一块内部存储器,进入到内核态之后方可访问到独具的地方空间,通过内部存款和储蓄器来传递参数

由此库函数API使用系统调用获取系统当下时光

澳门金沙国际 15

透过库函数API使用系统调用获取系统当下时刻

用汇编格局触发系统调用获取系统当下时光

澳门金沙国际 16

用汇编方式触发系统调用获取系统当下时刻

系统调用传递第四个参数使用ebx,那里是NULL
行使eax传递系统调用号,那里time是13
系统调用的重返值使用eax存款和储蓄,和平日函数一样

(完)

相关文章