系统调用不是用户级程序或共享库的一部分,它们是内核提供的系统服务,并且在内核空间中执行..为了从用户空间移至内核空间,需要执行一些特殊的汇编告诉处理器进入主管模式的指令,在此之前,处理器将要向寄存器中推送一些信息,以便内核侧知道要执行的系统调用-它具有指向各种功能的功能指针表“服务”每个系统调用)-
#include "SYS.h"
ENTRY(syscall)
pop %ecx /* rta */
pop %eax /* syscall number */
push %ecx
KERNCALL
push %ecx /* need to push a word to keep stack frame intact
upon return; the word must be the return address. */
jb 1f
ret
KERNCALL依赖于体系结构,并且是一些汇编语言指令,这些指令告诉CPU在内核空间中跳入超级用户模式-
./lib/libc/amd64/SYS.h:#define KERNCALL movq %rcx,%r10; syscall
./lib/libc/i386/SYS.h:#define KERNCALL int $0x80
这就是问题..编译程序时,优化器有时会将函数的参数扔到寄存器中,而不是将它们放在程序堆栈中..此优化有效,因为编译器同时为调用者和被调用者发出代码因此双方都意识到了这一点小技巧。但是,对于内核不是这样。.它不知道在哪个寄存器中寻找什么,因此所有用于系统调用的参数都必须位于用户界面程序的堆栈中。
,
链接告诉编译器在CPU堆栈上查找功能参数,而不是寄存器
实际上,它使用GCC的regparam属性(Function-Attributes)或IA64使用syscall_linkage
:
#define asmlinkage CPP_ASMLINKAGE __attribute__((regparm(0)))
但是您的问题是为什么这是必要的。系统调用是用户空间可以调用以请求内核为其执行某些操作(因此在内核空间中执行)的服务。这些函数在您不能期望它们像普通函数那样运行的意义上是非常不合常规的,在这些函数中,参数通常是通过写入程序堆栈来传递的,而实际上是写入寄存器的。虽然仍在用户空间中,但调用syscall时需要将某些值写入某些寄存器中。系统呼叫号码将始终以eax写入,而其余参数将输入ebx,ecx等。
现在,当发生软件中断时,CPU切换到内核模式,然后执行system_call()。当CPU切换到内核模式时,首先将所有寄存器保存在CPU堆栈中(eax,ebx,ecx等)。在检查了其他内容(例如验证参数)之后,如果一切正常,它将调用相应的系统调用。因此,因为从用户空间一直传递到此点的所有参数信息都很好地存储在堆栈中,必须指示编译器有关此内容,因此请注意该链接。
另一个原因是,在处理来自用户空间的系统调用请求时,内核无论如何都需要将所有寄存器保存到堆栈中(以便在返回用户空间之前恢复环境),因此在堆栈上可用参数之后,不需要额外的努力。
本文链接:https://www.f2er.com/3147864.html