汇编:遍历一系列字符并交换它们

Assembly: loop through a sequence of characters and swap them

我的任务是在汇编中实现一个函数,该函数将执行以下操作: 遍历一系列字符并交换它们,使得最终结果是原始字符串的反向(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;

  }

你没有评论你的代码,所以我知道你到底想做什么,但看起来你是用 MOV / ADD 手动进行数组索引,而不是使用 [=11= 这样的寻址模式].

但是,看起来您正在修改原始值,然后以未修改的情况下有意义的方式使用它。

  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,因为它们可以在不相等的情况下相互交叉。)

总的来说,从字符串的两端开始交换元素直到到达中间是正确的想法。虽然实施很糟糕。

mov ebp,0         ;move 0 to base pointer

这好像是循环计数器(注释没用甚至更糟);我猜想法是交换 length/2 元素,这非常好。提示我只是比较 pointers/indexes 并在它们发生碰撞后退出。

mov edx,0     ; set data register to 0
...
add ecx,edx
mov edx, eax

无用且具有误导性。

mov edi,0
mov esi , ecx
dec esi

看起来像字符串 start/end 的索引。好的。提示我会使用指向字符串 start/end 的指针;但索引也有效

cmp ebp , ecx
je allDone

如果进行了 length/2 次迭代,则退出。好的。

mov edx, eax
add eax , edi
add edx , esi

eaxedx 指向要交换的当前符号。几乎可以,但是 这破坏了 eax!秒后的每次循环迭代都会使用错误的指针!这首先是导致您出现问题的原因。如果您使用指针而不是索引,或者如果您使用偏移寻址 [eax+edi]/[eax+esi]

,就不会发生这种情况
...

交换部分可以

cmp edi, esi
je allDone

第二个退出条件,这次比较索引冲突!通常一个退出条件就足够了;几个退出条件通常是多余的或暗示算法中的某些缺陷。相等比较也是不够的——在单次迭代中索引可以从 edi<esi 变为 edi>esi