系统调用的实现细节(用户态) 系统调用的主要作用
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)...
你 发表评论:
欢迎- 一周热门
- 最近发表
-
- “版本末期”了?下周平衡补丁!国服最强5套牌!上分首选
- VS2017 C++ 程序报错“error C2065:“M_PI”: 未声明的标识符"
- 东营交警实名曝光一批酒驾人员名单 88人受处罚
- Qt界面——搭配QCustomPlot(qt platform)
- 大话西游2分享赢取种族坐骑手办!PK趣闻录由你书写
- 测试谷歌VS Code AI 编程插件 Gemini Code Assist
- 顾爷想知道第4.5期 国服便利性到底需优化啥?
- 掌握Visual Studio项目配置【基础篇】
- 还嫌LED驱动设计套路深?那就来看看这篇文章吧
- Visual Studio Community 2022(VS2022)安装图文方法
- 标签列表
-
- wireshark怎么抓包 (75)
- qt sleep (64)
- cs1.6指令代码大全 (55)
- factory-method (60)
- sqlite3_bind_blob (52)
- hibernate update (63)
- c++ base64 (70)
- nc 命令 (52)
- wm_close (51)
- epollin (51)
- sqlca.sqlcode (57)
- lua ipairs (60)
- tv_usec (64)
- 命令行进入文件夹 (53)
- postgresql array (57)
- statfs函数 (57)
- .project文件 (54)
- lua require (56)
- for_each (67)
- c#工厂模式 (57)
- wxsqlite3 (66)
- dmesg -c (58)
- fopen参数 (53)
- tar -zxvf -c (55)
- 速递查询 (52)