成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

系統調用,讓世界轉起來!

系統 Linux
這篇文章講解系統調用,系統調用與調用一個庫有何區別,以及在操作系統/應用程序接口上的刺探工具。如果徹底了解了應用程序借助操作系統發生的哪些事情,那么就可以將一個不可能解決的問題轉變成一個快速而有趣的難題。

 [[229002]]

我其實不想將它分解開給你看,用戶應用程序其實就是一個可憐的甕中大腦brain in a vat

它與外部世界的每個交流都要在內核的幫助下通過系統調用才能完成。一個應用程序要想保存一個文件、寫到終端、或者打開一個 TCP 連接,內核都要參與。應用程序是被內核高度懷疑的:認為它到處充斥著 bug,甚至是個充滿邪惡想法的腦子。

這些系統調用是從一個應用程序到內核的函數調用。出于安全考慮,它們使用了特定的機制,實際上你只是調用了內核的 API。“系統調用system call”這個術語指的是調用由內核提供的特定功能(比如,系統調用 open())或者是調用途徑。你也可以簡稱為:syscall

這篇文章講解系統調用,系統調用與調用一個庫有何區別,以及在操作系統/應用程序接口上的刺探工具。如果徹底了解了應用程序借助操作系統發生的哪些事情,那么就可以將一個不可能解決的問題轉變成一個快速而有趣的難題。

那么,下圖是一個運行著的應用程序,一個用戶進程:

它有一個私有的 虛擬地址空間—— 它自己的內存沙箱。整個系統都在它的地址空間中(即上面比喻的那個“甕”),程序的二進制文件加上它所使用的庫全部都 被映射到內存中。內核自身也映射為地址空間的一部分。

下面是我們程序 pid 的代碼,它通過 getpid(2) 直接獲取了其進程 id:

  1. #include <sys/types.h>
  2. #include <unistd.h>
  3. #include <stdio.h>
  4.  
  5. int main()
  6. {
  7. pid_t p = getpid();
  8. printf("%d\n", p);
  9. }

pid.c download

在 Linux 中,一個進程并不是一出生就知道它的 PID。要想知道它的 PID,它必須去詢問內核,因此,這個詢問請求也是一個系統調用:

它的***步是開始于調用 C 庫的 getpid(),它是系統調用的一個封裝。當你調用一些函數時,比如,open(2)read(2) 之類,你是在調用這些封裝。其實,對于大多數編程語言在這一塊的原生方法,最終都是在 libc 中完成的。

封裝為這些基本的操作系統 API 提供了方便,這樣可以保持內核的簡潔。所有的內核代碼運行在特權模式下,有 bug 的內核代碼行將會產生致命的后果。能在用戶模式下做的任何事情都應該在用戶模式中完成。由庫來提供友好的方法和想要的參數處理,像 printf(3) 這樣。

我們拿一個 web API 進行比較,內核的封裝方式可以類比為構建一個盡可能簡單的 HTTP 接口去提供服務,然后提供特定語言的庫及輔助方法。或者也可能有一些緩存,這就是 libc 的 getpid() 所做的:***調用時,它真實地去執行了一個系統調用,然后,它緩存了 PID,這樣就可以避免后續調用時的系統調用開銷。

一旦封裝完成,它做的***件事就是進入了超空間hyperspace:內核。這種轉換機制因處理器架構設計不同而不同。在 Intel 處理器中,參數和 系統調用號加載到寄存器中的,然后,運行一個 指令 將 CPU 置于 特權模式 中,并立即將控制權轉移到內核中的全局系統調用 入口。如果你對這些細節感興趣,David Drysdale 在 LWN 上有兩篇非常好的文章(其一其二)。

內核然后使用這個系統調用號作為進入 sys_call_table 的一個 索引,它是一個函數指針到每個系統調用實現的數組。在這里,調用了 sys_getpid

在 Linux 中,系統調用大多數都實現為架構無關的 C 函數,有時候這樣做 很瑣碎,但是通過內核優秀的設計,系統調用機制被嚴格隔離。它們是工作在一般數據結構中的普通代碼。嗯,除了完全偏執的參數校驗以外。

一旦它們的工作完成,它們就會正常返回,然后,架構特定的代碼會接手轉回到用戶模式,封裝將在那里繼續做一些后續處理工作。在我們的例子中,getpid(2) 現在緩存了由內核返回的 PID。如果內核返回了一個錯誤,另外的封裝可以去設置全局 errno 變量。這些細節可以讓你知道 GNU 是怎么處理的。

如果你想要原生的調用,glibc 提供了 syscall(2) 函數,它可以不通過封裝來產生一個系統調用。你也可以通過它來做一個你自己的封裝。這對一個 C 庫來說,既不神奇,也不特殊。

這種系統調用的設計影響是很深遠的。我們從一個非常有用的 strace(1) 開始,這個工具可以用來監視 Linux 進程的系統調用(在 Mac 上,參見 dtruss(1m) 和神奇的 dtrace;在 Windows 中,參見 sysinternals)。這是對 pid 程序的跟蹤:

  1. ~/code/x86-os$ strace ./pid
  2.  
  3. execve("./pid", ["./pid"], [/* 20 vars */]) = 0
  4. brk(0) = 0x9aa0000
  5. access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory)
  6. mmap2(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7767000
  7. access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory)
  8. open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
  9. fstat64(3, {st_mode=S_IFREG|0644, st_size=18056, ...}) = 0
  10. mmap2(NULL, 18056, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7762000
  11. close(3) = 0
  12.  
  13. [...snip...]
  14.  
  15. getpid() = 14678
  16. fstat64(1, {st_mode=S_IFCHR|0600, st_rdev=makedev(136, 1), ...}) = 0
  17. mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7766000
  18. write(1, "14678\n", 614678
  19. ) = 6
  20. exit_group(6) = ?

輸出的每一行都顯示了一個系統調用、它的參數,以及返回值。如果你在一個循環中將 getpid(2) 運行 1000 次,你就會發現始終只有一個 getpid() 系統調用,因為,它的 PID 已經被緩存了。我們也可以看到在格式化輸出字符串之后,printf(3) 調用了 write(2)

strace 可以開始一個新進程,也可以附加到一個已經運行的進程上。你可以通過不同程序的系統調用學到很多的東西。例如,sshd 守護進程一天都在干什么?

  1. ~/code/x86-os$ ps ax | grep sshd
  2. 12218 ? Ss 0:00 /usr/sbin/sshd -D
  3.  
  4. ~/code/x86-os$ sudo strace -p 12218
  5. Process 12218 attached - interrupt to quit
  6. select(7, [3 4], NULL, NULL, NULL
  7.  
  8. [
  9. ... nothing happens ...
  10. No fun, it's just waiting for a connection using select(2)
  11. If we wait long enough, we might see new keys being generated and so on, but
  12. let's attach again, tell strace to follow forks (-f), and connect via SSH
  13. ]
  14.  
  15. ~/code/x86-os$ sudo strace -p 12218 -f
  16.  
  17. [lots of calls happen during an SSH login, only a few shown]
  18.  
  19. [pid 14692] read(3, "-----BEGIN RSA PRIVATE KEY-----\n"..., 1024) = 1024
  20. [pid 14692] open("/usr/share/ssh/blacklist.RSA-2048", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
  21. [pid 14692] open("/etc/ssh/blacklist.RSA-2048", O_RDONLY|O_LARGEFILE) = -1 ENOENT (No such file or directory)
  22. [pid 14692] open("/etc/ssh/ssh_host_dsa_key", O_RDONLY|O_LARGEFILE) = 3
  23. [pid 14692] open("/etc/protocols", O_RDONLY|O_CLOEXEC) = 4
  24. [pid 14692] read(4, "# Internet (IP) protocols\n#\n# Up"..., 4096) = 2933
  25. [pid 14692] open("/etc/hosts.allow", O_RDONLY) = 4
  26. [pid 14692] open("/lib/i386-linux-gnu/libnss_dns.so.2", O_RDONLY|O_CLOEXEC) = 4
  27. [pid 14692] stat64("/etc/pam.d", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
  28. [pid 14692] open("/etc/pam.d/common-password", O_RDONLY|O_LARGEFILE) = 8
  29. [pid 14692] open("/etc/pam.d/other", O_RDONLY|O_LARGEFILE) = 4

看懂 SSH 的調用是塊難啃的骨頭,但是,如果搞懂它你就學會了跟蹤。能夠看到應用程序打開的是哪個文件是有用的(“這個配置是從哪里來的?”)。如果你有一個出現錯誤的進程,你可以 strace 它,然后去看它通過系統調用做了什么?當一些應用程序意外退出而沒有提供適當的錯誤信息時,你可以去檢查它是否有系統調用失敗。你也可以使用過濾器,查看每個調用的次數,等等:

  1. ~/code/x86-os$ strace -T -e trace=recv curl -silent www.google.com. > /dev/null
  2.  
  3. recv(3, "HTTP/1.1 200 OK\r\nDate: Wed, 05 N"..., 16384, 0) = 4164 <0.000007>
  4. recv(3, "fl a{color:#36c}a:visited{color:"..., 16384, 0) = 2776 <0.000005>
  5. recv(3, "adient(top,#4d90fe,#4787ed);filt"..., 16384, 0) = 4164 <0.000007>
  6. recv(3, "gbar.up.spd(b,d,1,!0);break;case"..., 16384, 0) = 2776 <0.000006>
  7. recv(3, "$),a.i.G(!0)),window.gbar.up.sl("..., 16384, 0) = 1388 <0.000004>
  8. recv(3, "margin:0;padding:5px 8px 0 6px;v"..., 16384, 0) = 1388 <0.000007>
  9. recv(3, "){window.setTimeout(function(){v"..., 16384, 0) = 1484 <0.000006>

我鼓勵你在你的操作系統中的試驗這些工具。把它們用好會讓你覺得自己有超能力。

但是,足夠有用的東西,往往要讓我們深入到它的設計中。我們可以看到那些用戶空間中的應用程序是被嚴格限制在它自己的虛擬地址空間里,運行在 Ring 3(非特權模式)中。一般來說,只涉及到計算和內存訪問的任務是不需要請求系統調用的。例如,像 strlen(3)memcpy(3) 這樣的 C 庫函數并不需要內核去做什么。這些都是在應用程序內部發生的事。

C 庫函數的 man 頁面所在的節(即圓括號里的 23)也提供了線索。節 2 是用于系統調用封裝,而節 3 包含了其它 C 庫函數。但是,正如我們在 printf(3) 中所看到的,庫函數最終可以產生一個或者多個系統調用。

如果你對此感到好奇,這里是 Linux (也有 Filippo 的列表)和 Windows 的全部系統調用列表。它們各自有大約 310 和 460 個系統調用。看這些系統調用是非常有趣的,因為,它們代表了軟件在現代的計算機上能夠做什么。另外,你還可能在這里找到與進程間通訊和性能相關的“寶藏”。這是一個“不懂 Unix 的人注定最終還要重新發明一個蹩腳的 Unix ” 的地方。(LCTT 譯注:原文 “Those who do not understand Unix are condemned to reinvent it,poorly。” 這句話是 Henry Spencer 的名言,反映了 Unix 的設計哲學,它的一些理念和文化是一種技術發展的必須結果,看似糟糕卻無法超越。)

與 CPU 周期相比,許多系統調用花很長的時間去執行任務,例如,從一個硬盤驅動器中讀取內容。在這種情況下,調用進程在底層的工作完成之前一直處于休眠狀態。因為,CPU 運行的非常快,一般的程序都因為 I/O 的限制在它的生命周期的大部分時間處于休眠狀態,等待系統調用返回。相反,如果你跟蹤一個計算密集型任務,你經常會看到沒有任何的系統調用參與其中。在這種情況下,top(1) 將顯示大量的 CPU 使用。

在一個系統調用中的開銷可能會是一個問題。例如,固態硬盤比普通硬盤要快很多,但是,操作系統的開銷可能比 I/O 操作本身的開銷 更加昂貴。執行大量讀寫操作的程序可能就是操作系統開銷的瓶頸所在。向量化 I/O 對此有一些幫助。因此要做 文件的內存映射,它允許一個程序僅訪問內存就可以讀或寫磁盤文件。類似的映射也存在于像視頻卡這樣的地方。最終,云計算的經濟性可能導致內核消除或最小化用戶模式/內核模式的切換。

最終,系統調用還有益于系統安全。一是,無論如何來歷不明的一個二進制程序,你都可以通過觀察它的系統調用來檢查它的行為。這種方式可能用于去檢測惡意程序。例如,我們可以記錄一個未知程序的系統調用的策略,并對它的異常行為進行報警,或者對程序調用指定一個白名單,這樣就可以讓漏洞利用變得更加困難。在這個領域,我們有大量的研究,和許多工具,但是沒有“殺手級”的解決方案。

這就是系統調用。很抱歉這篇文章有點長,我希望它對你有用。接下來的時間,我將寫更多(短的)文章,也可以在 RSSTwitter 關注我。這篇文章獻給 glorious Clube Atlético Mineiro。

責任編輯:龐桂玉 來源: Linux中國
相關推薦

2023-04-23 11:27:04

云計算

2010-06-12 17:07:17

TCP IP協議

2010-06-18 10:13:17

虛擬機消失

2009-10-20 11:12:26

綜合布線系統

2024-09-18 15:24:23

飛輪數據大模型系統

2018-03-18 08:28:04

數據中心運維組織架構數據中心

2024-03-13 08:21:53

冒泡排序動畫

2013-06-18 10:21:43

云計算云服務公共云服務

2013-12-18 13:17:56

多核CPU

2010-08-19 14:49:28

OSPFv3

2021-11-19 07:55:17

存儲鏡像部署

2021-08-04 10:40:20

混合IT數字業務CIO

2018-08-21 21:30:32

云計算公有云數據中心

2019-03-26 09:28:05

大數據部署架構

2021-01-22 14:03:34

Flutter系統鴻蒙

2010-03-17 08:55:10

ASP.NETWeb Server

2016-06-27 15:55:15

移動

2017-01-11 14:19:26

JVM源碼All

2015-12-15 13:49:33

數據中心市場競爭法則

2011-05-24 15:29:05

程序CC++
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 久久国产精品久久国产精品 | 精品国产乱码久久久久久牛牛 | 欧美一区二区在线 | 久久人体视频 | 欧美精品一区二区三区在线播放 | 国产日韩视频在线 | 亚洲久视频 | 成人做爰999 | 国产精品国产精品国产专区不蜜 | 日韩精品在线一区 | 婷婷久久五月 | 精品乱码一区二区三四区 | 视频一区二区三区四区五区 | 日韩中文字幕在线视频观看 | 极品粉嫩国产48尤物在线播放 | 黄免费观看 | 亚洲精品黄 | 欧美黑人体内she精在线观看 | 欧美精品久久 | 在线视频 中文字幕 | 综合久久99 | 欧美日韩高清在线一区 | 欧美vide| 久久久久久久久久久久久91 | 天天操精品视频 | 久久久91精品国产一区二区精品 | 国产一区二区三区高清 | 精品免费国产一区二区三区四区 | 日日夜夜天天 | 日韩国产三区 | 日韩精品极品视频在线观看免费 | 在线成人精品视频 | 91看片网| 99热激情 | 国产一区二区三区在线免费观看 | 91久久久久 | 91久久精品视频 | 毛片软件 | 国产一区2区 | 正在播放一区二区 | 国产精品久久久久久久久久久久久 |