2017-03-16 2 views
-2

Cette fonction prend une chaîne d'entrée et vérifie s'il s'agit d'un palindrome ou non. Il casse cependant en raison d'une erreur de mémoire. Je l'ai regardé pendant quelques heures mais je n'arrive pas à comprendre le problème. Il y a beaucoup de poussées inutiles mais j'ai peur de jouer avec et de casser encore plus. Apprécierait toute aide.Vérification de Palindrome dans l'assemblage MASM

__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 
} 

}

+0

donc si vous lui donnez chaîne " abba ", quelles sont les valeurs que vous voyez dans les registres dans la seconde profondeur d'appel? Si je lis correctement le code, la seconde profondeur de la profondeur a déjà presque toutes les valeurs d'argument erronées (plus après le retour, le niveau supérieur échouera probablement à retourner). Vous n'avez pas besoin de le regarder, de le lancer dans l'instruction du débogueur par instruction, avec du papier + stylo au bureau, d'écrire des notes sur les valeurs dans les registres et de les comparer avec les attentes et les définitions des données. – Ped7g

+0

Oui, le problème est que la fonction est appelée avec les anciens arguments, les index gauche et droit ne sont pas mis à jour dans l'appel reclus. –

+0

Ce n'est tout simplement pas vrai. Lors de la première entrée de la fonction, 'left_index' est à l'adresse' esp + 8', ce qui donnera par exemple 0x0150. Au second niveau de récursion, le 'left_index' est à nouveau' esp + 8', mais après avoir évalué cela ne pointe plus vers '0x0150', donc vous ne récupérez pas les anciens arguments. Vous pouvez obtenir des arguments faux, mais le "vieux" est toujours assis à "0x0150" en mémoire. Alors commencez à prêter attention à la valeur 'esp', et ouvrez également la fenêtre de mémoire pour regarder le contenu de la pile, comment cela évolue. Cela dit, beaucoup de débogueurs ont une vue spécialisée juste pour la pile, ce qui la rend bien mise à jour) – Ped7g

Répondre

0

Il y a quelques problèmes ici. Tout d'abord, je dois dire que je ne pense pas que ce problème soit un bon candidat pour une solution récursive car la fournir avec une grande chaîne pourrait entraîner (j'ose le dire) un débordement de pile, et la récursivité est juste unnessesary.

En regardant votre proc de la même façon, il tente de regarder la chaîne, la première question que je vois est votre préambule/épilogue:

push ebp 
push edi 
mov ebp, esp 

ne correspond pas à:

pop edi 
mov esp, ebp 
pop ebp 

Vous finirez avec ebp = votre edi d'origine, puis essayez de revenir à l'adresse ebp d'origine (plantage). Évidemment, soit 'pop edi' devrait être après 'mov esp, ebp', ou plus probablement vous voulez 'push edi' après 'mov ebp, esp'

Comme l'inclusion de edi dans ces se démarque comme étant très Je suppose que vous l'avez ajouté dans une tentative de soutenir votre récurrence et que cela n'est pas utile.

Pour le proc, vous commencez avec:

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

à ce stade, votre pile ressemble à:

[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 

(et, évidemment, vous avez défini ebp = esp)

en supposant vous essayez d'obtenir les deux valeurs d'index dans esi et edi, elles ne sont pas là où elles étaient car vous avez ajouté un 'push edi' avant de stocker esp dans ebp.

Peu de temps après vous:

mov ebx, input_string 
mov edi, right_index 

et il y a aussi un commenté « mov esi, left_index »

Si votre compilateur prend en charge le suivi des arguments de procédure par nom, vous feriez mieux d'utiliser plutôt que [ebp + xx] qui est ce que ces références seront généralement respectées, mais il semble étrange que vous soyez en train de coder votre prélude/code de sortie si cela était le cas. Avez-vous coupé & sortie de désassembleur collé ici? Si oui, alors vous ne devriez pas inclurons:

; prelude 
push ebp 
mov ebp, esp 

; exit 
mov esp, ebp 
pop ebp 
;   (or possibly 'leave' which does the same thing) 

L'ASM commence par « mov eax, 0 » qui semble indiquer que la valeur de votre retour par défaut est 0, mais l'ASM semble essayer de revenir 1 pour vrai ou -1 pour faux. Dans l'ensemble de 32 bits -1 = 0xFFFFFFFF qui, dans un test booléen standard, équivaudrait à 'VRAI'.

Je suppose que ce code devrait retourner '0' et non '-1' pour faux. Peut-être que '-1' est utilisé comme code d'erreur pour un pointeur NULL, etc.

tout cela étant dit, je pense c'est ce que vous cherchez:

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 

et déclare à l'aide __stdcall au lieu de __declspec (nu)