Reputation: 758
I am trying to write an x86 assembly code for NASM assembler, which will convert a hexadecimal number into a string and print it. For simplicity I have assumed that my hexadecimal number will only contain digits(eg. 0x1234). Here is the code:
print_hex.asm
[org 0x7c00]
mov dx, 0x1234
call print_hex
jmp $
print_hex:
push bx
push cx
push dx
push ax
mov bx, HEX_STR
mov cx, 0x000f
mov ax, 0x0000 ; length counter
loop:
push bx ; save bx
and cx, dx ; 0xabcd & 0x000f
add bx, 5 ; find position in the template
sub bx, ax
add [bx], cl
pop bx
shr dx, 4 ; next digit
mov cx, 0x000f
inc ax ; increment counter
cmp ax, 4
jl loop ; loop through the digits
pop ax
call print_string
pop dx
pop cx
pop bx
ret
%include "print_string.asm"
HEX_STR: ; template string
db '0x0000', 0
times 510-($-$$) db 0
dw 0xaa55
print_string.asm
print_string:
mov ah, 0x0e
push bx
loop:
cmp BYTE [bx], 0
je end
mov al, [bx]
int 0x10
inc bx
jmp loop
end:
pop bx
ret
If I try to assemble/compile print_hex.asm
with NASM, it gives following error:
print_hex.asm:error: Can't find valid values for all labels after 1004 passes, giving up.
print_hex.asm:error: Possible causes: recursive EQUs, macro abuse.
I have noticed if I don't use any labels(like loop label here) code works fine.
Upvotes: 2
Views: 2028
Reputation: 364068
Your actual problem is that you defined the label loop:
twice.
NASM 2.14.02 prints a nice error message:
$ nasm print_hex.asm
print_string.asm:5: error: label `loop' inconsistently redefined
print_hex.asm:19: note: label `loop' originally defined here
The %include
preprocessor directive works just like in C #include
: the sources effectively become part of the same file, sharing the same namespace for symbols.
Presumably you have an older version of NASM that printed the insane and unhelpful error message. IDK if the it's related to the fact that loop
is also an instruction mnemonic. It shouldn't be, but it's hard to imagine NASM having such an unhelpful handling of duplicate labels in any recent version. That's a common enough mistake in hand-written asm, and that's what NASM is usually used on. So perhaps NASM had a bug that snuck loop
past the usual duplicate detection and got it to try and fail.
loop:
disambiguates the line as definitely a label, not an instruction line for NASM. (But not YASM: it won't let you use loop:
as a label)
.loop:
is scoped to the previous non-local label. So it's like shorthand for print_hex.loop
and print_string.loop
in both the declaration and use.
https://www.nasm.us/doc/nasmdoc3.html#section-3.9
BTW, your code is pretty bloated. You don't need to save/restore every register in every function; just let them clobber regs.
Also, you can convert int->hex more efficiently, and without needing a template to add into. (The initial 0x
is handy but the rest you can calculate in regs). Also, I don't think your code handles the 0..9
vs. a..f
split: those ranges of ASCII character codes are unfortunately not adjacent to each other.
See How to convert a number to hex? for a simple 32-bit version you can easily port to 16-bit, with a lookup table or with a conditional to handle the 0..9 vs. a..f. See also https://codegolf.stackexchange.com/revisions/193842/1 for a simple version with a conditional branch. (A later version saves even more code size using DAS).
Use small constants as immediate operands, like and al, 0xf
, instead of putting them into CX. Decrement a pointer from the end of the buffer if you want, or with hex you can use a rotate to get nibbles from the top and generate in printing order.
Upvotes: 3