调试分析Linux 0.00引导程序
Bochs虛擬機的配置文件
簡介 Bochs 虛擬機的配置文件
描述待啟動的虛擬機的配置,例如內存大小、啟動鏡像、網絡功能、存儲配置。
Bochs運行后,會先查找配置文件,解析模擬器要虛擬的系統相關信息后啟動系統。
如何設置從軟驅啟動
floppya: 1_44="Image", status=inserted
boot: a
如何設置從硬盤啟動
ata0-master: type=disk, path="30M.sample", cylinders=615, heads=6, spt=17
boot: disk
如何設置調試選項
-
log: bochsout.txt:設置日志生成文件。 -
config_interface:配置界面,一系列菜單和對話框。根據平臺的不同,有3種配置界面可供選擇。 -
display_library:這一行指定了Bochs如何渲染模擬機的顯示輸出。
# windows
config_interface: win32config
display_library: win32, options="gui_debug"
# Linux
# display_library: x, options="gui_debug"
# MacOS
# display_library: sdl2
-
win32表示它將使用Windows原生的GUI庫。options="gui_debug"表示在GUI中啟用調試功能。
Bochs虛擬機的調試技巧
如何單步跟蹤?
命令s,或點擊Step(s)。
如何設置斷點進行調試?
-
vb / vbreak seg:0ffset在虛擬地址上設置指令斷點。 -
lb / lbreak addr在線性地址上設置斷點。 -
b / break / pb / pbreak addr在物理地址上設置斷點。 -
info break顯示當前所有斷點的信息。 -
d / del / delete n刪除斷點 n。(斷點是從1開始編號的)
如何查看通用寄存器的值?
registers / reg / r
如何查看系統寄存器的值?
-
sreg查看段寄存器 -
info flags查看標志寄存器 -
cr查看控制寄存器
如何查看內存指定位置的值?
-
x /nuf addr檢查位于線性地址addr處的內存內容 -
xp /nuf addr檢查位于物理地址addr處的內存內容 - 參數
n:顯示內存單元的計數值,默認為1 - 參數
u:單元大小,默認為w-
b:bytes 1字節 -
h:halfwords 2字節 -
w:words 4字節 -
g:giantwords 8字節
-
- 參數
f:顯示格式,默認為x-
x:hex 十六進制數 -
d:decimal 十進制數 -
u:unsigned 無符號十進制 -
o:octal 八進制 -
t:binary 二進制數 -
c:char 對應的字符
-
如何查看各種表,如 gdt ,idt ,ldt 等?
-
info gdt-
info gdt [num]顯示第num項
-
info idtinfo ldt
如何查看 TSS?
info tss
如何查看棧中的內容?
print-stack
如何在內存指定地方進行反匯編?
u/disasm/disassemble start end-
u /10:反匯編從當前地址開始的10條指令
計算機引導程序
如何查看 0x7c00 處被裝載了什么?
查看數據: View -> Linear Dump 輸入 0x7c00。
反匯編:u/disasm/disassemble 0x7c00 end
如何把真正的內核程序從硬盤或軟驅裝載到自己想要放的地方;
調用BIOS中斷int 0x13功能2從啟動盤讀取代碼。
如何查看實模式的中斷程序?
實模式的中斷向量表處于內存0開始的地方。中斷向量表中中斷向量保存著中斷程序的入口地址。
如何靜態創建 gdt 與 idt ?
在程序中定義數據,靜態輸入對應的gdt與idt的值。
如何從實模式切換到保護模式?
控制寄存器CR0位0,為標志PE。置位時為保護模式,復位時為實模式。
利用lmsw指令,Load Machine State Word,將PE置為1,切換到保護模式。
調試跟蹤 jmpi 0,8 ,解釋如何尋址?
此時不是實模式下的段基址與偏移地址的尋址方式了。段值已經是段選擇子。
0為偏移量,8為段選擇子,對應GDT中的段描述符2。
即從GDT中找到段選擇子為 8的段描述符,然后從段描述符中,取出基地址(base address),與偏移量合成線性地址。
該指令執行后,CS:IP即變為0x8:0x0。
實驗報告
請簡述 head.s 的工作原理
- 初始化GDT和IDT,設置GDHR和IDTR。
- 設置8253定時芯片。
- 設置定時中斷門描述符和系統調用陷阱門描述符,分別在IDT表的第8項和第128項。
- 利用
iret命令,跳轉到程序 任務0。
記錄head.s的內存分布狀況
簡述head.s 57至62行在做什么
57至62行:
<57> pushl $0x17 # 堆棧段選擇符(SS)入棧
<58> pushl $init_stack # 堆棧段偏移(SP)入棧
<59> pushfl # 標志寄存器入棧
<60> pushl $0x0f # 代碼段選擇符(CS)入棧
<61> pushl $task0 # 代碼段偏移(IP)入棧
<62> iret
因為當前head.s 程序是內核程序,特權級別為 0。
由于處于特權級0的代碼不能直接把控制權轉移到特權級3的代碼中執行,但中斷返回操作可以。因此,可以利用中斷返回指令 iret來啟動任務0。
具體操作是,在初始堆棧init_stack中人工設置一個返回環境(初始堆棧也是任務0的用戶棧):
- 任務0的 TSS段選擇符加載到任務寄存器
LTR。 - 任務0的 LDT段選擇符加載到
LDTR。 - 任務0的用戶棧指針(
SS:SP),代碼指針(CS:IP)以及標志寄存器壓入棧中。 - 執行返回中斷指令
iret。彈出棧中內容,對應到任務0的堆棧指針、代碼指針、標志寄存器。
簡述iret執行后,pc如何找到下一條指令?
由于在iret前,棧中壓入了代碼指針,即代碼段的段選擇符和偏移量(CS:IP),所以iret后,彈出代碼指針,pc根據當前代碼指針執行下一條指令。
記錄 iret 執行前后,棧是如何變化的?
執行前:可以看到,棧頂自下的5個內容(雙字)分別為 IP、CS、EFLAGS、SP、SS。對應壓棧的順序。
執行后:可見,彈出5個雙字,
當任務進行系統調用時,即 int 0x80 時,記錄棧的變化情況。
任務0進行系統調用int 0x80前:
SS:0x17 ESP:0x0bd8
CS:0x0F EIP:0x10E9
棧空間為任務0的用戶棧,即init_stack。
系統調用后:
SS:0x10 ESP:0x0e4c
CS:0x08 EIP:0x166
棧空間為任務0的內核棧。ESP不為0x0e60,可知棧中壓入了內容。
觀察圖,發現棧中壓入了5個雙字,由棧頂自下分別為 調用前的EIP、調用前的CS、調用前的EFLAGS、調用前的ESP、調用前的SS。
可知,在調用中斷時,指令int 0x80,會將當前任務的該 5個寄存器內容壓入調用后的棧空間中。也就是被調用者保存。
總結
以上是生活随笔為你收集整理的调试分析Linux 0.00引导程序的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 从像素到洞见:图像分类技术的全方位解读
- 下一篇: 初探 Linux Cgroups:资源控