问题描述
我正在开发Hello World内核和引导程序...我编写了这段代码,但是当我尝试通过NASM编译它时,它说:"bootloader.asm:30:error:TIMES value -44 is negative"./p>
bootloader.asm:
[BITS 16]
[ORG 0x7C00]
MOV DL, 0x80
MOV DH, 0x0
MOV CH, 0x0
MOV CL, 0x02
MOV BX, 0x1000
MOV ES, BX
MOV BX, 0x0
ReadFloppy:
MOV AH, 0x02
MOV AL, 0x01
INT 0x13
JC ReadFloppy
MOV AX, 0x1000
MOV DS, AX
MOV ES, AX
MOV FS, AX
MOV GS, AX
MOV SS, AX
JMP 0x1000:0x0
TIMES 510 - ($ - $$) db 0
DW 0xAA55
kernel.asm:
MOV AH, 0x0E
MOV BH, 0x00
MOV BL, 0x07
MOV SI, msg
CALL PrintString
JMP $
PrintString:
nextch:
MOV AL, [SI]
OR AL, AL
JZ exit
INT 0x10
INC SI
JMP nextch
RET
exit:
RET
msg db 'Hello world from the kernel!', 13, 10, 0
TIMES 512 - ($ - $$) db 0
我用过; nasm -f bin bootloader.asm -o bootloader.bin -p kernel.asm
与双重使用times
相比,您有一个更根本的问题:您正在使用NASM的-p
开关预先包含文件kernel.asm,而建立bootloader.asm.即使您放弃了一个或两个times
用法,内核也会被首先组装并首先执行,而不是您的加载器首先执行.
我修复了您的示例以执行应做的事情:将kernel.asm输出写入第二个512字节扇区,然后在加载程序中,从引导单元加载该扇区并跳转到该扇区.
这是固定源bootloader.asm:
cpu 8086
bits 16
section loader vstart=7C00h start=0
MOV AX, 0x1000
MOV DS, AX
MOV ES, AX
MOV SS, AX
xor sp, sp
MOV DH, 0x0
MOV CH, 0x0
MOV CL, 0x02
xor bx, bx
mov di, 16
ReadFloppy:
dec di
jz .error
MOV AH, 0x02
MOV AL, 0x01
INT 0x13
JC ReadFloppy
JMP 0x1000:0x0
.error:
mov ax, '!' | 0E00h
mov bx, 7
int 10h
.halt:
sti
hlt
jmp .halt
TIMES 510 - ($ - $$) db 0
DW 0xAA55
%include "kernel.asm"
这是kernel.asm:
section kernel vstart=0 follows=loader
MOV AH, 0x0E
MOV BH, 0x00
MOV BL, 0x07
MOV SI, msg
CALL PrintString
halt:
sti
hlt
jmp halt
PrintString:
nextch:
MOV AL, [SI]
OR AL, AL
JZ exit
INT 0x10
INC SI
JMP nextch
exit:
RET
msg db 'Hello world from the kernel!', 13, 10, 0
TIMES 512 - ($ - $$) db 0
这是构建和运行整个示例的方法:
$ nasm -f bin bootloader.asm -o bootloader.bin && qemu-system-i386 -drive file=bootloader.bin,if=floppy,format=raw,index=0,media=disk
$ nasm -f bin bootloader.asm -o bootloader.bin && qemu-system-i386 -drive file=bootloader.bin,format=raw,index=0,media=disk
请注意,我更改了以下内容:
-
代替
org
,我使用了带有vstart=7C00h
和start=0
的加载程序的段指令.这基本上与您的原始作品相同,但与其他部分比较合适. -
使用
%include
指令包含内核,并将其放置在加载器的 之后,而不是加载器的前面(例如您使用-p
的情况). -
因此,kernel.asm文件不再出现在NASM命令行上.
-
内核放置在一个单独的节中,该节具有
vstart=0
(计算标签,就像该节在段的开头加载一样)和follows=loader
(将其正确地放置在输出文件中)第二部门). -
在设置
ss
之后的指令中,我设置了sp
,因为在此之前我们无法确定sp
的值.置零sp
(使用xor
)意味着堆栈从段的顶部开始,这与我们读取内核扇区的方式不符. -
我在
JMP nextch
之后放下了RET
.从未达到. -
我将暂停循环从
JMP $
更改为sti
\hlt
\jmp
,使其在暂停时变为空闲.这意味着qemu进程在运行此循环时不会浪费CPU时间. -
我放弃了您的
MOV DL, 0x80
.这允许从硬盘单元或软盘引导;在我们的入口点,ROM-BIOS已使用要加载的单元初始化了dl
. -
我将这些段和堆栈初始化移动到了扇区读取之前.这样可以确保堆栈不与读取目标重叠.
-
我在
di
中添加了一个循环计数器以进行读取尝试.我添加了一个额外的分支,如果它用完了,它会显示一个感叹号,然后停止.重试读取操作没有错,但是,如果读取操作永久失败,则应进行最大量的重试. -
我放弃了
fs
和gs
的设置,因为它们从未使用过.
I'm developing a Hello World kernel and bootloader...I wrote this code but when I try to compile it via NASM It says : "bootloader.asm:30: error: TIMES value -44 is negative".
bootloader.asm:
[BITS 16]
[ORG 0x7C00]
MOV DL, 0x80
MOV DH, 0x0
MOV CH, 0x0
MOV CL, 0x02
MOV BX, 0x1000
MOV ES, BX
MOV BX, 0x0
ReadFloppy:
MOV AH, 0x02
MOV AL, 0x01
INT 0x13
JC ReadFloppy
MOV AX, 0x1000
MOV DS, AX
MOV ES, AX
MOV FS, AX
MOV GS, AX
MOV SS, AX
JMP 0x1000:0x0
TIMES 510 - ($ - $$) db 0
DW 0xAA55
kernel.asm:
MOV AH, 0x0E
MOV BH, 0x00
MOV BL, 0x07
MOV SI, msg
CALL PrintString
JMP $
PrintString:
nextch:
MOV AL, [SI]
OR AL, AL
JZ exit
INT 0x10
INC SI
JMP nextch
RET
exit:
RET
msg db 'Hello world from the kernel!', 13, 10, 0
TIMES 512 - ($ - $$) db 0
I used; nasm -f bin bootloader.asm -o bootloader.bin -p kernel.asm
You have a more fundamental problem than your doubled usage of times
: You are using NASM's -p
switch to pre-include the file kernel.asm while building bootloader.asm. Even if you drop one or both times
usages, the kernel will be assembled first and executed first, instead of your loader executing first.
I fixed your example to do what it seems supposed to do: Write the kernel.asm output into the second 512-bytes sector, then in the loader, load that sector from the boot unit and jump to it.
Here's the fixed source, bootloader.asm:
cpu 8086
bits 16
section loader vstart=7C00h start=0
MOV AX, 0x1000
MOV DS, AX
MOV ES, AX
MOV SS, AX
xor sp, sp
MOV DH, 0x0
MOV CH, 0x0
MOV CL, 0x02
xor bx, bx
mov di, 16
ReadFloppy:
dec di
jz .error
MOV AH, 0x02
MOV AL, 0x01
INT 0x13
JC ReadFloppy
JMP 0x1000:0x0
.error:
mov ax, '!' | 0E00h
mov bx, 7
int 10h
.halt:
sti
hlt
jmp .halt
TIMES 510 - ($ - $$) db 0
DW 0xAA55
%include "kernel.asm"
This is kernel.asm:
section kernel vstart=0 follows=loader
MOV AH, 0x0E
MOV BH, 0x00
MOV BL, 0x07
MOV SI, msg
CALL PrintString
halt:
sti
hlt
jmp halt
PrintString:
nextch:
MOV AL, [SI]
OR AL, AL
JZ exit
INT 0x10
INC SI
JMP nextch
exit:
RET
msg db 'Hello world from the kernel!', 13, 10, 0
TIMES 512 - ($ - $$) db 0
This is how to build and run the entire example:
$ nasm -f bin bootloader.asm -o bootloader.bin && qemu-system-i386 -drive file=bootloader.bin,if=floppy,format=raw,index=0,media=disk
$ nasm -f bin bootloader.asm -o bootloader.bin && qemu-system-i386 -drive file=bootloader.bin,format=raw,index=0,media=disk
Note that I changed the following:
Instead of
org
I used a section directive for the loader, withvstart=7C00h
andstart=0
. This is essentially the same as your original, but fits better with the other section.The kernel is included using the
%include
directive, and is placed after the loader, not before it (like with your-p
use).The file kernel.asm thus does not occur on the NASM command line any longer.
The kernel is put in a separate section, which has
vstart=0
(calculates labels as if that section was loaded at the start of a segment) andfollows=loader
(to correctly place it in the output file as the second sector).In the instruction immediately after setting
ss
I setsp
, as we cannot be sure of the value ofsp
prior to this. Zeroingsp
(withxor
) means the stack starts at the top of the segment, that is out of the way of where we read the kernel sector to.I dropped the
RET
afterJMP nextch
. It was never reached.I changed the halting loop from
JMP $
tosti
\hlt
\jmp
to idle while halting. This means the qemu process won't waste CPU time while running this loop.I dropped your
MOV DL, 0x80
. This allows booting from either a hard disk unit or a diskette; at our entrypoint the ROM-BIOS has initialiseddl
with the unit we're being loaded from.I moved the segments and stack initialisation to before the sector reading. This insures the stack does not overlap with the read destination.
I added a loop counter in
di
for the read attempts. I added an additional branch for if this runs out, which displays an exclamation mark then halts. Retrying the read operation is not wrong, but if it fails permanently then there should be a maximum amount of retries.I dropped setting
fs
andgs
as they are never used.
这篇关于如何解决'bootloader.asm:30:错误:TIMES值-44为负'NASM中的问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!