Search code examples
assemblyx86real-mode

Whats is wrong with this real mode code


I have got a piece of code which runs in realmode and printf a message on screen,I am using Dosbox 0.7 as my execution environment .Below is the code

 jmp 0x7c0:start

 start:
 mov ax, cs ; set up segments
 mov ds, ax
 mov es, ax
 mov al,03h
 mov ah,0
 int 10h
 welcome db "This is insane now"
 mov si, welcome
 call print_string
 print_string:
 lodsb        ; grab a byte from SI

 or al, al  ; logical or AL by itself
 jz .done   ; if the result is zero, get out
 mov ah, 0x0E
 int 0x10      ; otherwise, print out the character!
 jmp print_string
.done:
 ret

I am able assemble this code fine but when I run this ,It just hangs there and a message I can see in linux terminal

    Illegal read from b0671921, CS:IP      7c0:    4468

This is how I am assembling it

      nasm PRINT.ASM -o out.com 

I have tried searching this message in google and found it could be a problem with DOSBox version.

Can anybody let me know what could be the problem here??


Solution

  • The problem with the code is the place of the string constant. It must be placed where it will never be "executed" because it is not a code.

    Another issue is how the code ends. The boot record should load some other code (OS kernel, or bigger boot program) and jump to it. Or at least (if you only want to test something) simply make infinite loop. In your case, the program falls to the print_string subroutine and then tries to "return" to nowhere.

    Here is the fixed version:

            org 7c00h
    
    start:
            mov     ax, cs ; set up segments
            mov     ds, ax
            mov     es, ax
    
            mov     al, 03h
            mov     ah, 0
            int 10h
    
            mov     si, welcome
            call    print_string
    
    .sleep:
            jmp     .sleep
    
    
    
    print_string:
            lodsb        ; grab a byte from SI
    
            test    al, al  ; logical or AL by itself
            jz      .done   ; if the result is zero, get out
    
            mov     ah, 0x0E
            int 0x10      ; otherwise, print out the character!
            jmp     print_string
    .done:
            ret
    
    
    welcome db "This is insane now", 0
    

    Why the jump is removed? The BIOS, after loading the boot sector from the disk, places it on address 0000h:7c00h. Respectively, it jumps to $0000:$7c00 in order to start the execution of the code.

    As long as (probably) the inial code was compiled at offset $0000, the first jump simply changes the segment to 7c0h and offset to 0000h in order to provide proper execution of the program.

    But we can set the origin of our program to 7c00h (org 7c00h) and this way simply avoid using one more instruction.