加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

系统调用API,系统调用指令和异常机制(中断)之间的关系

发布时间:2020-12-16 10:37:53 所属栏目:百科 来源:网络整理
导读:我试图理解C语言系统调用API,系统调用汇编程序指令和用于在进程之间切换上下文的异常机制(中断)之间的关系.我自己要研究很多,所以请耐心等待. 我的理解是正确的,C语言系统调用是由编译器作为系统调用实现的,其中各自的代码在汇编中,而这些代码又由OS实现为异
我试图理解C语言系统调用API,系统调用汇编程序指令和用于在进程之间切换上下文的异常机制(中断)之间的关系.我自己要研究很多,所以请耐心等待.

我的理解是正确的,C语言系统调用是由编译器作为系统调用实现的,其中各自的代码在汇编中,而这些代码又由OS实现为异常机制(中断)?

所以在以下C代码中调用write函数:

#include <unistd.h>

int main(void)
{
    write(2,"There was an error writing to standard outn",44);
    return 0;
}

作为系统调用指令编译为程序集:

mov eax,4       ; system call number (sys_write)
syscall

反过来,指令由OS实现为异常机制(中断)?

解决方法

TL; DR

syscall指令本身就像一个美化的跳跃,它是一种硬件支持的方式,可以有效,安全地从无特权的用户空间跳转到内核.
syscall指令跳转到调度调用的内核入口点.

在x86_64之前,使用了另外两种机制:int指令和sysenter指令.
它们具有不同的入口点(目前仍然存在于32位内核中,以及可以运行32位用户空间程序的64位内核).
前者使用x86中断机制,可以与异常调度混淆(也使用中断机制).
但是,异常是虚假事件,而int用于生成软件中断,同样是一个美化的跳跃.

C语言不涉及系统调用,它依赖于the C runtime来执行与未来程序环境的所有交互.

C运行时通过特定于环境的机制实现上述交互.
可能存在各种层次的软件抽象,但最终会调用OS API.

术语API用于表示合同,严格来说使用API??不需要调用一段内核代码(趋势是在用户空间中实现非关键功能以限制可利用的代码),这里我们只对此感兴趣在需要权限切换的API子集中.

在Linux下,内核公开了一组可从用户空间访问的服务,这些入口点称为system calls.
在Windows下,内核服务(使用与Linux类似物相同的机制访问)被认为是私有的,因为它们不需要在不同版本之间保持稳定.
一组DLL / EXE导出函数用作入口点(例如ntoskrnl.exe,hal.dll,kernel32.dll,user32.dll),后者又通过(私有)系统调用使用内核服务.
请注意,在Linux下,大多数系统调用都有一个POSIX包装器,因此可以使用这些包装器(即普通的C函数)来调用系统调用.
底层ABI是不同的,错误报告也是如此;包装器在两个世界之间进行转换.

C运行时调用OS API,在Linux的情况下,系统调用是直接使用的,因为它们是公共的(在某种意义上,在各个版本中是稳定的),而对于Windows,通常的DLL,如kernel32.dll,被标记为依赖项和使用.

我们被简化到一个用户模式程序,它是C运行时(Linux)的一部分或API DLL(Windows)的一部分,需要调用内核中的代码.

x86架构历史上提供了不同的方法,例如,call gate.
另一种方法是通过int指令,它有一些优点:

>这是BIOS和DOS在他们的时代所做的.
在实模式中,使用int指令是合适的,因为向量数(例如21h)比远地址(例如0f000h:0fff0h)更容易记忆.
>它保存标志.
>设置简单(设置ISR相对容易).

随着架构的现代化,这种机制变得有一个很大的缺点:它很慢.
在引入sysenter(注意,sysenter而不是syscall)指令之前,没有更快的替代方法(调用门同样会很慢).

随着Pentium Pro / II[1]的出现,引入了一对新的指令sysenter和sysexit,以便更快地进行系统调用.
Linux开始使用它们since the version 2.5,我相信它现在仍在32位系统上使用.
我不会解释sysenter指令的整个机制以及使用它所需的伴侣VDSO,只需要说它比int机制更快(我找不到Andy Glew的文章,他说那个sysenter在奔腾III上变得很慢,我不知道它现在的表现如何).

随着x86-64的出现,AMD对sysenter的响应,即syscall / sysret对,开始了从用户模式切换到内核模式的事实上的方式.
这是因为sysenter实际上很快且非常简单(它分别将rip和rflags复制到rcx和r11,屏蔽rflags并跳转到IA32_LSTAR中设置的地址).

Linux和Windows的64位版本都使用系统调用.

总结一下,可以通过三种机制给内核控制:

>软件中断.
对于32位Linux(2.5之前的版本),这是int 80h,对于32位Windows,这是int 2eh.
>通过sysenter.
自2.5以来由32位版本的Linux使用.
>通过系统调用.
由64位版本的Linux和Windows使用.

Here is a nice page to put it in a better shape.

C运行时通常是一个静态库,因此是预编译的,它使用上述三种方法之一.

syscall instruction直接将控制权转移到内核入口点(见entry_64.s).
它是一个只是这样做的指令,它不是由OS实现的,而是由OS使用.

术语异常在CS中重载,C有异常,Java和C#也是如此.
操作系统可以有一个与语言无关的异常捕获机制(在windows下它曾经被称为SEH,现在已被重写).
CPU也有例外.
我相信我们正在谈论最后的意义.

异常是通过中断发送的,它们是一种中断.
它没有说明,虽然异常是同步的(它们发生在特定的,可重放的点)它们是“不需要的”,但它们是特殊的,因为程序员倾向于避免它们,当它们发生时是由于一个bug,一个未处理的角落情况或糟糕的情况.
因此,它们不用于将控制转移到内核(它们可以).

使用软件中断(也是同步的);机制几乎完全相同(异常可以在内核堆栈上推送状态代码)但语义不同.我们从不引用空指针,访问未映射的页面或类似的方法来调用系统调用,我们使用int指令代替.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读