松下伺服err340(系统调用的实现细节(用户态))
Posted
篇首语:如果终止了学习,人就结束了成长的进步。本文由小常识网(cha138.com)小编为大家整理,主要介绍了松下伺服err340(系统调用的实现细节(用户态))相关的知识,希望对你有一定的参考价值。
松下伺服err340(系统调用的实现细节(用户态))
该文档以一个具体的事例来描述系统调用的细节。本文档的事例在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_syscall0240 #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_syscall1252 #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_syscall2266 #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 )280281 #undef internal_syscall3282 #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_syscall4300 #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_syscall5320 #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_syscall6343 #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指令,实现系统调用,从用户态到核心态。
其他体系架构的系统调用基本是这个流程,但从用户态到核心态的汇编指令各不相同,如下:

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