arrays - 在 Visual Studio 上的内联汇编函数中传递指针的内容

标签 arrays visual-studio pointers assembly x86

我想在 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/

相关文章:

Java数组降序排序?

Javascript 数组 filter() 与 bind()

c# - 什么是C(COM)中的接口(interface)它和C#中的接口(interface)一样吗

c# - 如何在WPF中使用动画使文本 block 向上移动( float )

c# - 指定了无效的 DN 语法 - Visual Studio 错误

c - 使用字符串上的堆栈进行插入和弹出操作

python - 使用 Cython 包装 C++ 类时处理指针

c - 打印出两个输入是否是彼此的字谜

arrays - C 中 char ** 和 char (*)[100] 有什么区别?

与 C 指针混淆