3

I have a code segment which was located at sector 37 of boot.img file, and in my master boot record I loaded this code into memory 0x5678:0x1234, here is my asm code:

[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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

my emulator is dosbox, operation system is lubuntu running on Oracle VM virtual box, my own operating system is win8 x64 notice the variable field at the end of file, if I put this filed at the top, right after I updated my DS and ES register, I got a issue: cls and dspmsg subroutine won't work however if I change the value to center: db 30 or just put this field at the end of my code, it will work. Can someone explain why putting the variable field on top of my code and changing the value of my label will effect the program's performance? Does this has to do with my segment register?

here is my loader:

;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 Petch
  • 46,082
  • 8
  • 107
  • 198
paradox
  • 258
  • 4
  • 19
  • 2
    Presumably your loader that you didn't show still transfers control to `0x5678:0x1234` which would then contain your data, not the code to execute. Note that `30` happens to be the opcode for `PUSH DS` which would still let your code execute properly. PS: learn to use a debugger. – Jester Jan 24 '17 at 01:31
  • understood, thank you again! – paradox Jan 24 '17 at 01:39
  • 1
    You know you can run DOSBox directly under Windows. – Ross Ridge Jan 24 '17 at 03:13

1 Answers1

5

As mentioned by Jester (and myself in your last question) I highly recommend using a debugger. That comment was:

I'd recommend BOCHS for debugging bootloaders. It has a command line debugger that understands real mode addressing and can be used to watch instructions as they are executed,set breakpoints, display registers, examine memory etc.

If you wish to see what happened when you placed center: db 25 at the top of the code, you can use NDISASM to dump the instructions that were encoded. Assuming your second stage is still dt.bin you can use this command to get disassembled output of that binary:

ndisasm -b16 dt.bin

This command disassembled dt.bin with the assumption that it is 16-bit instructions. If you were to place center: db 25 before the code at the top of dt.asm and assembled dt.bin and ran the command above you'd get something like this output:

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

That's not the code you were expecting! Where is that value 25? The output is in hex. That 25 decimal is 0x19. If you examine that first instruction decoding 198CC88E you'll see 19 is the first byte. That single byte changed the instruction decoding into complete nonsense.

What happens if you change center: db 25 to center: db 30? If you try and assemble it and use the NDISASM command above again you should see this:

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 decimal is 0x1e. As Jester pointed out 0x1e is an instruction by itself push ds. That single byte instruction does something useless but all the instructions afterwards are as you expect. Placing data above code when outputting to binary files like this using-f bin with NASM can cause unusual problems. For this reason it is best to place your data after the code where it will not interfere with instruction decoding.

Michael Petch
  • 46,082
  • 8
  • 107
  • 198