Re: [問題] QEMU+GDB 開機, int 跳不過去的問題

看板LinuxDev作者 (送喔)時間12年前 (2013/03/23 18:33), 編輯推噓7(7030)
留言37則, 2人參與, 最新討論串2/2 (看更多)
※ 引述《ericwang1017 (Eric)》之銘言: : 各位版大好 : 我使用 QEMU -fda os.img -s -S + GDB remote 去 debug 我自己很簡單的 asm : 在使用 target remote localhost:1234 之後很順利的連線到了qemu : 下斷點 b *0x7c00 也可以順利地停在 eip 0x7c00 : 我第一個指令是 : ljmp $0x7C00, $_start : 但遇到個一個問題, ljmp 雖然可以把 CS:IP 設為 0x7c00:0, 但是之後的int 10使用 si 或是ni 就一去不回頭了 : 對int 10之後下斷點也沒用(例如對fin下斷點, 並不會在那邊中斷) : 但是如果ld使用 -Ttext = 0x7c00 , 並且註解掉ljmp $0x7C00, $_start的話 : cs = 0 , eip = 0x7c00 時, 似乎GDB 就可以讓我使用int 10 : 而且這兩種寫法, qemu 都可以正常模擬, 只是CS:IP 設為 0x7c00:0這種情況的 gdb 不給debug : 是我 gdb 的參數沒有設好嗎, 我也設過 set architecture i8086 似乎也沒用 : code 如下 : .code16 : ljmp $0x07C0, $_start : _start: : mov %cs,%ax : mov %ax,%ds : mov %ax,%es : mov $0xFF00, %sp : mov $12,%cx : mov $MsgMove, %ax : mov %ax, %bp : mov $0x1301,%ax : mov $0x00c,%bx : int $0x10 : fin: : hlt : jmp fin : MsgMove:.ascii "Hello World!" : .org 510 : .word 0xaa55 小弟也只是x86新手 最近也在閱讀自己寫作業系統的書籍 所以不保證我所說的是100%正確的 純粹就我的理解來跟大家分享... 以下節錄自《Orange's 一個作業系統的實現》的書籍內容: ------------------------------------- 當電腦電源被打開時 它會先進行加電自檢(POST) 然後尋找開機磁片 如果是選擇從軟碟啟動 電腦就會檢查軟碟的0面0磁軌1扇區 如果發現它以0xAA55結束 則BIOS認為它是一個開機磁區 當然,一個正確的開機磁區除了以0xAA55結束之外 還應該包含一段少於512位元組的執行碼 一旦BIOS發現了開機磁區 就會將這512位元組的內容裝載到記憶體位址:0000:7c00處 然後跳轉到0000:7c00處將控制權徹底的交給這段開機程式碼 -------------------------------------- 由以上的說明,我們可以知道為何最後需要: .org510 .word 0xaa55 就是為了要在512位元組的開機磁區最後兩個bytes填上0xAA55 來讓BIOS可以知道這是一個開機磁區 而由於BIOS會自動將開機磁區512位元組的內容裝載(複製)到記憶體位址:0000:7c00處 因此你必須將你的這段程式連結到0000:7c00處 這樣程式在執行的時候才會執行在正確的位址 這也就是為何需要在連結的時候透過-Ttext = 0x7c00 (在不使用ljmp $0x07c0, $_start的情況) 來告訴Linker將我們的這段程式連結到0000:7c00處 -------------------------------------- 順帶一提,算是我當初看《Orange's 一個作業系統的實現》這段開機程式碼的心得: 這邊用的int $0x10實際上是使用BIOS的Video Service 可以上Wikipedia搜尋相關說明:http://goo.gl/w8TJb 上面說明了當%ah = 0x13時,BIOS提供的Video Service為:Write string 需要設定: %al (Write Mode) %bh (Page Number) %bl (Color) %cx (String Length) %dh (Row) %dl (Column) %es:bp (Offset of String) 這幾個暫存器的值... 一開始我看到這段codes的時候完全不知道為何要設定這些暫存器 在以往的印象int指令都是Software interrupt 根本不知道其實這是BIOS所提供的功能 之後才發現原來BIOS有這段玄機在 -------------------------------------- 最後附上《Orange's 一個作業系統的實現》書中附的開機程式碼: (P.S. 書中所使用的語法是NASM,而非GAS) org 07c00h ; 告訴編譯器程序加載到7c00處 ; 相當於在連結時使用-Ttext = 0x7c00 mov ax, cs mov ds, ax mov es, ax call DispStr ; 使用顯示字元串例程 jmp $ ; 無限循環 DispStr: mov ax, BootMessage mov bp, ax ; ES:BP = 串位址 mov cx, 16 ; CX = 串長度 mov ax, 01301h ; AH = 13, AL = 01h mov bx, 000ch ; 頁號為0(BH = 0) ; 黑底紅字(BL = 0Ch,高亮) mov dl, 0 int 10h ; 10h 號中斷 ret BootMessage: db "Hello, OS world!" times 510-($-$$) db 0 ; 填充剩下的空間,使生成的二進制程式碼 ; 恰好為512字節 dw 0xaa55 ; 結束標誌 -------------------------------------- 如果你也有興趣自己學怎寫一個簡單的作業系統的話.... 《Orange's 一個作業系統的實現》其實是一本非常不錯的書籍 我自己是已經看到第9章檔案系統的部份了 推薦給你參考一下 我也還在學習中,所以不保證我講的東西都是正確的 有問題的話歡迎提出來討論... :) -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 114.36.234.151 ※ 編輯: frank0125 來自: 114.36.234.151 (03/23 18:55)

03/23 19:18, , 1F
謝謝你的回覆, 不過ljmp 是CS:ip , 所以是0x07c0 :)
03/23 19:18, 1F

03/23 19:25, , 2F
我發現我位置有打錯, 以更正
03/23 19:25, 2F

03/23 19:26, , 3F
不過code 那邊是沒打錯的
03/23 19:26, 3F

03/23 19:35, , 4F
喔喔!! 忘記要乘0x10了~ 拍謝!! 8086真的是有點討厭...
03/23 19:35, 4F

03/23 19:36, , 5F
我也修改一下我的回文好了... 不過大致上觀念是相同的~
03/23 19:36, 5F

03/23 19:36, , 6F
您可以試看看把這些code 用qemu + gdb 跑看看
03/23 19:36, 6F

03/23 19:37, , 7F
並且分別用"沒有ljmp"與 "有ljmp"的方式做看看
03/23 19:37, 7F

03/23 19:38, , 8F
就會發現GDB很笨,只認 EIP的數值
03/23 19:38, 8F
※ 編輯: frank0125 來自: 114.36.234.151 (03/23 19:39)

03/23 19:41, , 9F
其實甚至Linux都很少用分段機制...
03/23 19:41, 9F

03/23 19:41, , 10F
Linux都直接把%cs, %es, %ds... 分段暫存器直接設成0x0
03/23 19:41, 10F

03/23 19:43, , 11F
這種模式還有個專有名詞叫做叫做Flat memory model...
03/23 19:43, 11F

03/23 19:44, , 12F
03/23 19:44, 12F

03/23 19:44, , 13F
至於GDB怎做的我就不太清楚了... 不過連Linux都不想用它
03/23 19:44, 13F

03/23 19:45, , 14F
我想一定是有它的麻煩之處... XD
03/23 19:45, 14F

03/23 19:46, , 15F
ㄜ, linux011 的 bootsec.s的第一行就是 LJMP
03/23 19:46, 15F

03/23 19:47, , 16F
事實上, 我的code 上半部就是抄那邊的..
03/23 19:47, 16F

03/23 19:49, , 17F
抱歉更正, linux011的code 我是拿GCC改過的
03/23 19:49, 17F

03/23 19:50, , 18F
Linux 0.01的codes我是沒有trace過... 或許它有用分段
03/23 19:50, 18F

03/23 19:50, , 19F
機制... 不過我看Wiki上是說現在的Linux都已經捨棄分段
03/23 19:50, 19F

03/23 19:50, , 20F
機制不用,只使用分頁機制了...
03/23 19:50, 20F

03/23 19:51, , 21F
當然詳細的情況還是要trace codes才知道~ 不過我想分段
03/23 19:51, 21F

03/23 19:52, , 22F
機制的觀念大概就是那樣... 有機會再多交流~ :)
03/23 19:52, 22F

03/23 20:34, , 23F
不過講了這麼多... 好像改成:ljmp $0x0000, $_start
03/23 20:34, 23F

03/23 20:34, , 24F
配上-Text = 0x7C00應該就可以正確執行了吧?! XDDD
03/23 20:34, 24F
※ 編輯: frank0125 來自: 114.36.234.151 (03/23 20:35)

03/23 20:48, , 25F
兩種方式都可以在qemu正常執行, 只是GDB有差異
03/23 20:48, 25F

03/23 21:02, , 26F
了解... ljmp $0x07C0, $_start應該也是OK的~
03/23 21:02, 26F

03/23 21:03, , 27F
是我想錯了... 回文我再修改一下~
03/23 21:03, 27F

03/23 21:05, , 28F
看來應該是GDB在處理分段機制的時候有問題...
03/23 21:05, 28F

03/23 21:05, , 29F
所以才會載錯位址... 至於程式碼兩者應該都是對的寫法~
03/23 21:05, 29F
※ 編輯: frank0125 來自: 114.36.234.151 (03/23 21:16)

03/24 02:17, , 30F
我也是這樣想, 不過我在猜是否是gdb有參數沒設好..
03/24 02:17, 30F

03/24 02:18, , 31F
還是感謝你回文嚕 :)
03/24 02:18, 31F

03/24 02:21, , 32F
對了, facebook上有個juluOSDev社團, 我想你會有興趣
03/24 02:21, 32F

03/24 08:57, , 33F
我已經加入了, Jsev和Descent兩位都是久仰其名的大大們
03/24 08:57, 33F

03/24 08:59, , 34F
一開始因為記憶體位址的問題而想錯方向了...
03/24 08:59, 34F

03/24 08:59, , 35F
拍謝沒有回答到你真正的問題... QQ
03/24 08:59, 35F

03/24 14:45, , 36F
我的問題已經找到解法了, 回在社團上面, 你可以看看
03/24 14:45, 36F

03/24 16:44, , 37F
OK... Thanks a lot :)
03/24 16:44, 37F
文章代碼(AID): #1HJOJijK (LinuxDev)
文章代碼(AID): #1HJOJijK (LinuxDev)