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]
(在清单文件中验证或在调试器中反汇编)…(在这种情况下,您还可以将其用于其他参数,但不确定为什么要混合这些参数,只使用一种样式,这很容易混淆)。