Как решить 'bootloader.asm: 30: ошибка: значение TIMES -44 отрицательно' Проблема в NASM - PullRequest
0 голосов
/ 02 апреля 2020

Я занимаюсь разработкой ядра и загрузчика Hello World ... Я написал этот код, но когда я пытаюсь скомпилировать его через NASM, он говорит: «bootloader.asm: 30: error: значение TIMES -44 отрицательно».

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

1 Ответ

2 голосов
/ 02 апреля 2020

У вас есть более фундаментальная проблема, чем двойное использование times: вы используете ключ -p NASM для предварительного включения файла 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 я использовал директиву section для загрузчика с vstart=7C00h и start=0. По сути, это то же самое, что и ваш оригинал, но лучше подходит для другого раздела.

  • Ядро включено с помощью директивы %include и помещается после загрузчик, а не до него (как при использовании -p).

  • Таким образом, файл kernel.asm больше не встречается в командной строке NASM.

  • Ядро помещено в отдельный раздел, который имеет vstart=0 (вычисляет метки, как если бы этот раздел был загружен в начале сегмента) и follows=loader (чтобы правильно разместить его в выходном файле как второй сектор).

  • В инструкции сразу после установки ss я установил sp, так как мы не можем быть уверены в значении sp до этого. Обнуление spxor) означает, что стек начинается в верхней части сегмента, то есть в месте, куда мы читаем сектор ядра.

  • Я отбросил RET после JMP nextch. Это никогда не было достигнуто.

  • Я изменил остановку l oop с JMP $ на sti \ hlt \ jmp на холостой ход при остановке. Это означает, что процесс qemu не будет тратить процессорное время при запуске этого l oop.

  • Я сбросил ваш MOV DL, 0x80. Это позволяет загружаться либо с жесткого диска, либо с дискеты; на нашей точке входа ROM-B IOS инициализировал dl с единицей, из которой мы загружаемся.

  • Я переместил сегменты и инициализацию стека до чтения сектора. Это гарантирует, что стек не перекрывается с местом назначения чтения.

  • Я добавил счетчик al oop в di для попыток чтения. Я добавил дополнительную ветку, если она заканчивается, и на ней отображается восклицательный знак, а затем останавливается. Повторная попытка чтения не является неправильной, но если она не удалась постоянно, максимальное количество попыток должно быть максимальным.

  • Я отбросил настройки fs и gs, поскольку они никогда не используются .

...