专栏首页编程修养Linux 库函数与系统调用

Linux 库函数与系统调用

上周总结了《C 标准库的基础 IO》,其实这些功能函数通过「系统调用」也能实现相应功能。这次文章并不是要详细介绍各系统调用接口的使用方法,而是要深入理解「库函数」与「系统」调用之间的关系和区别。

一、系统调用

系统调用,我们可以理解是操作系统为用户提供的一系列操作的接口(API),这些接口提供了对系统硬件设备功能的操作。这么说可能会比较抽象,举个例子,我们最熟悉的 hello world 程序会在屏幕上打印出信息。程序中调用了 printf() 函数,而库函数 printf 本质上是调用了系统调用 write() 函数,实现了终端信息的打印功能。

二、库函数

库函数可以理解为是对系统调用的一层封装。系统调用作为内核提供给用户程序的接口,它的执行效率是比较高效而精简的,但有时我们需要对获取的信息进行更复杂的处理,或更人性化的需要,我们把这些处理过程封装成一个函数再提供给程序员,更方便于程序猿编码。

库函数有可能包含有一个系统调用,有可能有好几个系统调用,当然也有可能没有系统调用,比如有些操作不需要涉及内核的功能。可以参考下图来理解库函数与系统调用的关系。

三、系统调用意义

  • 避免了用户直接对底层硬件进行编程。比如最简单的hello world程序是将信息打印到终端,终端对系统来说是硬件资源,如果没有系统调用,用户程序需要自己编写终端设备的驱动,以及控制终端如何显示的代码。
  • 隐藏背后的技术细节。比如读写文件,如果使用了系统调用,用户程序无须关心数据在磁盘的哪个磁道和扇区,以及数据要加载到内存什么位置。
  • 保证系统的安全性和稳定性。要知道用户程序是不能直接操作内核地址空间的,比如一个刚出道的程序猿,让他直接去访问内核底层的数据,那么内核系统的安全性就无法保证。而系统调用的功能是由内核来实现,用户只需要调用接口,无需关心细节,也避免了系统的安全隐患。
  • 方便程序的移植性。如果针对一个系统资源的功能操作比如 write(),大家都按照自己思路去实现这个功能,那么我们写出来的程序的移植性就会非常差。

总而言之,我们只需要把系统调用当作一个接口,而这个接口能实现我们的一个功能,既方便又安全。

四、库函数 vs 系统调用

参考了《C 专家编程》书籍中的附录 A.4,书中关于两者区别的回答是这样的,函数库调用是语言或应用程序的一部分,而系统调用是操作系统的一部分。

  • 所有 C 函数库是相同的,而各个操作系统的系统调用是不同的。
  • 函数库调用是调用函数库中的一个程序,而系统调用是调用系统内核的服务。
  • 函数库调用是与用户程序相联系,而系统调用是操作系统的一个进入点
  • 函数库调用是在用户地址空间执行,而系统调用是在内核地址空间执行
  • 函数库调用的运行时间属于「用户」时间,而系统调用的运行时间属于「系统」时间
  • 函数库调用属于过程调用,开销较小,而系统调用需要切换到内核上下文环境然后切换回来,开销较大
  • 在C函数库libc中大约 300 个程序,在 UNIX 中大约有 90 个系统调用
  • 函数库典型的 C 函数:system, fprintf, malloc,而典型的系统调用:chdir, fork, write, brk

据书中记载,库函数调用大概花费时间为半微妙,而系统调用所需要的时间大约是库函数调用的 70 倍(35微秒),因为系统调用会有内核上下文切换的开销。纯粹从性能上考虑,你应该尽可能地减少系统调用的数量,但是,你必须记住许多 C 函数库中的程序通过系统调用来实现功能。

五、正确理解库函数高效于系统调用

首先解释,上述说明的库函数性能远高于系统调用的前提是,库函数种没有使用系统调用。再来解释下某些包含系统调用的库函数,然而其性能确实也要高于系统调用。比如上篇文章中关于文件 IO 函数 fread、fwrite、fputc、fgetc 等,这些函数通常情况下性能确实比系统调用高,原因在于这些库函数使用了缓冲区,减少了系统调用的次数,因而显得性能比较高。

六、系统调用是如何运行的

上述内容基本说清楚了库函数与系统调用的概念以及它们之间的关系,下面我们来理解系统调用到底是如何运行的。

当一个进程正在运行,遇到读写文件操作,会发生一个中断,中断后系统会把当前用户进程的一些寄存器信息保存在内核堆栈中,接着去处理中断服务程序,这里是要去执行系统调用,Linux 中通过执行 int $0x80 来执行系统调用的中断,但内核实现了很多系统调用,这时需要传递「系统调用号」来指明需要哪个系统调用。

为了更清楚的说明系统调用的过程,我们这里参考网上的一段代码来实现系统调用:

int main()
{
   time_t tt;
   struct tm *t;
   asm volatile (        
        "mov $0,%%ebx\n\t"
       "mov $0xd,%%eax\n\t"
       "int $0x80\n\t"
       "mov %%eax,%0\n\t"
       : "=m" (tt)
   );  
   t = localtime(&tt);    
    printf("Time: %d-%02d-%02d %02d:%02d:%02d\n",
          t->tm_year + 1900,
          t->tm_mon + 1, t->tm_mday,
          t->tm_hour, t->tm_min, t->tm_sec);
}[linuxblogs@host ~]$ gcc a.c -oa && ./a
Time: 2018-05-06 03:23:46

首先通过 mov 0xd %%eax 来将系统调用放入 %eax 寄存器中,time() 的系统调用号是 13,然后执行 int 0x80 系统就会去执行 time() 这个系统调用了。其实代码中的汇编部分就是实现 time() 系统调用的功能,汇编代码不懂没关系(我也不太懂),这里主要是为了说清楚系统调用的整个过程。

本文分享自微信公众号 - 编程修养(chopin11vip),作者:肖邦

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2018-05-07

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 系统调用和库函数的区别

    从用户的角度来看,系统调用和库函数似乎没有什么区别,它们都是以C函数的形式出现,并且两者都为应用程序提供服务。但从实现者角度来看,它们之间是有根本的区别。那么,...

    编程珠玑
  • Linux系统下C++标准库函数

    函数名作用isalnum()测试字符是否为英文字母或数字isalpha()测试字符是否为英文字母isascii()测试字符是否为ASCII码字符isblank(...

    用户7886150
  • Linux 系统与数据库安全

    Linux 系统与数据库安全 目录 1. 帐号安全 1.1. Shell 安全 1.2. .history 文件 2. 临时文件安全 3. 其他安全问题 4. ...

    netkiller old
  • Linux 系统与数据库安全

    Linux 系统与数据库安全 目录 1. 帐号安全 1.1. Shell 安全 1.2. .history 文件 2. 临时文件安全 3. 其他安全问题 4. ...

    netkiller old
  • Linux 系统与数据库安全

    目录 1. 帐号安全 1.1. Shell 安全 1.2. .history 文件 2. 临时文件安全 3. 其他安全问题 4. 防火墙配置 5. 数据库安全 ...

    netkiller old
  • 使用Excel调用ABAP系统的函数

    效果:在excel里创建一个按钮,开发一些VB script,可以连接指定的ABAP系统并执行系统里的ABAP function module。

    Jerry Wang
  • 使用Excel调用ABAP系统的函数

    效果:在excel里创建一个按钮,开发一些VB script,可以连接指定的ABAP系统并执行系统里的ABAP function module。

    Jerry Wang
  • 调用MKL函数库

    MKL是Intel公司出品的数学函数库,有C和Fortran接口。它集成BLAS, LAPACK 和 ScalLAPACK 等函数库。其中,Lapack 包含了...

    fem178
  • linux系统参数调优

    执行 ulimit -a 查看系统配置 需要修改max user processes 和 open files 这两个值 vim /etc/sec...

    千往
  • linux系统编程之基础必备(二):C 标准IO 库函数与Unbuffered IO函数

    先来看看C标准I/O库函数是如何用系统调用实现的。  fopen(3)  调用open(2)打开指定的文件,返回一个文件描述符(就是一个int 类型的编号),...

    s1mba
  • Linux系统调用过程

    1 系统调用的作用 系统调用是操作系统提供给用户(应用程序)的一组接口,每个系统调用都有一个对应的系统调用函数来完成相应的工作。用户通过这个接口向操作系统申请服...

    233333
  • Linux系统调用原理

    系统调用 跟用户自定义函数一样也是一个函数,不同的是 系统调用 运行在内核态,而用户自定义函数运行在用户态。由于某些指令(如设置时钟、关闭/打开中断和I/O操作...

    用户7686797
  • Linux系统下virtuoso数据库安装与使用详解

    最近在调研关联数据的一些东西,需要用到rdf数据库,所以接触了virtuoso数据库。安装的坑其实并不多,之前在windows 10上安过一次。这次在ubunt...

    砸漏
  • Linux系统下virtuoso数据库安装与使用详解

    最近在调研关联数据的一些东西,需要用到rdf数据库,所以接触了virtuoso数据库。安装的坑其实并不多,之前在windows 10上安过一次。这次在ubunt...

    砸漏
  • 深入iOS系统底层之函数调用

    可执行程序是为了实现某个功能而由不同机器指令按特定规则进行组合排列的集合。无论高级还是低级程序语言,无论是面向对象还是面向过程的语言最终的代码都会转化为一条条机...

    欧阳大哥2013
  • 60秒问答:系统调用之send函数

    今天上午 回顾了 TCP/IP编程之select函数详解 ,发现还有问题。进行总结

    程序员小王
  • python调用linux系统命令

    py3study
  • Linux系统编程:基本I/O系统调用

    Tencent JCoder
  • iOS使用UIImagePickerController调用系统相机、相册与图库

            UIImagePickerController是系统封装好的一个导航视图控制器,使用其开发者可以十分方便的进行相机相册相关功能的调用。UIIma...

    珲少

扫码关注云+社区

领取腾讯云代金券