hi, i need some information on those large 64 bit numbers (2 dwords), the kind you see in file sizes
at the moment the two main things i need to do are addition and converting the number to text so it can be displayed to the user
so for the addition, how for example do i add 0FFFFFFFFFFh and 0FFFFFFFFFFh ( = 01FFFFFFFFFEh)
this is what i want:
dword value1_low = 0FFFFFFFFh
dword value1_high = 0FFh
dword value2_low = 0FFFFFFFFh
dword value2_high = 0FFh
dword result_low = 0FFFFFFFEh
dword result_high = 01FFh
i want unsigned addition, it's for file sizes (and because i hate signed numbers)
i would prefer to avoid floating point, but if it's more efficient then it doesn't matter, as long as it's unsigned and i can get a
full maximum value of 0FFFFFFFFFFFFFFFFh
as for the second thing, now how can i convert the number to a string, basically i need a function the same as dwtoa as
in the masm32 extra includes, something like a qwtoa, but i can't get that to work
(p.s. please don't just give me links to masses of information in other places to read, i have been looking into this
literally for years, and finally resorted to posting at a forum to ask, some simple code examples would be best)
thanks if you can help
Floating point would be fine and can handle larger than 64 bit (IE: 80 bit).
Quote from: someone on March 27, 2010, 06:53:32 AM
as for the second thing, now how can i convert the number to a string, basically i need a function the same as dwtoa as
in the masm32 extra includes, something like a qwtoa, but i can't get that to work
There are other ways to do it, but Str$() is fairly simple to use:
Quoteinclude \masm32\MasmBasic\MasmBasic.inc ; get the library here (http://www.masm32.com/board/index.php?topic=12460)
.code
start:
mov eax, 123456789 ; create a nice qword number
mov ecx, eax
mov edx, 1000000000
mul edx
Print Str$("edx::eax+ecx=%i\n\n", edx::eax+ecx)
inkey "Press any key"
Exit
end start
Output:
edx::eax+ecx=123456789123456789
In its simplest form, you can use
Print Str$("%i", edx::eax)
but how, i only know the basics of floating point, and so far can only do division, all the documents i have are too complicated and don't
explain the simple basic step by step process of adding two numbers, it must be unsigned too, which is another thing i'm not too sure about with fp
i kind of wanted to avoid floating point, only because i don't know enough about it, if i could get it too work any way, even with fp, it would be great
the main problem i have had so far with floating point is that i don't know how to get a 64 bit value (via two seperate dwords) pushed onto the floating
point stack, and then later popped off into the right seperate dwords
is there some (efficient) mathematical way of doing it (avoiding floating point), for example adding the high and low seperately then shifting the bits left
i know that wouldn't work, but something similar
once again this problem has plagued me for years and i want to get it sorted
------------------------------
thanks for the suggestion, but MasmBasic isn't what i'm looking for, for the string conversion, i just need a basic function (in code) that i can add to my
own code (something i can completely rewrite my own way), rather than a seperate library, better yet i would prefer just an explanation of the process
of converting a long value to a string, that way i can develop my own module
You can use MSVCRT's (s)printf to render 64-bit numbers.
This example isn't written for Masm32, but I guess you'll get the idea:
;*** 64bit numbers
.386
.MODEL FLAT, stdcall
option casemap:none
.nolist
.nocref
WIN32_LEAN_AND_MEAN equ 1
include windows.inc
include stdio.inc
include macros.inc
.list
.cref
lf equ 10
.CODE
main proc c
local pMem:ptr byte
mov edx,12345678h
mov eax,0ABCDEF00h
invoke printf, CStr(<"EDX::EAX=%I64X",lf>),edx::eax
mov eax, 2000000000
mov edx, 32
mul edx
invoke printf, CStr(<"2000000000*32=%I64u",lf>),edx::eax
ret
main endp
mainCRTStartup proc c
call main
invoke ExitProcess, 0
mainCRTStartup endp
end mainCRTStartup
Here's the makefile. Note that MSVCRT.LIB is used!
name = testl
DEBUG=0
OUTDIR=RELEASE
LOPTD=
AOPTD=
ASM = jwasm -c -Sg -Fl$* -Fo$* -coff -I \win32inc\include -I\asm\inc $(AOPTD)
CLIB=msvcrt.lib
#CLIB=libc32.lib
LOPT=/OUT:$*.exe /MAP:$*.map /SUBSYSTEM:CONSOLE $(LOPTD) /FIXED:NO /LIBPATH:\win32inc\lib
LINK=link
MODS=$*.obj
LIBS=kernel32.lib $(CLIB)
$(OUTDIR)\$(name).exe: $*.obj $(name).mak
$(LINK) $(MODS) $(LIBS) $(LOPT) /OUT:$*.exe
$(OUTDIR)\$(name).obj: $(name).asm $(name).mak
$(ASM) $(name).asm
Quote from: someone on March 27, 2010, 08:31:38 AM
the main problem i have had so far with floating point is that i don't know how to get a 64 bit value (via two seperate dwords) pushed onto the floating point stack
...
i just need a basic function (in code) that i can add to my own code (something i can completely rewrite my own way)
If you have difficulties for years to find out how to push a qword on the FPU, then inserting
include \masm32\MasmBasic\MasmBasic.inc on top of your code, and using
mov eax, Str$("%i", edx::eax) seems the most adequate solution.
once again, i don't want to add a large module of someone elses code to my apps, so i won't be using MasmBasic, sorry
and i like things to be pure asm, so i'd like to avoid the printf function, however it is viable, and if i can't find a solution
for the string conversion i might consider printf as a last resort, again thanks for your suggestions, still not the answers
i'm looking for, i really want to get the addition problem solved
> the main problem i have had so far with floating point is that i don't know how to get a 64 bit value (via two seperate dwords) pushed onto the floating point stack, and then later popped off into the right seperate dwords
My apologies that I suggested Basic. Let's go for a compromise: Once you have learned "how to get a 64 bit value (via two seperate dwords) pushed onto the floating point stack, and then later popped off into the right seperate dwords", I will point you to drizz' qword to Ascii routine (part of the Basic), so that you can "completely rewrite" it your own way.
Quote from: someone on March 27, 2010, 09:01:58 AM
... i really want to get the addition problem solved
the "addition problem" is none - or, more exactly, it's a question for the campus:
v1 dq 0ffffffffffh
v2 dq 0ffffffffffh
mov eax,dword ptr v1+0
mov edx,dword ptr v1+4
add eax,dword ptr v2+0
adc edx,dword ptr v2+4
someone,
The dwtoa procedure has been optimized for speed, and that tends to make the code much harder to understand. If you are having problems with this, then you should start with simple, easy to understand code.
In japheth's example above the ADD instruction adds the low-order dwords and leaves any overflow in the carry flag. The ADC instruction adds the high-order dwords, and adds in the value of the carry flag.
You could load the 64-bit integers into the FPU, do the addition, and store the result in v2 (or where ever) with just four instructions:
fild v1 ; ST(0)=v1
fild v2 ; ST(0)=v2, ST(1)=v1
fadd ; ST(0)=sum, ST(1)-ST(7) empty
fistp v2 ; store result to memory and pop, leaving ST(0)-ST(7) empty
Your example values are in hex, so I'll assume that you wish to display in hex. Note that in a hex string each hex digit represents the value of one 4-bit nibble. Knowing this, a value can be converted to a hex string by decomposing the value into nibbles and using the value of each nibble as an index into a table of hex digits. The data could be defined like this:
.data
v1 dq 0FFFFFFFFFFh
v2 dq 0FFFFFFFFFFh
buffer db 16 dup(0),0
hexDigits db "0123456789ABCDEF"
And assuming that the result were stored in v2, the code to set up the conversion and convert the low-order DWORD only could be like this:
mov edx, DWORD PTR v2 ; copy low-order dword of result to EDX
mov edi, OFFSET buffer
add edi, 15 ; set EDI to end of buffer
mov ecx, 8 ; load digit counter
@@:
mov ebx, edx ; copy value to EBX
and ebx, 0Fh ; mask off all but lower nibble
mov al, hexDigits[ebx] ; get the corresponding hex digit
mov [edi], al ; store it in the buffer
shr edx, 4 ; shift next nibble into position
dec edi ; adjust EDI for next digit
dec ecx
jnz @B ; loop if digit counter not zero
And instead of trying to simultaneously debug the conversion code and the display code, I would at least start out using the CRT printf procedure to display the values:
invoke crt_printf, cfm$("%I64x\n"), v2
someone,
There is some wisdom in what you have been told in that there are a number of examples that you can clearly look at and learn how they are done. JJ has written code that will do the conversion, the MASM32 library has bits that should be able to help you, Japheth has made suggestions that can help you and Michael has shown you how to use the simplest method in floating point to do the job.
Coming from a large range of people who have written assembler for years, the best way to fail is to take on too many things that you don't know how to do and among the things you are trying to do is write a runtime library and that is not a beginners task. Lay out you task in bits to get it going using anything you can to make it work then rewrite each part your own way. A runtime library is in fact written in bits and when you have enough bits you can perform more complex tasks.
"as for the second thing, now how can i convert the number to a string, basically i need a function the same as dwtoa as
in the masm32 extra includes, something like a qwtoa, but i can't get that to work"
just download b2a3264.zip from http://www.masm32.com/board/index.php?topic=8974.45 :wink
For the second part, I usually use The Svin's qword to ascii routine:
qw2a PROC uses ebx esi edi pqwValue:DWORD,lpBuffer:DWORD
LOCAL qtemp :QWORD
LOCAL qstore :QWORD
; The Svin
movq [qstore],mm7
emms
mov esi,[pqwValue]
mov edi,[lpBuffer]
mov edx,[esi]
mov eax,[esi+4]
cmp eax,0DE0B6B3h
jc C1
jne C2
cmp edx,0A7640000h
jc C1
C2:
cmp eax,8AC72304h
jc D1
jne D2
cmp edx,89E80000h
jc D1
D2:
mov BYTE PTR [edi],'1'
sub edx,89E80000h
lea edi,[edi+1]
sbb eax,8AC72304h
D1:
mov BYTE PTR [edi],'/'
@@:
inc BYTE PTR [edi]
sub edx,0A7640000h
sbb eax,0DE0B6B3h
jnc @B
add edx,0A7640000h
adc eax,0DE0B6B3h
inc edi
C1:
mov DWORD PTR [qtemp],edx
mov DWORD PTR [qtemp+4],eax
sub esp,10
fild QWORD PTR [qtemp]
fbstp TBYTE PTR [esp]
xor esi,esi
@@:
pop eax
bswap eax
mov ebx,eax
mov ecx,eax
mov bl,bh
shr ecx,16
mov ah,al
shr bl,4
shr al,4
and bh,0fh
and ah,0fh
shl ebx,16
and eax,0FFFFh
mov edx,ecx
mov cl,ch
mov dh,dl
shr cl,4
shr dl,4
and ch,0fh
and dh,0fh
shl ecx,16
lea eax,[eax+ebx+30303030h]
lea edx,[edx+ecx+30303030h]
mov [edi+10],eax
mov [edi+14],edx
xor esi,1
lea edi,[edi-8]
jne @B
mov ah,[esp]
add edi,16
mov al,ah
add esp,2
shr al,4
mov esi,[lpBuffer]
and eax,0f0fh
or eax,3030h
mov [edi],ax
cmp edi,esi
mov BYTE PTR [edi+18],0
jne P1
mov ecx,-20
add edi,19
@@:
inc ecx
cmp BYTE PTR [edi+ecx],30h
je @B
mov eax,ecx
js Z0
neg eax
add esi,eax
@@:
mov al,[edi+ecx]
mov [esi+ecx],al
inc ecx
jne @B
P1:
movq mm7,[qstore]
emms
ret
Z0:
mov BYTE PTR [esi+1],0
jmp P1
qw2a endp
"I usually use The Svin's qword to ascii routine"
Really? :wink
Would you be so kind to explain the meaning of the register mm7 and the local variable qstore?
What do you think about MCoder's optimization here: http://www.asmcommunity.net/board/index.php?topic=5197.15
Hey Lingo,
I didn't write it, you could ask The Svin, he obviously had some reason to preserve the register, I never bothered to remove it.
Edgar
Quote from: lingo on March 27, 2010, 02:15:26 PM
What do you think about MCoder's optimization here: http://www.asmcommunity.net/board/index.php?topic=5197.15
Nice, I have used the Svin's routine as a copy and paste for many years, probably since I first started in assembly, never saw any reason to change it or even look for a better solution as it worked and was more than enough for my purposes. Also there are exceedingly few times I ever need to convert qwords to ascii, I could probably count the number of times I needed one in the last 8 years on one hand...
ok thank you very much everybody the problems are solved now
special thanks to japeth, that was exactly the answer i was looking for, i didn't know about adc
here's my proc for those interested:
Add64Bit proc lpQwordOut:DWORD, dwInValueToAddHigh:DWORD, dwInValueToAddLow:DWORD
mov ecx, lpQwordOut
mov eax, dwInValueToAddLow
mov edx, dwInValueToAddHigh
add dword ptr [ecx], eax
adc dword ptr [ecx+4], edx
ret
Add64Bit endp
and also special thanks to donkey for the qw2a proc, that's also exactly what i was looking for, although
it's strange in the code that mm7 is preserved, anyway i'll remove that, and also avoid using bswap
to keep it with 386
also thanks to MichaelW for the floating point point example, it's so simple, i'm sure i have tried that in the past
but it never worked for me, i must have missed something, probably because in my debugger the fpu register
shows a decimal value and that threw me off
i guess the next stage would be 96 bit values, but thats for another day
also on a side note, i'm no beginner at assembly programming, it's been my main programming language for at
least 7 years now, i have just avoided dealing with these small things, until now
thanks again to everybody
Just wondering because i know nothing about this subject, when the ADC is performed would we then check to see that the total wasn't larger than 64 bits?
Example:
Num1 = F000000000000000
Num2 = 1000000000000000
Num1 + Num2 = 10000000000000000
Which is now a 72 bit number because it requires at least 9 bytes to store now, doesnt it? (68 bits if you allow nibbles instead of bytes)
HR,
Ghandi
yes you are right, you can check
for my situation, i'm relying on not ever needing a number larger than 64 bits, so there isn't much need
but adc still sets the next carry flag if the number goes over 64 bits, i think means that the addition can
go on as many times as you want it to, by basically just repeating the last two lines
here are my procedures for those interested, now i have one that adds 96 bit numbers as well
also they check if the result is too big, and if it is then it sets the result to the maximum FFFF...
Add64Bit proc lp64BitNumber:DWORD, dwAddValueHigh:DWORD, dwAddValueLow:DWORD
mov ecx, lp64BitNumber
mov eax, dwAddValueLow
add dword ptr [ecx], eax
mov eax, dwAddValueHigh
adc dword ptr [ecx+4], eax
jc @too_big
ret
@too_big: ;will jump here, if the result is bigger than a 64 bit number
mov dword ptr [ecx], 0FFFFFFFFh
mov dword ptr [ecx+4], 0FFFFFFFFh
ret
Add64Bit endp
Add96Bit proc lp96BitNumber:DWORD, dwAddValueHighest:DWORD, dwAddValueHigh:DWORD, dwAddValueLow:DWORD
mov ecx, lp96BitNumber
mov eax, dwAddValueLow
add dword ptr [ecx], eax
mov eax, dwAddValueHigh
adc dword ptr [ecx+4], eax
mov eax, dwAddValueHighest
adc dword ptr [ecx+8], eax
jc @too_big
ret
@too_big: ;will jump here, if the result is bigger than a 64 bit number
mov dword ptr [ecx], 0FFFFFFFFh
mov dword ptr [ecx+4], 0FFFFFFFFh
mov dword ptr [ecx+8], 0FFFFFFFFh
ret
Add96Bit endp
Quote from: lingo on March 27, 2010, 02:15:26 PM
"I usually use The Svin's qword to ascii routine"
Really? :wink
Would you be so kind to explain the meaning of the register mm7 and the local variable qstore?
Actually, going through some old old old code I found that it was me who added the preservation of mm7 because I needed it once and modified the function. After that I must have C&P'ed it from that program and it was viral at that point. So I can't blame that one on the Svin, it was my fault.
someone,
Just in case you may want to learn a bit more, the latest version of the Fpulib contains two functions to convert qwords to ascii, one for unsigned and the other for signed qwords. Both are based on using multiplications instead of division to perform the conversion.
That latest version of the Fpulib also accepts qwords as input for many of the functions using the FPU.
AND, the source code of each function is included for your education in the downloadable file from:
http://www.ray.masmcode.com/fpu.html#fpulib
PLUS, if you ever want to learn how to program the FPU yourself, a tutorial explaining almost every aspect of using floats is available on the same page of the above link. You can browse it online or download the entire tutorial. Be sure to read and understand the first two chapters.