Dlaczego aplikacja nie pozwala wybrać opcji

0

Witajcie,

piszę sobie prosty kalkulatorek w NASM'ie i zastanawiam się dlaczego program wywala się po zakończeniu dokonywania obliczeń, kiedy chcę skoczyć na początek (do menu).
Aplikacja wywala się dokładnie w miejscu wywołania 'jmp poczatek'.

Trochę nie wiem o co chodzi. Wcześniej pisałem sobie trochę w ASM ale 16'to bitowym, jeszcze pod DOS'a z jego przerwaniami etc...

global _main
extern _printf
extern _scanf

section .data
liczbaA    dd    0
liczbaB    dd    0
wynik      dd    0

naglowek   db    "Kalkulator", 0dh, 0ah, "1. Dodawanie", 0dh, 0ah, "2. Odejmowanie", 0dh, 0ah, "K. Koniec", 0dh, 0ah, "Wybierz: ", 0
opcja      dd    0

wprLiczbaA db    "Liczba A: ", 0
wprLiczbaB db    "Liczba B: ", 0
wprWynik   db    "Wynik: ",0 

formatZnak db    "%s", 0
formatLicz db    "%d", 0

section .text

_main:
    push ebp
    mov ebp, esp

; Menu oraz wybór działania
poczatek:
    push naglowek
    call _printf
    add esp, 4
    
    push opcja
    push formatZnak
    call _scanf
    add esp, 8
    
    cmp byte[opcja], '1'
    je dodawanie
    
    cmp byte[opcja], '2'
    je odejmowanie
    
    cmp byte[opcja], 'k'
    je koniec
    jmp koniec
    
; Użycie funkcji z 'C' do wczytania liczb i pokazywania komunikatów.
dodawanie:
    push wprLiczbaA
    call _printf
    add esp, 4
    
    push liczbaA
    push formatLicz
    call _scanf
    add esp, 8
    
    push wprLiczbaB
    call _printf
    add esp, 4
    
    push liczbaB
    push formatLicz
    call _scanf
    add esp, 8
    
    push wprWynik
    call _printf
    add esp, 4
    
    mov eax, [liczbaA]
    mov ebx, [liczbaB]
    add eax, ebx
    mov [wynik], eax
    
    push dword[wynik]
    push formatLicz
    call _printf
    mov esp, 8
    
    jmp poczatek
    
; To samo co w dodawaniu
odejmowanie:
    push wprLiczbaA
    call _printf
    add esp, 4
    
    push liczbaA
    push formatLicz
    call _scanf
    add esp, 8
    
    push wprLiczbaB
    call _printf
    add esp, 4
    
    push liczbaB
    push formatLicz
    call _scanf
    add esp, 8
    
    push wprWynik
    call _printf
    add esp, 4
    
    mov eax, [liczbaA]
    mov ebx, [liczbaB]
    sub eax, ebx
    mov [wynik], eax
    
    push dword[wynik]
    push formatLicz
    call _printf
    mov esp, 8
    
    jmp poczatek
    
koniec:        
    mov esp, ebp
    pop ebp
ret
0

Debuger w dłoń. Nikt tego za ciebie nie zrobi...

0

Napisałem to od nowa, ponieważ nawet nie chciało się specjalnie debugować. Teraz działa jak należy.

global _main
extern _printf
extern _scanf

section .data
naglowek    db    0dh, 0ah, 0dh, 0ah, "..:: Kalkulator ::..", 0dh, 0ah, 0
opcje       db    "1. Dodaj", 0dh, 0ah, "2. Odejmij", 0dh, 0ah, 0dh, 0ah, "Wybor: ", 0
fmtZnak     db    "%s", 0
fmtLiczba   db    "%d", 0
prosbaA     db    "Wpisz 'A': ", 0
prosbaB     db    "Wpisz 'B': ", 0
etykietaWyn db    "Wynik: ", 0
pytanie     db    0dh, 0ah, 0dh, 0ah, "Czy powtorzyc? ", 0

section .bss
wybor       resd    1
liczbaA     resd    1
liczbaB     resd    1
wynik       resd    1

section .text
_main:
    mov ebp, esp; for correct debugging
    
menu:
    push naglowek
    call _printf
    add esp, 4
    
    push opcje
    call _printf
    add esp, 4
    
    push wybor
    push fmtZnak
    call _scanf
    add esp, 8  
    
    cmp byte[wybor], "1"
    je dodawanie
    cmp byte[wybor], "2"
    je odejmowanie
    
    jmp koniec
    
wprowadzanieLiczb:
    push prosbaA
    call _printf
    add esp, 4
    
    push liczbaA
    push fmtLiczba
    call _scanf
    add esp, 8
    
    push prosbaB
    call _printf
    add esp, 4
    
    push liczbaB
    push fmtLiczba
    call _scanf
    add esp, 8

    push etykietaWyn
    call _printf
    add esp, 4
    ret
   
dodawanie:
    call wprowadzanieLiczb
            
    mov eax, [liczbaA]
    mov ebx, [liczbaB]
    add eax, ebx
    mov [wynik], eax
        
    push dword[wynik]
    push fmtLiczba
    call _printf
    add esp, 8
    
    jmp czyJeszczeRaz
    
odejmowanie:
    call wprowadzanieLiczb
            
    mov eax, [liczbaA]
    mov ebx, [liczbaB]
    sub eax, ebx
    mov [wynik], eax
        
    push dword[wynik]
    push fmtLiczba
    call _printf
    add esp, 8
    
    jmp czyJeszczeRaz

czyJeszczeRaz:
    push pytanie
    call _printf
    add esp, 4
    
    push wybor
    push fmtZnak
    call _scanf
    add esp, 8
    
    cmp byte[wybor], "t"
    je menu
    jmp koniec

koniec:
    xor eax, eax
    ret
0
  1. Wrzuć sobie do nieużywanych rejestrów ESI EDI EBX adresy funkcji _printf i _scanf, mov esi, offset _printf (lub jeśli to bezpośredni adres mov esi,dword ptr[_printf], staraj się jakieś użyteczne adresy funkcji, zmiennych, stałych, z których korzystasz w wielu miejsach trzymać w tych rejestrach, które nie są modyfikowane pomiędzy wywołaniami funkcji w konwencjach stdcall, cdecl, czyli właśnie ESI EDI EBX

  2. Tymczasowe operacje wykonuj na EAX, ECX, EDX

  3. Skoryguj ESP po serii wywołań funkcji w jednym bloku (optymalizacja rodem z GCC), czyli nie dawaj po każdym call instrukcji korygującej add esp,x , ale po serii call-ow np. add esp,8*3

  4. Kombinacja cmp byte[wybor], 't' + je menu + jmp koniec zamien po prostu na cmp byte [wybor], 't' + jne menu i jesteś o instrukcje mniej do przodu :)

1 użytkowników online, w tym zalogowanych: 0, gości: 1