我使用了第一个扇区中的所有内存,现在我想在第二个扇区(第二个阶段)中存储一个新的变量字符串并打印它。例如:
hello db 'Hello World'
新字符串应该在另一个扇区中(因为第一个扇区中没有更多内存)。我使用INT 13h,ah=2执行此操作以读取第二个磁盘扇区以解决900h:0000。我将变量hello
存储在该扇区中以及要打印的代码中。当我在这样的代码中使用INT 10h/ah=13h时,它无法打印我的字符串:
mov ax, 7c0h
mov es, ax
mov bp, hello
mov ah,13h ; function 13 - write string
mov al,01h ; attrib in bl, move cursor
mov bl,0bh ; attribute - magenta
mov cx,30 ; length of string
mov dh,1 ; row to put string
mov dl,4 ; column to put string
int 10h ; call BIOS service
当变量位于第一个扇区时,它打印得很好,但是当我将它存储在第二个扇区时,即使我这样做也不会打印出来:
mov ax, 900h
mov es, ax
示例代码:
xchg bx, bx
mov ax, 7c0h
mov ds, ax
sector_2:
mov bx, 900h
mov es, bx
mov bx, 0
mov ah, 2
mov al, 1
mov ch, 0
mov cl, 2
mov dh, 0
mov dl, 80h
int 13h
call 900h:0000
jmp $
times 510 - ($-$$) db 0 ; Fill empty bytes to binary file
dw 0aa55h ; Define MAGIC number at byte 512
;;;;;;;;;;;;;;;;;;;;;;;;
sector_2:
mov ax, 900h
mov es, ax
mov bp, hello
mov ah,13h ; function 13 - write string
mov al,01h ; attrib in bl, move cursor
mov bl,0bh ; attribute - magenta
mov cx,5 ; length of string
mov dh,1 ; row to put string
mov dl,4 ; column to put string
int 10h ; call BIOS service
retf
jmp $
hello db 'Hello'
times 1024 - ($-$$) db 0
times 2*8*63*512 - ($-$$) db 0
答案 0 :(得分:7)
我认为您的示例代码中存在一些复制和粘贴错误。你写道:
xchg bx, bx
mov ax, 7c0h
mov ds, ax
但我认为你的意思是:
xchg bx, bx
mov ax, 7c0h
mov es, ax ; Int 10h/ah=13h takes string address in ES:BP
您的代码在第一个代码段中是正确的。您的示例有两个sector_2
标签,因此可能会导致 NASM 一些悲伤。我相信您应该只删除代码中标签的第一个外观。
我假设您正在使用以下内容组装代码:
nasm -f bin boot.asm -o boot.img
文件名将不同,您可以省略-f bin
,因为它是默认值。
由于您的代码中没有明确的 ORG 指令,因此 NASM 默认采用org 0h
。所有绝对内存引用都相对于0的偏移量。在您的情况下,您希望汇编程序文件的第一个扇区(512字节)。您已将引导加载程序编码为使用0x7c0
段,您选择的段和原点0应指向7c00h的物理地址。在segment:offset寻址中,你有(7c0h<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<&quot
所有一切都很好,你在900h时正确地将扇区读入内存:0h。然后,通过call 900h:0000
从引导加载程序的第一阶段对其进行 FAR CALL 。这也是正确的。
如果这一切都正确,问题出在哪里?问题是 NASM 不知道你将前512个字节后的代码加载到内存中的另一个位置,并且所使用的segment:offset将再次相对于0(900h:0000h)。它将继续生成相对于引导加载程序开头的绝对地址。
如果您使用 NDISASM 显示从磁盘映像的字节512开始生成的代码,您将发现问题:
00000000 B80009 mov ax,0x900
00000003 8EC0 mov es,ax
00000005 BD1A02 mov bp,0x21a
00000008 B413 mov ah,0x13
这是使用以下命令生成的:
ndisasm -e 512 -b16 boot.img
boot.img
是您生成的图像文件的名称。 -e 512
表示跳过反汇编文件的前512个字节。我对输出的前几行感兴趣,特别是:
mov bp,0x21a
0x21a
是hello
的偏移量。但请注意0x21a
是十进制538,这是相对于整个引导加载程序的开头而不是相对于偏移量0(900h:0000h)的偏移量。要解决此问题,您需要指示 NASM 第二阶段(第二个扇区)中生成的代码需要相对于0的原点而不是相对于引导加载程序的开头。这可以通过将第二阶段(第二扇区)放置在原点(vstart)重置为0的新部分中来轻松完成。这可以通过在第二阶段的开头放置这样的section指令来完成: / p>
section stage2, vstart=0h
所以在你的代码中它看起来像:
dw 0aa55h ; Define MAGIC number at byte 512
;;;;;;;;;;;;;;;;;;;;;;;;
section stage2, vstart=0h ; Section name can be anything of your choosing
sector_2:
mov ax, 900h
mov es, ax
mov bp, hello
现在,如果您查看 NDISASM 输出,它将如下所示:
00000000 B80009 mov ax,0x900
00000003 8EC0 mov es,ax
00000005 BD1A00 mov bp,0x1a ; Notice hello offset is 0x1a not 0x21a
@Jester走在正确的轨道上,org 0h
被放置在第二阶段代码(第二个扇区)之前,但每个程序集文件中只能有一个 ORG 指令。无论您将它放在文件中的什么位置, NASM 都会像在文件顶部找到它一样。这种行为没有很好的记录!杰斯特的解决方案不会改变任何事情。可以在汇编文件中的任何位置使用 NASM 的 SECTION 指令来重置原点(在本例中为0)。
有关 ORG 和 SECTION 指令的更多信息,请参阅NASM documentation。 SECTION 指令和 VSTART 参数在7.1.3节对bin格式的多节支持
中进行了说明。