带有%的组装在顶部 - 打印输出意外结果:仅AN; s&quot
我对组装编程的新手相对较新,并且想知道为什么我的代码不打印预期的字符串。完成后,该项目应该是引导加载程序。我正在使用命令nasm -f bin boot.asm -o boot.bin
进行编译。汇编过程中没有错误。
boot.asm
bits 16
org 0x7C00
%include "print.asm"
%include "text.asm"
boot:
mov si, boot_string_00
call print
mov si, boot_string_01
call print
times 510 - ($-$$) db 0
dw 0xAA55
print.asm
print:
mov ah, 0x0E
.print_loop:
lodsb
or al, al
je .print_done
int 0x10
jmp .print_loop
.print_done:
cli
ret
text.asm
boot_string_00: db "Placeholder OS Title v0.0.1", 0
boot_string_01: db "Loading Operating system", 0
预期输出:
占位符os os os v0.0.1.1加载操作系统
实际输出:
s
另外,我想知道如何在汇编中实现新线,以便可以在字符串中使用'\ n'。
I'm relatively new to assembly programming and was wondering why my code does not print the expected strings. This project is supposed to be a bootloader when finished. I am compiling using the command nasm -f bin boot.asm -o boot.bin
. There are no errors during compilation.
boot.asm
bits 16
org 0x7C00
%include "print.asm"
%include "text.asm"
boot:
mov si, boot_string_00
call print
mov si, boot_string_01
call print
times 510 - ($-$) db 0
dw 0xAA55
print.asm
print:
mov ah, 0x0E
.print_loop:
lodsb
or al, al
je .print_done
int 0x10
jmp .print_loop
.print_done:
cli
ret
text.asm
boot_string_00: db "Placeholder OS Title v0.0.1", 0
boot_string_01: db "Loading Operating system", 0
Expected Output:
PlaceHolder OS Title v0.0.1Loading Operating System
Actual Output:
S
Also, I was wondering how i could implement newlines in assembly so that i could just use '\n' in my strings.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您在引导加载程序顶部包含了东西,它将首先执行。而是在不在执行主要路径的情况下包括额外功能,仅通过
呼叫
来达到。这应该有效,将
%include
指令放置在安全地放置额外功能或数据的地方,就像您将它们全部写入一个文件一样。boot.asm:
printf.asm:
text.s:
You included stuff at the top of your bootloader, where it will executes first. Instead include extra functions where they aren't in the main path of execution and are only reached by
call
.This should work, placing the
%include
directives where it's safe to put extra function or data, just like if you were writing them all in one file.boot.asm:
printf.asm:
text.S:
包括
%的指令时,请不要在顶部
,包括“ print.asm” ,nasm将插入文件 print.asm 的内容写了线。对于
%的%,也是如此。因此,扩展的源文本变为:
现在,当Bios在地址0x7C00上完成加载Bootsector代码时,它将控件转移到内存中的相同地址。 CPU遇到的第一个指令将是
MOV AH,0x0e
,因此我们的打印循环开始了。问题是,我们尚未设置通向消息的指针。目的是要使代码开始在 boot 标签上执行,并且包含在错误的标签上。一个快速解决方案是将
JMP启动
指令作为org 0x7c00
指令下方的第一个指令。但是,为什么当我们也可以浪费2或3个字节时,最好将包含的内容放在其余的代码下方呢?这将是首选的解决方案:让我们再次扩展包含,并验证问题是否解决。
两条消息都可以打印正常,但是,正如您所看到的,一旦第二个
呼叫print
返回,代码将在 print 例程中掉落并开始打印一个空消息(因为si
寄存器指向第一个由times
指令插入的零字节)。一个更糟糕的问题是,因为这(第三次),
ret
指令在堆栈上没有明智的返回地址,所以计算机会崩溃,但是以危险的方式崩溃会去!解决方案是防止在 print 子例程中掉落的代码。因为我们的程序无事可做,所以我们将插入一个停止循环,以便CPU不会在紧密的循环中浪费宝贵的周期。首选的方法是
CLI
HLT
JMP $ -2
。在当前 print 例程中有改进的空间
cli
指令是没有意义的。al
为零注册,将更好地使用test al,al
。ds
段寄存器。确保根据org 0x7c00
指令,确保“呼叫代码”xor ax,ax
mov ds,ax
。回答其他问题将进一步改善代码
在NASM中,您可以以3种不同的方式定义字符串英非常数字。使用单引号',使用双引号标记“ ”或使用Backticks `。
只有在backticks中,您才能在文本中包含逃生序列为了插入newlines
\ r \ n
,您的 text.asm 需要成为:
现在,新线已嵌入到消息中,您可以考虑简化代码并输出2行消息,总共节省了7个字节:
为什么
\ r \ r \ r \ n
序列,而不是简单的\ n
?引用Wikipedia文章中有关逃生序列的报价:
\ n
(newline)逃脱序列仅插入lineFeed byte(10),但由于这是引导加载程序代码,而不是DOS/Windows,BIOS将同时需要Carriagare Byte(13)和LineFeed Byte(10)为了执行 emote 的开头。这就是为什么我们需要编写\ r \ n
。Includes don't go at the top
When using a directive like
%include "print.asm"
, NASM will insert the contents of the file print.asm right where you have written the line. The same is true for%include "text.asm"
. The expanded source text thus becomes:Now, when BIOS has finished loading your bootsector code at the address 0x7C00, it will transfer control to that same address in memory. The first instruction that the CPU encounters will be
mov ah, 0x0E
and so our printing loop starts. Problem is, we haven't yet setup the pointer to the message. The intend was for the code to start executing at the boot label, and the includes made that go wrong.A quick solution would be to have a
jmp boot
instruction as the very first instruction beneath theorg 0x7C00
directive. But why waste 2 or 3 bytes when we could just as well, and better, place the includes below the rest of the code? That's going to be the preferred solution:Let's expand the includes again and verify that the problem is resolved.
Both messages print fine, but, as you can see, once the second
call print
returns, the code falls through in the print routine and starts printing an empty message (because theSI
register is pointing at the first zero-byte inserted by thetimes
directive).A far worse problem is, that because this (third) time, the
ret
instruction has no sensible return address on the stack, the computer will crash, but in a dangerous way because there's no telling about where execution will go to!The solution is to prevent the code falling through in the print subroutine. Because our program has nothing more to do, we will insert a halting loop so the CPU doesn't waste precious cycles in a tight loop. The preferred way is
cli
hlt
jmp $-2
.There's room for improvement in the present print routine
BH
register to contain the desired DisplayPage and theBL
register the desired GraphicsColor for when the screen is in a graphics mode.cli
instruction in this code.AL
register for zero, would better usetest al, al
.DS
segment register. Make sure the calling code hasxor ax, ax
mov ds, ax
in accordance with theorg 0x7C00
directive.Answering the additional question will improve the code even further
In NASM you can define string litterals in 3 different ways. Using single quotation marks ', using double quotation marks ", or using backticks `.
Only with the backticks can you include escape sequences in the text. In order to insert newlines
\r\n
, your text.asm would need to become:to produce
Now that the newlines are embedded in the messages, you could consider simplifying the code and output the 2-line message as a whole, for a total savings of 7 bytes:
Why the
\r\n
sequence, and not simply\n
?For reference a quote from the Wikipedia article about escape sequences:
The
\n
(newline) escape sequence only inserts the linefeed byte (10), but since this is bootloader code, and not DOS/Windows, BIOS will require both the carriage return byte (13) and the linefeed byte (10) in order to perform a move to the beginning of the next line. That's why we need to write\r\n
.