如何将寄存器放入 MASM 中的数组索引中?
Posted
技术标签:
【中文标题】如何将寄存器放入 MASM 中的数组索引中?【英文标题】:How do I put a register into an array index in MASM? 【发布时间】:2015-11-19 07:29:06 【问题描述】:我在 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
【问题讨论】:
这是在 Windows 上吗?我想是的,但你能确认一下吗? 【参考方案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;
在你的汇编代码中
您将“第一个数组元素的地址”通过mov ebx,[ebp+8]
存储到ebx
,因此arr
的地址将在那里。
不幸的是,它被add ebx, 4
和inc ebx
破坏了。
“将 edx 放入下一个数组索引”不,[ebp + edi]
不是下一个数组索引,它正在破坏堆栈上的数据。这很糟糕。
如果 char
的大小为 1 字节,请不要在“查找下一个索引”中添加 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;
。
【讨论】:
您可以通过调用 pop 和您想要的寄存器将似乎是寄存器的地址推送到堆栈中以便稍后到达? [ebp + 16] 如何等于输入的小数?这不是数组中的第一个元素吗?究竟是如何找到数组的?只是“[ebx]”? 是的,您可以推送和弹出内存地址,因为它们只是 IA-32 上的 32 位值。执行函数序言后,[ebp+0]
上将有 ebp
的旧值,[ebp+4]
上的返回地址,[ebp+8]
上的第一个参数,[ebp+12]
上的第二个参数,[ebp+16]
上的第三个参数如果每个参数为 4 个字节。出于这个原因,数组的(第一个元素的地址)将是[ebp+8]
,因为它作为第一个参数传递,decimal
将是[ebp+16]
,因为它作为第三个参数传递。最后,如你所写,第一个数组元素的地址将是[ebp+8]
,所以访问那里找到数组。【参考方案2】:
你有ebx
中第一个数组元素的地址,edi
是你的循环计数器。所以mov [ebx + edi], edx
会将edx
存储到arr[edi]
中。
另请注意,您的循环条件是错误的(您的 cmp
正在将元素数与数组的起始地址进行比较。)
尽可能避免使用div
。除以二,右移一。 div
非常慢(比轮班慢 10 到 30 倍)。
顺便说一句,由于您可以选择使用哪些寄存器(在 ABI 表示您可以在不保存/恢复的情况下破坏的寄存器中),edi
按照惯例用于“目标”指针(即当它不需要任何额外的指令时),而esi
用作“源”指针。
说到ABI,你需要在使用它的函数中保存/恢复ebx
,和ebp
一样。它在函数调用中保持其值(因为您调用的任何符合 ABI 的函数都会保留它)。我忘记了 32 位 ABI 中还保存了哪些其他寄存器。您可以查看https://***.com/tags/x86/info 中的有用链接。 32位已过时; 64 位具有更高效的 ABI,并将 SSE2 作为基线的一部分。
【讨论】:
32 位edx
不适合 8 位 arr[edi]
。
"除以二,右移一。"是的,您可以使用and eax, 1
来计算eax / 2
的余数。
@MikeCAT:是的,我只是注意到他代码中的错误,他将数组定义为char
。我被将指针增加 4 的 asm 愚弄了,并且将在我的答案中补充说使用 int8_t
数组会更有效!然后意识到他可能想要一个字符串,而不是整数零和一的数组......
实际上,您可能想要setc dl
或其他东西,根据进位标志将一个字节设置为零或一。如果你屏蔽你正在移动的寄存器,你会破坏仍然存在的值(所以你需要一个mov / and
组合)。 shift
将 CF 设置为移出的最后一位,因此您都可以使用 setc dl
或 sbb edx, edx
(将 edx 设置为 0 或 -1)。以上是关于如何将寄存器放入 MASM 中的数组索引中?的主要内容,如果未能解决你的问题,请参考以下文章