我的作业是在MASM中改变数组中的值,交换对。
array[0] = array[1]
array[1] = array[0]
array[2] = array[3]
array[3] = array[2]
等等……
我已经放弃使用var1
和var2
变量,因为我似乎无法让它们工作。我有
.data
; add data here
array01 DWORD 100, 200, 300, 400, 500, 600
var1 DWORD ?
var2 DWORD ?
.code
main PROC
mov edi, OFFSET array01 ; 1: EDI = address of array01
mov ecx, LENGTHOF array01 ; 2: initialize loop counter
mov eax, 0 ; 3: sum =0
L1: ; 4: Mark beginning of loop
mov eax, [edi] ; 5: Get var1
add edi, TYPE array01 ; 6: increment index
mov ebx, [edi] ; 7: Get var2
sub edi, TYPE array01 ; 8: decrement to get index to point to the right location
mov array01[edi], ebx ; 9: Change array01[i] to var1
add edi, TYPE array01 ; 10: increment index
mov array01[edi], eax ; 11: Change array01[i] to var1
loop L1 ; 12: repeats until ecx is 0
INVOKE ExitProcess, 0
main ENDP
End main
我的问题是在指令9。它给了我一个错误
Assignment_03.exe中0x007C1032处的未处理异常:0xC0000005:访问冲突写入位置0x00F88004。
从调试器中,我的EDI = 007C4000
,&array01
位于0x007C4000
,彼此匹配,但不是错误报告的数据地址。(我的EIP = 007C1032
,错误指令的代码地址。)
早期的运行具有Exception thrown at 0x00171029 in Assignment_03.exe: 0xC0000005: Access violation writing location 0x002E8000.
我知道它告诉我我正在访问一些我不被允许访问的东西,但我不知道如何修复它。
我已经尝试了mov [numList+ebx],dh
从https://termspar.wordpress.com/2019/10/12/x86-assembly-swap-array-elements/,但我仍然得到同样的错误。
我做错了什么?你能解释一下解决方案吗?我说清楚我不想要作业的答案。我需要帮助来改变数组中的值。mov dword ptr [array01], 700
可以更改第一个元素,但使用EDI进行索引不起作用。
1条答案
按热度按时间vof42yt11#
EDI已经是一个指针:使用
mov [edi], ebx
。mov array01[edi], ebx
将EDI中的指针添加到数组的地址。如果EDI是一个很小的数字,即从数组开始的一个字节偏移量,那么这是正确的。但这件案子不是这样的在循环之前,你用mov edi, OFFSET array01
把一个指针放进EDI。该地址计算类似于C
int *ptr = array01;
array01[ (int)ptr ] = tmp2;
,但没有按类型宽度进行缩放。在聊天中的讨论中,您使用调试器发现array01
的实际地址是0x007C4000
,但错误地址报告为写入0x00F88004
。这是更仔细地查看代码到底在做什么的线索。0x007C4000 * 2 = 0xF88000
,故障地址。我不知道额外的...4
是从哪里来的。第一次存储是在sub edi, 4
之后,所以应该用EDI恢复到其原始值。(内存保护使用4K页面粒度,所以如果0xF 88004出错,0xF 88000应该在第一次迭代中出错,就像调试器显示的那样。**那么,为什么它故障的商店,而不是负载?**您为加载使用了正确的寻址模式,
[edi]
,只是解引用指针,而不是向其添加另一个地址!一开始我觉得很奇怪,那个地址有只读存储器,但是没有,第一次访问是在商店里。
顺便说一句,从
[edi]
和[edi+4]
加载和存储要简单得多,所以你的循环只需要一个add edi, 8
就可以前进到下一对。(目前,每次迭代前进8步,后退4步,净前进一个4字节元素。)你必须调整你的循环计数器,以避免去结束;使用指向数组末尾的指针和
cmp /
jb L1against that, instead of calculating an iteration count for the slow
loopinstruction. You need to stop even if there's 0 or 1 elements left, like the bottom of a
do{.; ptr+=8;}while(ptr < endp-4);`其中endp是数组末尾的标签。顺便说一句,有趣的方法是使用SIMD加载4x 32位元素(2对), Shuffle ,并将它们存储回来。由于在这种情况下问题大小恰好是2对,我们可以放弃循环:P
您可能需要告诉MASM允许SSE 2向量指令。C编译器默认使用这些,甚至在32位代码中也是如此。但是很明显,使用16字节的shuffle并不能教会你写循环。
另一种有趣的方法是编写64位代码,并执行
ror qword ptr [rdi], 32
之类的操作,以执行64位旋转32,从而交换64位内存块的一半。