我是靠谱客的博主 复杂歌曲,这篇文章主要介绍Linux下C库函数到系统调用函数到内核函数调用的过程,现在分享给大家,希望可以做个参考。

当我们在shell写入一个程序的时候

复制代码
1
2
#include <stdio.h>

此处调用了stdio.h的C标准库,他是存在在glibc中的库函数,他里面通过一些预处理最终会调用系统调用函数,其中,系统调用函数一般是放在

复制代码
1
2
#include <unistd.h>

当然,我们也可以直接写一个系统调用函数调用内核函数

复制代码
1
2
ssize_t write(int fd, const void *buf, size_t count);
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/************************************************************************* > File Name: hello.c > Author: liuhao > Mail: 2226958871@qq.com > Created Time: Sat 19 Jun 2021 11:02:59 AM CST ************************************************************************/ #include<stdio.h> #include <unistd.h> int main() { printf("Hello Worldn"); write(1, "Hello Worldn", 20); return 0; }
复制代码
1
2
3
4
➜ C ./a.out Hello World Hello World

以write为例,系统调用函数和内核函数有一个接口来调用内核函数sys_write,该方法会直接调用硬件(比如write,会直接写入到屏幕上进行显示)

  • open: 打开文件或设备
  • read: 从打开的文件或设备中读取数据
  • write: 向打开的文件或设备中写入数据
  • close:关闭文件或者设备
  • ioctl:把控制信息传递给设备驱动文件

具体执行讲解可见ELF可执行文件执行全过程

复制代码
1
2
strace ./a.out
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
execve("./a.out", ["./a.out"], 0x7fffc106e0d0 /* 27 vars */) = 0 brk(NULL) = 0x564fe1e53000 arch_prctl(0x3001 /* ARCH_??? */, 0x7fff87737bd0) = -1 EINVAL (Invalid argument) access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory) openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3 fstat(3, {st_mode=S_IFREG|0644, st_size=102952, ...}) = 0 mmap(NULL, 102952, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f0272e45000 close(3) = 0 openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3 read(3, "177ELF21133>1360q2"..., 832) = 832 pread64(3, "64@@@"..., 784, 64) = 784 pread64(3, "4205GNU230043", 32, 848) = 32 pread64(3, "4243GNUt233222%2742603203133132610204276X>263"..., 68, 880) = 68 fstat(3, {st_mode=S_IFREG|0755, st_size=2029224, ...}) = 0 mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f0272e43000 pread64(3, "64@@@"..., 784, 64) = 784 pread64(3, "4205GNU230043", 32, 848) = 32 pread64(3, "4243GNUt233222%2742603203133132610204276X>263"..., 68, 880) = 68 mmap(NULL, 2036952, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f0272c51000 mprotect(0x7f0272c76000, 1847296, PROT_NONE) = 0 mmap(0x7f0272c76000, 1540096, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x25000) = 0x7f0272c76000 mmap(0x7f0272dee000, 303104, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x19d000) = 0x7f0272dee000 mmap(0x7f0272e39000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1e7000) = 0x7f0272e39000 mmap(0x7f0272e3f000, 13528, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f0272e3f000 close(3) = 0 arch_prctl(ARCH_SET_FS, 0x7f0272e44540) = 0 mprotect(0x7f0272e39000, 12288, PROT_READ) = 0 mprotect(0x564fe0654000, 4096, PROT_READ) = 0 mprotect(0x7f0272e8c000, 4096, PROT_READ) = 0 munmap(0x7f0272e45000, 102952) = 0 fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(0x88, 0), ...}) = 0 brk(NULL) = 0x564fe1e53000 brk(0x564fe1e74000) = 0x564fe1e74000 write(1, "Hello Worldn", 12Hello World ) = 12 exit_group(0) = ? +++ exited with 0 +++

其中的第一个系统调用函数execve

复制代码
1
2
int execve(const char *pathname, char *const argv[], char *const envp[]);

进入内核态执行sys_execve检查argv和envp、do_execve读入目标镜像文件、search_binary_handler搜索处理该二进制文件的队列、load_elf_binary检查elf文件架构并分配内存、没有动态链接库直接执行/有动态链接库进行链接write,_再次进入系统调用sys_write、把字符串写到屏幕上的进程进行等待、执行程序

最后

以上就是复杂歌曲最近收集整理的关于Linux下C库函数到系统调用函数到内核函数调用的过程的全部内容,更多相关Linux下C库函数到系统调用函数到内核函数调用内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(88)

评论列表共有 0 条评论

立即
投稿
返回
顶部