高階的 function library,是屬於 user mode 的函數,是給程式設計師方便使用的 API。而真正在 kernel 中運行的是低階的 system call,那才是成是真正執行的方式。譬如在一般程式中使用的 printf() 函數,他是屬於 C 語言的標準 function library,而在 kernel 中運行時,printf() 的動作會被轉化成一連串的 system call,將要輸出的資料轉變成一連串的字串,並透過低階的 write() system call,把字串寫到標準輸出設備上 (通常是螢幕) 被使用者看見。
就舉一個最簡單的 hello world 程式,來示範 printf() 函數好了:
#include <stdio.h>
int main(void)
{
printf("hello world\n");
return 0;
}
在 compile 完這個程式之後,執行他會出現 hello world 字串。而使用 strace 工具去解析這支程式的執行檔,就能看到他底層所進行的一連串 system call。
[root@Pomelo-14-61 LKMP]# gcc -o hello hello.c
[root@Pomelo-14-61 LKMP]# ./hello
hello world
[root@Pomelo-14-61 LKMP]# strace ./hello
execve("./hello", ["./hello"], [/* 26 vars */]) = 0
brk(0) = 0xf4c000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f0129b0e000
access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=91141, ...}) = 0
mmap(NULL, 91141, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f0129af7000
close(3) = 0
open("/lib64/libc.so.6", O_RDONLY) = 3
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0000\356\341p3\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=1926800, ...}) = 0
mmap(0x3370e00000, 3750152, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x3370e00000
mprotect(0x3370f8b000, 2093056, PROT_NONE) = 0
mmap(0x337118a000, 20480, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x18a000) = 0x337118a000
mmap(0x337118f000, 18696, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x337118f000
close(3) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f0129af6000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f0129af5000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f0129af4000
arch_prctl(ARCH_SET_FS, 0x7f0129af5700) = 0
mprotect(0x337118a000, 16384, PROT_READ) = 0
mprotect(0x3370c1f000, 4096, PROT_READ) = 0
munmap(0x7f0129af7000, 91141) = 0
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 1), ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f0129b0d000
write(1, "hello world\n", 12hello world
) = 12
exit_group(0) = ?
主要你會看到一堆 mmap 還有最後的 write 動作,mmap 就是就是將檔案或是 device 對應到記憶體的位址上,而最後的 write 就是將記憶體中的內容輸出。