【问题标题】:MASM Why doesn't decrementing a register find the next value in an array?MASM 为什么递减寄存器不能找到数组中的下一个值?
【发布时间】:2016-03-07 10:59:51
【问题描述】:

我正在测试输入的字符串是否是回文,方法是获取字符串,将其移动到字符数组中,然后将 char 数组的第一个和最后一个元素相互比较以进行测试。我可以获取数组的第一个元素以轻松找到第二个字符,但是要找到最后一个可接受的值并递减它,它不会在数组中找到下一个字符。因此,如果更正/清理的 char 数组如下所示:

['A']['B']['C']['D']['A']

ebx 将从 'A' -> 'B' 但 edi 不会从 'A' -> 'D' 改变

为什么 ebx 会改变字符,但 edi 只从它的寄存器值中减去 1?我该怎么做才能让 edi 更改字符值?谢谢!

C++ 代码:(以防万一)

#include <iostream>
#include <cstring>
#include <sstream>

using namespace std;

extern"C"
{
char stringClean(char *, int);
char isPalindrome(char *, int);
}

int main()
{
int pal = 0;
const int SIZE = 30;
string candidate = "";
char strArray[SIZE] = { '\0' };

cout << "enter a string to be tested: ";
getline(cin, candidate);


int j = 0;
for (int i = 0; i < candidate.length(); i++)        //getting rid of garbage before entering into array
{
    if (candidate[i] <= 'Z' && candidate[i] >= 'A' || candidate[i] <= 'z' && candidate[i] >= 'a')
    {
        strArray[j] = candidate[i];
        j++;
    }
}

if (int pleaseWork = stringClean(strArray, SIZE) == 0)
    pal = isPalindrome(strArray, SIZE);

if (pal == 1)
    cout << "Your string is a palindrome!" << endl;
else
    cout << "Your string is NOT a palindrome!" << endl;

system("pause");
return 0;
}

masm代码:

.686
.model flat
.code

_isPalindrome PROC ; named _test because C automatically prepends an underscode, it is needed to interoperate
    push ebp
    mov ebp,esp ; stack pointer to ebp

    mov ebx,[ebp+8] ; address of first array element
    mov ecx,[ebp+12] ; number of elements in array
    mov ebp,0
    mov edx,0
    mov eax,0
    push edi    ;save this
    push ebx    ;save this

    mov edi, ebx    ;make a copy of first element in array
    add edi, 29     ;move SIZE-1 (30 - 1 = 29) elements down to, HOPEFULLY, the last element in array

    mov bl, [ebx]
    mov dl, [edi]

    cmp dl, 0           ;checks if last element is null
    je nextElement      ;if null, find next
    jne Comparison      ;else, start comparing at Comparison:

nextElement:
    dec edi             ;finds next element
    mov dl, [edi]       ;move next element into lower edx
    cmp dl, 0           ;checks if new element is mull
    je nextElement      ;if null, find next
    jne Comparison      ;else, start comparing at Comparison:

Comparison:
    cmp bl,dl           ;compares first element and last REAL element
    je testNext         ;jump to textNext: for further testing

    mov eax,1           ;returns 1 (false) because the test failed
    jne allDone         ;jump to allDoneNo because it's not a palindrome

testNext:
    dec edi     ;finds last good element -1 --------THIS ISN'T DOING the right thing
    inc ebx             ;finds second element

    cmp ebx, edi        ;checks if elements are equal because that has tested all elements
    je allDone          

    ;mov bl,[ebx]       ;move incremented ebx into bl
    ;mov dl,[edi]       ;move decremented edi into dl
    jmp Comparison      ;compare newly acquired elements



allDone:
    xor eax, eax
    mov ebp, eax

    pop edi
    pop edx
    pop ebp
    ret
_isPalindrome ENDP

END 

【问题讨论】:

  • 你用调试器单步执行了吗? Microsoft 在 Visual Studio 中有一个不错的调试器,但 OllyDbg 也是一个非常好的调试器。
  • 你有一些错误,比如mov eax, 1 的返回值,但在返回allDone 之前总是清除eax。另外,不要写jcc label / label:。只是让执行失败,因为无论是否采用分支都会如此。通常在比较之后你只需要一个jcc,除非你有一个jg和一个jge什么的。但不是jg / jle。如果您需要跳到其他地方,要么不跳就跌倒,或者使用无条件的jmp 作为第二个。一旦你弄清楚了你的设计,你就可以探测了。重新安排以保存在树枝上。
  • 我发现我正在将一个寄存器的值移动到同一个寄存器的下部。 =p

标签: arrays assembly masm 32-bit palindrome


【解决方案1】:

我还没有测试过你的代码,但是看着它我发现了一些可能的问题。

为什么ebx会换字符

看起来是这样,但这不是你试图达到的。您在初始阶段之后注释掉了从内存/数组中读取字符的行(见下文)。所以事实上,您确实改变了 EBX 中的角色,但不是您期望的(并且应该是想要的)方式。使用INC EBX,您将字符值从“A”(65dec)增加到“B”(66dec)。 'B' 也是字符串的第二个字符只是一个巧合。尝试将字符串从 ABCDA 更改为 ARRCD 或其他东西,您仍然会在第二轮得到“B”。所以 EBX 确实发生了变化。

...
;mov bl,[ebx]       ;move incremented ebx into bl
;mov dl,[edi]       ;move decremented edi into dl
jmp Comparison      ;compare newly acquired elements
...

但 edi 只从它的寄存器值中减去 1? 我该怎么做才能让 edi 更改字符值?

是的。这就是你的代码所做的,它是正确的。取消注释上面包含[edi]的行,EDI指向的字符将被加载到EDX = DL的低字节中。

您的代码的问题是您将 EBX 用作指针和 (char) 值。将下一个字符加载到 EBX 中会破坏指针,并且您的程序可能会在下一次迭代中因 ACCESS_VIOLATION 崩溃或显示难以调试的随机行为。

像使用 EDI/EDX 一样将指针与值分开(EDI=指向 char 的指针,EDX(DL)=char 值。

另一个问题是:您的代码仅适用于奇数长度的字符串。

testNext:
    dec edi         ; !!!
    inc ebx         ; !!!
cmp ebx, edi        ; checks if elements are equal because that has tested all elements
je allDone  

因此,您正在增加和减少(应该是)指针,然后比较它们。现在考虑这种偶数长度字符串的情况:

  ABBA
  ^  ^   (EBX(first) and EDI(second))
=> dec both =>
  ABBA
   ^^    (EBX(first) and EDI(second))
=> dec both =>
  ABBA
   ^^    (EDI(first) and EBX(second))
=> dec both =>
  ABBA
  ^  ^   (EDI(first) and EBX(second))
=> dec both =>
  ABBA
 ^    ^  (EDI(first) and EBX(second)) 
... 

=> 问题!不会终止,永远不会满足条件 EBX=EDI* 可能的解决方案:在跳转中添加 A(Above = Greater for unsigned values)

...
cmp ebx, edi
jae allDone

【讨论】:

    猜你喜欢
    • 2012-06-24
    • 2020-03-10
    • 1970-01-01
    • 1970-01-01
    • 2014-10-31
    • 1970-01-01
    • 2021-07-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多