百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术分析 > 正文

系统调用的实现细节(用户态) 系统调用的主要作用

liebian365 2024-10-27 13:20 23 浏览 0 评论

该文档以一个具体的事例来描述系统调用的细节。本文档的事例在Ubuntu 14.04.4 LTS环境,CPU架构为x86_64,glibc版本为RELEASE = development,VERSION = 2.26.9000。

假如我们写了一个应用程序test.c如下所示:



fork的函数申明在/usr/include/unistd.h头文件中,如下所示:



我们知道gcc会在编译完成test.c后,然后链接libc.so动态库中的fork,所以fork的实现就在glibc代码中,下载glibc源代码,然而glibc中并没有找到fork()的实现。


所以先做一个小实验:编译test.c,然后静态链接libc.a,生成test,然后


反汇编可执行文件test,查看test.s

部分如下内容:



看到main函数实际调用的是__libc_fork。

__libc_fork实现在glibc工程sysdeps/nptl/fork.c路径下,代码略长,此处省略。

但是我们的应用程序调用fork的,是怎么链接到__libc_fork的?在__libc_fork实现下方有如下代码:



__weak_alias实现在glibc工程include/libc-symbols.h路径下,如下:



现在,我们来看看__libc_fork函数,它调用系统功能的代码如下:



可以看出是通过调用ARCH_FROK宏实现调用系统功能的。

该宏在glibc工程sysdeps/unix/sysv/linux/x86_64/arch-fork.h目录下,如下代码所示:



可以看出是通过INLINE_SYSCALL宏调用,传递的参数是clone,该宏在glibc工程sysdeps/unix/sysv/linux/x86_64/sysdep.h头文件定义,与体系结构相关,代码如下:



其中INTERNAL_SYSCALL定义在同文件中,代码如下:



SYS_ify宏定义,代码如下:



__NR_##syscall_name定义在ubuntu系统的/usr/include/x86_64-linux-gnu/asm/unistd_64.h文件中,它是系统调用具体调用系统函数的参数,它是一个编号,比如我们的fork系统调用,它实际通过__NR_clone标号传参,它的定义如下:

#define __NR_clone 56

其中internal_syscall##nr相关的宏在glibc工程sysdeps/unix/sysv/linux/x86_64/sysdep.h定义,如下:

239 #undef internal_syscall0
240 #define internal_syscall0(number, err, dummy...)            \
241 ({                                  \
242     unsigned long int resultvar;                    \
243     asm volatile (                          \
244     "syscall\n\t"                           \
245     : "=a" (resultvar)                          \
246     : "0" (number)                          \
247     : "memory", REGISTERS_CLOBBERED_BY_SYSCALL);            \
248     (long int) resultvar;                       \
249 })
250 
251 #undef internal_syscall1
252 #define internal_syscall1(number, err, arg1)                \
253 ({                                  \
254     unsigned long int resultvar;                    \
255     TYPEFY (arg1, __arg1) = ARGIFY (arg1);              \
256     register TYPEFY (arg1, _a1) asm ("rdi") = __arg1;           \
257     asm volatile (                          \
258     "syscall\n\t"                           \
259     : "=a" (resultvar)                          \
260     : "0" (number), "r" (_a1)                       \
261     : "memory", REGISTERS_CLOBBERED_BY_SYSCALL);            \
262     (long int) resultvar;                       \
263 })
264 
265 #undef internal_syscall2
266 #define internal_syscall2(number, err, arg1, arg2)          \
267 ({                                  \
268     unsigned long int resultvar;                    \
269     TYPEFY (arg2, __arg2) = ARGIFY (arg2);              \
270     TYPEFY (arg1, __arg1) = ARGIFY (arg1);              \
271     register TYPEFY (arg2, _a2) asm ("rsi") = __arg2;           \
272     register TYPEFY (arg1, _a1) asm ("rdi") = __arg1;           \
273     asm volatile (                          \
274     "syscall\n\t"                           \
275     : "=a" (resultvar)                          \
276     : "0" (number), "r" (_a1), "r" (_a2)                \
277     : "memory", REGISTERS_CLOBBERED_BY_SYSCALL);            \
278     (long int) resultvar;                       \
279 })
280
281 #undef internal_syscall3
282 #define internal_syscall3(number, err, arg1, arg2, arg3)        \
283 ({                                  \
284     unsigned long int resultvar;                    \
285     TYPEFY (arg3, __arg3) = ARGIFY (arg3);              \
286     TYPEFY (arg2, __arg2) = ARGIFY (arg2);              \
287     TYPEFY (arg1, __arg1) = ARGIFY (arg1);              \
288     register TYPEFY (arg3, _a3) asm ("rdx") = __arg3;           \
289     register TYPEFY (arg2, _a2) asm ("rsi") = __arg2;           \
290     register TYPEFY (arg1, _a1) asm ("rdi") = __arg1;           \
291     asm volatile (                          \
292     "syscall\n\t"                           \
293     : "=a" (resultvar)                          \
294     : "0" (number), "r" (_a1), "r" (_a2), "r" (_a3)         \
295     : "memory", REGISTERS_CLOBBERED_BY_SYSCALL);            \
296     (long int) resultvar;                       \
297 })
299 #undef internal_syscall4
300 #define internal_syscall4(number, err, arg1, arg2, arg3, arg4)      \
301 ({                                  \
302     unsigned long int resultvar;                    \
303     TYPEFY (arg4, __arg4) = ARGIFY (arg4);              \
304     TYPEFY (arg3, __arg3) = ARGIFY (arg3);              \
305     TYPEFY (arg2, __arg2) = ARGIFY (arg2);              \
306     TYPEFY (arg1, __arg1) = ARGIFY (arg1);              \
307     register TYPEFY (arg4, _a4) asm ("r10") = __arg4;           \
308     register TYPEFY (arg3, _a3) asm ("rdx") = __arg3;           \
309     register TYPEFY (arg2, _a2) asm ("rsi") = __arg2;           \
310     register TYPEFY (arg1, _a1) asm ("rdi") = __arg1;           \
311     asm volatile (                          \
312     "syscall\n\t"                           \
313     : "=a" (resultvar)                          \
314     : "0" (number), "r" (_a1), "r" (_a2), "r" (_a3), "r" (_a4)      \
315     : "memory", REGISTERS_CLOBBERED_BY_SYSCALL);            \
316     (long int) resultvar;                       \
317 })
318 
319 #undef internal_syscall5
320 #define internal_syscall5(number, err, arg1, arg2, arg3, arg4, arg5)    \
321 ({                                  \
322     unsigned long int resultvar;                    \
323     TYPEFY (arg5, __arg5) = ARGIFY (arg5);              \
324     TYPEFY (arg4, __arg4) = ARGIFY (arg4);              \
325     TYPEFY (arg3, __arg3) = ARGIFY (arg3);              \
326     TYPEFY (arg2, __arg2) = ARGIFY (arg2);              \
327     TYPEFY (arg1, __arg1) = ARGIFY (arg1);              \
328     register TYPEFY (arg5, _a5) asm ("r8") = __arg5;            \
329     register TYPEFY (arg4, _a4) asm ("r10") = __arg4;           \
330     register TYPEFY (arg3, _a3) asm ("rdx") = __arg3;           \
331     register TYPEFY (arg2, _a2) asm ("rsi") = __arg2;           \
332     register TYPEFY (arg1, _a1) asm ("rdi") = __arg1;           \
333     asm volatile (                          \
334     "syscall\n\t"                           \
335     : "=a" (resultvar)                          \
336     : "0" (number), "r" (_a1), "r" (_a2), "r" (_a3), "r" (_a4),     \
337       "r" (_a5)                             \
338     : "memory", REGISTERS_CLOBBERED_BY_SYSCALL);            \
339     (long int) resultvar;                       \
340 })
341 
342 #undef internal_syscall6
343 #define internal_syscall6(number, err, arg1, arg2, arg3, arg4, arg5, arg6) \
344 ({                                  \
345     unsigned long int resultvar;                    \
346     TYPEFY (arg6, __arg6) = ARGIFY (arg6);              \
347     TYPEFY (arg5, __arg5) = ARGIFY (arg5);              \
348     TYPEFY (arg4, __arg4) = ARGIFY (arg4);              \
349     TYPEFY (arg3, __arg3) = ARGIFY (arg3);              \
350     TYPEFY (arg2, __arg2) = ARGIFY (arg2);              \
351     TYPEFY (arg1, __arg1) = ARGIFY (arg1);              \
352     register TYPEFY (arg6, _a6) asm ("r9") = __arg6;            \
353     register TYPEFY (arg5, _a5) asm ("r8") = __arg5;            \
354     register TYPEFY (arg4, _a4) asm ("r10") = __arg4;           \
355     register TYPEFY (arg3, _a3) asm ("rdx") = __arg3;           \
356     register TYPEFY (arg2, _a2) asm ("rsi") = __arg2;           \
357     register TYPEFY (arg1, _a1) asm ("rdi") = __arg1;           \
358     asm volatile (                          \
359     "syscall\n\t"                           \
360     : "=a" (resultvar)                          \
361     : "0" (number), "r" (_a1), "r" (_a2), "r" (_a3), "r" (_a4),     \
362       "r" (_a5), "r" (_a6)                      \
363     : "memory", REGISTERS_CLOBBERED_BY_SYSCALL);            \
364     (long int) resultvar;                       \
365 })

可以看出internal_syscall##nr宏的number是每个系统调用内核中的入口函数向量地址,通过汇编syscall指令,实现系统调用,从用户态到核心态。


其他体系架构的系统调用基本是这个流程,但从用户态到核心态的汇编指令各不相同,如下:


本人水平有限,欢迎大家指正批评,欢迎私信联系我。

相关推荐

“版本末期”了?下周平衡补丁!国服最强5套牌!上分首选

明天,酒馆战棋就将迎来大更新,也聊了很多天战棋相关的内容了,趁此机会,给兄弟们穿插一篇构筑模式的卡组推荐!老规矩,我们先来看10职业胜率。目前10职业胜率排名与一周前基本类似,没有太多的变化。平衡补丁...

VS2017 C++ 程序报错“error C2065:“M_PI”: 未声明的标识符"

首先,程序中头文件的选择,要选择头文件,在文件中是没有对M_PI的定义的。选择:项目——>”XXX属性"——>配置属性——>C/C++——>预处理器——>预处理器定义,...

东营交警实名曝光一批酒驾人员名单 88人受处罚

齐鲁网·闪电新闻5月24日讯酒后驾驶是对自己和他人生命安全极不负责的行为,为守护大家的平安出行路,东营交警一直将酒驾作为重点打击对象。5月23日,东营交警公布最新一批饮酒、醉酒名单。对以下驾驶人醉酒...

Qt界面——搭配QCustomPlot(qt platform)

这是我第一个使用QCustomPlot控件的上位机,通过串口精确的5ms发送一次数据,再将读取的数据绘制到图表中。界面方面,尝试卡片式设计,外加QSS简单的配了个色。QCustomPlot官网:Qt...

大话西游2分享赢取种族坐骑手办!PK趣闻录由你书写

老友相聚,仗剑江湖!《大话西游2》2021全民PK季4月激燃打响,各PK玩法鏖战齐开,零门槛参与热情高涨。PK季期间,不仅各种玩法奖励丰厚,参与PK趣闻录活动,投稿自己在PK季遇到的趣事,还有机会带走...

测试谷歌VS Code AI 编程插件 Gemini Code Assist

用ClaudeSonnet3.7的天气测试编码,让谷歌VSCodeAI编程插件GeminiCodeAssist自动编程。生成的文件在浏览器中的效果如下:(附源代码)VSCode...

顾爷想知道第4.5期 国服便利性到底需优化啥?

前段时间DNF国服推出了名为“阿拉德B计划”的系列改版计划,截至目前我们已经看到了两项实装。不过关于便利性上,国服似乎还有很多路要走。自从顾爷回归DNF以来,几乎每天都在跟我抱怨关于DNF里面各种各样...

掌握Visual Studio项目配置【基础篇】

1.前言VisualStudio是Windows上最常用的C++集成开发环境之一,简称VS。VS功能十分强大,对应的,其配置系统较为复杂。不管是对于初学者还是有一定开发经验的开发者来说,捋清楚VS...

还嫌LED驱动设计套路深?那就来看看这篇文章吧

随着LED在各个领域的不同应用需求,LED驱动电路也在不断进步和发展。本文从LED的特性入手,推导出适合LED的电源驱动类型,再进一步介绍各类LED驱动设计。设计必读:LED四个关键特性特性一:非线...

Visual Studio Community 2022(VS2022)安装图文方法

直接上步骤:1,首先可以下载安装一个VisualStudio安装器,叫做VisualStudioinstaller。这个安装文件很小,很快就安装完成了。2,打开VisualStudioins...

Qt添加MSVC构建套件的方法(qt添加c++11)

前言有些时候,在Windows下因为某些需求需要使用MSVC编译器对程序进行编译,假设我们安装Qt的时候又只是安装了MingW构建套件,那么此时我们该如何给现有的Qt添加一个MSVC构建套件呢?本文以...

Qt为什么站稳c++GUI的top1(qt c)

为什么现在QT越来越成为c++界面编程的第一选择,从事QT编程多年,在这之前做C++界面都是基于MFC。当时为什么会从MFC转到QT?主要原因是MFC开发界面想做得好看一些十分困难,引用第三方基于MF...

qt开发IDE应该选择VS还是qt creator

如果一个公司选择了qt来开发自己的产品,在面临IDE的选择时会出现vs或者qtcreator,选择qt的IDE需要结合产品需求、部署平台、项目定位、程序猿本身和公司战略,因为大的软件产品需要明确IDE...

Qt 5.14.2超详细安装教程,不会来打我

Qt简介Qt(官方发音[kju:t],音同cute)是一个跨平台的C++开库,主要用来开发图形用户界面(GraphicalUserInterface,GUI)程序。Qt是纯C++开...

Cygwin配置与使用(四)——VI字体和颜色的配置

简介:VI的操作模式,基本上VI可以分为三种状态,分别是命令模式(commandmode)、插入模式(Insertmode)和底行模式(lastlinemode),各模式的功能区分如下:1)...

取消回复欢迎 发表评论: