查看“Babystep2”的源代码
←
Babystep2
跳到导航
跳到搜索
因为以下原因,您没有权限编辑本页:
您请求的操作仅限属于该用户组的用户执行:
用户
您可以查看和复制此页面的源代码。
__NOTOC__ {{Infobox Tutorial | name=Babystep2: 使用BIOS打印消息 | prev=[[Babystep1]] | next=[[Babystep3]] }} === 使用BIOS打印消息 === 快速回顾: # BIOS加载的引导扇区为512字节 # 磁盘引导扇区中的代码由BIOS在0000:7c00加载 # 机器开始于 [http://www.osdev.org/wiki/Real_Mode Real Mode 实模式] # 请注意,除非你发出 [[CLI]] 汇编命令,否则CPU仍可接受中断 许多 (但不是全部) BIOS中断需要在DS寄存器填充Real Mode(实模式)段值。(译者注:这里的'''BIOS中断'''是指调用BIOS功能的INT指令) 这就是许多BIOS中断在保护模式下不起作用的原因。 因此,如果你想使用int 10h/ah=0eh打印字符到屏幕上,那么你需要确保要打印的字符的seg:offset(段偏移)是正确的。 在实模式下,地址计算为 segment段 * 16 + offset偏移量。 由于偏移量可以远大于16(译者注:而使计算后的内存地址偏移到其它段中去), 所以可以有许多对的段和偏移量指向相同的地址。 例如,可以说引导加载程序在0000:7C00加载,而也可以说位置是在07C0:0000。 因为这两个实际上是同一个地址: 16 * 0x0000 + 0x7C00 = 16 * 0x07C0 + 0x0000 = 0x7C00。 无论你使用0000:7c00还是07c0:0000都是一样的, 但是,如果你使用ORG指令(译者注:这是一条伪指令,若有ORG伪指令,编译器则把其后的指令代码放到ORG伪指令指定的偏移地址。),则需要了解正在发生的事情。 默认情况下,原始二进制文件的起始位置为偏移量0,但是如果需要,可以将偏移量更改为不同的内容并使其正常工作。 例如,以下代码段访问具有段0x7C0的变量msg。 Asm示例: <source lang="asm"> ; boot.asm mov ax, 0x07c0 mov ds, ax mov si, msg cld ch_loop:lodsb or al, al ; zero=end of str jz hang ; get out mov ah, 0x0E mov bh, 0 int 0x10 jmp ch_loop hang: jmp hang msg db 'Hello World', 13, 10, 0 times 510-($-$$) db 0 db 0x55 db 0xAA </source> 以下是用ORG伪指令的版本。 这次,使用segment段基址0访问msg。(译者注:因为机器指令被载入的位置已经被ORG指令改变了) 请注意,你仍然需要设置DS的值,因为它开始可能会被初始化为任何值。 <source lang="asm"> [ORG 0x7c00] xor ax, ax ; make it zero mov ds, ax mov si, msg cld ch_loop:lodsb or al, al ; zero=end of string jz hang ; get out mov ah, 0x0E mov bh, 0 int 0x10 jmp ch_loop hang: jmp hang msg db 'Hello World', 13, 10, 0 times 510-($-$$) db 0 db 0x55 db 0xAA </source> === Procedures过程 === 为了保护写入空间,通常使用CALL/RET将传统上的 “过程” 与代码分开,如下所示: <source lang="asm"> [ORG 0x7c00] xor ax, ax ;make it zero mov ds, ax cld mov si, msg call bios_print hang: jmp hang msg db 'Hello World', 13, 10, 0 bios_print: lodsb or al, al ;zero=end of str jz done ;get out mov ah, 0x0E mov bh, 0 int 0x10 jmp bios_print done: ret times 510-($-$$) db 0 db 0x55 db 0xAA </source> 出于某种莫名其妙的原因,加载SI(译者注:lodsb指令做的事情) '''然后''' 跳到过程总是困扰着我。 幸运的是,对于像我这样的精神病,NASM的宏让我可以使用一种假装正在传递参数的写法 (调用前必须先定义宏)。 <source lang="asm"> %macro BiosPrint 1 mov si, word %1 ch_loop:lodsb or al, al jz done mov ah, 0x0E int 0x10 jmp ch_loop done: %endmacro [ORG 0x7c00] xor ax, ax mov ds, ax cld BiosPrint msg hang: jmp hang msg db 'Hello World', 13, 10, 0 times 510-($-$$) db 0 db 0x55 db 0xAA </source> 如果你的代码变得很长且不可读,则可以将其分解为多个文件, 然后在主代码的开头包含文件。就像这样: <source lang="asm"> jmp main %include "othercode.inc" main: ; ... rest of code here </source> 不要忘记写开头的jmp main - 否则将调用一些包含的其他过程。 [[Category:Babystep]]
本页使用的模板:
模板:If
(
查看源代码
)
模板:Infobox Tutorial
(
查看源代码
)
模板:Show1
(
查看源代码
)
返回至“
Babystep2
”。
导航菜单
个人工具
登录
命名空间
页面
讨论
变体
已展开
已折叠
查看
阅读
查看源代码
查看历史
更多
已展开
已折叠
搜索
导航
首页
最近更改
随机页面
MediaWiki帮助
工具
链入页面
相关更改
特殊页面
页面信息