前情回顧:html
經過系統調用進入內核空間的這個蟲洞我終於弄清楚了,可個人冒險還要繼續······詳情參見:內核地址空間大冒險:系統調用nginx
除0錯誤程序員
我是一個線程,出生在Linux帝國,今天個人任務是去執行一段人類用C語言編寫的代碼。瀏覽器
開始的工做很順利,一共執行了18次系統調用,對於來往於用戶空間與內核空間的那個蟲洞我已經輕車熟路,不再是萌新一枚。安全
後來,我拿到了一段數學運算的代碼,來來每每地奔波於內存與寄存器之間,把我累得夠嗆,熱的滿頭大汗,電腦風扇都轉的飛快給我降溫。網絡
沒多久,一條除法指令擺在個人面前,我瞟了一眼除數竟然是0,一種很差的預感涌上心頭。沒有辦法,硬着頭皮也得上啊,準備開始執行這個除法。異步
忽然!眼前閃過一道白光,而後變得漆黑,這不是執行系統調用的蟲洞嗎?但是我並無執行系統調用啊,怎麼跑到這裏來了。ide
我內心開始犯嘀咕,打算等會問問原來的白鬍子老頭到底是怎麼回事。函數
不久,光亮開始出現,來到了一個陌生的地方,白霧茫茫。spa
繼續前行,霧逐漸散去,一座大門出如今我面前,我定睛一看,上面寫着:0:divide_error。
除法錯誤?我愈加的緊張起來,這是到哪裏了?
「年輕人,歡迎來到內核地址空間」,熟悉的問候語響起,走過來一位白髮老頭,卻不是我在系統調用時見過的那位,拄着一根木棍,掛着一隻葫蘆,看起來年紀比系統調用那個老頭還要大一些。
「敢問老先生,我怎麼到這裏來了,我並無執行系統調用啊」,我向老頭打聽狀況。
「這裏並非系統調用的入口,由於你執行了除數爲0的除法,觸發了異常,因此來到了這裏」,老頭說完喝了一口葫蘆裏的酒。
「異常,這又是什麼意思?」,今天又聽到一個新的名詞。
只見老頭木棍一揮,大霧徹底散去,我這才注意到,這裏還有好多大門,它們一個挨着一個,造成了一面門牆。
「老先生,這些都是什麼啊,這究竟是什麼地方?」,我對眼前的景象感到愈加的好奇。
「這裏是中斷描述符表——IDT,是全部中斷和異常發生時,大家會來到的地方」,老頭用了一堆我不懂的話來回答我。
「中斷又是什麼?和異常又是什麼關係?IDT又是作什麼的?」,我向老頭髮出了靈魂三問。
「中斷就是有重要的事情發生,要打斷大家線程手頭的工做,讓出CPU必須去處理」
「什麼事情,這麼重要?」
「好比說有鍵盤按鍵被按下,鼠標被移動或點擊,網絡中有數據包到來等等狀況」。
「那異常呢?」
「異常就是大家這些線程在執行代碼指令的時候出現了一些錯誤的狀況,好比作除法的時候除數爲0,又好比訪問的內存地址錯誤等這些狀況,那遇到這些狀況怎麼辦呢?CPU會發現有問題,強制改變大家的執行流,去處理這些異常」。
「聽起來,跟中斷差很少嘛!「
「確實差很少,因此它們都用IDT來一塊兒記錄嘛!不過實際上差異仍是很大的哦。最大的區別在於中斷是異步,而異常是同步的!「
「這是爲何?」
「由於中斷何時來你是不知道的,你是被迫被打斷的,而異常是大家執行指令主動形成的」
「那IDT又是作什麼的?」
「剛纔我不是說發生中斷和異常大家就會被打斷嘛!那打斷後該去那裏呢?IDT就是把全部中斷和異常發生後要去的地方記錄成了一個表,也就是你眼前所看到的這一面門牆了,總共256扇門,你如今觸發的是除0錯誤,該抓緊時間去0號門裏去處理異常了!」
拜別老先生,我走進divide_error這扇門,接着又穿過了common_exception和do_divide_error,
越往前走,周遭愈加的陰森,直到來到了force_sig_info,我停下了腳步,想找人打聽下狀況。
正在這時,從force_sig_info裏面走出一人,瞧着年紀長我幾歲。
「大哥,前面是什麼地界,爲什麼這般陰森」,我上前請教。
「前面就是給你所屬進程投遞信號的地方了,你是準備去投遞什麼信號?」
「信號,什麼信號?」我不太聽得懂大哥的話。
「就是你手裏的第一個參數,讓我看一下。咦,是個SIGFPE信號,你是遇到除數是0的除法了嗎?」大哥竟然看出了個人來歷。
「不錯,我確實是由於除了一下0纔來到這裏的,不知大哥是如何得知的?」
「由於你手裏是SIGFPE,這是在數學運算出錯時纔會給進程發送的信號,而一般狀況下都是除法除以0時候發生,因此我才猜中的。」
「大哥,您口中一直所說的信號,究竟是個什麼意思?」
「這個信號就是Signal,用來告訴進程有事情發生了。好比經常使用的CTRL+C進程就是發送SIGINT信號,kill殺進程就是SIGTERM信號,你如今手裏的SIGFPE就是表示有數學運算錯誤。總而言之,這就是個通知而已」
「那這通知發送到了哪裏呢?又是何時去處理呢?」,我有些好奇。
「這就先不告訴你了,等會你本身去就知道了,快去吧,再見了」,大哥揮手離開。
歇息事後便又起身繼續前行,進入force_sig_info後,又前後跨過幾個函數來到send_signal,我看到我所屬進程的task_struct中有一個專門存放信號的隊列,原來信號是放在了這裏。
我準備了一個信號對象加入到了進程的信號隊列中,大功告成,準備返回。
很快回到了見到白髮老頭的地方,我一下難住了,我是經過異常這個蟲洞來到這裏的,如今我該回哪裏去呢?
「年輕人,事情都忙完了?」,老頭又一次出現了。
「老先生,嗯,我都忙完了,但是我如今該怎麼回去呢?」
「你如今看看你的內核堆棧上面存了什麼?」
我低頭看了一眼個人內核堆棧,發現上面竟然保存了除0指令以後那條指令的地址,這正是我要回去的地方。
「這是何時存進去的,我不記得我執行過push保存啊」
「在你剛來到這裏的時候就存進去了,確實不是你push進去的,而是當你經過異常這個蟲洞進入內核空間時,CPU自動完成的」
「原來如此,我知道我要去哪裏了,但是我該怎麼打開蟲洞回去呢?」
「你看前面,有一條iret指令,經過它,你就能開啓蟲洞之門,回到用戶態空間了」,老頭向我指了指方向。
「ret指令我卻是常常執行,就是函數返回嘛,這個iret是什麼,能有這麼強大能力?」
「iret就是interrupt return的意思,專門用於被中斷或異常打斷的線程處理完畢後返回用戶空間使用的。」
「明白了,感謝老先生,我就先告辭了,下次再見」,再次向老頭拜別,準備回到我原來的地方,來這裏過久了,都有點想念了。
「等一下,少年,你如今還不能回去」,老頭攔下了我。
「不能回去?爲何?」
「回去以前還有件事要去處理哦!」
「究竟是什麼事情啊?」
「你所在的進程有信號來了,須要先去處理!」
「納尼?那信號是我放的啊?」,我回頭一看,老先生居然已經走遠。
「別走啊,老先生請留步......」
未完待續·······
彩蛋
就在我準備起身去處理信號的時候,一道黑影從我眼前掠過,我擡頭一看,IDT門牆的20號門有過絲絲晃動,仔細一瞧,這門上的地址和我來時所見似有不一樣······
欲知後事如何,請關注後續精彩......
精彩回顧:
原文出處:https://www.cnblogs.com/xuanyuan/p/12220709.html