如何将寄存器放入 MASM 中的数组索引中?

How do I put a register into an array index in MASM?

我在 MASM 中使用数组时遇到了困难。我不明白如何将寄存器的值放入数组的索引中。我似乎找不到 arr[i] 在哪里。我错过了什么或者我做错了什么? 感谢您的宝贵时间!

C++代码:

    #include <iostream>
    using namespace std;

    extern"C"
    {
        char intToBinary(char *, int, int);
    }

    int main()
    {
        const int SIZE = 16;
        char arr[SIZE] = { '/0' };
        cout << "What integer do you want converted?" << endl;
        cin >> decimal;

        char value = intToBinary(arr, SIZE, decimal);

        return 0;
    }

汇编代码:

.686
.model flat

.code

_intToBinary PROC ; named _test because C automatically prepends an underscode, it is needed to interoperate
    push ebp
    mov ebp,esp ; stack pointer to ebp

    mov ebx,[ebp+8] ; address of first array element
    mov ecx,[ebp+12] ; number of elements in array
    mov edx, 0      ;has to be 0 to check remainder
    mov esi, 2      ;the new divisor
    mov edi, 12

    LoopMe:
        add ebx, 4
        xor edx, edx            ;keep this 0 at all divisions
        div esi                 ;divide eax by 2
        inc ebx                 ;increment by 1
        mov [ebp + edi], edx    ;put edx into the next array index

        add edi, 4              ;add 4 bytes to find next index
        cmp ecx, ebx            ;compare iterator to number of elements (16)
    jg LoopMe

    pop ebp                 ;return 
    ret
_intToBinary ENDP

END 

在你的 C++ 代码中

  • decimal 未定义。
  • '/0' 是无效的字符文字。使用 \,而不是 /,在 C++ 中编写转义序列。
  • value 未使用。

你的代码应该是这样的:

#include <iostream>
using namespace std;

extern"C"
{
    char intToBinary(char *, int, int);
}

int main()
{
    const int SIZE = 16;
    char arr[SIZE] = { '[=10=]' };
    int decimal;
    cout << "What integer do you want converted?" << endl;
    cin >> decimal;

    intToBinary(arr, SIZE, decimal);
    for (int i = SIZE - 1; i >= 0; i--) cout << arr[i];
    cout << endl;

    return 0;
}

在你的汇编代码中

  • 您通过 mov ebx,[ebp+8] 将 "address of first array element" 存储到 ebx,因此 arr 的地址将在那里。 不幸的是,它被 add ebx, 4inc ebx.
  • 摧毁了
  • "put edx into the next array index" 不,[ebp + edi] 不是下一个数组索引,它正在破坏堆栈上的数据。非常糟糕。
  • 如果 char 的大小是 1 个字节,请不要向 "find next index" 添加 4 个字节。

你的代码应该是这样的(对不起,这是nasm代码,因为我不熟悉masm):

bits 32

global _intToBinary
_intToBinary:
    push ebp
    mov ebp, esp ; stack pointer to ebp
    push esi ; save this register before breaking in the code
    push edi ; save this, too
    push ebx ; save this, too
    mov ebx, [ebp + 8] ; address of first array element
    mov ecx, [ebp + 12] ; number of elements in array
    mov eax, [ebp + 16] ; the number to convert
    xor edi, edi ; the index of array to store
    mov esi, 2 ; the new divisor

    LoopMe:
        xor edx, edx ; keep this 0 at all divisions
        div esi ; divide eax by 2
        add dl, 48 ; convert the number in dl to a character representing it
        mov [ebx + edi], dl ; put dl into the next array index
        inc edi ; add 1 byte to find next index
        cmp ecx, edi ; compare iterator to number of elements
    jg LoopMe

    xor eax, eax ; return 0
    pop ebx ; restore the saved register
    pop edi ; restore this, too
    pop esi ; restore this, too
    mov esp, ebp ; restore stack pointer
    pop ebp
    ret

请注意,此代码将以相反的顺序存储二进制文本,因此我编写了 C++ 代码以从后向前打印它们。
另请注意 arr 中没有终止空字符,因此不要执行 cout << arr;.

您有 ebx 中第一个数组元素的地址,edi 是您的循环计数器。所以 mov [ebx + edi], edx 会将 edx 存储到 arr[edi].

另请注意,您的循环条件是错误的(您的 cmp 正在将元素数量与数组的起始地址进行比较。)

尽可能避免div。除以二,右移一。 div 非常慢(比 shift 慢 10 到 30 倍)。


顺便说一句,因为你可以选择使用哪些寄存器(ABI 说你可以在没有 saving/restoring 的情况下进行破坏),edi 用于 "destination" 指针(即当它不需要任何额外指令时),而 esi 用作 "source" 指针。

说到 ABI,您需要在使用它的函数中 save/restore ebx,与 ebp 相同。它在函数调用中保持其值(因为您调用的任何符合 ABI 的函数都会保留它)。我忘记了在 32 位 ABI 中还有哪些其他寄存器是被调用者保存的。您可以查看 https://whosebug.com/tags/x86/info 中的有用链接。 32 位已过时; 64 位具有更高效的 ABI,并将 SSE2 作为基线的一部分。