作者frank0125 (送喔)
看板LinuxDev
标题Re: [问题] QEMU+GDB 开机, int 跳不过去的问题
时间Sat Mar 23 18:33:14 2013
※ 引述《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)
1F:推 ericwang1017:谢谢你的回覆, 不过ljmp 是CS:ip , 所以是0x07c0 :) 03/23 19:18
2F:→ ericwang1017:我发现我位置有打错, 以更正 03/23 19:25
3F:→ ericwang1017:不过code 那边是没打错的 03/23 19:26
4F:→ frank0125:喔喔!! 忘记要乘0x10了~ 拍谢!! 8086真的是有点讨厌... 03/23 19:35
5F:→ frank0125:我也修改一下我的回文好了... 不过大致上观念是相同的~ 03/23 19:36
6F:推 ericwang1017:您可以试看看把这些code 用qemu + gdb 跑看看 03/23 19:36
7F:→ ericwang1017:并且分别用"没有ljmp"与 "有ljmp"的方式做看看 03/23 19:37
8F:→ ericwang1017:就会发现GDB很笨,只认 EIP的数值 03/23 19:38
※ 编辑: frank0125 来自: 114.36.234.151 (03/23 19:39)
9F:→ frank0125:其实甚至Linux都很少用分段机制... 03/23 19:41
10F:→ frank0125:Linux都直接把%cs, %es, %ds... 分段暂存器直接设成0x0 03/23 19:41
11F:→ frank0125:这种模式还有个专有名词叫做叫做Flat memory model... 03/23 19:43
13F:→ frank0125:至於GDB怎做的我就不太清楚了... 不过连Linux都不想用它 03/23 19:44
14F:→ frank0125:我想一定是有它的麻烦之处... XD 03/23 19:45
15F:推 ericwang1017:ㄜ, linux011 的 bootsec.s的第一行就是 LJMP 03/23 19:46
16F:→ ericwang1017:事实上, 我的code 上半部就是抄那边的.. 03/23 19:47
17F:→ ericwang1017:抱歉更正, linux011的code 我是拿GCC改过的 03/23 19:49
18F:→ frank0125:Linux 0.01的codes我是没有trace过... 或许它有用分段 03/23 19:50
19F:→ frank0125:机制... 不过我看Wiki上是说现在的Linux都已经舍弃分段 03/23 19:50
20F:→ frank0125:机制不用,只使用分页机制了... 03/23 19:50
21F:→ frank0125:当然详细的情况还是要trace codes才知道~ 不过我想分段 03/23 19:51
22F:→ frank0125:机制的观念大概就是那样... 有机会再多交流~ :) 03/23 19:52
23F:→ frank0125:不过讲了这麽多... 好像改成:ljmp $0x0000, $_start 03/23 20:34
24F:→ frank0125:配上-Text = 0x7C00应该就可以正确执行了吧?! XDDD 03/23 20:34
※ 编辑: frank0125 来自: 114.36.234.151 (03/23 20:35)
25F:推 ericwang1017:两种方式都可以在qemu正常执行, 只是GDB有差异 03/23 20:48
26F:→ frank0125:了解... ljmp $0x07C0, $_start应该也是OK的~ 03/23 21:02
27F:→ frank0125:是我想错了... 回文我再修改一下~ 03/23 21:03
28F:→ frank0125:看来应该是GDB在处理分段机制的时候有问题... 03/23 21:05
29F:→ frank0125:所以才会载错位址... 至於程式码两者应该都是对的写法~ 03/23 21:05
※ 编辑: frank0125 来自: 114.36.234.151 (03/23 21:16)
30F:推 ericwang1017:我也是这样想, 不过我在猜是否是gdb有参数没设好.. 03/24 02:17
31F:→ ericwang1017:还是感谢你回文噜 :) 03/24 02:18
32F:推 ericwang1017:对了, facebook上有个juluOSDev社团, 我想你会有兴趣 03/24 02:21
33F:→ frank0125:我已经加入了, Jsev和Descent两位都是久仰其名的大大们 03/24 08:57
34F:→ frank0125:一开始因为记忆体位址的问题而想错方向了... 03/24 08:59
35F:→ frank0125:拍谢没有回答到你真正的问题... QQ 03/24 08:59
36F:推 ericwang1017:我的问题已经找到解法了, 回在社团上面, 你可以看看 03/24 14:45
37F:→ frank0125:OK... Thanks a lot :) 03/24 16:44