The MASM Forum

General => The Campus => Topic started by: yq8 on May 05, 2015, 03:38:23 AM

Title: [Help] - Digit Sum
Post by: yq8 on May 05, 2015, 03:38:23 AM
Hey Guys,

Today I am trying to calculate the digitsum of a number.

e.g.:

1234   -> 10
82749 -> 30


Often people have recommend me to first code myself in another easier language, then its easier to code it in asm.
So I did with C++ :


int DigitSum(int a)
{
int b = 0;
while (a > 0) {
b += a % 10;
a /= 10;
}
return b;
}


Pretty compact function.
Now I try to code this in inline asm in C++.
I am unsure how to realize this, this is my attempt and thats I thought I would do it:


int AsmDigSum(int a)
{
__asm
{
mov eax, a // Move inputnumber to eax
xor ecx, ecx // Set ecx to 0
jpl : // jumpmark
blabla      // somehow perform modulo of eax?
add edx, eax // add result of module operation into edx
idiv edx, 10 // div result by 10
mov eax, edx  // mov result of all calculation back to eax?
dec eax // decrease eax to prevent infinite loop?
jne jpl // if eax is > 0 jump to label
}
}


Obviously this code is not compileable.
Can someone tell me:

1) If my general idea of doing it (look at asm pseudocode) is correct?
2) How can I do this: b += a % 10 ?
3) Is my condition for the while loop correct? Also the decreasing operation?
4) Am I using the correct indices?

Would be cool if someone who is more experienced can give me some hints :)
Title: Re: [Help] - Digit Sum
Post by: jj2007 on May 05, 2015, 04:09:13 AM
You were pretty close, but you should urgently have a look at \Masm32\Help\opcodes.chm

mov eax, 1234567895 ; Move inputnumber to eax
push ebx ; non-volatile register must be preserved
xor ebx, ebx ; Set sum ebx to 0
mov ecx, 10 ; Set ecx to 10
jpl: ; jumpmark
cdq
idiv ecx ; div eax by 10; result in eax, remainder in edx
add ebx, edx    ; add remainder to sum
test eax, eax
jne jpl         ; if eax is > 0 jump to label
xchg eax, ebx ; shortest way to move result to eax
pop ebx         ; get old ebx back
Title: Re: [Help] - Digit Sum
Post by: yq8 on May 05, 2015, 04:28:16 AM
Hey,
Nice, I think I now understood it!
And yes, I will read a bit more into the .chm file now before asking my question ;)
Thanks for the advice and help !
Title: Re: [Help] - Digit Sum
Post by: Gunther on May 06, 2015, 12:36:22 AM
Hi yq8,

just another hint: If you have a working C or C++ source for your problem, compile the source with the switch -S on the command line. The result is the compiler's assembly language code which could give you the right direction to go. And welcome to the forum.

Gunther
Title: Re: [Help] - Digit Sum
Post by: yq8 on May 06, 2015, 01:55:35 AM
@Gunther : Check your PM :)
Title: Re: [Help] - Digit Sum
Post by: Gunther on May 06, 2015, 05:27:38 PM
Quote from: yq8 on May 06, 2015, 01:55:35 AM
@Gunther : Check your PM :)

Done. Check your PM, too.

Gunther
Title: Re: [Help] - Digit Sum
Post by: Gunther on May 06, 2015, 08:46:40 PM
Here is a simple example for using with the GCC. First the main procedure:

#include <stdio.h>
#include <stdlib.h>

extern int Add(int x, int y);

int main()
{
    int a = 3;
    int b = 4;
    int c = 0;
    c = Add(a, b);
    printf("c = %d\n",c);
    return 0;
}

Here the C code for the function Add in a seperate file:

int Add(int x, int y)
{
    return x+y;
}

Compiling the function Add with the following comand line switch:

gcc -O3 -S -masm=intel add.c

leads to following assembly language output:

.file "add.c"
.intel_syntax noprefix
.text
.p2align 4,,15
.globl _Add
.def _Add; .scl 2; .type 32; .endef
_Add:
mov eax, DWORD PTR [esp+8]
add eax, DWORD PTR [esp+4]
ret
.ident "GCC: (rev, Built by MinGW-builds project) 4.8.0 20130314 (experimental)"

The O switch determines the level of optimization. Without O switch ===> nothing optimized
O1 ===> level 1
O2 ===> level 2
O3 ===> level 3 (highest optimization level).

You should be able to do it similar with VS. I hope that gives the idea.

Gunther
Title: Re: [Help] - Digit Sum
Post by: yq8 on May 19, 2015, 11:34:49 PM
Hey,

I now tried to make the Parameter "a" customizable like in a function.
But something is wrong and I don't know what.
This is what I've coded :


push ebp
mov ebp, esp
mov eax,[ebp+0x0c]
xor ebx, ebx
push ebx
mov ecx, 10
jx:
cdq
idiv ecx
add ebx, edx
test eax, eax
jne jx
xchg eax, ebx
pop ebx
ret 0x0c         


What did I do wrong? ;o
Title: Re: [Help] - Digit Sum
Post by: Gunther on May 19, 2015, 11:41:51 PM
Hi yq8,

please show us your function call (number and type of passed parameters). Your last instruction is:

    ret    12

It could be that this is wrong.

Gunther
Title: Re: [Help] - Digit Sum
Post by: yq8 on May 19, 2015, 11:57:17 PM
My parameter is just the integer value  123.
It can't be the return which is wrong.
I tried :

ret 0xC
ret 0x8
ret 0x4
ret

None of them seems to be the right one.
Title: Re: [Help] - Digit Sum
Post by: dedndave on May 20, 2015, 12:07:02 AM
what he means is, show us the PROC and ENDP, perhaps the PROTO
also, show us where you pass arguments and call it
Title: Re: [Help] - Digit Sum
Post by: dedndave on May 20, 2015, 12:09:30 AM
you PUSH EBP, then PUSH EBX....

at the end, you POP EBX, but never POP EBP or LEAVE

when RET executes, it tries to return to an address that was the saved EBP contents - oops   :redface:
Title: Re: [Help] - Digit Sum
Post by: dedndave on May 20, 2015, 12:14:52 AM
it's probably simpler to let the assembler handle the stack frame

;###############################################################################################

        INCLUDE    \Masm32\Include\Masm32rt.inc

;###############################################################################################

MyFunction PROTO :DWORD,:DWORD

;###############################################################################################

    ;    .DATA

;***********************************************************************************************

     ;   .DATA?

;###############################################################################################

        .CODE

;***********************************************************************************************

main    PROC

        INVOKE  MyFunction,eax,5

        print   chr$(13,10)
        inkey
        INVOKE  ExitProcess,0

main    ENDP

;***********************************************************************************************

MyFunction PROC USES EBX arg1:DWORD,arg2:DWORD

    mov     ebx,arg1
    mov     eax,arg2
    print   ustr$(eax),13,10,13,10
    ret

MyFunction ENDP

;###############################################################################################

        END     main


on the PROC line, "USES EBX" will cause the assembler to preserve and restore the contents of EBX
the assembler will take care of the stack frame and balance the stack at exit
Title: Re: [Help] - Digit Sum
Post by: yq8 on May 20, 2015, 12:26:10 AM
Hey dedndave,
Thanks for your reply.
Since I call my asm function from C# I can't do the stack handling
automatically.

I tried to pop ebp too, as you've suggested, but that seems not to work either.

push ebp
mov ebp, esp
mov eax,[ebp+0x0c]
xor ebx, ebx
push ebx
mov ecx, 10
jx:
cdq
idiv ecx
add ebx, edx
test eax, eax
jne jx
xchg eax, ebx
pop ebx
pop ebp
ret 0x0c
Title: Re: [Help] - Digit Sum
Post by: dedndave on May 20, 2015, 12:38:13 AM
how many arguments are you passing to this function ?
Title: Re: [Help] - Digit Sum
Post by: dedndave on May 20, 2015, 12:39:46 AM
another problem....

you zero EBX before you preserve it
preserve it first, then do whatever you want with it, then restore it
Title: Re: [Help] - Digit Sum
Post by: dedndave on May 20, 2015, 12:46:10 AM
it looks like you are passing only 1 DWORD argument

try this code...
        push    ebx
        push    ebp
        mov     ebp,esp
        mov     eax,[ebp+12]
        xor     ebx,ebx
        mov     ecx,10

jx:     xor     edx,edx
        idiv    ecx
        add     ebx,edx
        test    eax,eax
        jne     jx

        xchg    eax,ebx
        leave
        pop     ebx
        ret     4
Title: Re: [Help] - Digit Sum
Post by: yq8 on May 20, 2015, 12:58:25 AM
One. An Integer.
Title: Re: [Help] - Digit Sum
Post by: yq8 on May 20, 2015, 01:00:26 AM
One. An Integer.
Btw: I just noticed, this is the wrong thread I posted this in :D
I am trying to calculate the amount of digits of the int, not calculating the digit sum ^^ (my bad).
Tho I am somehow doing something wrong :/
Title: Re: [Help] - Digit Sum
Post by: dedndave on May 20, 2015, 01:08:09 AM
ok - digit count...
        push    ebx
        push    ebp
        mov     ebp,esp
        xor     ebx,ebx
        mov     eax,[ebp+12]
        mov     ecx,10
        jmp     jy

jx:     xor     edx,edx
        idiv    ecx
        inc     ebx

jy:     test    eax,eax
        jne     jx

        xchg    eax,ebx
        leave
        pop     ebx
        ret     4
Title: Re: [Help] - Digit Sum
Post by: Gunther on May 20, 2015, 08:26:17 AM
Dave,

that's the right approach. But why not:

    push        ebp
    mov         ebp, esp
    push        ebx

    ...

    pop         ebx
    leave
    ret          4


Gunther
Title: Re: [Help] - Digit Sum
Post by: dedndave on May 20, 2015, 08:51:09 AM
Gunther - that's how the assembler does it if you let it handle the stack frame
i prefer to preserve registers before pushing and setting EBP

the reason is.....

1) preserve registers
2) set stack frame
3) push whatever locals you might like or create buffers
4) LEAVE - no need to balance the stack to get rid of locals and/or buffers
5) restore registers

i wish the assembler did it that way
Title: Re: [Help] - Digit Sum
Post by: dedndave on May 20, 2015, 08:53:31 AM
actually, because he has no locals - only has 1 argument - and only accesses it 1 time....
no need to use EBP - just grab the arg via ESP
Title: Re: [Help] - Digit Sum
Post by: dedndave on May 20, 2015, 09:11:05 AM
        push    ebx
        mov     ecx,10
        xor     ebx,ebx
        mov     eax,[esp+8]
        jmp     jy

jx:     xor     edx,edx
        idiv    ecx
        inc     ebx

jy:     test    eax,eax
        jne     jx

        xchg    eax,ebx
        pop     ebx
        ret     4
Title: Re: [Help] - Digit Sum
Post by: rrr314159 on May 20, 2015, 11:10:18 AM
Quote from: dedndave on May 20, 2015, 08:51:09 AM
Gunther - that's how the assembler does it if you let it handle the stack frame
i prefer to preserve registers before pushing and setting EBP
i wish the assembler did it that way

- To each his own, I prefer the assembler's way (which I always thought standard) for one reason, that way the first variable always in the same place, ebp+8 (using stack frame) or esp+4. If u preserve reg's first it will vary depending on how many registers. Often as one hacks at the code one might preserve an extra reg, or remove one: you'd have to change offset every time. If u save, say, five regs, u have to figure out 4th parameter is at ebp+40; then change to 32 if u remove two regs from list ... assembler way, always the same. Easier for those of us who avoid thinking whenever possible :biggrin:
Title: Re: [Help] - Digit Sum
Post by: dedndave on May 20, 2015, 09:31:45 PM
that's fine
but, my way is the right way   :lol:

you can create symbols for all the arguments and locals
then, it's not hard to make changes...

_lpNebulaRect    TEXTEQU <DWORD PTR [EBP+20]>
;RETurn address                     [EBP+16]
;EBX saved contents                 [EBP+12]
;ESI saved contents                 [EBP+8]
;EDI saved contents                 [EBP+4]
;EBP saved contents                 [EBP]
_dwTranslateX    TEXTEQU <DWORD PTR [EBP-4]>
_dwTranslateY    TEXTEQU <DWORD PTR [EBP-8]>
_dwWidth         TEXTEQU <DWORD PTR [EBP-12]>
_dwHeight        TEXTEQU <DWORD PTR [EBP-16]>
_lpPalette       TEXTEQU <DWORD PTR [EBP-20]>
Title: Re: [Help] - Digit Sum
Post by: Gunther on May 21, 2015, 07:31:27 PM
Dave,

Quote from: dedndave on May 20, 2015, 09:31:45 PM
that's fine
but, my way is the right way   :lol:

good to know, but rrr isn't wrong. I prefer his way.

Gunther
Title: Re: [Help] - Digit Sum
Post by: dedndave on May 21, 2015, 08:16:07 PM
it's ok with me - lol
you guys have to balance the stack before restoring registers upon exit
i just do a LEAVE and restore them   :P
whose code is faster/more efficient ?
Title: Re: [Help] - Digit Sum
Post by: nidud on May 21, 2015, 10:35:56 PM
deleted
Title: Re: [Help] - Digit Sum
Post by: Gunther on May 21, 2015, 10:47:41 PM
Dave,

Quote from: dedndave on May 21, 2015, 08:16:07 PM
it's ok with me - lol
you guys have to balance the stack before restoring registers upon exit
i just do a LEAVE and restore them   :P
whose code is faster/more efficient ?

are you sure? What about this:

    push        ebp
    mov         ebp, esp
    sub         esp, 8
    push        ebx
    push        edi
    push        esi

    ...

    pop         esi
    pop         edi
    pop         ebx
    leave
    ret


Gunther
Title: Re: [Help] - Digit Sum
Post by: nidud on May 21, 2015, 11:01:38 PM
deleted
Title: Re: [Help] - Digit Sum
Post by: dedndave on May 22, 2015, 01:42:27 AM
i don't know what alloca does
but it looks fine to me

Gunther
the code you posted balances the stack
it has no locals to balance out

try writing a proc that has locals - then disassemble it to examine how the stack is balanced
the way i write them, i create locals, including large buffers, and don't worry about balancing the stack
Title: Re: [Help] - Digit Sum
Post by: nidud on May 22, 2015, 02:13:17 AM
deleted
Title: Re: [Help] - Digit Sum
Post by: dedndave on May 22, 2015, 02:45:29 AM
mov esp,ebp
pop ebp


equiv of LEAVE
Title: Re: [Help] - Digit Sum
Post by: nidud on May 22, 2015, 03:02:25 AM
deleted
Title: Re: [Help] - Digit Sum
Post by: dedndave on May 22, 2015, 03:36:11 AM
my mistake - it does have 2 dwords

but, what if you want to create a buffer later on
in fact, i often calculate, then push, locals as the routine progresses
it just seems much more elegant to do it that way

i'm right - you're wrong   :lol:
Title: Re: [Help] - Digit Sum
Post by: nidud on May 22, 2015, 04:25:43 AM
deleted
Title: Re: [Help] - Digit Sum
Post by: jj2007 on May 22, 2015, 03:21:42 PM
Quote from: nidud on May 22, 2015, 02:13:17 AM
Quote from: dedndave on May 22, 2015, 01:42:27 AMi don't know what alloca does but it looks fine to me

It's one of many C functions and methods that manipulates the stack within a procedure which forces the compiler to push the user registers before the stack frame is created. The popping of the three registers will for this reason fail.

_alloca allocates size bytes from the program stack. (https://msdn.microsoft.com/en-us/library/aa246687%28v=vs.60%29.aspx)

How did you get alloca to work?

I tried this but both fail:
includelib "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\lib\libcmt.lib"
alloca PROTO C:DWORD
_alloca PROTO C:DWORD
Title: Re: [Help] - Digit Sum
Post by: Gunther on May 22, 2015, 06:09:16 PM
Dave,

Quote from: dedndave on May 22, 2015, 01:42:27 AM
Gunther
the code you posted balances the stack
it has no locals to balance out

a bit more concentration, please. My code has local variables, because:

     sub        esp, 8

makes room for a REAL 8 or 2 INTEGER ... You can address it via EBP-8.

Gunther
Title: Re: [Help] - Digit Sum
Post by: nidud on May 22, 2015, 08:12:13 PM
deleted
Title: Re: [Help] - Digit Sum
Post by: nidud on May 22, 2015, 08:14:03 PM
deleted
Title: Re: [Help] - Digit Sum
Post by: jj2007 on May 23, 2015, 12:02:03 AM
Quote from: nidud on May 22, 2015, 08:12:13 PM
You may try this:
_alloca PROTO C :DWORD

Which library? No such PROTO in \Masm32\include\*.inc ...
Title: Re: [Help] - Digit Sum
Post by: nidud on May 23, 2015, 01:39:13 AM
deleted
Title: Re: [Help] - Digit Sum
Post by: dedndave on May 23, 2015, 01:58:30 AM
NTDLL.DLL has an export named "alloca_probe" (not prototyped in ntdll.inc, and thus not in ntdll.lib)

so, alloca could be a wrapper - or maybe a compiler internal ?
Title: Re: [Help] - Digit Sum
Post by: Gunther on May 23, 2015, 07:59:44 PM
Hi nidud,

Quote from: nidud on May 22, 2015, 08:14:03 PM
Quote from: Gunther on May 22, 2015, 06:09:16 PM
a bit more concentration, please

:biggrin:

QuoteYou can address it via EBP+8.

you're right: It was a typing error. It's changed inside the original post now. I should be more concentrated, too.  :icon_redface:

Gunther