NASM汇编错误:TIMES值为负数(-23/-323)求助
问题描述
我是汇编语言新手,在制作简易操作系统时遇到以下NASM错误:
src/bootloader/bootloader.asm:292: error: TIMES value -23 is negative make: *** [build/bootloader.bin] Error 1
尝试减少代码行数后,负数数值变为-323,但问题仍未解决。以下是我的bootloader.asm代码:
org 0x7C00 bits 16 %define ENDL 0x0D, 0x0A jmp short start nop bdb_oem: db 'MSWIN4.1' bdb_bytes_per_sector: dw 512 bdb_sectors_per_cluster: db 1 bdb_reserved_sectors: dw 1 bdb_fat_count: db 2 bdb_dir_entries_count: dw 0E0h bdb_total_sectors: dw 2880 bdb_media_descriptor_type: db 0F0h bdb_sectors_per_fat: dw 9 bdb_sectors_per_track: dw 18 bdb_heads: dw 2 bdb_hidden_sectors: dd 0 bdb_large_sector_count: dd 0 ebr_drive_number: db 0 db 0 ebr_signature: db 29h ebr_volume_id: db 12h, 34h, 56h, 78h ebr_volume_label: db 'BESTMAT OS' ebr_system_id: db 'FAT12 ' start: jmp main main: mov ax, 0 mov ds, ax mov es, ax mov ss, ax mov sp, 0x7C00 push es push word .after retf .after: mov [ebr_drive_number], dl mov si, msg_hello call puts push es mov ah, 08h int 13h jc floppy_error pop es and cl, 0x3F xor ch, ch mov [bdb_sectors_per_track], cx inc dh mov [bdb_heads], dh mov ax, [bdb_sectors_per_fat] mov bl, [bdb_fat_count] xor bh, bh mul bx add ax, [bdb_reserved_sectors] push ax mov ax, [bdb_dir_entries_count] shl ax, 5 xor dx, dx div word [bdb_bytes_per_sector] test dx, dx jz .root_dir_after inc ax .root_dir_after: mov cl, al pop ax mov dl, [ebr_drive_number] mov bx, buffer call disk_read xor bx, bx mov di, buffer .search_kernel: mov si, file_kernel_bin mov cx, 11 push di repe cmpsb pop di je .found_kernel add di, 32 inc bx cmp bx, [bdb_dir_entries_count] jl .search_kernel jmp kernel_not_found_error .found_kernel: mov ax, [di + 26] mov [kernel_cluster], ax mov ax, [bdb_reserved_sectors] mov bx, buffer mov cl, [bdb_sectors_per_fat] mov dl, [ebr_drive_number] call disk_read mov bx, KERNEL_LOAD_SEGMENT mov es, bx mov bx, KERNEL_LOAD_OFFSET .load_kernel_loop: mov ax, [kernel_cluster] add ax, 31 mov cl, 1 mov dl, [ebr_drive_number] call disk_read add bx, [bdb_bytes_per_sector] mov ax, [kernel_cluster] mov cx, 3 mul cx mov cx, 2 div cx mov si, buffer add si, ax mov ax, [ds:si] or dx, dx jz .even .odd: shr ax, 4 jmp .next_cluster_after .even: and ax, 0x0FFF .next_cluster_after: cmp ax, 0x0FF8 jae .read_finish mov [kernel_cluster], ax jmp .load_kernel_loop .read_finish: mov dl, [ebr_drive_number] mov ax, KERNEL_LOAD_SEGMENT mov ds, ax mov es, ax jmp KERNEL_LOAD_SEGMENT:KERNEL_LOAD_OFFSET jmp wait_key_and_reboot cli hlt floppy_error: mov si, msg_read_failed call puts jmp wait_key_and_reboot kernel_not_found_error: mov si, msg_kernel_not_found call puts jmp wait_key_and_reboot wait_key_and_reboot: mov ah, 0 int 16h jmp 0FFFFh:0 .halt: cli hlt puts: push si push ax push bx .loop: lodsb or al, al jz .done mov ah, 0x0E mov bh, 0 int 0x10 jmp .loop .done: pop bx pop ax pop si ret lba_to_chs: push ax push dx xor dx, dx div word [bdb_sectors_per_track] inc dx mov cx, dx xor dx, dx div word [bdb_heads] mov dh, dl mov ch, al shl ah, 6 or cl, ah pop ax mov dl, al pop ax ret disk_read: push ax push bx push cx push dx push di push cx call lba_to_chs pop ax mov ah, 02h mov di, 3 .retry: pusha stc int 13h jnc .done popa call disk_reset dec di test di, di jnz .retry .fail: jmp floppy_error .done: popa pop di pop dx pop cx pop bx pop ax ret disk_reset: pusha mov ah, 0 stc int 13h jc floppy_error popa ret msg_hello: db "Hello World!", ENDL, 0 msg_read_failed: db "BESTMAT: Read from disk failed!", ENDL, 0 msg_kernel_not_found: db "BESTMAT: KERNEL.BIN file not found!", ENDL, 0 file_kernel_bin: db "KERNEL BIN" kernel_cluster: dw 0 KERNEL_LOAD_SEGMENT equ 0x2000 KERNEL_LOAD_OFFSET equ 0 times 510-($-$$) db 0 dw 0AA55h buffer:
解决方案
问题根源
times 510-($-$$) db 0 的作用是填充空字节,确保引导扇区(含末尾的0xAA55签名)总长度恰好为512字节。其中$-$$代表当前行到段起始(org 0x7C00)的字节数。出现负数错误,说明当前代码(包括末尾的buffer)的总长度已经超过了510字节。
你把buffer:放在了引导扇区签名之后,这部分会被计入$-$$的长度统计,直接导致总长度超标。而BIOS只会加载引导扇区的前512字节,缓冲区属于磁盘读取的临时存储,应该放在引导扇区之外的内存区域,不能占用引导扇区的空间。
修复步骤
- 删除代码末尾的
buffer:定义 - 定义缓冲区到引导扇区之外的内存:
在代码开头(org 0x7C00之后)添加缓冲区地址的定义:org 0x7C00 bits 16 %define ENDL 0x0D, 0x0A BUFFER_ADDR equ 0x7E00 ; 引导扇区加载在0x7C00,0x7E00是后续的空闲内存区域,安全可用 - 替换代码中所有的
buffer引用:
把所有用到buffer的地方替换为BUFFER_ADDR,比如:; 原代码:mov bx, buffer mov bx, BUFFER_ADDR call disk_read; 原代码:mov di, buffer mov di, BUFFER_ADDR; 原代码:mov si, buffer mov si, BUFFER_ADDR
额外说明
引导扇区有严格的长度限制:前510字节用于代码和必要数据,最后2字节必须是0xAA55签名。任何超过510字节的内容都会导致times指令计算出负数,因为510 - 总长度会变成负数。将缓冲区移到0x7E00开始的内存区域,既符合BIOS的加载规则,也不会占用引导扇区的宝贵空间。
内容的提问来源于stack exchange,提问作者user23120783
相关产品推荐
相关产品推荐

