1

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??

Amit Singh Tomar
  • 8,380
  • 27
  • 120
  • 199
  • 1
    Are you trying to write a bootloader? COM files are loaded at address 0x100, so you can't run a bootloader in this way. You'll have to create a virtual floppy drive or hard drive with your bootloader binary placed in the first sector. Also, your welcome string lacks a NUL terminator and shouldn't be placed in the middle of code, since the CPU doesn't know the difference between code and data. – Michael Jul 15 '13 at 09:18
  • 1
    If you're really trying to create a .COM file (and not a bootloader) you should use `[org 0x100]` and remove the `jmp` at the beginning (and also fix the aforementioned problems with your string variable). – Michael Jul 15 '13 at 09:37

2 Answers2

1

Let's step by step:

    jmp 0x7c0:start    ;jump to start

start:

     mov ax, cs        ; set up segments             
     mov ds, ax
     mov es, ax


     mov al,03h        ; Set up screen to 80 by 25
     mov ah,0
     int 10h

String is not executable code so put it before start label and after jmp. String must finish with zero character!

 welcome db "This is insane now"#0

 mov si, welcome     ;Print string
 call print_string

Missing finalize code to exit program properly so print_string will perform again

print_string:
     cld          ;Clear direction flag instruction is missing
     lodsb        

     or al, al    ; test if zero char
     jz .done     ; exit if zero char
     mov ah, 0x0E ; Write Char in Teletype Mode 
     mov bh, 0    ; Define 0 page if we have multiple pages
     int 0x10     ; print character!
     jmp print_string
    .done:
     ret
GJ.
  • 10,810
  • 2
  • 45
  • 62
1

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.

johnfound
  • 6,857
  • 4
  • 31
  • 60
  • Thanks @johnfound for the answer ,Would like to ask you couple of doubts 1) why jmp 0x7c0:start has removed from the code,Though Micheal explained about it above , wanted to hear from you as well 2). Or at least (if you only want to test something) simply make infinite loop ,could you please expain it in more detail or it would be great if add details of it in your answer. – Amit Singh Tomar Jul 15 '13 at 10:20
  • @AmitSinghTomar Now the answer is fixed. Not tested, but it should be OK. – johnfound Jul 15 '13 at 11:22
  • Thanks again Johnfound, will test it and let you know the result. – Amit Singh Tomar Jul 15 '13 at 11:51
  • The string should have a NUL terminator, since the `print_string` function relies on that. – Michael Jul 15 '13 at 13:57
  • @Michael Yes. It is fixed now. Thanks. – johnfound Jul 15 '13 at 13:59
  • @johnfound I tried running this code in my Dos box environment but could not see any message ,its just hangs which is because of .sleep and when I remove it ,Program just comes out without printing any message on to screen.What could be the problem now?? – Amit Singh Tomar Jul 15 '13 at 18:19
  • 1
    @AmitSinghTomar How you are testing this program? It has to be written in the MBR of some media and then boot from it. If you want to test it in DOS, simply replace 7c00h by 100h and the infinity loop by "ret". But in this form it can't be used as a boot sector. – johnfound Jul 15 '13 at 18:34
  • Thank you very-2 much @johnfound ,I can very well see the message on Dos now.But Could you please explain me ,Why and how replacing $7c00 to $100 and infinity loop to ret work here ,Concept wise I am still not able to understand it fully.Why now it can't be consider as bootsector?? – Amit Singh Tomar Jul 15 '13 at 18:53
  • @AmitSinghTomar - because of the labels. When your program starts from address 7c00h, then the label "start" has address 7c00h, every next label has some bigger address. Then when you make "mov si, welcome" the number in the si will be 7cxxh (some address after 7c00h) then imagine this program loaded on address 100h (but still compiled for 7c00h. Then it still will load si with 7cxxh but there will be nothing, because the program is actually on address 100h. So, the program must be load on the place for where it was compiled. At least it is a must for .com programs and bootloaders. – johnfound Jul 15 '13 at 21:03
  • Fine @Johnfound,what I understood from your above comment is .COM progams are loaded at address 100h by default but I was compiling my code with address 7c00h .Is it what you meant in your above comments?? – Amit Singh Tomar Jul 16 '13 at 08:51
  • I meant, that the simple kind of programs (like .com ) must to be compiled for the same address where they are supposed to be load and run. If you want to create .com program - use "org 100h". If boot record, use "org 7c00h" – johnfound Jul 16 '13 at 09:04
  • Thanks @Johfound ,one final thing wanted to get clarified from your end regarding setting up the segment ,When org 7c00h is called ,would it set cs=0 and offset to 07c00h and whats the reason for setting up es and ds to 0 . – Amit Singh Tomar Jul 16 '13 at 10:29
  • @AmitSinghTomar Well, "cs" is the segment from where the code is executed (cs:ip contains the address of the instruction executed); "ds" is the segment from where data is to be used. For example "mov al, [buffer] actually means [ds:buffer], so it must be set to the segment where your data resides. "es" is a second data segment. It is to be used for string instructions and when needed. In your example, there is not need for this register to be set. – johnfound Jul 16 '13 at 10:36
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/33554/discussion-between-amit-singh-tomar-and-johnfound) – Amit Singh Tomar Jul 16 '13 at 10:58