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 :)
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
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 !
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
@Gunther : Check your PM :)
Quote from: yq8 on May 06, 2015, 01:55:35 AM
@Gunther : Check your PM :)
Done. Check your PM, too.
Gunther
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
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
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
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.
what he means is, show us the PROC and ENDP, perhaps the PROTO
also, show us where you pass arguments and call it
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:
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
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
how many arguments are you passing to this function ?
another problem....
you zero EBX before you preserve it
preserve it first, then do whatever you want with it, then restore it
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
One. An Integer.
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 :/
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
Dave,
that's the right approach. But why not:
push ebp
mov ebp, esp
push ebx
...
pop ebx
leave
ret 4
Gunther
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
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
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
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:
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]>
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
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 ?
deleted
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
deleted
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
deleted
mov esp,ebp
pop ebp
equiv of LEAVE
deleted
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:
deleted
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
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
deleted
deleted
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 ...
deleted
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 ?
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