4

I'm learning assembly and of course I'm experimenting with the classic 0x10 bios interrupt. The resources I've looked at show using lodsb to print a string, so to understand that opcode I'm trying to mimic it's behavior. This works fine with lodsb, but not with what I have. What am I doing wrong?:

start:
    mov ah, 0Eh ;for bios interrupt
    mov si, text_string ;set source index to begining of text_string

.repeat:
    ;I'm trying to emulate the behavior of lodsb to learn how it works:
    mov al, [si] ;put character at si in al register
    add si, 1 ;increment source index

    cmp al, 0 ;if the character is a zero (end of the string)
    je done ;end execution

    int 10h ;bios interrupt to put character on screen
    jmp .repeat

    text_string db 'Hello, World!', 0

done:
    ret
nebuch
  • 6,475
  • 4
  • 20
  • 39

2 Answers2

5

It's not usually a good idea to:

  1. Assume that all registers are preserved across interrupt calls (or any calls, really); or
  2. Not set up all the required registers for a given call.

On that first note, I would set ah to 0eh immediately before the int 10h.

Int 10h/0eh requires the bh and bl be set to the page number and foreground color respectively. I would also do that immediately before the int 10h to ensure they're set correctly for the call.


As an aside, you may need to ensure that the ds segment register is correct, with something like:

push cs
pop ds

That's because it looks like you're putting the string into your code segment. However, since the lodsb version apparently works, I assume you've got that covered (such as if this code is a com file rather than an exe file).

And, from (admittedly faded) memory, 8086 has an inc si instruction that might save a small amount of space, not that it matters that much anymore but I was forged in a time when every byte counted :-)

paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
  • DOS and BIOS `int` calls don't modify AH as a rule; any that do will mention that in the documentation. (https://en.wikipedia.org/wiki/INT_10H / http://www.ctyme.com/intr/int-10.htm). Also, it's `int 10h`; `int 10` is `int 0xa`. Yes, `inc si` is only 1 byte, vs. 3 for `add si, 1`. – Peter Cordes Aug 23 '22 at 07:06
  • It totally depends on context whether setting DS=CS is appropriate. In a `.com` executable it would be redundant; all segment regs are equal. In a `.exe` executable, it would work: CS will I think be set so CS:0 is the first byte of the .text section, matching an `org 0`. In an MBR bootloader, CS:IP might be `07c0:0000` or `0000:7c00` depending on the BIOS, which might not match the ORG you assembled with. This code ends with `ret` so we can guess it must be a DOS executable; a bootloader wouldn't have anything to `ret` to. – Peter Cordes Aug 23 '22 at 07:08
  • Thanks, @Peter, fixed the interrupt and stressed "may need" rather than "need". For a com file, that will already be the case but no (functional) harm in doing so again. For an exe, the string appears to be in the code segment so, if `ds` is different to `cs`, you'll probably print out rubbish. I'm guessing it's the former (com) since the `lodsb` variant apparently worked. – paxdiablo Aug 23 '22 at 09:13
  • Indeed, an EXE or an MBR bootloader need segment registers set up. My point was that it would be good to add context for when it's safe/correct to copy CS to make absolute addresses of labels work: only in a DOS program, not in general. Jumps / calls are position-independent, so code can be working when running from the "wrong" CS:IP. In an MBR bootloader, the other major use-case for x86-16 BIOS stuff in SO Q&As, copying CS to DS might happen to make it work, or could be the wrong segment base. – Peter Cordes Aug 23 '22 at 09:44
0

First lodsb is a command that tells the computer to get a character in the code and increases the offset. The offset is determined by [SI], a register that can be easily set. Once SI is set lodsb gets the char and lodes it into al. From this point on its reading al and determing what to do. There is another question like this here.

Logan Rios
  • 87
  • 10