系統調用的實現細節(用戶態)

該文檔以一個具體的事例來描述系統調用的細節。本文檔的事例在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
"

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
"

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
"

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
"

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
"

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
"

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
"

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指令,實現系統調用,從用戶態到核心態。

其他體系架構的系統調用基本是這個流程,但從用戶態到核心態的彙編指令各不相同,如下:

本人水平有限,歡迎大家指正批評,歡迎私信聯繫我。


推薦閱讀:

一基於事件處理的RTOS原型內核的介紹-2_概念與約定
無人駕駛操作系統(OS)

TAG:Linux內核 | 操作系統 | syscall |