|
因為再深入我也不懂,所以就淺談吧~
1 i# v- _9 g' j+ A) ?5 X( U+ H3 [有錯請指正~
" k; y8 h& N3 t7 ?! N% k" T5 t) X7 H+ K# D. m
話說,身為一個程式設計人員,常常遇到一些程式跑著跑著就當掉的狀況也很合理的。3 D. l( X$ W; @- f& k
例如:『segmentation fault』。簡單講就是程式寫錯,然後它就當了。5 D1 ?3 g' `7 k' w/ D; [
0 ]; k' ~2 Z2 t0 ]) u* F7 }7 s
大家也應該都聽過,『開機之後CPU就會到固定位置去拿指令,然後開始跑,通: O' j7 a$ e( A8 `% O9 N7 H
常這個位置都是放BIOS,而這個位置通常是0』。4 P9 V7 R2 }: N( e
7 Z0 U ^. j, d7 N
那這個第一行指令究竟是長怎樣呢?這跟程式當掉有什麼關係?跟程式碼寫錯
H% h$ G( Z! e; d又有什麼關係?
" p1 I) d: g; d4 H: s+ w1 Y+ l% |7 x- `+ Y( r0 s
我們來看通常一般冷開機之後開始跑的程式碼都是怎樣的
' o, m$ v, D# Z- B K. Q( 通常就是跳到bootload or BIOS )
6 i8 e" ^$ {4 l+ W6 U0 l3 ~『
! ~# I+ c5 h, R5 l% F- V( L' Sb start' Y# a6 E8 n9 F5 P4 t
ldr pc, _undefined_instruction, k' k; I O6 S5 p
ldr pc, _software_interrupt7 U% l& T" Y3 C; M: [$ w" z' o
ldr pc, _prefetch_abort+ _$ y$ H2 S- A. {! R
ldr pc, _data_abort# p% j. D2 o! @! A
ldr pc, _not_used
: b; |9 `+ [) m( y) Bldr pc, _irq" U2 G |; L0 t) U
ldr pc, _fiq; A7 M4 F4 h+ ` F5 Y% ^
』
/ Z& x: J" ]4 S0 a3 x2 z5 v8 B) L9 J4 W( U+ Z7 [% b5 ~
上面是組語,我們只看兩行,第一行是『b start』,『b』的意思就是branch的4 m* V3 q, \8 @* W3 ]! u! s
意思,也就是jump到start這個地方開始執行。換句換說,CPU拿到手的第一個
, M, T# b0 |' r, ?( j7 [# X) [; V- j指令就是要它去找別人,顯然是相當不負責任的行為。讓人不禁懷疑那第二行第
# [# ~& x- H" e' `. Z" E$ @三行到底是幹麼的。3 [9 ~& N7 L8 ]9 O4 L2 P* O
, Q! d F! ]- v1 ]: [5 B( Z我們接著看『ldr pc, _undefined_instruction』,『ldr』的意思是說,將6 o: J8 t# R- ]% J# f; f
_undefined_instruction這個位址,放到pc這個暫存器當中。大家一定也聽過! g( _) w3 d; }+ U* i5 G: B5 ^" d
program counter這個東西,一個正常的CPU就是靠program counter所指6 X( z9 h5 t. x( r# M
的位置去抓指令進來執行。換句話說,第二行程式居然也是要CPU跳到別的地方
- x8 k# ^8 h+ @# `9 l& m執行。而且前面七八行都是做這件事情。很怪吧?!!!- C: x4 c/ W" k# ^) ?% o3 o
# B* @+ Q" J# S# a
到這裡我們解答了上面第一個疑問,第一行程式其實就是一個Jump的指令,跳到
# @4 G3 C8 e: x1 w9 V+ g* D8 Y真正的開機程序。
, n* M$ J6 ^# E. C! A* R7 U6 s5 C: }9 L! r; m8 e
看了程式碼之後,我們不禁好奇這些看起來排列很有規則的程式碼到底是做啥用
' l; B, t/ {- ]& c+ I/ R3 e的?其實答案就是『exception vector』。8 s% Q; `* ?, r3 p K5 Y
' ^1 x5 E2 a/ [/ m: A; ^& W
什麼是exception vector呢?其實就是CPU出錯了(其實不完全是出錯),它就會# }/ ` }* k; k9 L, U* N. R
來這個vector找看相對應的處理函式,例如遇到看不懂得指令,他就固定會抓0x4
' w$ i l5 E1 `6 u位址的指令,也就是『ldr pc, _undefined_instruction』,接著就會跳到處理undefined instruction的函式去處理。
$ h8 [: Y0 M$ o* `( ?$ c) ]# N# j" Y7 T, N2 x. {( b9 s4 |; i
到這邊我們回答了第二個問題,程式當掉的時候,就是會跑來這個地方,接著再3 P m# x* L9 ?9 h6 t+ [
Jump到處理的程式碼。同時我們也發現,一個CPU就是靠著這個vector在處理2 b6 Q5 G, M9 Y: Z
各種不同的exception。那....萬一這些vector被改掉了呢?
! L& V0 Q; T7 U/ w; k. v例如:你程式碼拿到一個null pointer,然後又對這個null pointer開始做寫入動
% d; u! F7 r: i$ y0 Z- c. Y作。9 Z% Z8 K! j; f4 U r
- j4 D* H4 ~3 N" F6 V" N t
char *ptr = NULL;
G/ C( x! b8 h1 [$ h$ I, xmemcpy( ptr, 0x0, 10 );
8 Z9 n3 m7 ]4 Q. r7 b
$ _+ g3 W6 d' z6 Q# D3 \5 k0 q那整個OS就完全不能動了。可是我們也知道我們現在這樣寫,頂多 segmentation
& j! K4 o% e$ b Bfault,並不會怎樣,OS還是照樣活著。why why why?
2 ]" \3 b n$ I% g. Y# q( W+ R" b原因很簡單,就是這些區段被一些方法保護住了。一般常見的有兩種方法,一種是( x- n5 o0 k+ Z# `5 G* b. `( w
MMU,一種是cpu有兩個exception vector存上的位址。
( |. M+ o1 S5 M5 ]. g& c/ U ^9 S6 j/ i. B4 P& m0 ^( E, a
MMU可以設定某個區段的存取權力,只能readable的話,那就不會有被改掉的問/ g: [* K7 [4 e8 E
題,另外一個方式是可以將exception vector的位址擺到不容易改到的地方,通常
8 x8 k8 ~' t* Q& J0 y9 h4 h* l: s是往高位址的地方擺(high vector address),例如,0xffff0000接近4GB的位& E v: g4 n0 o. c
置。(32bit 最多只能定址4GB)+ \. g& Y& z- S; }# K' q0 X% `
+ V% J. L+ p0 ]3 `第二種方式,通常是一開始開機vector還是從0x0那邊抓,可是經過設定CPU,可1 _1 T% M. q' ]( m6 N- T
以改變,在不斷電的狀態下,發生exception就會跳到高位位址去找exception
7 e1 R; p! E0 m% G" |8 g- v/ [vector。
4 _- X" H" }. I% ?
7 a5 R+ G7 F; L) `/ fp.s. 關於定址模式可能有些人沒感覺,可能要懂整個CPU的memory map之後,! ^8 q5 n5 @6 Z3 E* a
會比較有感覺。" e, y. W) Y4 R/ I( j
# n, i$ C, @3 Yp.s. 眼尖的人一定覺得很怪,為什麼vector第一行用『b』,其它卻是用『ldr』,
9 Y( _, K& G: j這個牽涉到本身指令的不同和程式碼是不是relocatable的程式有關,將來有機會
1 F2 r* q4 x8 t! K6 ^再深入討論吧!!
$ G# N4 ^( A3 V
! i% k5 W+ m+ t# |. A---) |& e- V: B- E( ]
想知道答案的朋友趕快call in進來/ T" R2 A! C, r2 k' z% { U
前五名我們有優惠
3 A4 P* @- T: y j; e9 Q. d0 @8 G- N現在進一段廣告~ |
評分
-
查看全部評分
|