Jump to content
Tuts 4 You
Sign in to follow this  
LCF-AT

How to calc with div & mul?

Recommended Posts

LCF-AT

Hi guys,

sorry to create a new topic but I got a little stupid problem with some calculation and I don't get it work. :(

Problem: I have created a slidebar and did set the maximum range to 100 (dec) = used as 0-100 %.The problem now are the calculations.So I remember I have done this in the past with a progressbar & filesize (downloader) and there is was working but now I don't get it work anymore.

<0100739D>

	MOV EDI,0x60 ; full lenght
	NOP

@L00000001:
	MOV EAX,EDI
	MOV EDX,0x0
	MOV ECX,0x64 ; 100 dec
	DIV ECX
	CMP EDX,0x0
	JE SHORT @L00000002
	DEC EDI
	JMP SHORT @L00000001

@L00000002:
	MOV EDI,EAX
	MOV ESI,0x30 ; is lenght
	NOP

@L00000003:
	MOV EAX,ESI
	MOV EDX,0x0
	DIV ECX
	CMP EDX,0x0
	JE SHORT @L00000004
	DEC ESI
	JMP SHORT @L00000003

@L00000004:
	MOV ESI,EAX
	IMUL ESI,ESI,0x64 ; 100 dec
	MOV EAX,ESI
	MOV ECX,EDI
	MOV EDX,0x0
	DIV ECX
	NOP
	NOP

Normaly I should get 96 % from that calculation to use this value to set the position of slidebar but I get 0.So I do anything wrong so maybe you can help how to make it correctly and easy too if possible. :)

Thank you

  • Like 1

Share this post


Link to post
CodeExplorer

0x60 = full lenght = 100%

0x30 = 50%

0x60                    ... 100 %
current progress ... ??? % (X)

X = (current_progress * 100) / 0x060

So for example:
if progress = 0x30 the result should be 50:
so we do:
x = (0x30 * 100) / 0x060
x = (48 dec * 100) / 96
x = 4800 / 96 = 50 %

So do: multiply current lenght with 100 (64h) and divide the result with full lenght
 

"Normaly I should get 96 % from that calculation to use this value to set the position of slidebar but I get 0"
if full lenght = 0x60 and you are position 0x30 you should get 50% from where 96 % ???

 

  • Like 1

Share this post


Link to post
CodeExplorer

From Kurapica post:
"The progress is less than 100 and when you divide the current progress on 100 it will return 0. "
Whell you supose to multiply by 100 not divide!

 

 

Share this post


Link to post
LCF-AT

Hi guys and thanks for the answers. :)

Ok now I wrote this....

mov eax, 30 ; current
mov ecx, 64 ; 100
mov edx, 0
mul ecx

mov ecx, 60 ; full length
mov edx, 0
div ecx

.....and I got 50 & in dec.Oh my so simple and I did spend yesterday few hours and didn't got it work.Now it works and slider does move correctly so far.Thanks again very much and sorry for asking about it.

greetz

Share this post


Link to post
LCF-AT

Hi again,

have another small question.Can anyone tell me how to calc size bytes to QWORD = int64?Lets say I do alloc any section with a size of 30000 hex bytes so how I have to calc to get this size into QWORD = int64 pushed to stack?

greetz

Share this post


Link to post
CodeExplorer

So you need the size in qword (int 64) of 30000 hex bytes;
An qword = 8 bytes (from what I know)
So we do 30000 hex bytes / 8 bytes, so we do 30000 / 8
probable the result value needs to be runded so if reminder of divide operation (30000 / 8) is not 0 increment the result with 1
 

Share this post


Link to post
LCF-AT

Hi again and thanks so far.

So have I to work with any QWORD commands maybe?FISTP or so?Problem is I wanna use a API and there I have to use QWORD into stack.

datalength : QWORD

DataLength [in] Length of that file 

There is also a other API...

function BassVideo_GetLength(handle: DWORD): Double; stdcall;

If successful, then the channel's length in seconds is returned, else -1 is returned

...so here I can see Double = also QWORD (2 DWORDs ) right?Now I did debug a file what used this API and right after this API call I see that operation commands...

			sub esp,8
			FISTP QWORD PTR SS:[ESP]

...also I am not sure whether it wants the filesize as lenght or seconds.

function BassVideo_StreamCreateFileMem(data :Pointer; datalength : QWORD; MediaType, Flags, BassFlags : DWORD; CallBackProc : VIDEOPROC; user : Pointer): DWORD; stdcall;
Unfortunately there is no example file using this API above which I could check.
 
greetz

Share this post


Link to post
LCF-AT

Hi guys,

I have again another questions about calculations with values getting higher than -1h.All in all I have really trouble to work with float and not float together and now I thought there would be any other easier solution which I could maybe use to prevent massiv calculation etc.My question is: Are there maybe some API of any module out there which I could use to handle math operations (+/-/*/div/percent) only by strings?Lets say I have 2 ASCII strings and wanna add them and as results I will get also a ASCII string back.
 

1234567890 ; String 1
445454     ; String 2

1234567890+445454=1235013344

Invoke CalcAPIxy,String1,String2,addition,Buffer
=
Buffer "1235013344"

Maybe you know any helpfully APIs which I could use if there some who can do such string operations etc maybe any msvcrt API or so.Would be nice.

greetz

Share this post


Link to post
T-rad

I don't know of any API the will do math directly on / using ASCII string but  you could do something like this...

invoke sscanf, addr String1, chr$("%d"), addr buf1    ;"1234567890"
invoke sscanf, addr String2, chr$("%d"), addr buf2    ;"445454"

mov eax, buf1
mov edx, buf2
add eax, edx

invoke sprintf, Buffer, chr$("%d"), eax            ; "1235013344"

 

Share this post


Link to post
LCF-AT

Hi,

no it dosen't work like I expected.You only can handle values till max -1h on that way like you did post above.I also don't whether there are any API which I could use to do calc operations only with dez ASCII strings.

But thanks for trying to help T-rad

greetz

Share this post


Link to post
T-rad

no problem.

Just a note. When using chr$("%d") you are limited to the max value of an integer so you would change it according to your variable

chr$("%d")    signed decimal or integer
chr$("%i")    signed decimal or integer
chr$("%u")    unsigned decimal or integer
chr$("%ld")    signed long decimal or integer
chr$("%lu")    unsigned long decimal or integer
chr$("%hd")    short
chr$("%l")    long
chr$("%f")    float
chr$("%lf")    double
chr$("%Lf")    long double
chr$("%lld")    signed long long decimal or integer
chr$("%I64d")    signed long long decimal or integer
chr$("%llu")    unsigned long long decimal or integer
chr$("%I64u")    unsigned long long decimal or integer
chr$("%llx")    long long decimal or integer in hex format
chr$("%I64x")    long long decimal or integer in hex format

for example... if you were to do something using a long double like this

String1        db "12345678909876", 0
String2        db "445454.123", 0

invoke sscanf, addr String1, chr$("%Lf"), addr buf1
invoke sscanf, addr String2, chr$("%Lf"), addr buf2
fld [buf1]
fld [buf2]
fadd
fstp [buf1]
invoke sprintf, serial, chr$("%Lf"), buf1

the result would yield "12345679355330.123000"

or an unsigned 64 bit integer

String1        db "1234567890987654", 0
String2        db "445454", 0

invoke sscanf, addr String1, chr$("%llu"), addr buf1
invoke sscanf, addr String2, chr$("%llu"), addr buf2
fld [buf1]
fld [buf2]
fadd
fst [buf1]
invoke sprintf, serial, chr$("%llu"), buf1

the result would yield "1234567891433108"

  • Like 1

Share this post


Link to post
LCF-AT

Hi and thanks for the infos so far.The example for unsigned 64 bit integer does not work for me.Maybe I wrote anything wrong.

00401C60  PUSH 0x40A960
00401C65  PUSH 0x4054DD                     ; ASCII "%llu"
00401C6A  PUSH 0x4054C5                     ; ASCII "1234567890987654"
00401C6F  CALL DWORD PTR DS:[0x404058]      ; msvcrt.sscanf
00401C75  ADD ESP,0xC
00401C78  PUSH 0x40A964
00401C7D  PUSH 0x4054E4                     ; ASCII "%llu"
00401C82  PUSH 0x4054D6                     ; ASCII "445454"
00401C87  CALL DWORD PTR DS:[0x404058]      ; msvcrt.sscanf
00401C8D  ADD ESP,0xC
00401C90  FLD DWORD PTR DS:[0x40A960]
00401C96  FLD DWORD PTR DS:[0x40A964]
00401C9C  FADDP ST(1),ST
00401C9E  FST DWORD PTR DS:[0x40A960]
00401CA4  PUSH DWORD PTR DS:[0x40A960]
00401CAA  PUSH 0x4054EC                     ; ASCII "%llu"
00401CAF  PUSH 0x40C978                     ; ASCII "1016588934"
00401CB4  CALL DWORD PTR DS:[0x40405C]      ; msvcrt.sprintf
00401CBA  ADD ESP,0xC

1016588934

1016588934 is the results I get. :(

.data
String1        db "1234567890987654", 0
String2        db "445454", 0
.data?
buf1 dd ?
buf2 dd ?
serial dd 256 dup (?)

invoke crt_sscanf, addr String1, chr$("%llu"), addr buf1
invoke crt_sscanf, addr String2, chr$("%llu"), addr buf2
fld [buf1]
fld [buf2]
fadd
fst [buf1]
invoke crt_sprintf, addr serial, chr$("%llu"), buf1

greetz

Share this post


Link to post
T-rad

dd is a dword (4 bytes) and not big enough to hold the the size of the int64. you should declare it as dq or qword (8 bytes)

Like this

.data?

buf1 dq ?
buf2 dq ?

 

 

 

Edited by T-rad (see edit history)

Share this post


Link to post
LCF-AT

Ok I did but still get not the right result back.

00401C60  PUSH 0x40A968
00401C65  PUSH 0x4054DD                   ; ASCII "%llu"
00401C6A  PUSH 0x4054C5                   ; ASCII "1234567890987654"
00401C6F  CALL DWORD PTR DS:[0x404058]    ; msvcrt.sscanf
00401C75  ADD ESP,0xC
00401C78  PUSH 0x40A970
00401C7D  PUSH 0x4054E4                   ; ASCII "%llu"
00401C82  PUSH 0x4054D6                   ; ASCII "445454"
00401C87  CALL DWORD PTR DS:[0x404058]    ; msvcrt.sscanf
00401C8D  ADD ESP,0xC
00401C90  FLD QWORD PTR DS:[0x40A968]
00401C96  FLD QWORD PTR DS:[0x40A970]
00401C9C  FADDP ST(1),ST
00401C9E  FST QWORD PTR DS:[0x40A968]
00401CA4  PUSH DWORD PTR DS:[0x40A96C]
00401CAA  PUSH DWORD PTR DS:[0x40A968]
00401CB0  PUSH 0x4054EC                   ; ASCII "%llu"
00401CB5  PUSH 0x40C988                   ; ASCII "1017034388"
00401CBA  CALL DWORD PTR DS:[0x40405C]    ; msvcrt.sprintf
00401CC0  ADD ESP,0x10

1017034388

0040A968  3C9EB694
0040A96C  00000000
0040A970  0006CC0E
0040A974  00000000

greetz

Share this post


Link to post
kao

For some reason, you have all zeroes at 0040A96C. It's incorrect, it should have value "000462d5". Quick look at the disassembly doesn't show anything particularly wrong, so I can only suggest that you debug it instruction-by-instruction.

For reference, here's the code produced by VS2010. I can see 2 main differences. First, it uses FADD QWORD PTR instead of FLD/FADDP. Second, it uses FLD/FSTP to prepare arguments for sprintf.

	sscanf("1234567890987654", "%llu", &a);
00D61269 68 30 62 D6 00       push        offset a (0D66230h)  
00D6126E 68 58 47 D6 00       push        offset string "%llu" (0D64758h)  
00D61273 68 44 47 D6 00       push        offset string "1234567890987654" (0D64744h)  
00D61278 FF 15 3C 72 D6 00    call        dword ptr [__imp__sscanf (0D6723Ch)]  
00D6127E 83 C4 0C             add         esp,0Ch  
	sscanf("445454", "%llu", &b);
00D61281 68 20 62 D6 00       push        offset b (0D66220h)  
00D61286 68 58 47 D6 00       push        offset string "%llu" (0D64758h)  
00D6128B 68 3C 47 D6 00       push        offset string "445454" (0D6473Ch)  
00D61290 FF 15 3C 72 D6 00    call        dword ptr [__imp__sscanf (0D6723Ch)]  
00D61296 83 C4 0C             add         esp,0Ch  
	c = a + b;
00D61299 DD 05 30 62 D6 00    fld         qword ptr [a (0D66230h)]  
00D6129F DC 05 20 62 D6 00    fadd        qword ptr [b (0D66220h)]  
00D612A5 DD 1D 28 62 D6 00    fstp        qword ptr [c (0D66228h)]  
	sprintf((char *)&result, "%llu", c);
00D612AB 83 EC 08             sub         esp,8  
00D612AE DD 05 28 62 D6 00    fld         qword ptr [c (0D66228h)]  
00D612B4 DD 1C 24             fstp        qword ptr [esp]  
00D612B7 68 58 47 D6 00       push        offset string "%llu" (0D64758h)  
00D612BC 68 20 61 D6 00       push        offset result (0D66120h)  
00D612C1 FF 15 40 72 D6 00    call        dword ptr [__imp__sprintf (0D67240h)]  
00D612C7 83 C4 10             add         esp,10h  

 

Share this post


Link to post
T-rad

my rip looks the same but everything is working here. I have attached my src so you can have a look.

sscanf app.rar

0040102A   PUSH Keygen.00403034
0040102F   PUSH Keygen.00403018                                       ; |format = "%llu"
00401034   PUSH Keygen.00403000                                       ; |s = "1234567890987654"
00401039   CALL DWORD PTR DS:[<&msvcrt.sscanf>]                       ; \sscanf
0040103F   ADD ESP,0C
00401042   PUSH Keygen.0040303C
00401047   PUSH Keygen.0040301D                                       ; |format = "%llu"
0040104C   PUSH Keygen.00403011                                       ; |s = "445454"
00401051   CALL DWORD PTR DS:[<&msvcrt.sscanf>]                       ; \sscanf
00401057   ADD ESP,0C
0040105A   FLD QWORD PTR DS:[403034]
00401060   FLD QWORD PTR DS:[40303C]
00401066   FADDP ST(1),ST
00401068   FST QWORD PTR DS:[403034]
0040106E   PUSH DWORD PTR DS:[403038]
00401074   PUSH DWORD PTR DS:[403034]                                 ; |
0040107A   PUSH Keygen.00403022                                       ; |format = "%llu"
0040107F   PUSH Keygen.00403044                                       ; |s = Keygen.00403044
00401084   CALL DWORD PTR DS:[<&msvcrt.sprintf>]                      ; \sprintf
0040108A   ADD ESP,10

 

Share this post


Link to post
LCF-AT

Hhmm.Thanks for the file / source but I get same as before too.See pic.

Wrong.png.a17570b548a5f40e7ff8325e9d16c1

Share this post


Link to post
ragdog

 

Fpu for a simply Qword Addition?:o
Crazy coding :wacko:

Share this post


Link to post
simple

None of the sample codes here have error checking. The return value of sscanf will indicate success/failure.

Besides, strtol(), strtoul(), etc (family of functions) are specifically designed for string/numerical conversions & probably the cleanest way.

Assuming you are using a MS compiler, atoi(), atof(), atoi64() etc are probably the easiest but they aren't cross platform. Personally, sscanf() would be my last choice for this, it has many odd things about it.

Share this post


Link to post
kao
2 hours ago, ragdog said:

Fpu for a simply Qword Addition?:o
Crazy coding :wacko:

That's LCF-AT, always having "unconventional" ideas. :) I'm already used to it..

  • Like 1

Share this post


Link to post
ragdog
Quote

That's LCF-AT, always having "unconventional" ideas. :) I'm already used to it..

Hehe but with Fpu is a really bad solution  No error checking no Overflow check.

And is not Optimized;)

Share this post


Link to post
simple

LCF, I had exact same problem as u w/Trad code, big number was getting cut off. For me, problem was %llu wasn't introduced till C99 or later and ur msvcrt is still running on C89. To fix this problem change the format string for arguments to sscanf & sprintf from "%llu" to C89 standard "%I64d" and it should work fine. When using masm w/libc functions probably best to use only C89. I still prefer other functions for this though.

edit - also to add 445454 all u have to do is use add instruction

Edited by simple
add (see edit history)
  • Like 3

Share this post


Link to post
LCF-AT

Hi guys,

yes maybe I am the one who has unconventional ideas and also looking for unconventional solutions too. :) All in all I wanna find special solutions (simple of course if possible) to prevent unnecessary headache.Ok it works now with the hint of simple to change the format.Thanks again so far guys.

greetz

Share this post


Link to post
T-rad

question... whats so wrong with FPU for the addition

i can use 3-ish lines of code with FPU

fld [buf1]
fadd [buf2]
fst [buf1]

or 6 lines without it.

MOV EAX,DWORD PTR DS:[buf1]
MOV EDX,DWORD PTR DS:[buf1+4]
ADD EAX,DWORD PTR DS:[buf2]
ADC EDX,DWORD PTR DS:[buf2+4]

MOV DWORD PTR DS:[buf1],EAX
MOV DWORD PTR DS:[buf1+4],EDX

Please note that this is a genuine question. I normally code in C/C++ so i don't code in ASM much and would like to learn the proper do's and dont's.

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  
×
×
  • Create New...