汇编:循环遍历一串字符并交换它们

Assembly: loop through a sequence of characters and swap them

本文关键字:字符 一串 交换 循环 遍历 汇编      更新时间:2023-10-16

我的任务是在汇编中实现一个函数,该函数将执行以下操作:循环遍历一个字符序列并交换它们,使最终结果是原始字符串的反转(100分)提示:从用户处收集字符串作为C-string,然后将其与用户输入的字符数一起传递给汇编函数。使用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;
  }

你没有注释你的代码,所以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呈几何级数增长(积分(x * dx) = x^2)

在调试器中单步执行应该很容易发现这个问题。


顺便说一句,正常的方法是一个指针向上走,一个指针向下走,当它们交叉时退出循环。那么你不需要单独的计数器,只需要cmp / ja。(不要检查JNE或JE,因为它们可以相互交叉而不相等。)

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

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

退出如果做长度/2迭代。好的。

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

eaxedx指向当前要交换的符号。几乎可以,但这是惨败!每隔一秒的循环迭代都会使用错误的指针!这就是你的问题的根源。如果您使用指针而不是索引,或者使用偏移地址[eax+edi]/[eax+esi]

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

交换部分可以

cmp edi, esi
je allDone

第二个退出条件,这次比较的是索引冲突!一般来说,一个退出条件就足够了;一些退出条件通常要么是多余的,要么暗示了算法中的一些缺陷。而且相等性比较是不够的——索引可以在单次迭代中从edi<esi移动到edi>esi