【问题标题】:To Pass The Content Of The Pointer In An Inline Assembly Function On Visual Studio在 Visual Studio 上的内联汇编函数中传递指针的内容
【发布时间】:2015-11-17 21:08:13
【问题描述】:

我想在 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 上的行为不同,我该如何解决?

【问题讨论】:

    标签: arrays visual-studio pointers assembly x86


    【解决方案1】:

    您实际上使用的是在堆栈上传递的数组地址(即参数的地址),而不是数组本身的地址。

    如果你使用另一个调试器,比如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
    

    【讨论】:

      【解决方案2】:

      正如您的问题标题所说,数组作为指向函数的指针传递。因此,您需要将其视为指针:mov esi, [intArr] 应该可以工作。

      作为说明,考虑以下 C 代码:

      #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;
      }
      

      样本输出:

      In main, sizeof(intArr) = 20
      In func, sizeof(intArr) = 4
      

      你可以看到main中的数组是func中的指针。

      【讨论】:

        猜你喜欢
        • 2017-05-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-07-08
        • 1970-01-01
        • 1970-01-01
        • 2023-03-25
        相关资源
        最近更新 更多