如何使用双寄存器寻址?汇编间接寻址代码执行问题排查
你的两个汇编问题解答
嘿,我来帮你拆解这两个汇编相关的问题,一步步给你讲清楚:
1. 如何使用两个寄存器进行寻址?
在32位x86汇编中,双寄存器寻址属于基址+变址寻址模式,它允许你结合两个寄存器的内容计算内存地址,常见的使用形式有两种:
基础形式:基址寄存器 + 变址寄存器
语法可以写成 [基址寄存器 + 变址寄存器] 或者等价的 [基址寄存器][变址寄存器],比如:
mov eax, [ebx + esi] ; 将EBX与ESI之和指向的内存值加载到EAX mov [ebp + edi], ecx ; 将ECX的值存储到EBP与EDI之和指向的内存
- 默认段前缀规则:如果基址寄存器是
EBP/ESP,默认使用SS段;如果是EBX/ESI/EDI这类寄存器,默认使用DS段,你也可以手动指定段前缀,比如mov eax, fs:[ebx+esi]。
带比例因子和位移的扩展形式
你还可以给变址寄存器加上比例因子(支持1/2/4/8,对应字节/字/双字/四字),再搭配固定位移,这种模式常用于访问数组或结构体:
mov eax, [ebx + esi*4 + 0x10] ; 计算地址 = EBX + ESI*4 + 0x10
比如用基址寄存器存数组首地址,变址寄存器存元素索引,比例因子对应元素的字节大小。
2. 你的汇编代码错误分析与修正
先把你的代码贴出来方便逐一排查:
unique proc invoke lstrlen, esi cmp eax, 1 jle quit mov ebx, 0; previous iterator mov edx, 0; next iterator dec eax mov ecx, eax inc eax next: inc edx cmp [esi][ebx], [esi][edx] ; 问题1:非法指令 je skip cmp inc ebx ; 问题2:语法错误 cmp ebx, edx dec ebx je skip inc ebx mov [esi][ebx], [esi][edx] ; 问题3:非法内存到内存传输 skip: loop next mov [esi][edx], '0' ; 问题4:终止符逻辑错误 quit: ret unique endp
核心错误点逐个解析:
cmp [esi][ebx], [esi][edx]指令非法
x86汇编中,cmp指令不支持两个内存操作数直接比较,必须至少有一个操作数是寄存器或立即数。你需要先把其中一个内存值读到寄存器里再比较,比如:mov al, [esi + ebx] ; 把第一个字符读到8位寄存器AL cmp al, [esi + edx] ; 再和第二个字符比较cmp inc ebx语法完全错误
这行是无效指令,你应该只是想执行inc ebx(递增EBX),直接删掉前面的cmp即可。mov [esi][ebx], [esi][edx]指令非法
x86的mov指令同样不支持直接从内存到内存的传输,必须通过寄存器中转,比如:mov al, [esi + edx] ; 先把源内存值读到AL mov [esi + ebx], al ; 再写入目标内存终止符设置逻辑错误
你最后把[esi+edx]设为字符'0',但edx在循环结束后等于原字符串长度,而且正确的字符串终止符是ASCII码0(不是字符'0')。正确的做法是把最后一个有效字符的下一个位置设为终止符,比如用ebx的最终值+1来定位:mov byte ptr [esi + ebx + 1], 0
修正后的代码示例(实现字符串去重逻辑)
unique proc invoke lstrlen, esi cmp eax, 1 jle quit ; 长度<=1直接返回,无需处理 mov ebx, 0 ; 指向当前保留的最后一个唯一字符 mov edx, 1 ; 遍历指针从第二个字符开始 mov ecx, eax ; 总长度存到ECX用于循环计数 next: mov al, [esi + ebx] cmp al, [esi + edx] je skip ; 字符重复,跳过当前遍历字符 inc ebx ; 唯一字符计数+1 mov al, [esi + edx] mov [esi + ebx], al ; 保存新的唯一字符到目标位置 skip: inc edx dec ecx jnz next ; 循环直到遍历完所有字符 mov byte ptr [esi + ebx + 1], 0 ; 添加字符串终止符 quit: ret unique endp
内容的提问来源于stack exchange,提问作者alexander.sivak
相关产品推荐
相关产品推荐

