2

I would like to print two hex-numbers separately in a bootable assembly file. Printing the second number seems to add it to the first, however. As some have pointed out, the problem is probably in the print_hex part.

Here is my code:

[org 0x7c00]

  mov dx, [number1]
  call print_hex  

  mov bx, space
  call print_string

  mov dx, [number2]
  call print_hex

  jmp $                 ; Hang once we're done

print_hex:
  pusha             ; save the register values to the stack for later

  mov cx,4          ; Start the counter: we want to print 4 characters
                    ; 4 bits per char, so we're printing a total of 16 bits

char_loop:
  dec cx            ; Decrement the counter

  mov ax,dx         ; copy bx into ax so we can mask it for the last chars
  shr dx,4          ; shift bx 4 bits to the right
  and ax,0xf        ; mask ah to get the last 4 bits

  mov bx, HEX_OUT   ; set bx to the memory address of our string
  add bx, 2         ; skip the '0x'
  add bx, cx        ; add the current counter to the address

  cmp ax,0xa        ; Check to see if it's a letter or number
  jl set_letter     ; If it's a number, go straight to setting the value
  add byte [bx],7   ; If it's a letter, add 7
                    ; Why this magic number? ASCII letters start 17
                    ; characters after decimal numbers. We need to cover that
                    ; distance. If our value is a 'letter' it's already
                    ; over 10, so we need to add 7 more.
  jl set_letter

set_letter:
  add byte [bx],al  ; Add the value of the byte to the char at bx

  cmp cx,0          ; check the counter, compare with 0
  je print_hex_done ; if the counter is 0, finish
  jmp char_loop     ; otherwise, loop again

print_hex_done:
  mov bx, HEX_OUT   ; print the string pointed to by bx
  call print_string

  popa              ; pop the initial register values back from the stack
  ret               ; return the function

print_string:     ; Push registers onto the stack
  pusha

string_loop:
  mov al, [bx]    ; Set al to the value at bx
  cmp al, 0       ; Compare the value in al to 0 (check for null terminator)
  jne print_char  ; If it's not null, print the character at al
                  ; Otherwise the string is done, and the function is ending
  popa            ; Pop all the registers back onto the stack
  ret             ; return execution to where we were

print_char:
  mov ah, 0x0e    ; Linefeed printing
  int 0x10        ; Print character
  add bx, 1       ; Shift bx to the next character
  jmp string_loop ; go back to the beginning of our loop

; global variables
  HEX_OUT: db '0x0000',0
  number1: dw 1
  number2: dw 2
  space: db " ",0

; Padding and stuff
  times 510-($-$$) db 0
  dw 0xaa55

It gives the output:

0x0001 0x0003

I expected the output:

0x0001 0x0002

Edit: Updated the code and problem statement, hopefully making it more complete and verifiable.

Michael Petch
  • 46,082
  • 8
  • 107
  • 198
bjarke15
  • 85
  • 5
  • 2
    Use a debugger to examine `dx` passed to `print_hex`. Also try printing `3` directly to verify `print_hex` works :) – Jester Feb 16 '18 at 15:24
  • 2
    I am *sure* `print_hex.asm` has *everything* to do with the problem. Do you have documentation for that function that explicitly states that all (or most) contents of registers are preserved *or* destroyed? – Jongware Feb 16 '18 at 15:28
  • I saw the include files (and the `jmp $`) and wondered if this was in Bootloader? – Michael Petch Feb 16 '18 at 19:31
  • 2
    Make this an [mcve]. Add all your code including from both include files and show us how you build and run your program. – Michael Petch Feb 16 '18 at 19:41
  • 1
    I'll have to agree though that this appears to be some problem with the routine `print_hex`. Because I have done bootloaders in the past I happened to have the include files with the same names previously. I sued them to make a bootloader (added a boot signature and org 0x7c00) ran it and worked. Built it as a DOS COM program with `org 0x100` and it worked too. If you coded `print_hex` yourself then you may have some kind of bug. – Michael Petch Feb 16 '18 at 19:56
  • If you intend to write a real bootloader at some point, I recommend you look at my [SO Answer with General Bootloader Tips](https://stackoverflow.com/a/32705076/3857942) . Among other things you really should set DS appropriately (in your case since you use `org 0x7c00, DS needs to be 0). This may make a difference if you run one real hardware. – Michael Petch Feb 17 '18 at 19:54

1 Answers1

3

Because the print_hex routine uses add byte [bx],al on the HEX_OUT data, it necessarily depends on the initial contents of HEX_OUT.

Simply reset the contents each time you use it:

print_hex:
 pusha 
 mov ax, "00"
 mov [HEX_OUT+2], ax
 mov [HEX_OUT+4], ax
 ...

HEX_OUT: db '0x0000',0
Fifoernik
  • 9,779
  • 1
  • 21
  • 27