我想在 c 程序中使用 __asm 关键字了解 Visual Studio 上的汇编语言。
我尝试做的是; - 创建一个包含 5 个元素的 int 数组 - 遍历数组并将值添加到累加器
这是一个运行良好的代码;
#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;
}
输出如下;
Sum=15
我想将内联汇编部分作为一个单独的函数使用,并通过下面的函数调用执行相同的操作;
#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;
}
输出很奇怪,如下所示;
Sum=2145099747
在调试时,我发现我只是将存储在 esi 寄存器中的地址值相加,而不是这些地址的内容强>。
我很困惑,为什么当我在主线程上运行同一个内联汇编例程时它可以正常工作,而当我尝试在单独的函数上调用它时为什么不工作。
问题出在哪里,为什么进程在 main 和 function 上的行为不同,我该如何解决?
最佳答案
您实际上使用的是在堆栈上传递的数组地址(即参数的地址),而不是数组本身的地址。
如果你使用另一个调试器,比如 windbg,这实际上更容易(当涉及到汇编时)。
这是调用 addIntArray
时的代码,一切正常:
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
让我们看一下调用时的堆栈:
0:000> dd @esp L1
00fbfdb0 00fbfdbc
上面的地址是数组的地址,只显示内容:
0:000> dd 00fbfdbc L5
00fbfdbc 00000001 00000002 00000003 00000004
00fbfdcc 00000005
现在让我们看一下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 ???
那么,ebp+8
中有什么?
0:000> dd @ebp+8 L1
00fbfdb0 00fbfdbc
这 (0x00fbfdbc) 是数组的地址,但是当您使用 LEA
而不是 MOV
时,您实际上加载的是 ebp+8 的地址
,不是数组的地址。
让我们在 LEA
执行后检查 esi
的值:
0:000> r @esi
esi=00fbfdb0
这个(0x00fbfdb0)是第一个参数的地址,它包含数组的地址,你不是直接使用数组。
下面的命令取消引用 esi
寄存器:
0:000> dd poi(@esi) L5
00fbfdbc 00000001 00000002 00000003 00000004
00fbfdcc 00000005
所以不要使用 LEA
,而是使用 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
; ...
使用 mov
而不是 LEA
执行程序现在显示预期值:
Sum=15
关于arrays - 在 Visual Studio 上的内联汇编函数中传递指针的内容,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33767025/