Tuts 4 You

How to calc with div & mul?

Recommended Posts

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

• 1

Maybe because you are doing integer divisions ?

The progress is less than 100 and when you divide the current progress on 100 it will return 0.

maybe you should use a different approach or try with floating points instructions.

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 % ???

• 1

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!

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

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

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

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
• 4 weeks later...

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

=
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

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

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

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

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]
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]
fst [buf1]
invoke sprintf, serial, chr\$("%llu"), buf1```

the result would yield "1234567891433108"

• 1

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
00401C78  PUSH 0x40A964
00401C7D  PUSH 0x4054E4                     ; ASCII "%llu"
00401C82  PUSH 0x4054D6                     ; ASCII "445454"
00401C87  CALL DWORD PTR DS:[0x404058]      ; msvcrt.sscanf
00401C90  FLD DWORD PTR DS:[0x40A960]
00401C96  FLD DWORD PTR DS:[0x40A964]
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

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]
fst [buf1]
invoke crt_sprintf, addr serial, chr\$("%llu"), buf1```

greetz

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 ?```

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
00401C78  PUSH 0x40A970
00401C7D  PUSH 0x4054E4                   ; ASCII "%llu"
00401C82  PUSH 0x4054D6                   ; ASCII "445454"
00401C87  CALL DWORD PTR DS:[0x404058]    ; msvcrt.sscanf
00401C90  FLD QWORD PTR DS:[0x40A968]
00401C96  FLD QWORD PTR DS:[0x40A970]
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

1017034388

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

greetz

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  ```

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

```0040102A   PUSH Keygen.00403034
0040102F   PUSH Keygen.00403018                                       ; |format = "%llu"
00401034   PUSH Keygen.00403000                                       ; |s = "1234567890987654"
00401039   CALL DWORD PTR DS:[<&msvcrt.sscanf>]                       ; \sscanf
00401042   PUSH Keygen.0040303C
00401047   PUSH Keygen.0040301D                                       ; |format = "%llu"
0040104C   PUSH Keygen.00403011                                       ; |s = "445454"
00401051   CALL DWORD PTR DS:[<&msvcrt.sscanf>]                       ; \sscanf
0040105A   FLD QWORD PTR DS:[403034]
00401060   FLD QWORD PTR DS:[40303C]
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

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

Fpu for a simply Qword Addition?
Crazy coding

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.

2 hours ago, ragdog said:

Fpu for a simply Qword Addition?
Crazy coding

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

• 1
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

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
• 3

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

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

i can use 3-ish lines of code with FPU

```fld [buf1]
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.

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