我有一个代码段位于boot.img文件的扇区37,在我的主启动记录中,我将此代码加载到内存0x5678:0x1234,这是我的asm代码:
[BITS 16] ;Set code generation to 16 bit mode ORG 0x1234 ;set addressing to begin at 0x5678:0x1234 mov ax, cs mov ds, ax mov es, ax call cls ;call routine to clear screen call dspmsg ;call routine to display message startdt: call date call cvtmo call cvtday call cvtcent call cvtyear call dspdate call time call cvthrs call cvtmin call cvtsec call dsptime jmp startdt ;use infinite loop to halt? cls: mov ah,06h ;function 06h (Scroll Screen) mov al, 0 ;scroll all lines mov bh,0x0a ;Attribute (light green on black) mov ch,0 ;Upper left row is zero mov cl,0 ;Upper left column is zero mov dh,24 ;Lower left row is 24 mov dl,79 ;Lower left column is 79 int 10H ;BIOS Interrupt 10h (video services) ret dspmsg: mov ah,13h ;function 13h (Display String) mov al,0 ;Write mode is zero mov bh,0 ;Use video page of zero mov bl,0x0c ;Attribute (light red on black) mov cx,msglen ;Character string is 25 long mov dh,3 ;position on row 3 mov dl,[center] ;and column 28 lea bp,[msg] ;load the offset address of string into BP int 10H ret msg: db 'Pradox V 0.1 Jiansong He',10,13 msglen: equ $-msg int 10H ret date: ;Get date from the system mov ah,04h ;function 04h (get RTC date) int 1Ah ;BIOS Interrupt 1Ah (Read Real Time Clock) ret ;CH - Century ;CL - Year ;DH - Month ;DL - Day cvtmo: ;Converts the system date from BCD to ASCII mov bh,dh ;copy contents of month (dh) to bh shr bh,1 shr bh,1 shr bh,1 shr bh,1 add bh,30h ;add 30h to convert to ascii mov [dtfld],bh mov bh,dh and bh,0fh add bh,30h mov [dtfld + 1],bh ret cvtday: mov bh,dl ;copy contents of day (dl) to bh shr bh,1 shr bh,1 shr bh,1 shr bh,1 add bh,30h ;add 30h to convert to ascii mov [dtfld + 3],bh mov bh,dl and bh,0fh add bh,30h mov [dtfld + 4],bh ret cvtcent: mov bh,ch ;copy contents of century (ch) to bh shr bh,1 shr bh,1 shr bh,1 shr bh,1 add bh,30h ;add 30h to convert to ascii mov [dtfld + 6],bh mov bh,ch and bh,0fh add bh,30h mov [dtfld + 7],bh ret cvtyear: mov bh,cl ;copy contents of year (cl) to bh shr bh,1 shr bh,1 shr bh,1 shr bh,1 add bh,30h ;add 30h to convert to ascii mov [dtfld + 8],bh mov bh,cl and bh,0fh add bh,30h mov [dtfld + 9],bh ret dtfld: db '00/00/0000' dspdate: ;Display the system date mov ah,13h ;function 13h (Display String) mov al,0 ;Write mode is zero mov bh,0 ;Use video page of zero mov bl,0x0a;Attribute mov cx,10 ;Character string is 10 long mov dh,4 ;position on row 4 mov dl,[center] ;and column 28 push ds ;put ds register on stack pop es ;pop it into es register lea bp,[dtfld] ;load the offset address of string into BP int 10H ret time: ;Get time from the system mov ah,02h int 1Ah ret ;CH - Hours ;CL - Minutes ;DH - Seconds cvthrs: ;Converts the system time from BCD to ASCII mov bh,ch ;copy contents of hours (ch) to bh shr bh,1 shr bh,1 shr bh,1 shr bh,1 add bh,30h ;add 30h to convert to ascii mov [tmfld],bh mov bh,ch and bh,0fh add bh,30h mov [tmfld + 1],bh ret cvtmin: mov bh,cl ;copy contents of minutes (cl) to bh shr bh,1 shr bh,1 shr bh,1 shr bh,1 add bh,30h ;add 30h to convert to ascii mov [tmfld + 3],bh mov bh,cl and bh,0fh add bh,30h mov [tmfld + 4],bh ret cvtsec: mov bh,dh ;copy contents of seconds (dh) to bh shr bh,1 shr bh,1 shr bh,1 shr bh,1 add bh,30h ;add 30h to convert to ascii mov [tmfld + 6],bh mov bh,dh and bh,0fh add bh,30h mov [tmfld + 7],bh ret tmfld: db '00:00:00' dsptime: ;Display the system time mov ah,13h ;function 13h (Display String) mov al,1 ;Write mode is zero mov bh,0 ;Use video page of zero mov bl,0x0a;Attribute mov cx,8 ;Character string is 8 long mov dh,5 ;position on row 5 mov dl,[center];and column 0 push ds ;put ds register on stack pop es ;pop it into es register lea bp,[tmfld] ;load the offset address of string into BP int 10H ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;variables;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; center: db 25 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;end variables;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
我的模拟器是dosbox,操作系统是运行在Oracle VM虚拟盒上的lubuntu,我自己的操作系统是win8 x64注意文件末尾的变量字段,如果我把这个文件放在顶部,我更新了我的DS和ES之后注册,我遇到了一个问题:cls和dspmsg子例程将无法工作,但如果我将值更改为center: db 30
或只是将此字段放在我的代码的末尾,它将工作.有人可以解释为什么将变量字段放在我的代码之上并更改标签的值会影响程序的性能吗?这与我的段寄存器有关吗?
这是我的装载机:
;bit16 ; 16bit by default org 0x7c00 jmp short start nop bsOEM db "OS423 v.0.1" ; OEM String start: ;;load sector into memory & 5678h:1234h mov bx, 0x5678 ;segmented address mov es, bx ;move segemented address to es mov bx,0x1234 ;base address to bx mov ah, 02 ;function read sectors mov al, 01 ;# of sectors to load mov ch, 00 ;track to read mov cl, 02 ;sector to read mov dh, 00 ;head to read mov dl, 00 ;drive number int 0x13 ;call interrupt 13 jmp 0x5678:0x1234 ;jump to memory address ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;variables;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; msg: db 'Welcome to Pradox OS 0.1! Authored by Jiansong he', 10, 13, '$' mlen equ $-msg padding times 510-($-$$) db 0 ;to make MBR 512 bytes bootSig db 0x55, 0xaa ;signature (optional)
Michael Petc.. 5
正如Jester(以及我在上一个问题中)所提到的,我强烈建议使用调试器.该评论是:
我建议使用BOCHS来调试bootloaders.它有一个命令行调试器,可以理解实模式寻址,可用于在执行时查看指令,设置断点,显示寄存器,检查内存等.
如果您希望查看放置center: db 25
在代码顶部时发生的情况,可以使用NDISASM转储已编码的指令.假设您的第二阶段仍然是dt.bin
您可以使用此命令来获取该二进制文件的反汇编输出:
ndisasm -b16 dt.bin
该命令dt.bin
在假设它是16位指令的情况下被反汇编.如果你要放在center: db 25
顶部的代码之前dt.asm
并组装dt.bin并运行上面的命令,你会得到类似这样的输出:
00000000 198CC88E sbb [si-0x7138],cx 00000004 D88EC0E8 fmul dword [bp-0x1740] 00000008 2600E8 es add al,ch 0000000B 3400 xor al,0x0 0000000D E86600 call word 0x76
那不是你期待的代码!那个值25在哪里?输出为十六进制.那个25十进制是0x19.如果你检查第一个指令解码,198CC88E
你会看到19
第一个字节.该单个字节将指令解码变为完全无意义.
如果换center: db 25
到center: db 30
?会发生什么?如果您尝试组装它并再次使用上面的NDISASM命令,您应该看到:
00000000 1E push ds 00000001 8CC8 mov ax,cs 00000003 8ED8 mov ds,ax 00000005 8EC0 mov es,ax 00000007 E82600 call word 0x30
30十进制是0x1e.正如Jester所指出的,0x1e本身就是一个指令push ds
.那个单字节指令做了一些无用的事情,但之后的所有指令都是你所期望的.输出到像这样使用二进制文件时将上述代码数据-f bin
与NASM会引起异常的问题.因此,最好将数据放在代码之后,它不会干扰指令解码.
正如Jester(以及我在上一个问题中)所提到的,我强烈建议使用调试器.该评论是:
我建议使用BOCHS来调试bootloaders.它有一个命令行调试器,可以理解实模式寻址,可用于在执行时查看指令,设置断点,显示寄存器,检查内存等.
如果您希望查看放置center: db 25
在代码顶部时发生的情况,可以使用NDISASM转储已编码的指令.假设您的第二阶段仍然是dt.bin
您可以使用此命令来获取该二进制文件的反汇编输出:
ndisasm -b16 dt.bin
该命令dt.bin
在假设它是16位指令的情况下被反汇编.如果你要放在center: db 25
顶部的代码之前dt.asm
并组装dt.bin并运行上面的命令,你会得到类似这样的输出:
00000000 198CC88E sbb [si-0x7138],cx 00000004 D88EC0E8 fmul dword [bp-0x1740] 00000008 2600E8 es add al,ch 0000000B 3400 xor al,0x0 0000000D E86600 call word 0x76
那不是你期待的代码!那个值25在哪里?输出为十六进制.那个25十进制是0x19.如果你检查第一个指令解码,198CC88E
你会看到19
第一个字节.该单个字节将指令解码变为完全无意义.
如果换center: db 25
到center: db 30
?会发生什么?如果您尝试组装它并再次使用上面的NDISASM命令,您应该看到:
00000000 1E push ds 00000001 8CC8 mov ax,cs 00000003 8ED8 mov ds,ax 00000005 8EC0 mov es,ax 00000007 E82600 call word 0x30
30十进制是0x1e.正如Jester所指出的,0x1e本身就是一个指令push ds
.那个单字节指令做了一些无用的事情,但之后的所有指令都是你所期望的.输出到像这样使用二进制文件时将上述代码数据-f bin
与NASM会引起异常的问题.因此,最好将数据放在代码之后,它不会干扰指令解码.