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

时间:2015-11-19 07:29:07

标签: arrays assembly x86 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 

2 个答案:

答案 0 :(得分:1)

在您的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] = { '\0' };
    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;
}

在汇编代码中

  • 您存储了第一个数组元素的&#34;地址&#34; ebxmov ebx,[ebp+8]arr的地址就在那里。 不幸的是,它被add ebx, 4inc ebx销毁。
  • &#34;将edx放入下一个数组索引&#34;不,[ebp + edi]不是下一个数组索引,它是堆栈上令人讨厌的数据。这非常糟糕。
  • 不要将4个字节添加到&#34;找到下一个索引&#34;如果char的大小是1个字节。

你的代码应该是这样的(对不起,这是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;

答案 1 :(得分:1)

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

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

尽可能避免使用div。除以2,右移一。 div非常慢(比移位慢10到30倍)。

顺便说一下,既然您可以选择使用哪些寄存器(ABI说允许您在不保存/恢复的情况下使用哪些寄存器),edi按惯例用于“目标”指针(即,当它不需要任何额外的指令时),而esi被用作“源”指针。

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