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

概述

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

#include <stdio.h>

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

#include <unistd.h>

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

ssize_t write(int fd, const void *buf, size_t count);
/*************************************************************************
	> 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;
}
➜  C ./a.out
Hello World
Hello World

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

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

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

strace ./a.out
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

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库函数到系统调用函数到内核函数调用的过程所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

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

评论列表共有 0 条评论

立即
投稿
返回
顶部