前面說了glibc以及标準C庫函數和系統調用,但總感覺有點隔靴撓癢,下面就來追蹤一下系統調用的源碼。(linux-3.3核心,glibc-2.17源碼)
系統調用以open函數為例
怎麼查呢?
用 man 2 open 檢視open的用法,看到需要包含三個頭檔案sys/types.h、sys/stat.h、fcntl.h,看了一下前兩個,不相關,
好像是fcntl.h,但這個頭檔案裡也沒給出open的定義,但這個頭檔案又包含了一個頭檔案io/fcntl.h,跟下去,看到168行:
extern int open (const char *__file, int __oflag, ...) __nonnull ((1));
引進了open函數,查找它的定義(我用的是source insight,直接按住Ctrl點選函數,就可以跳到該函數定義的地方),出現三個宏兩個定義,oldfileops.c和fileops.c參數不比對,另一個宏不可以,fcntl2.h裡的也不像。應該是loadmsgcat.c裡的
# define open(name, flags) open_not_cancel_2 (name, flags)
此時open_not_cancel_2對應glibc-2.17\sysdeps\unix\sysv\linux\Not-cancel.h 26行
#define open_not_cancel_2(name, flags) \
INLINE_SYSCALL (open, 2, (const char *) (name), (flags))
每個硬體平台的INLINE_SYSCALL封裝不一樣,對于ARM來說(在glibc-2.17\ports\sysdeps\unix\sysv\linux\arm\Sysdep.h)
#define INLINE_SYSCALL(name, nr, args...) \
({ unsigned int _sys_result = INTERNAL_SYSCALL (name, , nr, args); \
if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (_sys_result, ), 0)) \
{ \
__set_errno (INTERNAL_SYSCALL_ERRNO (_sys_result, )); \
_sys_result = (unsigned int) -1; \
} \
(int) _sys_result; })
跟蹤上面的宏裡INTERNAL_SYSCALL
#else /* ARM */
# undef INTERNAL_SYSCALL_RAW
# define INTERNAL_SYSCALL_RAW(name, err, nr, args...) \
({ \
register int _a1 asm ("r0"), _nr asm ("r7"); \
LOAD_ARGS_##nr (args) \
_nr = name; \
asm volatile ("swi 0x0 @ syscall " #name \
: "=r" (_a1) \
: "r" (_nr) ASM_ARGS_##nr \
: "memory"); \
_a1; })
#endif
看到上面嵌入的彙編指令 swi 異常,它會根據異常向量表實行系統調用,nr代表要實行的系統調用的編号,每一個系統調用對應一個編号。關于 swi 異常及系統調用請參見其他博文,這裡隻需要知道這條彙編指令能夠根據我們傳進來的系統調用函數的編号調用核心裡定義的系統調用函數,從這裡開始,系統調用就進入到核心态了。為什麼會進入到核心态,進入到核心态以後又做了什麼?
這就涉及到swi異常處理了,請參見之後的博文。