fsd*_*fff 3 assembly nasm osdev bootloader x86-16
我正在用汇编语言开发一个操作系统。\n在某个时间我从 NASM 收到此错误:
\n\n\n\n\nos.asm:113: 错误: TIMES 值 -138 为负数
\n
我想把这个项目进行到底。只有这样的错误才让我绝望!
\n\n这是代码:
\n\nBITS 16\n\nstart:\n mov ax, 07C0h ; Set up 4K stack space after this bootloader\n add ax, 288 ; (4096 + 512) / 16 bytes per paragraph\n mov ss, ax\n mov sp, 4096\n mov ax, 07C0h ; Set data segment to where we're loaded\n mov ds, ax\n call cls\n MOV AH, 06h ; Scroll up function\n XOR AL, AL ; Clear entire screen\n XOR CX, CX ; Upper left corner CH=row, CL=column\n MOV DX, 184FH ; lower right corner DH=row, DL=column \n MOV BH, 1Eh ; YellowOnBlue\n INT 10H\n mov si, text_string ; Put string position into SI\n call print_string ; Call our string-printing routine\npush bx ;push registers\npush cx\npush dx\nmov ah,0h\nint 16h\n cmp al, '1'\n je reboot\n cmp al, '2'\n je shutdown\n cmp al, '3'\n je about\n cmp al, '4'\n je message\n cmp al, '5'\n je shutdown\n cmp al, '6'\n je credits\n\n jmp $ ; Jump here - infinite loop!\n\n\n text_string db '|Main Menu| |Smile OS V1.4|',13,10,'1) Reboot',13,10,'2) Shutdown',13,10,'3) About',13,10,'4) Message',13,10,'5) System Halt',13,10,'6) Credits',0\n about_string db '|About|',13,10,'Smile OS is a console based operating system in assembly language. 8 hours of intense work done by Alex~s Software. Many errors but solved and very successful.',13,10,'Press any key to go back!',0\n message_str db '|Message|',10,13,'Hello, World!',13,10,'Press any key to go back!',0\n cr_str db '|Credits|',13,10,'Copyright \xc2\xa9 2018 Alex~s Software',13,10,'Main Programer: Alex',13,10,'Graphichs: What graphics?',13,10,'Idea: nobody :)',0\n\nreboot:\nmov ax, 0\nint 19h\n\nshutdown:\nmov ax, 0x1000\nmov ax, ss\nmov sp, 0xf000\nmov ax, 0x5307\nmov bx, 0x0001\nmov cx, 0x0003\nint 0x15\n\ncredits:\ncall cls\nmov si, cr_str ; Put string position into SI\ncall print_string ; Call our string-printing routine\npush bx ;push registers\npush cx\npush dx\nmov ah,0h\nint 16h\nje start\n\nmessage:\ncall cls\nmov si, message_str ; Put string position into SI\ncall print_string ; Call our string-printing routine\npush bx ;push registers\npush cx\npush dx\nmov ah,0h\nint 16h\nje start\n\ncls:\n pusha\n mov ah, 0x00\n mov al, 0x03 ; text mode 80x25 16 colours\n int 0x10\n popa\n ret\n\nabout:\ncall cls\nmov si, about_string ; Put string position into SI\ncall print_string ; Call our string-printing routine\npush bx ;push registers\npush cx\npush dx\nmov ah,0h\nint 16h \nje start\n\nprint_string: ; Routine: output string in SI to screen\n mov ah, 0Eh ; int 10h 'print char' function\n\n.repeat:\n lodsb ; Get character from string\n cmp al, 0\n je .done ; If char is zero, end of string\n int 10h ; Otherwise, print it\n jmp .repeat\n\n.done:\n ret \n\ntimes 512 - ($ - $$) db 0\nsignature dw 0xaa55\nRun Code Online (Sandbox Code Playgroud)\n\n为什么时代价值是负数?为什么其他人没有得到同样的错误?(或者像那样)
\n\n我用这个:
\n\n\n\n\nNASM 版本 2.14
\n\nOracle VM VirtualBox 版本 6.0.0_RC1
\n\nrawwrite dd 适用于 Windows 版本 0.5。
\n
对于编译:
\n\nnasm os.asm -f bin -o os.bin \ndd if=/dev/zero of=os.img bs=1024 count=1440 \ndd if=os.bin of=os.img\nRun Code Online (Sandbox Code Playgroud)\n
TL;DR:您的代码和数据太大,与文件最后 2 个字节中的启动签名发生冲突。下面的代码是一个软盘引导加载程序,它读取第二阶段(您的内核)并将控制权转移给它。提供的 BPB 适用于 1.44MiB 软盘。与引导加载程序不同,stage2 将被加载到物理地址 0x07e00(就在内存中引导加载程序之后)。这使得您的代码大小可达 32.5KiB。如果需要,您的第二阶段可以读取更多扇区。该代码经过精心设计,以便其他人可以使用它作为模板来读取第二阶段并将控制权转移给它。
\n\n这个问题实际上已经在您之前的Stackoverflow Question中得到了回答。有一个关于填充使用times 512 - ($ - $$) db 0x00需要为 510 而不是 512 的警告。答案警告代码和数据过多(超过 512 字节),以及从 NASM 获取有关大小的更好错误/警告的方法。我的其他答案中的注释将大小问题总结为:
\n\n\n如果文件 os.bin超过 512 字节,那么您将需要使用 BIOS 手动将更多磁盘扇区读取到内存中。可以使用INT 13h/AH=2h来完成从软盘的磁盘读取。
\n
没有提供一种机制(示例),该机制使用 NASM 和 INT 13h/AH=2h 在引导加载程序之后将更多磁盘扇区(又名 stage2)读取到物理地址 0x07E00 处的内存中。代码被注释了,但它实际上做了:
\n\nstage2_start)的 stage2 代码stage2.asm. stage2.asm被组装到stage2.bin并os.asm包含二进制文件stage2.bin,以便可以确定 stage2 的大小,以便引导加载程序将其加载到内存中。stage2.asm必须使用ORG 0x7e00,因为上面的过程会将此代码加载到 0x7e00,因此 ORG(原点)必须设置为匹配。stage2info.inc定义了常量来确定 stage2 的原点是什么,以及在将控制转移到 FAR JMP 时应使用什么段和偏移量。该文件的默认版本假定通过 0x0000:0x7e00 访问 stage2。该文件的替代版本2可用于将其变为 0x07e0:0x0000。后一个版本允许您的代码占用完整的 64kb 段。bpb.公司:
\n\n jmp boot_start\n TIMES 3-($-$$) DB 0x90 ; Support 2 or 3 byte encoded JMPs before BPB.\n\nbpb_disk_info:\n ; Dos 4.0 EBPB 1.44MB floppy\n OEMname: db "mkfs.fat" ; mkfs.fat is what OEMname mkdosfs uses\n bytesPerSector: dw 512\n sectPerCluster: db 1\n reservedSectors: dw 1\n numFAT: db 2\n numRootDirEntries: dw 224\n numSectors: dw 2880\n mediaType: db 0xf0\n numFATsectors: dw 9\n sectorsPerTrack: dw 18\n numHeads: dw 2\n numHiddenSectors: dd 0\n numSectorsHuge: dd 0\n driveNum: db 0\n reserved: db 0\n signature: db 0x29\n volumeID: dd 0x2d7e5a1a\n volumeLabel: db "NO NAME "\n fileSysType: db "FAT12 "\nRun Code Online (Sandbox Code Playgroud)\n\nstage2info.inc:
\n\nSTAGE2_ABS_ADDR equ 0x07e00 ; Physical address of stage2\n\n; Segment and Offset to use to transfer (FAR JMP) control to Stage2\n; Segment:Offset = 0x0000:0x7e00\nSTAGE2_RUN_SEG equ 0x0000\nSTAGE2_RUN_OFS equ STAGE2_ABS_ADDR\nRun Code Online (Sandbox Code Playgroud)\n\n操作系统.asm:
\n\n%include "stage2info.inc"\n\nSTAGE2_LOAD_SEG equ STAGE2_ABS_ADDR>>4\n ; Segment to start reading Stage2 into\n ; right after bootloader\n\nSTAGE2_LBA_START equ 1 ; Logical Block Address(LBA) Stage2 starts on\n ; LBA 1 = sector after boot sector\nSTAGE2_LBA_END equ STAGE2_LBA_START + NUM_STAGE2_SECTORS\n ; Logical Block Address(LBA) Stage2 ends at\nDISK_RETRIES equ 3 ; Number of times to retry on disk error\n\nbits 16\nORG 0x7c00\n\n; Include a BPB (1.44MB floppy with FAT12) to be more comaptible with USB floppy media\n%include "bpb.inc"\n\nboot_start:\n xor ax, ax ; DS=SS=ES=0 for stage2 loading\n mov ds, ax\n mov ss, ax ; Stack at 0x0000:0x7c00\n mov sp, 0x7c00\n cld ; Set string instructions to use forward movement\n\n ; Read Stage2 1 sector at a time until stage2 is completely loaded\nload_stage2:\n mov [bootDevice], dl ; Save boot drive\n mov di, STAGE2_LOAD_SEG ; DI = Current segment to read into\n mov si, STAGE2_LBA_START ; SI = LBA that stage2 starts at\n jmp .chk_for_last_lba ; Check to see if we are last sector in stage2\n\n.read_sector_loop:\n mov bp, DISK_RETRIES ; Set disk retry count\n\n call lba_to_chs ; Convert current LBA to CHS\n mov es, di ; Set ES to current segment number to read into\n xor bx, bx ; Offset zero in segment\n\n.retry:\n mov ax, 0x0201 ; Call function 0x02 of int 13h (read sectors)\n ; AL = 1 = Sectors to read\n int 0x13 ; BIOS Disk interrupt call\n jc .disk_error ; If CF set then disk error\n\n.success:\n add di, 512>>4 ; Advance to next 512 byte segment (0x20*16=512)\n inc si ; Next LBA\n\n.chk_for_last_lba:\n cmp si, STAGE2_LBA_END ; Have we reached the last stage2 sector?\n jl .read_sector_loop ; If we haven\'t then read next sector\n\n.stage2_loaded:\n mov ax, STAGE2_RUN_SEG ; Set up the segments appropriate for Stage2 to run\n mov ds, ax\n mov es, ax\n\n ; FAR JMP to the Stage2 entry point at physical address 0x07e00\n jmp STAGE2_RUN_SEG:STAGE2_RUN_OFS\n\n.disk_error:\n xor ah, ah ; Int13h/AH=0 is drive reset\n int 0x13\n dec bp ; Decrease retry count\n jge .retry ; If retry count not exceeded then try again\n\nerror_end:\n ; Unrecoverable error; print drive error; enter infinite loop\n mov si, diskErrorMsg ; Display disk error message\n call print_string\n cli\n.error_loop:\n hlt\n jmp .error_loop\n\n; Function: print_string\n; Display a string to the console on display page 0\n;\n; Inputs: SI = Offset of address to print\n; Clobbers: AX, BX, SI\n\nprint_string:\n mov ah, 0x0e ; BIOS tty Print\n xor bx, bx ; Set display page to 0 (BL)\n jmp .getch\n.repeat:\n int 0x10 ; print character\n.getch:\n lodsb ; Get character from string\n test al,al ; Have we reached end of string?\n jnz .repeat ; if not process next character\n.end:\n ret\n\n; Function: lba_to_chs\n; Description: Translate Logical block address to CHS (Cylinder, Head, Sector).\n; Works for all valid FAT12 compatible disk geometries.\n;\n; Resources: http://www.ctyme.com/intr/rb-0607.htm\n; https://en.wikipedia.org/wiki/Logical_block_addressing#CHS_conversion\n; /sf/ask/3180442961/\n; Sector = (LBA mod SPT) + 1\n; Head = (LBA / SPT) mod HEADS\n; Cylinder = (LBA / SPT) / HEADS\n;\n; Inputs: SI = LBA\n; Outputs: DL = Boot Drive Number\n; DH = Head\n; CH = Cylinder (lower 8 bits of 10-bit cylinder)\n; CL = Sector/Cylinder\n; Upper 2 bits of 10-bit Cylinders in upper 2 bits of CL\n; Sector in lower 6 bits of CL\n;\n; Notes: Output registers match expectation of Int 13h/AH=2 inputs\n;\nlba_to_chs:\n push ax ; Preserve AX\n mov ax, si ; Copy LBA to AX\n xor dx, dx ; Upper 16-bit of 32-bit value set to 0 for DIV\n div word [sectorsPerTrack] ; 32-bit by 16-bit DIV : LBA / SPT\n mov cl, dl ; CL = S = LBA mod SPT\n inc cl ; CL = S = (LBA mod SPT) + 1\n xor dx, dx ; Upper 16-bit of 32-bit value set to 0 for DIV\n div word [numHeads] ; 32-bit by 16-bit DIV : (LBA / SPT) / HEADS\n mov dh, dl ; DH = H = (LBA / SPT) mod HEADS\n mov dl, [bootDevice] ; boot device, not necessary to set but convenient\n mov ch, al ; CH = C(lower 8 bits) = (LBA / SPT) / HEADS\n shl ah, 6 ; Store upper 2 bits of 10-bit Cylinder into\n or cl, ah ; upper 2 bits of Sector (CL)\n pop ax ; Restore scratch registers\n ret\n\n; Uncomment these lines if not using a BPB (via bpb.inc)\n; numHeads: dw 2 ; 1.44MB Floppy has 2 heads & 18 sector per track\n; sectorsPerTrack: dw 18\n\nbootDevice: db 0x00\ndiskErrorMsg: db "Unrecoverable disk error!", 0\n\n; Pad boot sector to 510 bytes and add 2 byte boot signature for 512 total bytes\nTIMES 510-($-$$) db 0\ndw 0xaa55\n\n; Beginning of stage2. This is at 0x7E00 and will allow your stage2 to be 32.5KiB\n; before running into problems. DL will be set to the drive number originally\n; passed to us by the BIOS.\n\nNUM_STAGE2_SECTORS equ (stage2_end-stage2_start+511) / 512\n ; Number of 512 byte sectors stage2 uses.\n\nstage2_start:\n ; Insert stage2 binary here. It is done this way since we\n ; can determine the size(and number of sectors) to load since\n ; Size = stage2_end-stage2_start\n incbin "stage2.bin"\n\n; End of stage2. Make sure this label is LAST in this file!\nstage2_end:\nRun Code Online (Sandbox Code Playgroud)\n\n您将要测试的所有代码放入文件中,stage2.asm该文件将包含在我的os.asm. 删除了开头和结尾不必要部分的代码版本是:
阶段2.asm
\n\n%include "stage2info.inc"\nORG STAGE2_RUN_OFS\n\nBITS 16\n\nstart:\n ; Removed the segment and stack code\n call cls\n MOV AH, 06h ; Scroll up function\n XOR AL, AL ; Clear entire screen\n XOR CX, CX ; Upper left corner CH=row, CL=column\n MOV DX, 184FH ; lower right corner DH=row, DL=column\n MOV BH, 1Eh ; YellowOnBlue\n INT 10H\n mov si, text_string ; Put string position into SI\n call print_string ; Call our string-printing routine\npush bx ;push registers\npush cx\npush dx\nmov ah,0h\nint 16h\n cmp al, \'1\'\n je reboot\n cmp al, \'2\'\n je shutdown\n cmp al, \'3\'\n je about\n cmp al, \'4\'\n je message\n cmp al, \'5\'\n je shutdown\n cmp al, \'6\'\n je credits\n\n jmp $ ; Jump here - infinite loop!\n\n\n text_string db \'|Main Menu| |Smile OS V1.4|\',13,10,\'1) Reboot\',13,10,\'2) Shutdown\',13,10,\'3) About\',13,10,\'4) Message\',13,10,\'5) System Halt\',13,10,\'6) Credits\',0\n about_string db \'|About|\',13,10,\'Smile OS is a console based operating system in assembly language. 8 hours of intense work done by Alex~s Software. Many errors but solved and very successful.\',13,10,\'Press any key to go back!\',0\n message_str db \'|Message|\',10,13,\'Hello, World!\',13,10,\'Press any key to go back!\',0\n cr_str db \'|Credits|\',13,10,\'Copyright \xc2\xa9 2018 Alex~s Software\',13,10,\'Main Programer: Alex\',13,10,\'Graphichs: What graphics?\',13,10,\'Idea: nobody :)\',0\n\nreboot:\nmov ax, 0\nint 19h\n\nshutdown:\nmov ax, 0x1000\nmov ax, ss\nmov sp, 0xf000\nmov ax, 0x5307\nmov bx, 0x0001\nmov cx, 0x0003\nint 0x15\n\ncredits:\ncall cls\nmov si, cr_str ; Put string position into SI\ncall print_string ; Call our string-printing routine\npush bx ;push registers\npush cx\npush dx\nmov ah,0h\nint 16h\nje start\n\nmessage:\ncall cls\nmov si, message_str ; Put string position into SI\ncall print_string ; Call our string-printing routine\npush bx ;push registers\npush cx\npush dx\nmov ah,0h\nint 16h\nje start\n\ncls:\n pusha\n mov ah, 0x00\n mov al, 0x03 ; text mode 80x25 16 colours\n int 0x10\n popa\n ret\n\nabout:\ncall cls\nmov si, about_string ; Put string position into SI\ncall print_string ; Call our string-printing routine\npush bx ;push registers\npush cx\npush dx\nmov ah,0h\nint 16h\nje start\n\nprint_string: ; Routine: output string in SI to screen\n mov ah, 0Eh ; int 10h \'print char\' function\n\n.repeat:\n lodsb ; Get character from string\n cmp al, 0\n je .done ; If char is zero, end of string\n int 10h ; Otherwise, print it\n jmp .repeat\n\n.done:\n ret\nRun Code Online (Sandbox Code Playgroud)\n\n然后,您可以使用以下命令组装并构建磁盘映像1:
\n\n# Build stage2 (kernel) FIRST as os.asm will include stage2.bin\nnasm -f bin stage2.asm -o stage2.bin\n# Build and combine stage1 (boot sector) and stage2 (kernel)\nnasm -f bin os.asm -o os.bin\n\n# Build 1.44MB disk image\ndd if=/dev/zero of=disk.img bs=1024 count=1440\ndd if=os.bin of=disk.img conv=notrunc\nRun Code Online (Sandbox Code Playgroud)\n\n以 开头的行#只是注释,不是命令。
主菜单显示为:
\n\n\n\n信用屏幕显示为:
\n\n\n\n1您使用的这些命令包含错误:
\n\nnasm os.asm -f bin -o os.bin \ndd if=/dev/zero of=os.img bs=1024 count=1440 \ndd if=os.bin of=os.img\nRun Code Online (Sandbox Code Playgroud)\n\n最后一行应确保1.44MB 磁盘映像在写入文件dd if=os.bin of=os.img conv=notrunc时不会被截断。os.bin如果您查看磁盘映像的大小,您可能会发现这不是预期的 1474560。
2stage2info.inc使用 0x07e0:0x0000 而不是 0x0000:0x7e00 将控制权转移到 stage2 的替代文件:
STAGE2_ABS_ADDR equ 0x07e00 ; Physical address of stage2\n\n; Segment and Offset to use to transfer (FAR JMP) control to Stage2\n; Segment:Offset = 0x07e0:0x0000\nSTAGE2_RUN_SEG equ STAGE2_ABS_ADDR>>4\nSTAGE2_RUN_OFS equ 0x0000\nRun Code Online (Sandbox Code Playgroud)\n
| 归档时间: |
|
| 查看次数: |
2027 次 |
| 最近记录: |