Asembler: suma lub różnica po otrzymaniu znaku

0

Witam, zaczynam swoją przygodę z programowaniem w asmie i dostałem zadanie aby utworzyć sumę lub różnicę w zależności od podanego znaku. Nadmienię iż zakładam że gdy ktoś wpisze plus to jest dodawanie a gdy minus (lub byle co) to wykonam odejmowanie.

section .data
	napis db "Podaj znak zeby dodac lub odjac", 10
	len equ $-napis
	znak db " ",10                                               ;miejsce na znak podany na wejsciu
	lenz equ 1
	wpis db "Wpisales znak, wykonuje dzialanie", 10
	lenw equ $-wpis	
	plus db "+",10
	plusl equ 1
	

section .bss
	num1 resb 2  ;pierwsza liczba
	num2 resb 2  ;druga liczba
	res resb 1
section .text
	global _start

_start:
	mov rax, '5'                       ;wpisuje stala wartosc num1 i dalej num2
	sub rax, '0'
	mov [num1], rax
	mov rbx, '2'
	sub rbx, '0'
	mov [num2], rbx

	mov rax, 4		;wypisanie
	mov rbx, 1
	mov rcx, napis
	mov rdx, len
	int 80h

	mov rax, 3		;wpisanie znaku
	mov rbx, 0
	mov rcx, znak
	mov rdx, lenz
	int 80h

	mov rax, 4		;komunikat o wpisaniu znaku
	mov rbx, 1
	mov rcx, wpis
	mov rdx, lenw
	int 80h
	
	mov rax, [znak]		;wpisuje dwa znaki do rejestrów
	mov rbx, [plus]
	cmp rax, rbx		;porownuje dwa rejestry i tutaj gdzies moj program pada
	je _skok		;jezeli prawdziwe to skok
	mov rax, [num1]		;wpisz liczbe do raxa
	sub rax, [num2]		;odejmij
	mov [res], rax		;zapis liczby w res
	jmp _koniec

_skok:                            ;dodawanie
	mov rax, [num1]
	add rax, [num2]
	mov [res], rax

_koniec:			;wynik dzialania wyspisanie
	mov rax, 4
	mov rbx, 1
	mov rcx, [res]
	mov rdx, 1
	int 80h

	
	mov rax, 1	;wyjscie
	mov rbx, 0
	int 80h 

Jest to jeden z moich pierwszych programów poza hello worldem w asmie więc trochę ciężko mi się połapać, jestem otwarty na krytykę, opinie i sugestie. Z góry dziękuję za pomoc w rozwiązaniu problemu. Dodam że kompiluję na 64bit i nasm z linkerem ld.

0

A co takiego robi nie tak ?

Może przy wypisywaniu jest błąd.
Czy do wyniku nie należało by dodać '0' aby otrzymać znak ASCII z cyfrą ?
Czy przy wypisywaniu do rcx powinien być przekazany [res] czu może res

1

mov rax, [znak] a ile bajtów oczekujesz że zostanie wczytane? Bo rax ma 8 bajtow a znak to tylko 1 bajt, a "za nim" w pamięci są różne inne rzeczy.

0

@furas przy wypisywaniu chyba nie bo kompletnie przeskakuje instrukcje warunkową i zawarte w niej operacje. Możliwe ale to nic nie zmienia w działaniu programu i dalej się nie wykonuje :(
@Shalom nie wiem czego oczekuję, sam doszedłem do tego że może być z tym problem aczkolwiek nie wiem jak go rozwiązać. Nie wiem też czym się różni przekazanie wartości przez [] od "czystego" przekazania. Ale nawet jeśli by się różniły to powinno się wykonać odejmowanie, czy nie tak?

1

Moja rada: zacznij od 16 bitów pod 8086. Zainstaluj emu8086 i spróbuj najpierw ogarnąć jak to działa kiedy masz "tylko" 16 bitowe rejestry ax, bx,... i ich połówki al, ah,...

0

Chciałbym, ale za bardzo nie wiem na czym się oprzeć, muszę się nauczyć tego na laboratoria i tam i tak pracujemy na 64bit. Rozumiem że porównuję dwa rejestry które są czymś innym zapchane i dlatego nie jest możliwe dokładne porównanie. Ale dlaczego nie przechodzi chociaż do odejmowania?

1

[res] oznacza zawartość komórki o adresie res - np. pobranie wartości z komórki o adresie res lub zapisanie wartości do komórki o adresie res

res oznacza tylko adres komórki - czyli można powiedzieć "wskaźnik".

rax jest rejestrem 32bitowym czyli mieści 4 bajty. Tak więc przy pobieraniu czegoś do raxz pamięci pobiera 4 kolejne bajty a nie tylko jeden bajt zawierający znak.

Ale rax ma też krótsze wersje: ax ma 16 bitów czyli 2 bajty, ah i al po 8 bitów czyli 1 bajt. ah lub al pobierze z pamięci akurat jeden bajt zawierający znak

Podobnie jest z innymi rejestrami choć nie wszystkie mają te krótsze wersje.

0

@furas czy rax nie jest czasem 64bitowy?
Edit: no dobra rozumiem w czym rzecz, teraz program przechodzi dalej jak dostanie plusa, ale nic nie wypisuje

0

Faktycznie :) Ostatni raz miałem poważny kontakt z asemblerem gdy jeszcze DOS królował a procesory ledwie dorobiły się rejestrów 32bitowych :)

rax - 64bity
eax - 32bity
ax - 16bitów
ah - 8bitów ("starsza" część rejestru ax)
al - 8bitów ("młosdza" część rejestru ax)

0

To drzewko znałem, i porównałem te końcówki rejestrów, poszedł program dalej lecz nadal nie wypisuje zupełnie nic (wiem bo wrzuciłem na chwilę wypisanie że ma dodawać). Gdzieś dalej jest problem i nie wiem gdzie.

0

Przy wypisywaniu początkowego napisu stosujesz

    mov rax, 4        ;wypisanie
    mov rbx, 1
    mov rcx, napis  # wskaznik na napis
    mov rdx, len    # ilosc znakow
    int 80h

Podobnie powinno być przy wypisywaniu wyniku

_koniec:            ;wynik dzialania wyspisanie
    mov rax, 4
    mov rbx, 1
    mov rcx, [res]  # tu powinien być wskaznik czyli `res` a nie zawartość czyli `[res]`
    mov rdx, 1      # ilosc znakow
    int 80h
0

@furas Bangla! :D Dzięki za rozjaśnienie problemu.

0

Oprócz poprzedniego jest jeszcze zamiana wyniku na kod ASCII cyfey do wypisania

Najpierw zamieniałeś kod ASCII na wartość liczbową

    mov rax, '5'                       ;wpisuje stala wartosc num1 i dalej num2
    sub rax, '0'
    mov [num1], rax

i podobnie powinieneś zrobić w drugą stronę - wartość zamienić na kod ASCII

    mov rax, [res]   # pobranie cyfry
    add rax, '0'                   # zamiana na ASCII
    mov [res], rax               # zapisanie w to samo miejsce

Dla wyniku jednocyfrowego to nie problem ale gdy będziesz miał w jednym bajcie wartość dwucyfrową
to będzie więcej roboty bo trzeba każdą cyfrę przerzucić do osobnego bajtu i dodawać '0'.
Nie pamiętam czy jest jakaś wbudowana funkcja która to załatwia.

0

@furas zrobiłem tak już wcześniej. Po twoim pierwszym poście. Tak to teraz wygląda.

section .data
	napis db "Podaj znak zeby dodac lub odjac", 10
	len equ $-napis
	znak db " ",10
	lenz equ 1
	wpis db "Wpisales znak, wykonuje dzialanie", 10
	lenw equ $-wpis	
	plus db "+",10
	plusl equ 1
	dodawanie db "wykonuje dodawawnie", 10
	ldoda equ $-dodawanie

section .bss
	num1 resb 2
	num2 resb 2
	res resb 1
section .text
	global _start

_start:
	mov rax, '5'
	sub rax, '0'
	mov [num1], rax
	mov rbx, '2'
	sub rbx, '0'
	mov [num2], rbx

	mov rax, 4		;wypisanie
	mov rbx, 1
	mov rcx, napis
	mov rdx, len
	int 80h

	mov rax, 3		;wpisanie znaku
	mov rbx, 0
	mov rcx, znak
	mov rdx, lenz
	int 80h

	mov rax, 4		;komunikat o wpisaniu znaku
	mov rbx, 1
	mov rcx, wpis
	mov rdx, lenw
	int 80h

	mov rax, [znak]		
	mov rbx, [plus]
	cmp al, bl		;porownuje dwa rejestry
	je _skok		;jezeli prawdziwe to skok
	mov rax, [num1]		;wpisz liczbe do raxa
	sub rax, [num2]		;odejmij
	mov [res], rax		;zapis liczby w res
	jmp _koniec

_skok:
	mov rax, 4
	mov rbx, 1
	mov rcx, dodawanie
	mov rdx, ldoda
	int 80h
	mov rax, [num1]
	add rax, [num2]
	mov [res], rax

_koniec:			;wynik dzialania
	mov rax, [res]
	add rax, '0'
	mov [res], rax
	mov rax, 4
	mov rbx, 1
	mov rcx, res
	mov rdx, 1
	int 80h

	
	mov rax, 1	;wyjscie
	mov rbx, 0
	int 80h
0

To jescze rozbij sobie to na procedurki mniejsze, żeby taki blok instrukcji samych nie był, i prowadzący będzie już całkiem pewnie zadowolony : P

0

Dał nam jeszcze do zrobienia program liczący ilość a w zdaniu wpisanym przez użytkownika i program do którego wpisuje się znaki dopóki nie wpisze się 'k' jak ogarniam to drugie to pierwszego nie bardzo :C ale fakt faktem mógłby się zadowolić tylko że ja nie wiem jak coś takiego zrobić :D

0

@stacho688 a gdzie jest problem? Iterujesz po literkach i jeśli literka równa się a to podbijasz jakiś licznik. Nie bardzo rozumiem gdzie jest tu jakiś problem.

0

@Shalom właśnie z tym iterowaniem. Nie bardzo ogarniam obsługę stringów w asm'ie

1

Bo w asmie nie ma stringów. Masz po prostu bajty w pamięci.

mov bx, 0
mov al, [znaki+bx] ;pierwsza literka
inc bx
mov al, [znaki+bx] ; druga literka
inc bx
mov al, [znaki+bx] ; trzecia literka
...

Widzisz już jak iterować? ;]

0

Tak myślałem, dzięki! Jutro rano przed labkami to sobie napiszę.

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