汇编:遍历一系列字符并交换它们
Posted
技术标签:
【中文标题】汇编:遍历一系列字符并交换它们【英文标题】:Assembly: loop through a sequence of characters and swap them 【发布时间】:2016-11-06 18:27:58 【问题描述】:我的任务是在汇编中实现一个函数,该函数将执行以下操作: 循环遍历一系列字符并交换它们,以使最终结果是反向的原始字符串(100 分) 提示:从用户那里收集字符串作为 C 字符串,然后将其与用户输入的字符数一起传递给汇编函数。要找出字符数,请使用 strlen() 函数。
我已经编写了 c++ 和汇编程序,并且在范围内工作正常:例如,如果我输入 12345,则输出正确显示为 54321,但如果输入超过 5 个字符:输出开始不正确:对于例如,如果我输入 123456,则输出为:653241。我将非常感谢任何能指出我的错误所在的人:
.code
_reverse PROC
push ebp
mov ebp,esp ;stack pointer to ebp
mov ebx,[ebp+8] ; address of first array element
mov ecx,[ebp+12] ; the number of elemets in array
mov eax,ebx
mov ebp,0 ;move 0 to base pointer
mov edx,0 ; set data register to 0
mov edi,0
Setup:
mov esi , ecx
shr ecx,1
add ecx,edx
dec esi
reverse:
cmp ebp , ecx
je allDone
mov edx, eax
add eax , edi
add edx , esi
Swap:
mov bl, [edx]
mov bh, [eax]
mov [edx],bh
mov [eax],bl
inc edi
dec esi
cmp edi, esi
je allDone
inc ebp
jmp reverse
allDone:
pop ebp ; pop ebp out of stack
ret ; retunr the value of eax
_reverse ENDP
END
这是我的 C++ 代码:
#include<iostream>
#include <string>
using namespace std;
extern"C"
char reverse(char*, int);
int main()
char str[64] = NULL;
int lenght;
cout << " Please Enter the text you want to reverse:";
cin >> str;
lenght = strlen(str);
reverse(str, lenght);
cout << " the reversed of the input is: " << str << endl;
【问题讨论】:
还没有注意到任何实际错误,只是非常奇怪的东西。如果您打算将 EBP 用作通用寄存器,则应省略mov ebp,esp
的内容。 (并且只需使用 ESP 的偏移量访问您的参数)。 set data register to 0
之类的评论毫无用处。有用的是描述您的函数使用 EDX 的用途。函数顶部的mov eax,ebx
似乎没用,为什么不首先加载到 EAX 中呢?您在函数的其余部分中唯一使用 EBX 是将字节放入 BL 和 BH。
一个错误是您应该像执行 EBP 一样保存/恢复 EBX,因为它在所有常见的 32 位调用约定中都保留了调用。您可能在某处有另一个错误,因为踩到调用者的 EBX 值可能不会导致您看到的行为。您应该在调试器中单步执行您的代码,看看它做了什么。
非常感谢 Cordes 先生的出色和建设性的 cmets 我很抱歉我上传了如此糟糕的代码,根本没有评论,我对我的代码感到非常沮丧,我忘了在我愚蠢的 cmets。
代码的第一部分是我们的教练给我们的,所以我什至没有看里面发生了什么,我用 EAX 替换了 EBX,正如你告诉我的那样,它运行良好。修复了 cmets。保存并恢复 EBX。自从我在大学的第二个学期以来,我从来没有被告知过任何关于单步调试的事情。我做到了,并弄清楚我的错误在哪里。
【参考方案1】:
你没有评论你的代码,所以 IDK 你到底想做什么,但看起来你是手动使用 MOV / ADD 进行数组索引,而不是使用像 [eax + edi]
这样的寻址模式。
但是,您似乎正在修改原始值,然后以未经修改的方式使用它。
mov edx, eax ; EAX holds a pointer to the start of array, read every iter
add eax , edi ; modify the start of the array!!!
add edx , esi
Swap:
inc edi
dec esi
EAX 每一步都通过 EDI 增长,而 EDI 线性增长。所以EAX呈几何级数增加(integral(x * dx) = x^2)。
在调试器中单步执行这个应该很容易找到。
顺便说一句,执行此操作的正常方法是向上移动一个指针,向下移动一个指针,然后在它们交叉时退出循环。那你就不需要单独的计数器了,只需要cmp / ja
。 (不要检查 JNE 或 JE,因为它们可以相互交叉而不相等。)
【讨论】:
我已经使用了你告诉我的寻址模式,并以几何方式固定了 EAX 的增量。还使用指针而不是索引进行比较,因为我不知道它们甚至可以在不相等的情况下相互交叉,所以我按照你的建议使用了 JA 推荐,它工作得很好 @ArashDe:很高兴它有帮助。如果您觉得它回答了问题,则应单击投票箭头下方的复选框以将此答案标记为已接受。【参考方案2】:总的来说,从字符串的两端开始并交换元素直到到达中间是正确的想法。但实施起来很糟糕。
mov ebp,0 ;move 0 to base pointer
这似乎是循环计数器(注释无用甚至更糟);我想想法是交换 length/2
元素,这很好。提示我只是比较指针/索引并在它们发生冲突时退出。
mov edx,0 ; set data register to 0
...
add ecx,edx
mov edx, eax
无用且具有误导性。
mov edi,0
mov esi , ecx
dec esi
看起来像字符串开始/结束的索引。好的。提示我会使用指向字符串开始/结束的指针;但索引也有效
cmp ebp , ecx
je allDone
如果进行了 length/2 次迭代,则退出。好的。
mov edx, eax
add eax , edi
add edx , esi
eax
和 edx
指向要交换的当前符号。几乎没问题,但是这破坏了 eax!秒后的每个循环迭代都将使用错误的指针!这就是首先导致您的问题的原因。如果您使用指针而不是索引,或者使用偏移寻址[eax+edi]
/[eax+esi]
...
交换部分没问题
cmp edi, esi
je allDone
第二个退出条件,这次比较索引冲突!通常一个退出条件就足够了;几个退出条件通常要么是多余的,要么暗示了算法中的某些缺陷。等式比较也是不够的 - 在单次迭代期间,索引可以从 edi<esi
变为 edi>esi
。
【讨论】:
以上是关于汇编:遍历一系列字符并交换它们的主要内容,如果未能解决你的问题,请参考以下文章