目录

  • man查看类型
    • 基础说明
    • glibc库函数的范例
    • 系统调用的范例
  • 系统调用查看
    • 查看内核代码的方法
    • 内核中的系统调用函数的查找方法
    • 范例一:socket的系统调用
    • 范例二:kill的系统调用实现
  • glibc库文件源码查看
    • glibc版本查看
    • 源码查看
  • 参考

man查看类型

基础说明

man man

如上所示:

  • 左上角有1表示为linux命令/可执行文件;
  • 左上角有2表示为系统调用(内核提供);
  • 左上角有3表示为库函数(一般为glibc提供);

glibc库函数的范例

man 3 printf
man 3 printf 表示直接看printf的库函数;如果man printf,则默认是printf(1),即printf命令;如下所示:


如上所示:

  • 左上角的3表示是库函数;
  • <stdio.h> 以及 <stdlib.h> 头文件也说明是库函数;

系统调用的范例

man getpid

如上所示:

  • 函数什么在头文件 <sys/types.h> 中,说明是系统调用;
  • 左上角的getpid(2)中的2也说明是系统调用;

系统调用查看

系统调用的函数实现,一般是在内核中实现。

查看内核代码的方法

  • 下载对应内核版本(uname -r)的代码进行查看;
    【https://github.com/torvalds/linux : github linux 代码】
  • 选择对应的内核版本,在线查看、搜索源码
    【https://elixir.bootlin.com/linux/v4.18/C/ident/ : 在线查看、搜索源码】

    如上所示,还可以在线查看dpdk, glibc等的源码;

内核中的系统调用函数的查找方法

  • Tips 1: 用户空间的方法xxx,对应系统调用层方法则是sys_xxx;
  • Tips 2: unistd.h文件记录着系统调用中断号的信息。
    故用户空间kill方法则对应系统调用层便是sys_kill,这个方法去哪里找呢?从/kernel/include/uapi/asm-generic/unistd.h等还有很多unistd.h去慢慢查看,查看关键字sys_kill,便能看到下面几行:

    /* kernel/signal.c */
    __SYSCALL(__NR_kill, sys_kill)
    

    根据这个能得到一丝线索,那就是kill对应的方法sys_kill位于/kernel/signal.c文件。

  • Tips 3: 宏定义SYSCALL_DEFINEx(xxx,…),展开后对应的方法则是sys_xxx;
    SYSCALL_DEFINEx 中的 x 表示系统调用的参数个数;
    比如 SYSCALL_DEFINE, SYSCALL_DEFINE1, SYSCALL_DEFINE2;

实用技巧
根据参数个数,以及系统调用的名称,直接搜索即可,比如 kill 函数,存在2个参数,直接搜索:SYSCALL_DEFINE2(kill, 即可直接找到。


如上所示:如果是在线搜索,则直接基于SYSCALL_DEFINE2(kill,来进行搜索,则搜索不到,因为没有这样的标签,且不能基于字符串来搜索。
此时的方法为:
1.先查看kill的man定义,判断可能的函数定义位于哪个文件。此中猜测在signal.c文件中;
2.基于SYSCALL_DEFINE2来搜索,然后过滤signal文件;
3.进入到signal.c文件中,在基于SYSCALL_DEFINE2(kill来过滤。

SYSCALL_DEFINE的定义,如下:

#define SYSCALL_DEFINE0(name)       asmlinkage long sys_##name(void)
#define SYSCALL_DEFINE1(name, ...) SYSCALL_DEFINEx(1, _##name, __VA_ARGS__)
#define SYSCALL_DEFINE2(name, ...) SYSCALL_DEFINEx(2, _##name, __VA_ARGS__)
#define SYSCALL_DEFINE3(name, ...) SYSCALL_DEFINEx(3, _##name, __VA_ARGS__)
#define SYSCALL_DEFINE4(name, ...) SYSCALL_DEFINEx(4, _##name, __VA_ARGS__)
#define SYSCALL_DEFINE5(name, ...) SYSCALL_DEFINEx(5, _##name, __VA_ARGS__)
#define SYSCALL_DEFINE6(name, ...) SYSCALL_DEFINEx(6, _##name, __VA_ARGS__)#define SYSCALL_DEFINEx(x, name, ...)                    \asmlinkage long sys##name(__SC_DECL##x(__VA_ARGS__));      \static inline long SYSC##name(__SC_DECL##x(__VA_ARGS__));  \asmlinkage long SyS##name(__SC_LONG##x(__VA_ARGS__))       \{                              \__SC_TEST##x(__VA_ARGS__);             \return (long) SYSC##name(__SC_CAST##x(__VA_ARGS__));   \}                              \SYSCALL_ALIAS(sys##name, SyS##name);               \static inline long SYSC##name(__SC_DECL##x(__VA_ARGS__))##: 表示连接字符串;
__VA_ARGS__代表前面...里面的可变参数

范例一:socket的系统调用

原形:int socket(int domain, int type, int protocol);
存在3个参数,SYSCALL_DEFINEx里面的x代表的是系统调用参数个数;
所以为:
SYSCALL_DEFINE3(socket, int, family, int, type, int, protocol)展开为:
SYSCALL_DEFINEx(3, _socket,  int, family, int, type, int, protocol)再次展开为:
asmlinkage long sys_socket(__SC_DECL3(int, family, int, type, int, protocol));      \static inline long SYSC_socket(__SC_DECL3(int, family, int, type, int, protocol)); \asmlinkage long SyS_socket(__SC_LONG3(int, family, int, type, int, protocol))      \{                              \__SC_TEST3(int, family, int, type, int, protocol);             \return (long) SYSC_socket(__SC_CAST3(int, family, int, type, int, protocol));  \}                              \SYSCALL_ALIAS(sys_socket, SyS_socket);             \static inline long SYSC_sockt(__SC_DECL3(int, family, int, type, int, protocol))第一行熟悉的sys_socket了。这只是一个函数声明,不是定义;
定义其实在最后一行,结尾没有加分号,下面再加上一对大括号,就是定义。

范例二:kill的系统调用实现

kill 函数的系统调用:kernel/signal.c
SYSCALL_DEFINE2(kill, pid_t, pid, int, sig)
{struct siginfo info;clear_siginfo(&info);info.si_signo = sig;info.si_errno = 0;info.si_code = SI_USER;info.si_pid = task_tgid_vnr(current);info.si_uid = from_kuid_munged(current_user_ns(), current_uid());return kill_something_info(sig, &info, pid);
}

glibc库文件源码查看

glibc版本查看

  • 方法一:ldd --version
  • 方法二:通过 libc.so 获取版本号
  1. 首先查找到 libc 库的位置
    如何找到 GLIBC 库, 有多种方法:
方法一: ldd 一个当前系统中 C 库编写的动态可执行程序;
ldd `which top` | grep "libc.so"libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f6e32226000)方法二:从正在运行的程序,查看其打开的文件中查看;lsof -p $$  | grep "libc-"方法三:GNU_LIBC_VERSION
标记 GLIBC 版本号的变量为 GNU_LIBC_VERSION, 直接查看它即可;
#getconf GNU_LIBC_VERSION
glibc 2.17方法四:函数中获取glibc版本信息;
gnu_get_libc_version 和 gnu_get_libc_release 就是这样的内置信息,
我们可以通过 man 手册来获取详细信息.方法五:查看发行版安装包版本
发行版打包的软件包一般都是有版本号后缀的,
因此查看我们发行版安装的 GLIBC 包的名字, 就可以知道版本号.
Centos 可以使用 rpm -q glibc / yum list installed |grep glibc
查看对应软件包的名称及版本.

源码查看

  • 方法一:下载源码查看
    【https://www.jianshu.com/p/939a5137222c:glibc源码下载】
    【https://ftp.wayne.edu/gnu/libc/ : 清华大学开源网站,包含很多包,比如glibc, gcc, gdb 等等】
  • 方法二:线上源码查看
    【https://elixir.bootlin.com/glibc/latest/A/ident/sprintf :glibc源码查看】

参考

https://blog.csdn.net/gatieme/article/details/108945425 (glibc版本查看)
http://gityuan.com/2016/05/21/syscall/ (如何在内核代码中查找系统调用函数1)
https://blog.csdn.net/hxmhyp/article/details/22699669 (如何在内核代码中查找系统调用函数2)

Linux-C中libc函数以及系统调用函数查看相关推荐

  1. 十三、linux编程中目录IO常用编程函数

    概念: 索引节点,Inode是Index Node的缩写,存储于文件系统上的任何文件都可以用索引节点来表示,所以也可以说索引节点是整个linux文件系统的基础.操作系统在读取硬盘的时候不是一个块一个块 ...

  2. 操原上机(一) 在Linux系统中增加新的系统调用

    在LINUX中增加新的系统调用 编写新的系统调用函数(指函数实现部分) 注册新的系统调用(声明系统调用函数和编号) 编译新LINUX内核 编译和安装模块 启动新的LINUX内核 编写应用程序测试新的系 ...

  3. linux 打印函数宏,linux内核中的嵌入式汇编宏函数

    在看linux内核代码时,常会遇到诸如:static inline _syscall0(int,fork)这样的函数.经查阅资料,发现该函数是嵌入式汇编宏函数. linux内核提供了7个非常有用的宏定 ...

  4. linux中min函数用法,linux内核中的min、max函数

    这些天为了整理一下前段时间看ldd3时所学的驱动知识,所以就去看了看usb驱动.不看不知道,一看吓一跳,里面有很多语法我发现用的太好了,不像我们平时那样写代码.里面写的代码真是太好了.然而要理解到里面 ...

  5. linux查看运行的程序c pu,在Linux系统中,采用()一命令查看进程输出的信息,得到下图所示的结果。系统启动时最先运行的进程是...

    Routing.protocols use different techniques for assigning[S1]to individual networks.Further,each rout ...

  6. linux 3.5.0-23-generic内核版本系统调用数目,Linux操作系统分析(三)- 更新内核与添加系统调用...

    环境:Ubuntu 12.10     学号:SA****199 1.更新内核: 直接安装的系统内核版本一般不是最新,用 uname -a 查看一下 自己的版本,OK,我的是: Linux chenh ...

  7. 基于Linux系统中进程调度分析

    本文作者(院 浩),请您在阅读本文时尊重作者版权. [摘要]Linux是一个多用户多任务的操作系统,Linux中实现了对多个进程公平.高效的调度,并不是采用单一的调度策略,而是几种调度策略有机地综合应 ...

  8. 如何在linux内核中读写文件

    在VFS的支持下,用户态进程读写任何类型的文件系统都可以使用read和write着两个系统调用,但是在linux内核中没有这样的系统调用我们如何操作文件呢?我们知道read和write在进入内核态之后 ...

  9. Linux内核之旅/张凯捷——系统调用分析(2)

    在<系统调用分析(1)>Linux内核之旅/张凯捷--系统调用分析(1)中,首先介绍了系统调用的概念,并对早期通过软中断(int 80)来进行系统调用的相关过程进行了分析,最后分析和介绍了 ...

最新文章

  1. 图灵九月书讯 ——金秋时节推荐给程序员们的书
  2. java groovy jar包_如何将jar包包含在groovy脚本中?
  3. 深入理解分布式技术 - Paxos 算法解读
  4. Brainfuck解释器(C#)
  5. 10张架构图详解数据中台,附全套数据中台PPT
  6. zabbix自动同步ldap帐号到数据库
  7. 计算机c盘如何扩大,C盘太小怎么办?教你扩大容量!
  8. 儿童时间管理表,让孩子学会善待时间
  9. AspUpload 组件上传 安装方法及其Demo(全)
  10. Linux+v4l2自动设置相机曝光时间
  11. jquery实现回到顶部和回到底部
  12. ubuntu 启动 meld、diffuse失败
  13. centOS7下实践查询版本/CPU/内存/硬盘容量等硬件信息
  14. 发送文件的过程计算机,用电脑给别人传文件的方法步骤图
  15. LTE-TDD随机接入过程(4)-RIV的解析和Preamble资源的选择
  16. 跬智信息(Kyligence)荣获浦东新区人工智能创新应用大赛一等奖
  17. 学习下 BlackHat Asia 2021 大会议题
  18. 计算机没去考 禁考一年,自考报名不去考会禁考吗 弃考有什么影响
  19. idea提示非法字符
  20. 用几何画板怎么画三维坐标轴

热门文章

  1. 闪存浪潮下不得不知的知识(1)-厂商篇
  2. 面经-Bosch博世无锡amp;UL美华
  3. rz后远程服务器没反应,“通过jumpserver远程登录linux服务器,rz上传文件速度过慢”问题的解决...
  4. 2021原创计算机考研全程班辅导
  5. zufeoj_珠心算测验(入门第三关数组)
  6. SUMO 仿真建模--事件模拟
  7. oracle正整数集,Oracle 整理
  8. SimFAS中控iPad控制电脑开关机实现方法
  9. 超越 Nginx,号称下一代 Web 服务器,用起来够优雅~
  10. 阿里云盘的几个资源搜索平台(应有尽有)