第十五章 習(xí)題解析(以及完整源碼)
準(zhǔn)備文件 .lst文件
-
.lst文件根據(jù)同名.asm文件由配書工具nasmide.exe生成
c13_mbr.lst
ex15-1_core.lst
ex15-1_A.lst
ex15-1_B.lst
Bochs 調(diào)試命令(以及配置方法)
-
s: 單步執(zhí)行 -
b: 斷點(diǎn)設(shè)置 -
c: 繼續(xù)執(zhí)行 -
r: 查看寄存器 -
sreg: 查看段寄存器 -
xp: 查看內(nèi)存
Bochs 完整調(diào)試過程
- 調(diào)試過程:加載程序mbr 到 內(nèi)核程序core 到用戶程序 user(任務(wù)Task-A Mss-1) 回 內(nèi)核程序core;
-
<bochs:n> XXXX: XXXX 處輸入 bochs指令 ;
<bochs:1> s
<bochs:2> b 0x7c00
<bochs:3> c
---- 進(jìn)入 mbr -----
<bochs:4> b 0x7d38
<bochs:5> c
---- 跳轉(zhuǎn)到 mbr 最后一條指令 ----------------------
| c13_mbr.lst
| 136 00000138 FF6F10 jmp far [edi+0x10]
| 0x7D38 = 0x7c00 + 0x138
--------------------------------------------------
<bochs:6> s
--------- 進(jìn)入core -------------------------------------------------------------
| Bochs
| (0) [0x0000000415e2] 0038:00000000000003fa (unk. ctxt): mov ecx, 0x00000030
| 讀出內(nèi)核代碼段選擇子是 0x38
| ex15-1_core.lst
| 946 000003FA B930000000 mov ecx,core_data_seg_sel ;令DS指向核心數(shù)據(jù)段
| 0x03FA正是 .lst文件中 的指令前面的匯編地址
---------------------------------------------------------------------------------
<bochs:7> b 0x0038:0x053c
<bochs:8> c
----------- (core)來(lái)到習(xí)題 ex15-1 的第一條指令 ----------
| ex15-1_core.lst
| 1041 0000053C B946000000 mov ecx,0x46
---------------------------------------------------------
<bochs:9> b 0x0038:0x055d
<bochs:10> c
---------(core)即將切換去user Task-A Mss-1 -----------------------------------
| Bochs
| (0) [0x000000041745] 0038:000000000000055d (unk. ctxt): callf es:[ecx+20]
| ex15-1_core.lst
| 1049 0000055D 26FF5914 call far [es:ecx+0x14]
--------------------------------------------------------------------------------
<bochs:11> s
---------------- (user)切換到 任務(wù) Task-A Mss-1 ----------------------
| Bochs
| (0) [0x0000001004c0] 000f:0000000000000000 (unk. ctxt): mov ax, ds
------------------------------------------------------------------------
<bochs:16> s
----------------- (user)一直單步執(zhí)行 直到 執(zhí)行完 賦值語(yǔ)句 ----------------------
| Bochs
| (0) [0x0000001004cb] 000f:000000000000000b (unk. ctxt): mov edx, dword ptr fs:0x00000328 ; 648b1528030000
| ex15-1_A.lst
| 80 0000000B 648B15[28030000] mov edx,[fs:mss_type]
------------------------------------------------------------------------------------------------
<bochs:18> r
rdx: 00000000_00000001
<bochs:19> sreg
fs:0x0007, dh=0x0040f310, dl=0x0150032b, valid=3
Data segment, base=0x00100150, limit=0x0000032b, Read/Write, Accessed
-----------------------------------------------------------------------
| fs 寄存器此時(shí)指向 用戶程序 頭部段
| 讀出 其線性地址 base=0x00100150
| 讀出 段內(nèi)偏移量 見單步調(diào)試結(jié)果里的 fs:0x00000328
| [fs:mss_type] 內(nèi)存真實(shí)物理地址 = 線性地址(0x100150) + 段內(nèi)偏移量(0x328)= 0x100478
------------------------------------------------------------------------
<bochs:21> xp 0x100478
[bochs]:
0x0000000000100478 <bogus+ 0>: 0x00000001
------------------- 查看內(nèi)存具體數(shù)值 --------
| rdx: 00000000_00000001
| 數(shù)值一致,正確√
--------------------------------------------
<bochs:23> b 0x000f:0x0037
<bochs:24> c
-----------------(user) 執(zhí)行完 user,即將切換回core -------------------------------------------------
| Bochs
| (0) [0x0000001004f7] 000f:0000000000000037 (unk. ctxt): callf fs:0x00000128 ; 64ff1d28010000
------------------------------------------------------------------------------------------------------
<bochs:25> s
-----------------(user)調(diào)用門 TerminateProgram -----------------------------------------------
| ex15-1_core.lst
| (0) [0x000000040212] 0028:00000000000001fa (unk. ctxt): pushf ; 9c
-----------------------------------------------------------------------------------------------
<bochs:26> b 0x0028:0x0230
<bochs:27> c
--------------(user)調(diào)用門 TerminateProgram 的最后一條返回指令 ---------------------------------
| Bochs
| (0) [0x000000040248] 0028:0000000000000230 (unk. ctxt): iret ; cf
-----------------------------------------------------------------------------------------------
<bochs:28> s
----------------(core) 回到內(nèi)核程序 ----------------------------------------------------------------
| Bochs
| (0) [0x000000041749] 0038:0000000000000561 (unk. ctxt): mov ebx, 0x00000f72 ; bb720f0000
| ex15-1_core.lst
| 1052 00000561 BB[720F0000] mov ebx,prgman_msg4
| 接下來(lái)就是 任務(wù) Task-B Mss-1 相關(guān)
| 想要查看edx寄存器的內(nèi)容 以及 內(nèi)存的內(nèi)容
| 重復(fù) <bochs:9> 開始的指令,根據(jù)對(duì)應(yīng)的.LST文件,將段內(nèi)偏移進(jìn)行替換即可
----------------------------------------------------------------------------------------------------
Bochs快速調(diào)試過程
- 任務(wù) Task-B Mss-1
<bochs:1> s
<bochs:2> b 0x7c00
<bochs:3> c
---- 進(jìn)入 mbr -----
<bochs:4> b 0x7d38
<bochs:5> c
<bochs:6> s
<bochs:7> b 0x0038:0x056D
<bochs:8> c
(0) [0x000000041755] 0038:000000000000056d (unk. ctxt): mov ecx, 0x00000046
<bochs:9> b 0x0038:0x058E
<bochs:10> c
(0) [0x000000041776] 0038:000000000000058e (unk. ctxt): callf es:[ecx+20]
-----------------------------------------------------------------
| 因?yàn)楹芮宄?,?nèi)核代碼段選擇子是 0x0038
| 段內(nèi)偏移量只要查 .lst 文件,找匯編地址填寫上去就可以了
-------------------------------------------------------------------
<bochs:11> s
(0) [0x000000104a10] 000f:0000000000000000 (unk. ctxt): mov ax, ds
---------- 進(jìn)入了 user Task-B Mss-1 ---------------
<bochs:15> s
(0) [0x000000104a1b] 000f:000000000000000b (unk. ctxt): mov edx, dword ptr fs:0x00000328 ; 648b1528030000
<bochs:17> r
rdx: 00000000_00000001
<bochs:18> sreg
fs:0x0007, dh=0x0040f310, dl=0x46a0032b, valid=3
Data segment, base=0x001046a0, limit=0x0000032b, Read/Write, Accessed
------------ 計(jì)算真實(shí)內(nèi)存地址 ---------
| fs:0x00000328
| base=0x001046a0
| 0x001046a0+ 0x328 = 1049C8
----------------------------------------------
<bochs:19> xp 0x1049c8
[bochs]:
0x00000000001049c8 <bogus+ 0>: 0x00000001
關(guān)于調(diào)試過程
設(shè)置斷點(diǎn)

設(shè)置斷點(diǎn).png
- 知道段選擇子(
Bochs讀出),知道匯編地址(查看.lst文件),就可以精確地設(shè)置斷點(diǎn),比如在內(nèi)核代碼段執(zhí)行的時(shí)候,段選擇子是0x0038,那么斷點(diǎn)肯定是0x0038:NNNN,由于任務(wù)切換返回的時(shí)候要通過調(diào)用門,走到內(nèi)核公用例程段,公用例程段的選擇子是0x0028,處理器就是根據(jù)這些段選擇子是去GDT里查找段描述符的。
執(zhí)行流程的基本判斷
---------------------------- ex15-1_A.lst ----------------------------
77 ;-------------------------------------------------------------
78 ; ex15-1
79 ;-------------------------------------------------------------
80 0000000B 648B15[28030000] mov edx,[fs:mss_type]
81
82 00000012 81FA01000000 cmp edx,1
83 00000018 7511 jne .mss2
84 0000001A BB[00000000] mov ebx,mss_1
85 0000001F 64FF1D[28000000] call far [fs:PrintString]
86 00000026 E90C000000 jmp .mssend
87 .mss2:
88 0000002B BB[21000000] mov ebx,mss_2
89 00000030 64FF1D[28000000] call far [fs:PrintString]
90 .mssend:
91 ;---------------------------------------------------------------
92
93
94 00000037 64FF1D[28010000]
舉例說(shuō)明:當(dāng)執(zhí)行 Task-A Mss-1(任務(wù)A 顯示消息1)的切換任務(wù)時(shí),根據(jù)代碼的條件判斷,可以知道代碼的正確流程走向就是執(zhí)行這條跳轉(zhuǎn)
86 00000026 E90C000000 jmp .mssend,因此,調(diào)試設(shè)置斷點(diǎn)的時(shí)候,不能設(shè)置斷點(diǎn)到.mss2 后面的 88 0000002B BB[21000000] mov ebx,mss_2,任務(wù)A的消息1的切換過程走不到這里的,然而,此時(shí),在bochs里面,會(huì)看到無(wú)論哪次切換到用戶程序,顯示的段選擇子都是0x000F,因此如果貿(mào)然用了b 0x 000F:0000002B(企圖進(jìn)入.mss2標(biāo)號(hào)后面),那么bochs就會(huì)走到這一步(它會(huì)走到這一步的),因?yàn)樵谌康拇a流程里,的確是有一次可以走到這里,那就是再次切換到任務(wù)A顯示消息2的時(shí)候;全部的代碼流程是A1 B1 A2 B2,這樣就是直接跳到了A2,在bochs的虛擬機(jī)窗口可以看到A1 B1的輸出驗(yàn)證這一點(diǎn)。雖然
fs看上去都是0x000F,但是本質(zhì)上不同,通過sreg查看段寄存器,可以看到base的數(shù)據(jù)都是不同的!這恰恰說(shuō)明了,A1 B1 A2 B2 其實(shí)就是4個(gè)完全不同的任務(wù),它們在內(nèi)存的不同位置存放著,它們彼此毫無(wú)關(guān)系。
詳細(xì)圖解(根據(jù)文件名對(duì)應(yīng)具體步驟)

[core]1.進(jìn)入內(nèi)核程序 使用斷點(diǎn) 跳轉(zhuǎn)到顯示完CPU信息處.png

[core]2、跳轉(zhuǎn)到習(xí)題1 解答代碼開始處.png

[user]1、切換到任務(wù)A 顯示message1.png

[user]2、讀出用戶程序代碼段選擇子.png

[user]3、查看控制消息顯示參數(shù)的值是否正確傳遞.png

[user]4、調(diào)用門 執(zhí)行內(nèi)核程序 公用例程段的子程序.png

[user]5、第一次切換到任務(wù)A 顯示消息1 并返回.png

真實(shí)內(nèi)存地址.png

如何計(jì)算 mss_type 所在的真實(shí)內(nèi)存物理地址.png

任務(wù)A 消息2.png

任務(wù)B 消息2.png