I'm currently writing a simple program in x86 assembly that gets the data at an arbitrary memory address and prints it to the terminal in hexadecimal. It's being assembled in NASM 2.12.02 and I'm running the resulting bin with bochs 2.6.8. I've written a routine called print_hex.asm
that uses db
to define an index of ascii characters, as seen below.
ascii_table: db "0123456789ABCDEF"
When assembling the full program and running the result, the same line
(an increasing number)i[CPU0 ] MOV_EwSw: using of nonexisting segment register 7
prints out over an over again to terminal preceded by a number that keeps increasing. What's strange is if I change the line to
ascii_table: db "0123456789ABC"
by simply omitting the last three letters of the string, it works just fine (although the assembled program gets a runtime error when it tries to convert hex values of D, E or F)
What's going on here? Am I not allowed to declare so much data in a row? Is NASM bugging out on me?
Edit: See below for full source code. Note that it is still a work in progress and might have logic errors elsewhere.
print_hex: ; prints the value stored at bx in hex
pusha ; push all the local registers to the stack
ascii_table: ; define a table to store ascii characters for conversion
db "0123456789ABCDEF"
mov ah, 0x0e ; move 0x0e to the high byte of ax in preparation for a teletype interrupt
mov al, "0" ; move the ascii char 0 to the lower byte of ax
int 0x10 ; perform a teletype interrupt
mov al, "x" ; move the ascii char x to the lower byte of ax
int 0x10 ; perfrom a teletype interrupt
mov dx, 0 ; move 0 to dx in preparation for the loop
mov cx, 0 ; zero out cx
hex_print_loop_start:
mov cl, bl ; move bl to cl to isolate the lowest nybble of bx
add cl, ascii_table ; set the table offset with cx
mov al, cl ; get the value at the offset index of the table and store it in al for printing
int 0x10 ; perform a teletype interrupt
inc dx ; increment dx by one
shr bx, 1 ; shift bx right in preparation for reading the next character
cmp dx, byte 0x04 ; check if the loop has been performed 4 times
jl hex_print_loop_start ; if it hasn't been performed 4 times, jump to the beginning of the loop
popa ; restore local registers
ret ; return
You must move the string data outside the code, because the CPU, after executing pusha
instruction will execute the string as instructions. Your string is interpreted as the following code:
'01' 30 31 XOR BYTE PTR [BX+DI],DH
'23' 32 33 XOR DH,BYTE PTR [BP+DI]
'45' 34 35 XOR AL,35H
'67' 36:37 SS:AAA ; Superfluous prefix
'89' 38 39 CMP BYTE PTR [BX+DI],BH
'A' 41 INC CX
'B' 42 INC DX
'C' 43 INC BX
'D' 44 INC SP
'E' 45 INC BP
'F' 46 INC SI
As long as these instructions are pretty random, so random behavior is expected. Notice also, that the stack pointer is modified, so on the exit of the procedure more chaos is expected.