当前位置: 技术问答>linux和unix
问:系统调用的原理,一个C函数的系统调用是怎样进入到系统的?
来源: 互联网 发布时间:2015-08-31
本文导语: 最近学习操作系统,了解到操作系统很大一部分可以说是由其提供的系统调用组成。 以前学微机原理时只知道Dos下系统调用int 21h等中断进入到系统的代码,这样系统通过中断向用户程序开放了功能调用。 而到了现...
最近学习操作系统,了解到操作系统很大一部分可以说是由其提供的系统调用组成。
以前学微机原理时只知道Dos下系统调用int 21h等中断进入到系统的代码,这样系统通过中断向用户程序开放了功能调用。
而到了现代这个时代,不管是Linux还是Windows,系统调用好像都是通过一系列的C库函数提供的。依据我对C语言的理解,编写好的程序总要链接成一个可执行文件。最近我又了解到Linux内核编译后,所有提供系统调用功能的函数应该都是链接到一个内核映像文件里,然后由引导器加载然后执行的。然后由引导器加载然后执行的。
那么,通过 C 函数来调用的系统功能,是如何进入到系统的?我的程序显然不是和内核链接在一起的。好像这也不像通常那样的动态链接呀?动态链接又是怎么实现的?
谢谢各位老大!
以前学微机原理时只知道Dos下系统调用int 21h等中断进入到系统的代码,这样系统通过中断向用户程序开放了功能调用。
而到了现代这个时代,不管是Linux还是Windows,系统调用好像都是通过一系列的C库函数提供的。依据我对C语言的理解,编写好的程序总要链接成一个可执行文件。最近我又了解到Linux内核编译后,所有提供系统调用功能的函数应该都是链接到一个内核映像文件里,然后由引导器加载然后执行的。然后由引导器加载然后执行的。
那么,通过 C 函数来调用的系统功能,是如何进入到系统的?我的程序显然不是和内核链接在一起的。好像这也不像通常那样的动态链接呀?动态链接又是怎么实现的?
谢谢各位老大!
|
内核模块是和内核代码连接到一起运行的,并且和内核代码有一样的CPU运行级别所以可以不通过系统调用就直接访问内核空间的内容。如果用户空间要访问这部分代码同样要通过系统调用这个门来进行。
用C/C++等语言编程的时候你虽然没有直接用到int 80h来进行系统调用但是你调用的一些函数编译以后也是编程int 80h,只是你直接看不到而已。
动态连接是一个用户空间的概念,不同的系统有自己不同的可执行文件格式,Linux使用的是elf格式的可执行文件,动态连接只是把多个符合格式的文件在需要的时候加载到用户空间内存,然后把那段地址空间映射到需要调用它的进程空间中。这样用到动态库的进程就可以顺利的访问了。
PS:DOS操作系统提供的21h中断其实不是现在意义上的系统调用,而只是一个函数的入口表而已,因为DOS并没有用户空间的概念,它是一个运行的实模式下的系统。
用C/C++等语言编程的时候你虽然没有直接用到int 80h来进行系统调用但是你调用的一些函数编译以后也是编程int 80h,只是你直接看不到而已。
动态连接是一个用户空间的概念,不同的系统有自己不同的可执行文件格式,Linux使用的是elf格式的可执行文件,动态连接只是把多个符合格式的文件在需要的时候加载到用户空间内存,然后把那段地址空间映射到需要调用它的进程空间中。这样用到动态库的进程就可以顺利的访问了。
PS:DOS操作系统提供的21h中断其实不是现在意义上的系统调用,而只是一个函数的入口表而已,因为DOS并没有用户空间的概念,它是一个运行的实模式下的系统。
|
这个应该随着c标准库的不同而不同的吧。下面以getuid()在glibc中的实现为例:
在glibc中定义了__getuid(),然后给__getuid()去了一个别名叫getuid()。__getuid()会调用INTERNAL_SYSCALL (getuid32, err, 0)这个宏,这个宏的主要是一段汇编代码:
define INTERNAL_SYSCALL(name, err, nr, args...)
({
unsigned int resultvar;
asm volatile (
LOADARGS_##nr
"movl %1, %%eaxnt"
"int $0x80nt"
RESTOREARGS_##nr
: "=a" (resultvar)
: "i" (__NR_##name) ASMFMT_##nr(args) : "memory", "cc");
(int) resultvar; })
不过这段我也看得不是很懂,大概的意思就是用movl把__NR_getuid32这个值(对于上面的getuid来说)移到eax寄存器中,然后执行int $0x80陷入到系统调用中,再具体的过程就应该要看一下linux的系统调用的实现。
这段代码具体是做了什么还是请哪位大牛说一下
在glibc中定义了__getuid(),然后给__getuid()去了一个别名叫getuid()。__getuid()会调用INTERNAL_SYSCALL (getuid32, err, 0)这个宏,这个宏的主要是一段汇编代码:
define INTERNAL_SYSCALL(name, err, nr, args...)
({
unsigned int resultvar;
asm volatile (
LOADARGS_##nr
"movl %1, %%eaxnt"
"int $0x80nt"
RESTOREARGS_##nr
: "=a" (resultvar)
: "i" (__NR_##name) ASMFMT_##nr(args) : "memory", "cc");
(int) resultvar; })
不过这段我也看得不是很懂,大概的意思就是用movl把__NR_getuid32这个值(对于上面的getuid来说)移到eax寄存器中,然后执行int $0x80陷入到系统调用中,再具体的过程就应该要看一下linux的系统调用的实现。
这段代码具体是做了什么还是请哪位大牛说一下
|
用户态的进程通过系统调用进入核心态,就是通过80h中断