NASM - The Netwide Assembler
NASM Forum => Programming with NASM => Topic started by: RagingGrim on December 28, 2014, 06:03:20 AM
-
So I'm just toying around with binary so I have a few new tricks to teach when school starts again next year ( gotta hate physics classes! ) but anyway I got this working which prints out a decimal number's binary in reverse ( the quotients ) ; So now I got a program that turns 10 into 0101 ( 1010 would be correct ) ; How do I reverse these bits? Should I be storing them as a specific datatype? I wrote the same function in delphi ages ago and I handled the sequence as a string which made reversing it that much easier but then again I don't want to do that this time.
BITS 32
extern __cprintf
extern __getch
extern _ExitProcess
global main
section .data
CharFormat db "%",0
State_One db "1",0
State_Zero db "0",0
StateMsg db 0ah,"Quotient %i",0ah,"Remainder %i",0ah,0
IntFormat db 0ah,"Result : %i",0ah,0
DoneMsg db 0ah,"Done",0ah,0
ANumber dd 10
Answer dd 0
section .text
main:
mov EAX , 1500
mov dword [Answer] ,1500
;Save Initial Value
;DIV performs unsigned integer division. The explicit operand provided is the divisor; the dividend and destination operands are implicit, in the following way:
;For DIV r/m8, AX is divided by the given operand; the quotient is stored in AL and the remainder in AH.
;For DIV r/m16, DX:AX is divided by the given operand; the quotient is stored in AX and the remainder in DX.
;For DIV r/m32, EDX:EAX is divided by the given operand; the quotient is stored in EAX and the remainder in EDX.
aLoop:
mov EDX , 0
mov EAX , dword [Answer]
mov ECX , 2
DIV ECX
mov dword [Answer] , EAX
push EDX
push dword [Answer]
push StateMsg
CMP EAX,0
JE Done
call __cprintf
call __getch
JMP aLoop
Done:
push 1
push EAX
push StateMsg
call __cprintf
call __getch
Is there some sort of an array I can use? Suggestions?
Thanks! ( working with nasm on Win64 )
-
Well, this is for dos and not really suitable for 32-bit code... but I happened to have it on hand... :)
; prints the value of ax as decimal, hex, and binary ascii
; nasm -f bin -o showax.com showax.asm
org 100h
section .text
mov ax, 12345
call ax2dec
call newline
call ax2hex
call newline
call ax2bin
mov ah, 4Ch
int 21h
;--------------
;--------------
ax2dec:
push ax
push bx
push cx
push dx
mov bx, 10 ; divide by ten
xor cx, cx ; zero our counter
.push_digit:
xor dx, dx ; clear dx for the div
div bx ; dx:ax/bx -> ax quotient, dx remainder
push dx ; save remainder
inc cx ; bump digit counter
or ax, ax ; is quotient zero?
jnz .push_digit ; no, do more
mov ah, 2 ; print character subfunction
.pop_digit:
pop dx ; get remainder back
add dl, '0' ; convert to ascii character
int 21h ; print it
loop .pop_digit ; cx times
pop dx
pop cx
pop bx
pop ax
ret
;-------------------
;-------------------
ax2hex:
push cx
push dx
mov cx, 4 ; four digits to show
.top
rol ax, 4 ; rotate one digit into position
mov dl, al ; make a copy to process
and dl, 0Fh ; mask off a single (hex) digit
cmp dl, 9 ; is it in the 'A' to 'F' range?
jbe .dec_dig ; no, skip it
add dl, 7 ; adjust
.dec_dig:
add dl, 30h ; convert to character
push ax
mov ah, 2 ; print the character
int 21h
pop ax
loop .top
pop dx
pop cx
ret
;--------------------------
;--------------------------
ax2bin:
push cx
push dx
mov cx, 16
.top
rcl ax, 1 ; rotate and set/clear carry
mov dl, '0'
adc dl, 0 ; make it '1' if carry set
push ax
mov ah, 2 ; print it
int 21h
pop ax
loop .top
pop dx
pop cx
ret
;----------------------------
;----------------------------
newline:
push ax
push dx
mov ah, 2 ; print character in dl
mov dl, 13 ; carriage return
int 21h
mov dl, 10 ; and linefeed
int 21h
pop dx
pop ax
ret
;----------------------------
Besides giving us the remainders in the wrong order, "div" is dog slow. For dividing by two, or powers of two, a shift or rotate might be more appropriate. As you can see, I rotate a bit into the carry flag and then use "adc" to bump the character '0' up to '1' if necessary. (I only use dl 'cause that's what dos wants to print) This won't fit into your "framework" very well, but might give you some ideas...
I'll try to get back to you on this. (I'll get back to you on the private message Real Soon Now, too. Sorry for the delay - just haven't been "in the mood" to write much lately - sorry.)
Later,
Frank
-
No problem! I considered using shifts but I wasn't sure about the math behind it and what happens to what, while I wait I'll take look at what happens and look take a deeper look into the operations ( including rotate which I have never heard of but I suppose it's like a shift XD )
I did as I said I would and i've been playing around with the rotate operations ; I get what they do although I'm a bit lost .
mov eax,0b1010
ror eax,1
so rotate 1010 right with one would result in 0101 which is 5 and mighty fine!
However if I use ror eax,2 I get a negative value . The videos I watched mentioned a few things amongst which now seems the most striking is that the rotate operations don't work on the result if you rotate 2 times for example. I actually have no idea what's meant by that but I'll continue twiddling and reading.
Maybe I had the wrong idea but if you had a binary value of 11101 and rotated it in any direction with the amount of elements ( if I can put it like that eg. 5 ) you would have reversed the sequence? If I try this on 1010 I get a decimal value of -1610612736 which in binary is -1100000000000000000000000000000 (__cprintf handles the conversion from binary to int so I suppose it might be something wront there as well ). Somehow that doesn't seem right. For one I'm not sure what a signed ( negative specifically ) integer looks like in binary. I suppose a 0/1 would be used to represent positive and negative . I should probably look into that.
I am aware of what the carry flag is ( well not it's exact definition but I understand why it's there ) although I don't see why I'd use this here. If i rotate left with four the binary value 1010 I get a result of 160 in decimal which is equal to 10100000. It seems like those four zeros just get paddded in :/
Thanks Again!
-
Here is a tut I wrote about this:
http://www.dreamincode.net/forums/topic/343696-nasmlinux-converting-integer-to-binary-string/
-
That's an interesting way to do it :O
I was curious about a few things. For one when I call DIV for example isn't that number converted to binary anyway ( seeing as how computers work with binary ) . The other is that by using shifts on the integers you the program converts the integer to a binary value and shifts the binary value ( I guess this is the same as the first question ) .
Am I wasting my time doing this ? Or is there something I don't understand properly? ^^
-
mov eax,0b1010
ror eax,1
Rotate does only work when the last bit is zero. Use shift, that works in any cases and stores the reminder of the division into the carry flag.
-
I couldn't find anything regarding rotate only working when the last bit is zero but I'll continue looking at that.
As for shift storing the remainder in the carry flag ; A shift would divide or multiply depending on the correction you shift to ? It also seems more apparent that shift actually shifts rather than multiply and divide - I guess my point is that the division/multiplication is a result of the shift rather than an operation performed on the bits.