-2

I am trying to write a little function to print either a null-terminated or fixed-length string in a specific memory location. Here is my code:

vbrstart:
    xor eax, eax
    mov sp, 0x7a00
    mov bp, 0x6000
    mov ss, ax
    mov ds, ax
    mov es, ax
    xor ebx, ebx
    xor ecx, ecx
    push strict dword initializing
    push strict word 0x0000
    call printmsg
    jmp end


;push strict dword memloc
;push strict word length
;call printmsg
printmsg:
    pop strict dword [store_ret]
    mov [store_cx], cx
    mov [store_esi], esi
    pop cx
    pop esi
    push eax
    push ebx
    mov ah, 0x0E
    mov bx, 0x0007
    cmp cx, 0x0000
    je printnullterm
printgivenlen:
    lodsb
    cmp cx, 0x0000
    je printdone
    int 10h
    dec cx
    jmp printgivenlen
printnullterm:
    lodsb
    cmp al, 0x00
    je printdone
    int 10h
    jmp printnullterm
printdone:
    pop ebx
    pop eax
    mov esi, [store_esi]
    mov cx, [store_cx]
    push strict dword [store_ret]
    ret
printdata:
    store_cx dw 0
    store_esi dd 0
    store_ret dd 0

end:
    hlt
    jmp end

initializing db 10,13,'Initializing...',0

When tested, it prints indefinately, and doesn't stop at the null byte. Where did I make a mistake?

Wyllow Wulf
  • 410
  • 4
  • 23
  • 3
    How about using a debugger to see where it went wrong? – Sami Kuhmonen Jun 02 '16 at 15:08
  • 1
    downvoted for no details from a debugger on what was in which register, and which part of debugging you're stuck on. – Peter Cordes Jun 02 '16 at 15:55
  • compiling it to an ELF binary that the debugger can use, and compiling it to a flat binary, which im using, dd'ed to the VBR, is providing different code and results, so the debugger is not offering me much useful information – Wyllow Wulf Jun 02 '16 at 16:17
  • If anyone knows of a freeware debugger that supports flat binaries, please let me know... that would help a lot... i can hexdump or disassemble, but that's about all – Wyllow Wulf Jun 02 '16 at 16:21
  • 1
    bochs builtin debugger or attach gdb to bochs or qemu. PS: it's unclear what mode you are in, be careful with mixing 16 and 32 bit stuff especially your stack manipulation seems very strange. – Jester Jun 02 '16 at 16:31
  • Attach GDB to VirtualBox or Bochs. – David Hoelzer Jun 02 '16 at 21:52

2 Answers2

2

I see 2 problems with your code:

  • You've written a bootloader. Such a program runs in the 16-bit real address mode. This implies that the return address from a call will be a word and not a dword like your code is expecting.

    printmsg:
    pop word [store_ret]
    
  • You setup the stack in a risky manner. You need to first change the SS register and immediately after that the SP register.

    xor ax, ax
    mov ss, ax      <<< Keep these together 
    mov sp, 0x7a00  <<< and in this order!
    

Since this is 16-bit code there's no need to push/pop the address as a dword.

push word initializing
...
pop si
Fifoernik
  • 9,779
  • 1
  • 21
  • 27
1

Your stack is not properly aligned with all that pushes and pops. Check parameters passing and it's usage in the routine. To start, here's a hint:

vbrstart:
xor eax, eax
mov sp, 0x7a00
mov bp, 0x6000
mov ss, ax
mov ds, ax
mov es, ax
xor ebx, ebx
xor ecx, ecx
push strict dword initializing
push strict word 0x0000
call printmsg                   ; near call, only 16 bits ret addr stored
jmp end

;push strict dword memloc
;push strict word length
;call printmsg
printmsg:
    pop strict dword [store_ret]    ; pop dword (ret address + 16 bits- 1st argument)
    mov [store_cx], cx              ; store_cx = 0
    mov [store_esi], esi            ; store_esi = ??
    pop cx                          ; cx = initializing
    . . .
Alexander Zhak
  • 9,140
  • 4
  • 46
  • 72