2016-07-07 1 views
0

J'apprends comment travailler avec les procédures masm32 j'ai donc écrit procédure écrire un numéro:SIGSEGV, Segmentation fault tout en faisant « ret »

.386 
.model flat, stdcall 
option casemap : none 

include \masm32\include\masm32.inc 
include \masm32\include\kernel32.inc 
include \masm32\macros\macros.asm 
includelib \masm32\lib\masm32.lib 
includelib \masm32\lib\kernel32.lib 

.data 
    number dw 397 
    temp db 10 
    symbol dw ? 
    i dw ? 

.code 
    printnumber proc num:WORD 
    mov ecx, 0 
    mov ax, num 
    @@: 
    mov edx, 0 
    div temp 
    mov bh, 0 
    mov bl, ah  
    push bx 
    inc cx 
    cmp al, 0 
    mov bl, al 
    mov ax, bx 
    jnz @B 
    mov i, cx 
    @@: 
    pop symbol 
    add symbol, 48 
    mov ax, symbol 
    print ADDR symbol 
    dec i 
    cmp i, 0 
    jnz @B 
    ret 
printnumber endp 

start: 
    push number 
    call printnumber 
    ret ;here program fails 
end start 

imprime du programme « 397 » avec succès, mais après avoir essayé de faire "ret" il y a un problème: "Programme reçu signal SIGSEGV, erreur de segmentation.". Que devrais-je faire?

+0

Vous avez déséquilibré la pile. Vous voulez supprimer le 'nombre' que vous avez poussé. – Jester

Répondre

0

Vous déséquilibrez la pile en ne la nettoyant pas correctement.

En haut de votre fichier de code, vous avez cette directive:

.model flat, stdcall 

La partie importante est la directive stdcall, qui précise la convention d'appel que vos fonctions utiliseront. C'est la convention d'appel la plus courante pour les programmes Windows, et c'est la même que celle utilisée par l'API Windows. Il existe deux caractéristiques importantes de la convention d'appel stdcall:

  1. Les arguments sont poussés sur la pile de droite à gauche.
  2. L'appelé est responsable du nettoyage de la pile avant son retour.

La première caractéristique est la même que l'autre convention d'appel commune, cdecl, mais la seconde est exactement opposée. C'est ce que vous vous trompez dans ce cas. (En fait, votre code ne nettoie pas la pile du tout, donc il serait cassé indépendamment de la convention d'appel!)

Fondamentalement, lorsque vous utilisez la convention d'appel stdcall, vous utiliserez la version du ret instruction qui prend un immédiat comme argument. Cet argument spécifie le nombre d'octets à sortir de la pile lors du retour.

Dans ce cas, vous avez un argument, le mot taille number, de sorte que vous utiliseriez ret 2:

printnumber proc num:WORD 
    mov ecx, 0 
    mov ax, num 
    @@: 
    mov edx, 0 
    div temp 
    mov bh, 0 
    mov bl, ah  
    push bx 
    inc cx 
    cmp al, 0 
    mov bl, al 
    mov ax, bx 
    jnz @B 
    mov i, cx 
    @@: 
    pop symbol 
    add symbol, 48 
    mov ax, symbol 
    print ADDR symbol 
    dec i 
    cmp i, 0 
    jnz @B 
    ret 2   ; clean up the stack by popping 2 bytes, 
        ; since 2 bytes were pushed by the caller 
printnumber endp 

En dehors de cela, je crois que, avec point d'entrée de MASM32 start étiquette, vous devez appeler ExitProcess pour retourner le contrôle à Windows. All the MASM32 samples Je l'ai vu do it this way:

start: 
    push number 
    call printnumber 
    invoke ExitProcess, 0 
end start 

Mais je peux me tromper à ce sujet. Je n'utilise pas réellement le SDK MASM32. Normalement, votre point d'entrée serait une fonction cdecl qui renverrait simplement le contrôle avec ret.