-1

I am trying to write my own Os and I needed some print_string func that will print string in sI It is like this

print_string:
    Pusha
    mov ah,0Eh

    .repeat:
    lodsb
    cmp al,0
    je .done
    int 10h
    Jmp .repeat

    .done:
    Popa
    Ret

But the output in

mov si,Msg
call print_string

is like Wn=Wn=

while the Msg is "hello"

Michael Petch
  • 46,082
  • 8
  • 107
  • 198
  • Sry i forgor to write the rest – Gamer0010101 Mar 21 '18 at 12:34
  • 1
    That's not a [MCVE]. Anyway, you probably set up `DS` wrong, if at all. – Jester Mar 21 '18 at 12:35
  • @Jester How can i set ds Anyway – Gamer0010101 Mar 21 '18 at 12:35
  • make sure the directory flag, and the segment registers, are set correctly – Tommylee2k Mar 21 '18 at 13:20
  • 2
    You just set it? If you want to create x86 OS, you should know what is segment:offset addressing in 16 bit real mode of x86 CPU, you should know which registers are available, why `lodsb` does use `ds` implicitly and how you can even override it to use different segment register, and how the memory map looks after x86 machine is powered on, i.e. where you can put your data, and to which values you want to set your segment registers, etc... and under all of that you should already know x86 assembly basics, i.e. that there's `MOV Sreg,r/m16` variant of `mov` instruction. Use some book/tutorial? – Ped7g Mar 21 '18 at 13:59
  • 1
    Once you will learn some x86 assembly basics, there's reasonable resource for OS development (or more like OS development **basics**): https://wiki.osdev.org/Main_Page ... if you are really into OS development, after learning these basics (may take few months or years), you may want to check some real OS like linux or BSD, the sources, and what their developers are working on, and what kind of problems they are trying to resolve. After few years in such community you will be probably capable to contribute meaningfully. – Ped7g Mar 21 '18 at 14:01
  • @Ped7g i know what segments and offset is I know where to put my data I know how RAM works and I know MOV Sreg,r/m16 and i also looked at the OsDev wiki ... THE THING I DONT KNOW IS I dont know why my int 10 print_string function doesnt work – Gamer0010101 Mar 21 '18 at 14:09
  • Verify in debugger that `ds:si` points to the "hello" string. Either it points to the correct memory place, and it is already overwritten with "Wn=Wn=" by whatever code which decided to write into that part of memory, or your `ds:si` does point elsewhere. The routine you posted is correct as is, no problem there, your problem is elsewhere. – Ped7g Mar 21 '18 at 14:51
  • If you are bored, you can try to damage the source memory at the beginning of `print__string:`, after `pusha`, do `mov eax,0333231h` `mov [si],eax` to hardcode string "123" into "msg" area, then the remaining `print__string` routine should print it correctly, to prove that it works. ... also it's completely normal that you don't know what your own assembly actually **really** does when run on the machine, as human is not accurate enough to correctly asses all instruction effects and states when writing source, that's why you should verify every new part of code in debugger several times. – Ped7g Mar 21 '18 at 14:57
  • I think the problem was about ds:si because i took out lodsb and added code that will get string from bx by pointing the adress of it that worked pretty well Thanks anyway tho – Gamer0010101 Mar 21 '18 at 17:55
  • Have you looked at my answer and tried it? It would have helped if you showed your complete bootloader. The reality is that I think you may not have a firm grasp on real mode and the nuances of bootloaders. It is possible ds:si didn't work because a) you have the wrong `org`, b) you had garbage in _DS_ or a combination of both. My answer was also an idea of what a minimal complete verifiable example looks like. You can take my answer, build it up and test it. No guessing as to what the other code is or isn't doing. – Michael Petch Mar 21 '18 at 18:41
  • Do you have two SO accounts. I was wondering why something seemed familiar. You say the output is `Wn=Wn=`. I did some digging and realized user @Programmer made that exact same comment under his post here: https://stackoverflow.com/questions/49366858/nasm-stopped-working-properly . – Michael Petch Mar 21 '18 at 19:12
  • Because if you are the author of the other question https://stackoverflow.com/questions/49366858/nasm-stopped-working-properly , or your code is likd what is in the other question, then you never actually set _DS_ to 0x07c0. you do set the stack segment to that, but not _DS_. Under that question I made the comment that you didn't initialize _DS_. Which is likely still the same reason why it still doesn't work now. – Michael Petch Mar 21 '18 at 19:31
  • @MichaelPetch Yes I have two accounts Ok i ll try settings ds I didnt do that before I only used Org 0x7c00 – Gamer0010101 Mar 21 '18 at 19:38
  • `org` doesn't emit any machine code, and the `ds` is set to unknown value upon receiving control from BIOS (it can be even random value, although that's unlikely, lot more likely it will be zeroed), so if you don't set it up, and then you use it to address memory, you can end anywhere in the memory (first 1MiB of address space). *"didnt do that before"* - yes, your bootloader is lacking in many more aspects, wouldn't work in real world on many PCs. But as long as you test in some stable friendly environment like qemu or bochs, many things will work "for free", unlike on real PC. – Ped7g Mar 22 '18 at 09:58

1 Answers1

1

This isn't a minimal complete example, but the issue is pretty common. Even without seeing the rest of the code I'd guess that you have a mismatch in the segment being used by the processor (or simulated processor) at boot up and the offset being used by your assembly code.

With 16-bit segment:offset addressing there are many combinations of segments and offsets that point to the same physical memory address. The most common ones used by BIOSes are 0x07c0:0x0000 and 0x0000:0x0000. (0x07c0 << 4)+0x0000 = physical address 0x07c00. (0x0000 << 4) + 0x7c00 = physical address 0x07c00 too. The idea is that you want your ORG directive to reflect the offset portion what you want to use and then manually set DS when your bootloader starts. The lack of an ORG directive in NASM (when building using -f bin) defaults to org 0x0000.

I have General Bootloader Tips that say this:

  • When the BIOS jumps to your code you can't rely on CS,DS,ES,SS,SP registers having valid or expected values. They should be set up appropriately when your bootloader starts. You can only be guaranteed that your bootloader will be loaded and run from physical address 0x00007c00 and that the boot drive number is loaded into the DL register. [snip]
  • The direction flag used by lodsb, movsb etc could be either set or cleared. If the direction flag is set improperly SI/DI registers may be adjusted in the wrong direction. Use STD/CLD to set it to the direction you wish (CLD=forward/STD=backwards). In this case the code assumes forward movement so one should use CLD. More on this can be found in an instruction set reference

You can't rely on the direction DF flag (needed for LODSB) and the segment registers (like DS) being a particular value (or the right one) when your bootloader starts. You need to set it explicitly at the start of your code. If you don't, the string you wish to print will be read from the wrong part of RAM and the result will be gibberish. The fact that you seem to be printing the same gibberish twice suggests another issue and that is that you don't have an infinite loop of some sort to end your bootloader. I have another Stackoverflow Answer that I believe is related.

I will fill out a missing bootloader that calls the print_string function you have provided that uses 0x0000 as the segment and we use and org 0x7c00 as the starting offset:

; Create bootloader with: nasm -f bin boot.asm -o boot.bin
; To test in QEMU use:    qemu-system-i386 -fda boot.bin 
org 0x7c00
main:
    xor ax, ax          ; XOR register with itself zeroes the register
    mov ds, ax          ; We want DS:ORG to be 0x0000:0x7c00
    cld                 ; Forward direction for string instructions like LODSB

    mov si,Msg
    call print_string   ; Print the message

    ; This is a preferred way to do an infinite loop but
    ; you could also do: JMP $. This prevents falling through
    ; the code below and off to memory we don't intend to execute
    cli
.endloop:
    hlt
    loop .endloop

print_string:
    Pusha
    mov ah,0Eh
    xor bx,bx          ; Ensure we are writing to page 0
                       ; XOR register with itself zeroes the register
    .repeat:
    lodsb
    cmp al,0
    je .done
    int 10h
    Jmp .repeat

    .done:
    Popa
    Ret

; Place data after the code but before the boot signature.
Msg db "hello",0            ; Nul terminated string

times 510 - ($ - $$) db 0   ; padding with 0 at the end
dw 0xAA55                   ; PC boot signature

Alternatively we could have used a segment of 0x07c0 and used org 0x0000 (or omitted it) and it should still work. The beginning of the code could look like:

org 0x0000
main:
    mov ax, 0x07c0
    mov ds, ax          ; We want DS:ORG to be 0x07c0:0x0000
    cld                 ; Forward direction for string instructions like LODSB

This is the output I get using QEMU for both versions:

enter image description here

Michael Petch
  • 46,082
  • 8
  • 107
  • 198
  • 1
    I tested it it works perfectly but i found another way of doing that so thnx anyway I am marking this as approved,working answer so that others have this issue may resolve it thnx I will be carefull on setting ds – Gamer0010101 Mar 21 '18 at 19:42