Asembler+Cpp - prosty kalkulator

0

Cześć. Ostatnio dostałem za zadanie napisać prosty kalkulator w asemblerze, który przyjmuje zmienne i wypisuje wynik w cpp. Program działa, jeśli wyrzucę z niego mnożenie i dzielenie(jakiś problem z rejestrami się pojawia kiedy chcę mnożyć lub dzielić), ale dobrze chodzi jedynie odejmowanie więc popełniam też jakiś błąd w instrukcjach warunkowych. Mógłby ktoś zerknąć? Bo już siedzę trochę nad tym a mam jeszcze kilka rzeczy do zrobienia :(

section .text

global calc

calc:
push ebp
mov ebp,esp
mov ebx,[ebp+16]

_add:
cmp ebx, 49
jne _sub
mov eax, [ebp+12]
add eax, [ebp+8]
jmp _end

_sub:
cmp ebx, 50
jne _mul
mov eax, [ebp+12]
sub eax, [ebp+8]
jmp _end

_mul:
cmp ebx, 51
jne _div
mov eax, [ebp+12]
mul eax, [ebp+8]
jmp _end

_div:
mov eax, [ebp+12]
div eax, [ebp+8]
jmp _end

_end:
mov esp, ebp
pop ebp
ret
 
#include<iostream>
using namespace std;

extern "C" int calc(int, int);

int main()
{
int a, b, i;
cout<<"podaj liczbe a"<<endl;
cin>>a;
cin>>b;
cout<<"podaj opcje"<<endl;
cin>>i;
switch(i)
{
case 1:
cout<<"suma= "<<(calc(a, b));
break;
case 2:
cout<<"roznica= "<<(calc(a,b));
break;
case 3:
cout<<"iloczyn= "<<(calc(a,b));
break;
case 4:
cout<<"Iloraz= "<<(calc(a,b));
break;}
return 0;
}
1

W ogóle dziwnie to jakoś robisz, szczególnie dzielenie i mnożenie. Zobacz np. coś takiego w inline asm:

#include <iostream>
using namespace std;

int add(int a, int b){
	int res = 0;
	_asm{
		mov eax, a
		mov ebx, b
		add eax, ebx
		mov [res], eax
	}
	return res;
}

int sub(int a, int b){
	int res = 0;
	_asm{
		mov eax, a
		mov ebx, b
		sub eax, ebx
		mov [res], eax
	}
	return res;
}

int mul(int a, int b){
	int res = 0;
	_asm{
		mov eax, a
		mov ebx, b
		mul ebx
		mov [res], eax
	}
	return res;
}

int divide(int a, int b){
	int res = 0;
	_asm{
		xor edx, edx
		mov eax, a
		mov ecx, b
		cmp ecx, 0
		jz error
		jnz correct

	correct:
		div ecx
		mov [res], eax
		jmp ending

	error:	
		mov [res], 0
	ending:
	}
	return res;
}

int main() {
    cout << divide(16,4) << endl;
    return 0;
}

Wyniki są poprawne więc napisałem dobrze aczkolwiek pewnie da się bardziej optymalnie zrobić dzielenie :)
Może spróbuj inline asm jednak.

0

Na zajęciach akurat tego nie mieliśmy. Inline faktycznie wydaje się być prostszy, a przynajmniej dla mnie taki jest. Dzięki.
Mam z kolei do Was jeszcze jedno pytanie, tym razem sytuacja jest odwrotna. O ile na wstawkę asemblerową w C++ mogę znaleźć jakieś źródła to z następnym zadaniem robi się problem.
Napisz funkcję, która dostaje jako argument nieujemną liczbę całkowitą n i zwraca jako wartość liczbę 2^n(to w C++). Z kolei w asemblerze powinna zostać pobrana owa zmienna n oraz powinien zostać wypisany wynik. Tego akurat nie mogę zrozumieć, a i w sieci nie mogę znaleźć niczego co mogłoby mi pomóc :(

0

google: call c function from assembly

0
 
;main
    global main
    extern foo

    section .text
    main:
    mov eax, 3
    mov ebx, 0
    mov ecx, [n]
    mov edx, [n_dl]
    int 80h

    push ecx
    call foo
    add esp, 4

    xor eax, eax
    ret
    pop ecx

    mov eax, 1
    int 80h


    section .data
    n db 0
    n_dl dd $-n

Słabo szukałem, dzięki. Zrobiłem coś takiego, ale program nie wypisuje mi zwróconej wartości. Możliwe że popełniam jakiś głupi błąd, ale orłem z asma nie jestem. Mógłbyś zerknąć Shalom?

0

Nie bardzo rozumiem co ma niby robić ten kod który pokazałeś. Robisz call foo to jest ok, potem przesuwasz stack pointer żeby pozbyć się argumentów funkcji to jest ok, potem kasujesz (!) wynik funkcji który jest w eax i to jest smutne, a potem robisz już w ogóle jakis hardkor bo wołasz ret czyli powrót z aktualnej funkcji co w twoim przypadku spowoduje pobranie ze stosu wartości i skok pod ten adres, który na nic sensownego nie pokazuje, szczególnie że na stosie nic juz nie ma... Potem robisz jeszcze inne cuda, ale one sie juz nie wykonają bo ret zrobi skok w otchłań :D

0

No tak... Za mało myślenia, a za dużo grzebania po kodach ludzi :D
Usunąłem tamte błędy i nie poszło, więc wartość z eaxa, czyli mój wynik wrzuciłem sobie do jakiejś zmiennej, użyłem standardowego strumienia wyjścia, a później wypisu na ekran ale nadal coś nie trybi. Powooli siada mi głowa :(

1

To może czas, zamiast robić jakieś losowe cuda na kiju, użyc debuggera i zobaczyć co się faktycznie w tym kodzie dzieje?

1

A może po prostu o to Ci chodzi?


#include<iostream>
using namespace std;

int power(int n) { return 1 << n; }

int main() {
	int n = 2;
	int res = 0;
	_asm{
		push n
		call power
		add esp, 4
		mov [res], eax
	}
	cout << res << endl;
	return 0;
}

Wersja z printf'em:

#include<iostream>
using namespace std;

int power(int n) { return 1 << n; }

int main() {
	int n = 8;
	char* fmt = "%d\n";
	_asm{
		push n
		call power

		push eax
		push fmt
		call printf
		add esp, 12
	}
	return 0;
}

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