加载引导加载程序的第二阶段和/或将控制权转移给它时出现问题 [英] Problems loading second stage of a bootloader and/or transferring control to it
问题描述
我的主引导记录代码:
;bit16;默认 16 位组织 0x7c00jmp 短启动没有bsOEM db "OS423 v.0.1" ;原始设备制造商字符串开始:;;CLSmov ah,06h ;函数06h(滚动屏幕)mov al,0 ;滚动所有行mov bh,0x0f ;属性(蓝底浅绿)mov ch,0 ;左上一行为零mov cl,0 ;左上列为零mov dh,24 ;左下一行是24mov dl,79 ;左下栏是79int 10h ;BIOS 中断 10h(视频服务);;打印欢迎信息mov ah,13h ;函数13h(显示字符串),仅限XT机mov al,1 ;写模式为零:光标停留在最后一个字符之后mov bh,0 ;使用视频页面为零mov bl,0x0f ;属性(蓝底浅绿)mov cx,mlen ;字符串长度mov dh,0 ;位置在第0行mov dl,0 ;和第0列lea bp,[msg] ;将字符串的偏移地址加载到BP中,es:bp;同 mov bp, msg10 小时;;将扇区加载到内存中5678h:1234hmov bx, 0x5678 ;分段地址mov es, bx ;移动分段地址到esmov bx,0x1234 ;基地址到bxmov ah, 02 ;函数读取扇区mov al, 01 ;要加载的扇区数mov ch, 00 ;要读取的轨道mov cl, 02 ;要读取的扇区mov dh, 00 ;读头mov dl, 00 ;驱动器号int 0x13 ;调用中断13jmp 0x5678:0x1234 ;跳转到内存地址整数 20;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;msg: db '欢迎使用 Pradox OS 0.1!作者:何建松', 10, 13, '$'mlen equ $-msg填充时间 510-($-$$) db 0 ;使 MBR 为 512 字节bootSig db 0x55, 0xaa ;签名(可选)
我用于 nasm 编译并将二进制文件放入我的 .img 软盘的终端命令:
line1:定义一个名为boot.img的软盘,块大小512字节,共2880字节
line2:使用nasm编译器,将mbr.asm文件编译成二进制格式,存放在名为mbr.bin的文件中(这是我的主引导记录)
line3: 在 dt.bin 处将 dt.asm 编译成二进制
line4:将mbr.bin的内容放入boot.img,块大小512,共放入1块
line5:将dt.bin的内容放入boot.img,块大小512,物理扇区#2(逻辑扇区#1)
dd if=/dev/zero of=boot.img bs=512 count=2880nasm -f bin mbr.asm -o mbr.binnasm -f bin dt.asm -o dt.bindd if=mbr.bin of=boot.img bs=512 count=1 conv=notruncdd if=dt.bin of=boot.img bs=512 seek=1 count=1 conv=notrunc
dt.asm 中的代码:
[BITS 16] ;设置代码生成为16位模式ORG 0x5647:0x1234 ;设置地址从 579b4H 开始开始:;call cls ;调用例程清除屏幕;call dspmsg ;调用例程来显示消息通话日期呼叫 cvtmo致电 cvtday呼叫中心呼叫 cvtyear调用 dspdate通话时间呼叫 cvthrs呼叫 cvtmin呼叫 cvtsec呼叫 dsptimeint 20h ;停止操作(非常重要!!!)分类:mov ah,06h ;function 06h (滚动屏幕)mov al,0 ;滚动所有行mov bh,0x0f ;属性(蓝底白字)mov ch,0 ;左上一行为零mov cl,0 ;左上列为零mov dh,24 ;左下一行是24mov dl,79 ;左下栏是79int 10H ;BIOS 中断 10h(视频服务)回复dspmsg:mov ah,13h ;function 13h (显示字符串)mov al,1 ;写模式为零mov bh,0 ;使用视频页面为零mov bl,0x0a ;属性(亮蓝上亮白)mov cx,mlen2 ;字符长度mov dh,0 ;在第0行的位置mov dl,0 ;和第0列lea bp,[welcom] ;将字符串的偏移地址加载到BP10小时回复welcom: db 'jiangong Hes first Operating System :D',10,13,'$'mlen2 equ $-welcom;日期:;从系统获取日期mov ah,04h ;function 04h (获取 RTC 日期)int 1Ah ;BIOS 中断 1Ah(读实时时钟)回复;CH - 世纪;CL - 年;DH - 月;DL - 天简历:;将系统日期从 BCD 转换为 ASCIImov bh,dh ;复制月份(dh)的内容到bhshr bh,1shr bh,1shr bh,1shr bh,1添加 bh,30h ;添加 30h 转换为 asciimov [dtfld],bhmov bh,dh和 bh,0fh添加 bh,30hmov [dtfld + 1],bh回复生日:mov bh,dl ;将天(dl)的内容复制到bhshr bh,1shr bh,1shr bh,1shr bh,1添加 bh,30h ;添加 30h 转换为 asciimov [dtfld + 3],bhmov bh,dl和 bh,0fh添加 bh,30hmov [dtfld + 4],bh回复浓度:mov bh,ch ;复制世纪(ch)的内容到bhshr bh,1shr bh,1shr bh,1shr bh,1添加 bh,30h ;添加 30h 转换为 asciimov [dtfld + 6],bhmov bh,ch和 bh,0fh添加 bh,30hmov [dtfld + 7],bh回复年份:mov bh,cl ;复制年份(cl)的内容到bhshr bh,1shr bh,1shr bh,1shr bh,1添加 bh,30h ;添加 30h 转换为 asciimov [dtfld + 8],bhmov bh,cl和 bh,0fh添加 bh,30hmov [dtfld + 9],bh回复dtfld: db '00/00/0000'日期:;显示系统日期mov ah,13h ;function 13h (显示字符串)mov al,0 ;写模式为零mov bh,0 ;使用视频页面为零mov bl,0x0f ;属性mov cx,10 ;字符串长度为10mov dh,4 ;在第 4 行的位置mov dl,0 ;和第 28 列push ds ; 将 ds 寄存器放入堆栈pop es ;pop 到 es 寄存器lea bp,[dtfld] ;将字符串的偏移地址加载到BP中10小时回复时间:;从系统中获取时间移动啊,02h1Ah回复;CH - 小时;CL - 分钟;DH - 秒cvthrs:;将系统时间从BCD转换为ASCIImov bh,ch ;复制小时(ch)的内容到bhshr bh,1shr bh,1shr bh,1shr bh,1添加 bh,30h ;添加 30h 转换为 asciimov [tmfld],bhmov bh,ch和 bh,0fh添加 bh,30hmov [tmfld + 1],bh回复cvtmin:mov bh,cl ; 将分钟 (cl) 的内容复制到 bhshr bh,1shr bh,1shr bh,1shr bh,1添加 bh,30h ;添加 30h 转换为 asciimov [tmfld + 3],bhmov bh,cl和 bh,0fh添加 bh,30hmov [tmfld + 4],bh回复cvtsec:mov bh,dh ;复制秒(dh)的内容到bhshr bh,1shr bh,1shr bh,1shr bh,1添加 bh,30h ;添加 30h 转换为 asciimov [tmfld + 6],bhmov bh,dh和 bh,0fh添加 bh,30hmov [tmfld + 7],bh回复tmfld: db '00:00:00'时间:;显示系统时间mov ah,13h ;function 13h (显示字符串)mov al,0 ;写模式为零mov bh,0 ;使用视频页面为零mov bl,0x0f;属性mov cx,8 ;字符串长度为8mov dh,5 ; 位置在第 5 行mov dl,0;和第0列push ds ; 将 ds 寄存器放入堆栈pop es ;pop 到 es 寄存器lea bp,[tmfld] ;将字符串的偏移地址加载到BP中10小时回复20小时
我的测试环境是 dosbox,我可以在屏幕上成功显示欢迎消息,但无法将另一个扇区加载到内存中,从 0x5647:0x1234 开始谢谢
由于其他答案中未涵盖许多问题,我将提供一个新答案.
我建议在其他 Stackoverflow 答案中查看我的一般引导加载程序提示.特别是前几个技巧在这里适用:
<块引用>当 BIOS 跳转到您的代码时,您不能依赖 CS、DS、ES、SS,SP 寄存器具有有效值或预期值.当您的引导加载程序启动时,它们应该被适当地设置.您只能保证您的引导加载程序将从物理地址 0x00007c00 加载并运行,并且引导驱动器编号已加载到 DL 寄存器中.
中找到更多相关信息lodsb
、movsb
等使用的方向标志可以设置或清除.如果方向标志设置不当,SI/DI 寄存器可能会调整到错误的方向.使用STD
/CLD
将其设置为您希望的方向(CLD=forward/STD=backwards).在这种情况下,代码假定向前移动,因此应使用CLD
.可以在 指令集参考当跳转到一个内核时,通常一个好主意是 FAR JMP 到它,以便它正确地将 CS:IP 设置为预期值.这可以避免内核代码可能在同一段内执行absolute near JMPs 和CALLs 的问题.
在您的代码中,您的引导加载程序应该在 SS:SP 中设置一个堆栈指针.将它放在引导加载程序正下方是合理的 0x0000:0x7c00.您应该在销毁DL 寄存器之前保存它,因为它包含引导驱动器编号.您可以在开始时将其压入堆栈,并在设置访问的磁盘相关例程时将其恢复 int 13h
.您不应假设 ES 或 DS(特别是 DS)的值设置为 0.因为您使用的 ORG 为 0x7c00这些段需要 0x0000.(0x0000<<4)+0x7c00 = 物理地址 0x07c00.
要解决这些问题,您可以在 start
标签后添加这些行:
开始:mov [bootdrv],dl;将通过DL传入的启动盘保存到bootloaderxor ax,ax ; 因为我们使用 ORG 0x7c00,所以将 ES 和 DS 设置为零移动,斧头mov ds,axmov ss,ax ;将 SS:SP 设置为引导加载程序下方的 0x0000:0x7c00mov sp,0x7c00cld ;设置方向标志向前
您需要在拥有 msg
bootdrv
变量bootdrv: db 0
在使用 int 13h
磁盘读取功能之前,您现在可以在发出中断之前使用 bootdrv
中的值并将其放入 DL称呼.这一行应该被替换:
mov dl, 00 ;驱动器号
与:
mov dl,[bootdrv];获取bootloader启动时保存的启动盘
在 jmp 0x5678:0x1234
之后,您的引导加载程序中有 int 20
.我相信你的意思是 int 20h.JMP 永远不会返回,所以在它什么都不做之后放置代码.但是,int 20h
是 DOS 中断,只有在 MS-DOS 系统从磁盘加载到内存后才可用.当然,您的磁盘上没有 MS-DOS.在引导加载程序(裸机)环境中,根本不要使用 DOS 中断.
在 dt.asm
中你有一些问题.您FAR JMP 到 0x5678:0x1234 处新加载的代码.在这样做时 CS 被设置为 0x5678.您需要手动设置ES 和DS,您可以通过将CS 中的值复制到DS 来实现> 和 ES.您还需要设置适当的 ORG.在这种情况下,原点是从段的开头 (0x5678) 开始的 0x1234,因此您必须使用 org 0x1234
.dt.asm
的顶部可以修改为:
BITS 16 ;设置代码生成为16位模式ORG 0x1234 ;设置原点为0x1234mov ax, cs ;复制 CS 到 DS 和 ES;或者可以使用 mov ax, 0x5678mov ds, ax移动,斧头开始:
前面讨论的 int 20h
问题是 dt.asm
中的问题.删除它的所有出现.相反,您可以将处理器置于无限循环中.dt.asm
中执行的最后一段代码是在 call dsptime
返回之后.在 CALL 之后,您可以使用以下内容进行无限循环:
jmp $
一个更可取的可以减少处理能力的无限循环是使用 CLI,使用 HLT 指令,然后为了安全措施,如果 HLT 返回 JMP 并再次执行 HLT(如果存在 NMI 非-可屏蔽中断).HLT 等待下一个中断发生.这是您经常看到的:
cli结束循环:高jmp 结束循环
其他观察
它出现在您将参数发布到 的代码的第一个版本中INT 13h/AH=2 磁盘读取功能不正确.扇区编号从 1 开始,磁头和柱面从零开始.中断信息的最佳来源是 Ralph Brown 的中断列表,其中涵盖了 BIOS 和 MS-DOS 中断.如果您需要有关中断参数的信息,这是一个很好的参考.
我建议使用 BOCHS 来调试引导加载程序.它有一个命令行调试器,可以理解实模式寻址,可用于在指令执行时观察指令、设置断点、显示寄存器、检查内存等.
my code for master boot record:
;bit16 ; 16bit by default
org 0x7c00
jmp short start
nop
bsOEM db "OS423 v.0.1" ; OEM String
start:
;;cls
mov ah,06h ;Function 06h (scroll screen)
mov al,0 ;Scroll all lines
mov bh,0x0f ;Attribute (lightgreen on blue)
mov ch,0 ;Upper left row is zero
mov cl,0 ;Upper left column is zero
mov dh,24 ;Lower left row is 24
mov dl,79 ;Lower left column is 79
int 10h ;BIOS Interrupt 10h (video services)
;;print welcome msg
mov ah,13h ;Function 13h (display string), XT machine only
mov al,1 ;Write mode is zero: cursor stay after last char
mov bh,0 ;Use video page of zero
mov bl,0x0f ;Attribute (lightgreen on blue)
mov cx,mlen ;Character string length
mov dh,0 ;Position on row 0
mov dl,0 ;And column 0
lea bp,[msg] ;Load the offset address of string into BP, es:bp
;Same as mov bp, msg
int 10h
;;load sector into memory & 5678h:1234h
mov bx, 0x5678 ;segmented address
mov es, bx ;move segemented address to es
mov bx,0x1234 ;base address to bx
mov ah, 02 ;function read sectors
mov al, 01 ;# of sectors to load
mov ch, 00 ;track to read
mov cl, 02 ;sector to read
mov dh, 00 ;head to read
mov dl, 00 ;drive number
int 0x13 ;call interrupt 13
jmp 0x5678:0x1234 ;jump to memory address
int 20
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;variables;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
msg: db 'Welcome to Pradox OS 0.1! Authored by Jiansong he', 10, 13, '$'
mlen equ $-msg
padding times 510-($-$$) db 0 ;to make MBR 512 bytes
bootSig db 0x55, 0xaa ;signature (optional)
my terminal command for nasm compiling and puting the binary files into my .img floppy disk:
line1: define a floppy dick named boot.img, block size 512 byte, in total of 2880 byte
line2: use nasm compiler, compile mbr.asm file into binary format, store it at file named mbr.bin(which is my master boot record)
line3: compile dt.asm into binary at dt.bin
line4: put mbr.bin's content into boot.img, block size 512, put total 1 block
line5: put dt.bin's content into boot.img, block size 512, at physical sector #2(logical sector #1)
dd if=/dev/zero of=boot.img bs=512 count=2880
nasm -f bin mbr.asm -o mbr.bin
nasm -f bin dt.asm -o dt.bin
dd if=mbr.bin of=boot.img bs=512 count=1 conv=notrunc
dd if=dt.bin of=boot.img bs=512 seek=1 count=1 conv=notrunc
code in dt.asm:
[BITS 16] ;Set code generation to 16 bit mode
ORG 0x5647:0x1234 ;set addressing to begin at 579b4H
startdt:
;call cls ;call routine to clear screen
;call dspmsg ;call routine to display message
call date
call cvtmo
call cvtday
call cvtcent
call cvtyear
call dspdate
call time
call cvthrs
call cvtmin
call cvtsec
call dsptime
int 20h ;halt operation (VERY IMPORTANT!!!)
cls:
mov ah,06h ;function 06h (Scroll Screen)
mov al,0 ;scroll all lines
mov bh,0x0f ;Attribute (bright white on blue)
mov ch,0 ;Upper left row is zero
mov cl,0 ;Upper left column is zero
mov dh,24 ;Lower left row is 24
mov dl,79 ;Lower left column is 79
int 10H ;BIOS Interrupt 10h (video services)
ret
dspmsg:
mov ah,13h ;function 13h (Display String)
mov al,1 ;Write mode is zero
mov bh,0 ;Use video page of zero
mov bl,0x0a ;Attribute (bright white on bright blue)
mov cx,mlen2 ;Character length
mov dh,0 ;position on row 0
mov dl,0 ;and column 0
lea bp,[welcom] ;load the offset address of string into BP
int 10H
ret
welcom: db 'jiansong Hes first Operating System :D',10,13,'$'
mlen2 equ $-welcom;
date:
;Get date from the system
mov ah,04h ;function 04h (get RTC date)
int 1Ah ;BIOS Interrupt 1Ah (Read Real Time Clock)
ret
;CH - Century
;CL - Year
;DH - Month
;DL - Day
cvtmo:
;Converts the system date from BCD to ASCII
mov bh,dh ;copy contents of month (dh) to bh
shr bh,1
shr bh,1
shr bh,1
shr bh,1
add bh,30h ;add 30h to convert to ascii
mov [dtfld],bh
mov bh,dh
and bh,0fh
add bh,30h
mov [dtfld + 1],bh
ret
cvtday:
mov bh,dl ;copy contents of day (dl) to bh
shr bh,1
shr bh,1
shr bh,1
shr bh,1
add bh,30h ;add 30h to convert to ascii
mov [dtfld + 3],bh
mov bh,dl
and bh,0fh
add bh,30h
mov [dtfld + 4],bh
ret
cvtcent:
mov bh,ch ;copy contents of century (ch) to bh
shr bh,1
shr bh,1
shr bh,1
shr bh,1
add bh,30h ;add 30h to convert to ascii
mov [dtfld + 6],bh
mov bh,ch
and bh,0fh
add bh,30h
mov [dtfld + 7],bh
ret
cvtyear:
mov bh,cl ;copy contents of year (cl) to bh
shr bh,1
shr bh,1
shr bh,1
shr bh,1
add bh,30h ;add 30h to convert to ascii
mov [dtfld + 8],bh
mov bh,cl
and bh,0fh
add bh,30h
mov [dtfld + 9],bh
ret
dtfld: db '00/00/0000'
dspdate:
;Display the system date
mov ah,13h ;function 13h (Display String)
mov al,0 ;Write mode is zero
mov bh,0 ;Use video page of zero
mov bl,0x0f ;Attribute
mov cx,10 ;Character string is 10 long
mov dh,4 ;position on row 4
mov dl,0 ;and column 28
push ds ;put ds register on stack
pop es ;pop it into es register
lea bp,[dtfld] ;load the offset address of string into BP
int 10H
ret
time:
;Get time from the system
mov ah,02h
int 1Ah
ret
;CH - Hours
;CL - Minutes
;DH - Seconds
cvthrs:
;Converts the system time from BCD to ASCII
mov bh,ch ;copy contents of hours (ch) to bh
shr bh,1
shr bh,1
shr bh,1
shr bh,1
add bh,30h ;add 30h to convert to ascii
mov [tmfld],bh
mov bh,ch
and bh,0fh
add bh,30h
mov [tmfld + 1],bh
ret
cvtmin:
mov bh,cl ;copy contents of minutes (cl) to bh
shr bh,1
shr bh,1
shr bh,1
shr bh,1
add bh,30h ;add 30h to convert to ascii
mov [tmfld + 3],bh
mov bh,cl
and bh,0fh
add bh,30h
mov [tmfld + 4],bh
ret
cvtsec:
mov bh,dh ;copy contents of seconds (dh) to bh
shr bh,1
shr bh,1
shr bh,1
shr bh,1
add bh,30h ;add 30h to convert to ascii
mov [tmfld + 6],bh
mov bh,dh
and bh,0fh
add bh,30h
mov [tmfld + 7],bh
ret
tmfld: db '00:00:00'
dsptime:
;Display the system time
mov ah,13h ;function 13h (Display String)
mov al,0 ;Write mode is zero
mov bh,0 ;Use video page of zero
mov bl,0x0f;Attribute
mov cx,8 ;Character string is 8 long
mov dh,5 ;position on row 5
mov dl,0;and column 0
push ds ;put ds register on stack
pop es ;pop it into es register
lea bp,[tmfld] ;load the offset address of string into BP
int 10H
ret
int 20H
my testing environment is dosbox, I can successfully display the welcome message on screen but failed to load another sector into memory starting at 0x5647:0x1234 thanks
Since there are a number of issues not covered in the other answer, I'll provide a new answer.
I recommend looking at my General Bootloader Tips in this other Stackoverflow answer. In particular the first few tips apply here:
When the BIOS jumps to your code you can't rely on CS,DS,ES,SS,SP registers having valid or expected values. They should be set up appropriately when your bootloader starts. You can only be guaranteed that your bootloader will be loaded and run from physical address 0x00007c00 and that the boot drive number is loaded into the DL register.
The direction flag used by
lodsb
,movsb
etc could be either set or cleared. If the direction flag is set improperly SI/DI registers may be adjusted in the wrong direction. UseSTD
/CLD
to set it to the direction you wish (CLD=forward/STD=backwards). In this case the code assumes forward movement so one should useCLD
. More on this can be found in an instruction set referenceWhen jumping to a kernel it is generally a good idea to FAR JMP to it so that it properly sets CS:IP to expected values. This can avoid problems with kernel code that may do absolute near JMPs and CALLs within the same segment.
In your code your bootloader should set up a stack pointer in SS:SP. Placing it just below the bootloader is reasonable at 0x0000:0x7c00. You should save DL register before destroying it because it contains the boot drive number. You could push it on the stack at the start and restore it when you set up the disk related routines accessed int 13h
. You shouldn't assume that ES or DS (DS in particular) are set to the value of 0. Since you use an ORG of 0x7c00 the segments need 0x0000. (0x0000<<4)+0x7c00 = physical address 0x07c00.
To resolve these issues you could add these lines after the start
label:
start:
mov [bootdrv],dl;Save the boot drive passed in via DL to the bootloader
xor ax,ax ;Set ES and DS to zero since we use ORG 0x7c00
mov es,ax
mov ds,ax
mov ss,ax ;Set SS:SP to 0x0000:0x7c00 below bootloader
mov sp,0x7c00
cld ;Set direction flag forward
You'll need to add a bootdrv
variable after you have msg
bootdrv: db 0
Before you use the int 13h
disk read feature you can now use the value in bootdrv
and place it into DL before issuing the interrupt call. This line should be replaced:
mov dl, 00 ;drive number
With:
mov dl,[bootdrv];Get the boot drive saved at start of bootloader
You have int 20
in your bootloader after the jmp 0x5678:0x1234
. I believe you meant int 20h. The JMP will never return so placing code after it will do nothing. However, int 20h
is a DOS interrupt that is only available after MS-DOS system is loaded from disk into memory. You have no MS-DOS on your disk of course. In a bootloader (bare metal) environment just don't use DOS interrupts at all.
In dt.asm
you have some issues. You FAR JMP to the newly loaded code at 0x5678:0x1234. In doing so CS was set to 0x5678. You'll need to manually set ES and DS, You can do this by copying the value in CS to DS and ES. You also need to set the appropriate ORG. In this case the origin point is 0x1234 from the beginning of the segment (0x5678) so you must use org 0x1234
. The top of dt.asm
could be modified to look like:
BITS 16 ;Set code generation to 16 bit mode
ORG 0x1234 ;set origin point to 0x1234
mov ax, cs ;copy CS to DS and ES
;alternatively could have used mov ax, 0x5678
mov ds, ax
mov es, ax
startdt:
The issue with int 20h
discussed previously is an issue in dt.asm
. Remove all occurrences of it. Instead you can put the processor in an infinite loop. The last of your code in dt.asm
that is executed is after call dsptime
returns. After that CALL you can put an infinite loop with something like:
jmp $
A more preferable infinite loop that can take less processing power is to turn off the interrupts using CLI, use a HLT instruction and then for safe measure if HLT returns JMP back and do HLT again (Could happen if there is an NMI Non-Maskable Interrupt). HLT waits until the next interrupt occurs. This is what you'll often see instead:
cli
endloop:
hlt
jmp endloop
Other Observations
It appears in the first version of the code you posted the parameters to INT 13h/AH=2 disk read function were incorrect. Sector numbers start at 1 and heads and cylinders are zero based. The best source of interrupt information is Ralph Brown's Interrupt List which covers both BIOS and MS-DOS interrupts. If you need information on the parameters of the interrupts it is an excellent reference.
I'd recommend BOCHS for debugging bootloaders. It has a command line debugger that understands real mode addressing and can be used to watch instructions as they are executed,set breakpoints, display registers, examine memory etc.
这篇关于加载引导加载程序的第二阶段和/或将控制权转移给它时出现问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!