1. 程式人生 > >核心地址空間大冒險2:中斷與異常

核心地址空間大冒險2:中斷與異常

前情回顧:

通過系統呼叫進入核心空間的這個蟲洞我終於弄清楚了,可我的冒險還要繼續······詳情參見:核心地址空間大冒險:系統呼叫

 

除0錯誤

 

我是一個執行緒,出生在Linux帝國,今天我的任務是去執行一段人類用C語言編寫的程式碼。

開始的工作很順利,一共執行了18次系統呼叫,對於來往於使用者空間與核心空間的那個蟲洞我已經輕車熟路,再也不是萌新一枚。

 

後來,我拿到了一段數學運算的程式碼,來來往往地奔波於記憶體與暫存器之間,把我累得夠嗆,熱的滿頭大汗,電腦風扇都轉的飛快給我降溫。

沒多久,一條除法指令擺在我的面前,我瞟了一眼除數居然是0,一種不好的預感湧上心頭。沒有辦法,硬著頭皮也得上啊,準備開始執行這個除法。

 

突然!眼前閃過一道白光,然後變得漆黑,這不是執行系統呼叫的蟲洞嗎?可是我並沒有執行系統呼叫啊,怎麼跑到這裡來了。

我心裡開始犯嘀咕,打算等會問問原來的白鬍子老頭究竟是怎麼回事。

 

不久,光亮開始出現,來到了一個陌生的地方,白霧茫茫。

繼續前行,霧逐漸散去,一座大門出現在我面前,我定睛一看,上面寫著: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號門有過絲絲晃動,仔細一瞧,這門上的地址和我來時所見似有不同······

 

欲知後事如何,請關注後續精彩......

 

 

 

 

精彩回顧:

一個DNS資料包的驚險之旅

DDoS攻擊:無限戰爭

一條SQL注入引出的驚天大案

核心地址空間大冒險:系統呼叫

闖蕩Linux帝國:nginx的創業故事

一個HTTP資料包的奇幻之旅

遠去的傳說:安全軟體群雄混戰史

我是一個流氓軟體執行緒

產品vs程式設計師:你知道www是怎麼來的嗎?

位元宇宙-TCP/IP的誕生

我是一個IE瀏覽器執行緒

我是一個防毒軟體執行緒

我是一個explorer的