如何修复“从引导加载程序跳转到 C 代码时出现无限循环错误”
How to fix " Infinite Loop error on jumping to C code from bootloader"
我实际上正在尝试 运行 C 代码来编写我的操作系统内核,以研究操作系统的工作原理。当引导加载程序跳转到我的 C 代码时,我陷入了这个无限循环。我应该如何防止这个错误
虽然我的引导加载程序工作正常,但当我的引导加载程序跳转到用 C 编写的内核代码作为 a.COM
程序时,问题就来了。最主要的是,尽管代码必须 运行 一次,但伪代码只是一次又一次地打印一个字符。似乎主代码被一次又一次地调用。这是 startpoint.asm
程序集 header 和 bootmain.cpp
文件的代码。
这里是 startpoint.asm
的代码,最初是 linking 时使用的代码,以便可以自动调用代码。 (写在MASM)
注:代码加载地址2000H:0000H
。
;------------------------------------------------------------
.286 ; CPU type
;------------------------------------------------------------
.model TINY ; memory of model
;---------------------- EXTERNS -----------------------------
extrn _BootMain:near ; prototype of C func
;------------------------------------------------------------
;------------------------------------------------------------
.code
main:
jmp short start ; go to main
nop
;----------------------- CODE SEGMENT -----------------------
start:
cli
mov ax,cs ; Setup segment registers
mov ds,ax ; Make DS correct
mov es,ax ; Make ES correct
mov ss,ax ; Make SS correct
mov bp,2000h
mov sp,2000h ; Setup a stack
sti
; start the program
call _BootMain
ret
END main ; End of prog
bootmain.cpp
代码
extern "C" void BootMain()
{
__asm
{
mov ah,0EH
mov al,'G'
int 10H
}
return;
}
编译和linker命令如下:
编译代码bootmain.cpp
:
CL.EXE /AT /G2 /Gs /Gx /c /Zl bootmain.cpp
编译代码startpoint.asm
:
ML.EXE /AT /c startpoint.asm
代码 link 它们(按保留顺序):
LINK.EXE /T /NOD startPoint.obj bootmain.obj
预期输出:
G
实际输出:
GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG
仔细看看start
的结尾。
start
永远不会被调用——它被直接跳转到,并且它自己设置堆栈。当_BootMain
returns时,栈为空; start
末尾的 ret
将从堆栈末尾上方弹出垃圾数据并尝试跳转到它。如果该内存包含零,程序流将从 return 到 main
.
您需要设置在 _BootMain
return 秒后发生的特定事件。如果你只是想让系统在执行完_BootMain
后挂起,插入一个无限循环(例如jmp .
)到start
的末尾而不是错误的ret
.
或者,考虑让您的引导加载程序设置堆栈本身和 call
COM 可执行文件。当 returns 时,引导加载程序可以采取适当的操作。
我实际上正在尝试 运行 C 代码来编写我的操作系统内核,以研究操作系统的工作原理。当引导加载程序跳转到我的 C 代码时,我陷入了这个无限循环。我应该如何防止这个错误
虽然我的引导加载程序工作正常,但当我的引导加载程序跳转到用 C 编写的内核代码作为 a.COM
程序时,问题就来了。最主要的是,尽管代码必须 运行 一次,但伪代码只是一次又一次地打印一个字符。似乎主代码被一次又一次地调用。这是 startpoint.asm
程序集 header 和 bootmain.cpp
文件的代码。
这里是 startpoint.asm
的代码,最初是 linking 时使用的代码,以便可以自动调用代码。 (写在MASM)
注:代码加载地址2000H:0000H
。
;------------------------------------------------------------
.286 ; CPU type
;------------------------------------------------------------
.model TINY ; memory of model
;---------------------- EXTERNS -----------------------------
extrn _BootMain:near ; prototype of C func
;------------------------------------------------------------
;------------------------------------------------------------
.code
main:
jmp short start ; go to main
nop
;----------------------- CODE SEGMENT -----------------------
start:
cli
mov ax,cs ; Setup segment registers
mov ds,ax ; Make DS correct
mov es,ax ; Make ES correct
mov ss,ax ; Make SS correct
mov bp,2000h
mov sp,2000h ; Setup a stack
sti
; start the program
call _BootMain
ret
END main ; End of prog
bootmain.cpp
extern "C" void BootMain()
{
__asm
{
mov ah,0EH
mov al,'G'
int 10H
}
return;
}
编译和linker命令如下:
编译代码bootmain.cpp
:
CL.EXE /AT /G2 /Gs /Gx /c /Zl bootmain.cpp
编译代码startpoint.asm
:
ML.EXE /AT /c startpoint.asm
代码 link 它们(按保留顺序):
LINK.EXE /T /NOD startPoint.obj bootmain.obj
预期输出:
G
实际输出:
GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG
仔细看看start
的结尾。
start
永远不会被调用——它被直接跳转到,并且它自己设置堆栈。当_BootMain
returns时,栈为空; start
末尾的 ret
将从堆栈末尾上方弹出垃圾数据并尝试跳转到它。如果该内存包含零,程序流将从 return 到 main
.
您需要设置在 _BootMain
return 秒后发生的特定事件。如果你只是想让系统在执行完_BootMain
后挂起,插入一个无限循环(例如jmp .
)到start
的末尾而不是错误的ret
.
或者,考虑让您的引导加载程序设置堆栈本身和 call
COM 可执行文件。当 returns 时,引导加载程序可以采取适当的操作。