2017-01-24 44 views
3

我有一个代码段位于boot.img文件的扇区37,在我的主引导记录中,我将这段代码加载到内存0x5678:0x1234,这是我的汇编代码:8086汇编:把代码段开头的变量区域

[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中,操作系统是lubuntu在Oracle VM虚拟机器上运行,我自己的操作系统是win8的64 通知变量字段在文件的结尾,如果我把这个申请在在我更新了我的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) 
+2

假设您没有显示的加载程序仍将控制权转移到0x5678:0x1234,然后它将包含您的数据,而不是要执行的代码。请注意,'30'恰好是'PUSH DS'的操作码,它仍然会让您的代码正确执行。 PS:学习使用调试器。 – Jester

+0

了解,再次感谢你! – paradox

+1

你知道你可以直接在Windows下运行DOSBox。 –

回答

5

如小丑(在你的最后一个问题和我自己)提到的,我强烈建议使用调试器。该评论是:

我建议BOCHS调试引导程序。它有一个命令行调试,理解真正的寻址模式,并可以作为它们被执行,设置断点,显示寄存器看说明书,检查存储等

如果你希望看到当你放置center: db 25发生了什么在代码顶部,您可以使用NDISASM来转储编码的指令。假设你的第二个阶段是仍然dt.bin你可以使用这个命令来获取二进制进行拆解输出:

ndisasm -b16 dt.bin 

此命令拆解dt.bin与假设它是16位指令。如果你是放置在center: db 25dt.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 binNASM可能会导致异常问题。出于这个原因,最好将您的数据放在代码之后,而不会干扰指令解码。