Reputation: 11612
I want to understand the assembly language on Visual Studio using the __asm keyword in a c program.
What I try to do is; - Create an int array with 5 elements - Loop thru the array and add the values to the accumulator
Here is a code which is working fine;
#include <stdio.h>
int main()
{
int intArr[5] = { 1, 2, 3, 4, 5 };
int sum;
char printFormat[] = "Sum=%i\n";
__asm
{
lea esi, [intArr] // get the address of the intArr
mov ebx,5 // EBX is our loop counter, set to 5
mov eax, 0 // EAX is where we add up the values
label1: add eax, [esi] // add the current number on the array to EAX
add esi, 4 // increment pointer by 4 to next number in array
dec ebx // decrement the loop counter
jnz label1 // jump back to label1 if ebx is non-zero
mov[sum],eax // save the accumulated valu in memory
}
printf(printFormat, sum);
return 0;
}
The output is as below;
Sum=15
I want to use the inline assembly part as a separate function, and do the same with a function call as below;
#include <stdio.h>
// function declaration
int addIntArray(int[], int);
int main()
{
int intArr[5] = { 1, 2, 3, 4, 5 };
char printFormat[] = "Sum=%i\n";
int result;
result = addIntArray(intArr, 5);
printf(printFormat, result);
return 0;
}
int addIntArray(int intArr[], int size)
{
int sum;
__asm
{
lea esi, [intArr] // get the address of the intArr
mov ebx, 5 // EBX is our loop counter, set to 5
mov eax, 0 // EAX is where we add up the values
label1: add eax, [esi] // add the current number on the array to EAX
add esi, 4 // increment pointer by 4 to next number in array
dec ebx // decrement the loop counter
jnz label1 // jump back to label1 if ebx is non-zero
mov[sum], eax // save the accumulated value in memory
}
return sum;
}
The output is weird and as below;
Sum=2145099747
As I debug, I found that I just add up the address values which is stored in the esi register, instead of the contents of those addresses.
I am confused that, why the same inline assembly routine is working as I run it on the main thread, and why not working as I try to call it on a separate function.
Where is the problem, why is the process behaves different on main and function, and how can I fix it?
Upvotes: 2
Views: 1788
Reputation: 8176
You are actually using the address of array that was passed on stack (that is, the address of the argument), not the address of the array itself.
This is actually easier (when it comes to assembly) if you use another debugger, like windbg.
Here's the code when addIntArray
is called, everything's OK:
00b91010 c745e001000000 mov dword ptr [ebp-20h],1 ; start filling array
00b91017 c745e402000000 mov dword ptr [ebp-1Ch],2
00b9101e c745e803000000 mov dword ptr [ebp-18h],3
00b91025 c745ec04000000 mov dword ptr [ebp-14h],4
00b9102c c745f005000000 mov dword ptr [ebp-10h],5
[...]
00b91044 6a05 push 5 ; pass number of elements in array
00b91046 8d55e0 lea edx,[ebp-20h] ; load array address in edx
00b91049 52 push edx ; pass edx to addIntArray
00b9104a e831000000 call Tmp!addIntArray
Let's take a look at the stack when the CALL is made:
0:000> dd @esp L1
00fbfdb0 00fbfdbc
The above address is the address of the array, just display the content:
0:000> dd 00fbfdbc L5
00fbfdbc 00000001 00000002 00000003 00000004
00fbfdcc 00000005
Now let's take a look at addIntArray
:
Tmp!addIntArray:
00b91080 55 push ebp
00b91081 8bec mov ebp,esp
00b91083 83ec08 sub esp,8
[...]
00b91090 53 push ebx
00b91091 56 push esi
00b91092 8d7508 lea esi,[ebp+8] ; load what ???
So, what's in ebp+8
?
0:000> dd @ebp+8 L1
00fbfdb0 00fbfdbc
This (0x00fbfdbc) is the address of the array, but as you are using LEA
instead of MOV
you are actually loading the address of ebp+8
, not the address of the array.
Let's check the value of esi
after the LEA
has been executed:
0:000> r @esi
esi=00fbfdb0
This (0x00fbfdb0) is the address of the first argument, and it contains the address of the array, you're not using the array directly.
The command below dereferences the esi
register:
0:000> dd poi(@esi) L5
00fbfdbc 00000001 00000002 00000003 00000004
00fbfdcc 00000005
So instead of using LEA
, use MOV
:
; ...
mov esi, [intArr] // get the address of the intArr
mov ebx, 5 // EBX is our loop counter, set to 5
mov eax, 0 // EAX is where we add up the values
; ...
Executing the program with a mov
instead of an LEA
now displays the expected value:
Sum=15
Upvotes: 7
Reputation: 58792
As your question title says, arrays are passed as pointers to functions. Thus, you need to treat it as a pointer: mov esi, [intArr]
should work.
As illustration, consider this C code:
#include <stdio.h>
void func(int intArr[])
{
printf("In func, sizeof(intArr) = %d\n", sizeof(intArr));
}
int main()
{
int intArr[5] = { 1, 2, 3, 4, 5 };
printf("In main, sizeof(intArr) = %d\n", sizeof(intArr));
func(intArr);
return 0;
}
Sample output:
In main, sizeof(intArr) = 20 In func, sizeof(intArr) = 4
You can see what was an array in main
is a pointer in func
.
Upvotes: 5