Assembly 检查Assbembly MASM中的回文

Assembly 检查Assbembly MASM中的回文,assembly,masm,Assembly,Masm,这个函数接受一个输入字符串并检查它是否是回文。但是,由于内存错误,它会中断。我已经盯着它看了几个小时了,但没能找出问题所在。有很多不必要的推,但我害怕玩它,甚至打破更多。非常感谢您的帮助 __declspec(naked) int isPalindrome(char *input_string, int left_index, int right_index) { // C code to be converted to x86 assembly /* // Input Validat

这个函数接受一个输入字符串并检查它是否是回文。但是,由于内存错误,它会中断。我已经盯着它看了几个小时了,但没能找出问题所在。有很多不必要的推,但我害怕玩它,甚至打破更多。非常感谢您的帮助

__declspec(naked)
int isPalindrome(char *input_string, int left_index, int right_index)
{

// C code to be converted to x86 assembly
/*
    // Input Validation
    if (NULL == input_string || left_index < 0 || right_index < 0){
        return -1;
    }
    // Recursion termination condition
    if (left_index >= right_index)
        return 1;
    if (input_string[left_index] == input_string[right_index]){
        return isPalindrome(input_string, left_index + 1, right_index - 1);
    }
    return -1;
*/

__asm{

        mov eax, 0
        // BEGIN YOUR CODE HERE

        push ebp
        push edi
        mov ebp, esp;

        mov ebx, input_string
        mov esi, [ebp+12]
        mov edi, [ebp+16]
        //push edi;
        push esi;
        push ebx;

        // mov some_register, [esp + 8]


        mov ebx, input_string
       // mov esi, left_index  // esi
            // mov esi, [esp + 8]
        mov edi, right_index // edi
        cmp esi, 0;
        jl FALSE;
        cmp edi, 0
        jl FALSE
        cmp ebx, 0x00
        je FALSE

        cmp esi, edi
        jge TRUE


        mov cl, byte ptr[ebx + esi]
        mov dl, byte ptr[ebx + edi]
        cmp cl, dl 
        je RECURSIVE
            jmp FALSE

    RECURSIVE:

        inc esi 
        dec edi
        push eax
        push ecx
        push edx

        push esi
        push edi
        call isPalindrome
        //sub ebp, 8
        pop edx
        pop ecx
        pop edx
            jmp END
    FALSE:

        mov eax, -1
        jmp END

    TRUE:

        mov eax, 1
        jmp END
    END:
        pop ebx;
        pop esi;
        pop edi;


        mov esp, ebp;
        pop ebp;


        // END YOUR CODE HERE
        ret
}
\uuu declspec(裸体)
int isPalindrome(字符*输入字符串,int左索引,int右索引)
{
//要转换为x86程序集的C代码
/*
//输入验证
if(NULL==输入_字符串| |左|索引<0 | |右|索引<0){
返回-1;
}
//递归终止条件
如果(左索引>=右索引)
返回1;
if(输入字符串[左索引]==输入字符串[右索引]){
返回isAlindrome(输入字符串,左索引+1,右索引-1);
}
返回-1;
*/
__asm{
mov-eax,0
//从这里开始你的代码
推ebp
推式电子数据交换
mov-ebp,esp;
mov ebx,输入_字符串
mov esi,[ebp+12]
移动电子数据交换[ebp+16]
//推行电子数据交换;
推动esi;
推ebx;
//mov一些_寄存器,[esp+8]
mov ebx,输入_字符串
//mov esi,左索引//esi
//电影esi[esp+8]
mov edi,右索引//edi
cmp-esi,0;
jl假;
cmp edi,0
jl假
cmp ebx,0x00
我错了
cmp esi,edi
真的
mov cl,字节ptr[ebx+esi]
mov dl,字节ptr[ebx+edi]
化学机械抛光
je递归
jmp错误
递归:
公司esi
十二月电子数据交换
推送eax
推ecx
推式edx
推动esi
推式电子数据交换
呼叫isPalindrome
//副ebp,8
波普edx
波普ecx
波普edx
jmp端
错误:
mov-eax,-1
jmp端
正确:
mov-eax,1
jmp端
完:
流行性ebx;
pop-esi;
pop-edi;
mov-esp,ebp;
pop-ebp;
//在这里结束你的代码
ret
}

}这里有几个问题。 首先,我必须说,我不认为这个问题是递归解决方案的好选择,因为为它提供一个大字符串可能会导致(我敢说)堆栈溢出,而递归是不必要的

以试图查看字符串的方式查看进程,我看到的第一个问题是序言/尾声:

push ebp
push edi
mov ebp, esp
与以下内容不匹配:

pop edi
mov esp, ebp
pop ebp
您将以ebp=原始edi结束,然后尝试返回原始ebp地址(崩溃)。显然,“pop edi”应该在“mov esp,ebp”之后,或者更可能在“mov ebp,esp”之后是“push edi”

在我看来,将edi包含在这些文件中是非常不标准的,我认为您添加edi是为了支持您的复发,并建议这是没有帮助的

对于proc,您可以从以下内容开始:

mov ebx, input_string
mov esi, [ebp+12]
mov edi, [ebp+16]
此时,堆栈看起来像:

[esp+00]  edi value
[esp+04]  original ebp value
[esp+08]  return address
[esp+12]  *input_string
[esp+16]  left_index
[esp+20]  right_index
(显然您已经设置了ebp=esp)

假设您正试图将这两个索引值放入esi和edi中,它们不是原来的位置,因为您在将esp存储到ebp中之前添加了“推式edi”

不久之后,你就有了:

mov ebx, input_string
mov edi, right_index
还有一个被注释掉的“movesi,left_index”

如果您的编译器支持按名称跟踪过程参数,那么最好使用它们,而不是[ebp+xx],这是此类引用通常要遵循的,然而,如果是这种情况,您将手工编写前奏/退出代码,这似乎很奇怪。您是否在此处剪切并粘贴了反汇编程序输出?如果是,则不应包括:

; prelude
push ebp
mov ebp, esp

; exit
mov esp, ebp
pop ebp
;          ( or possibly 'leave' which does the same thing )
ASM以“mov eax,0”开头,这似乎表明您的默认返回值为0,但是ASM似乎试图返回1表示true或-1表示false。在32位汇编中-1=0xFFFFFFFF,在标准布尔测试中等于“真”

我假设此代码应该返回'0'而不是'1'表示false。可能'-1'正被用作空指针等的错误代码

尽管如此,我认为这就是你想要的:

  push edi
  push esi
  push ebx
  push edx

  mov ebx, input_string
  mov esi, left_index
  mov edi, right_index

  // - ERROR -
  mov eax, -1 

  cmp ebx,0
jbe pEND
  cmp esi,0
jb pEND
  cmp edi,0
jb pEND

  // - FALSE -
  mov eax, 0  

  cmp esi, edi
  jge pTRUE

mov dl, byte ptr[ebx + edi]
cmp dl, byte ptr[ebx + esi]

  jne pEND

// RECURSIVE

inc esi 
dec edi

push edi
push esi
push ebx
call isPalindrome

  jmp pEND

  pTRUE:
mov eax, 1

  pEND:
  pop edx
  pop ebx
  pop esi
  pop edi

  ret

并使用uu stdcall而不是u declspec(裸)声明它

因此,如果给它字符串“abba”,在第二个调用深度的寄存器中会看到什么值?如果我正确地阅读了代码,那么第二个深度几乎所有的参数值都是错误的(加上返回后,上层可能无法返回)。你不需要“盯着”它,在调试器中逐条指令运行它,把纸+笔放在桌子上,写下关于寄存器中值的注释,并将它们与数据的期望值和定义进行比较。是的,问题是函数是用旧参数调用的,左侧和右侧索引不会在隐秘调用中得到更新。这根本不是真的。第一次进入该功能时,
左索引
位于地址
esp+8
,这将导致例如0x0150。在第二级递归中,
左索引再次位于
esp+8
,但经过计算后,它不再指向
0x0150
,因此不会得到旧参数。您可能会得到错误的参数,但“old”仍然位于内存中的
0x0150
。所以,开始关注
esp
值,并打开内存窗口来观察堆栈的内容,以及它是如何演变的。(顺便说一句,许多调试器都有专门针对堆栈的视图,使其非常及时)也就是说,您也应该从参数中获取字符串指针,因此
mov ebx,input_string
是欺骗,除非编译器足够神奇,可以将其视为本地参数并将其编译为
[ebp+x]
(在清单文件中验证或在调试器中反汇编)…(在这种情况下,您还可以将其用于其他参数,但不确定为什么要混合这些参数,只使用一种样式,这很容易混淆)。