Program w asm. Pomoc

0

Witam.

Ostatnio na studiach mamy początki asemblera i ćwiczeniowiec zlecił nam wykonanie programu.
Ale do rzeczy

Mam do napisania program który liczy ilość wystąpień łańcucha y w łańcuchu x.
Muszę oczywiście wyprowadzić wynik za pomocą wywołania systemowego, ale tym zajmę się później...
Do rzeczy. Napisałem program i najzwyczajniej w świecie nie działa.
Czy ktoś mógłby mi pomóc?

Oto kod :

#include <stdio.h>
 
int main() {
        char *x="abcabab_xxabc";   //0
        char *y="ab";               //1
        int i=0;
		//char bufor[4];
      
        asm (
        ".intel_syntax noprefix;"  /*  składnia intel  */
       
        "mov ecx, %1;" 
        "push ecx;"  
		"mov ecx, %0;"
		"mov ebx,%2;"
		"call zadanie1;"
		"jmp wyjscie;"	
		"zadanie1:"
		
		
		"push ebp;"
		"mov ebp,esp;"
		"push ecx;"
		"push ebx;"
		"push eax;"
		"push edx;"
		
		"mov eax,[ebp+8];" //do rejestru wrzucamy wartosc y bo tak go ustawilismy na stosie
		"mov edx,[ebp-4];" //do edx wrzucamy wartosc x
		
		
		
		"xor cx,cx;" //wyzerowanie licznika
		
		//NAJPIERW SPRAWDZAMY CZY KTORYS Z ŁANCUCHOW NIE JEST PUSTY, LUB OBA NIE SA PUSTE
		"cmp [eax],[edx];"
		"jz dodajlicznikizakoncz;"
		"jnz przeskoczjeslinierowne;" //-
									  //|
		"dodajlicznikizakoncz:"		  //|
		"inc cx;"					  //| jesli ktorys z nich nie jest pusty
		"jmp koniec;"				  //|
									  //|
		"przeskoczjeslinierowne:"     //-
		"cmp [eax],byte ptr 0;"
		"jz koniec;"
		"cmp [edx],byte ptr 0;"
		"jz koniec;"
		///////////////////////////////////////////////////////////////////////////////////////
		
		"jmp sprawdz;"
		
		
		"jeslirowne:"
		"inc eax;"
		"cmp [eax],byte ptr 0;"
		"jz wrocdopoczatku;"

		"jmp przesunedx;"

		
		
		"przesunedx:"
		"inc edx;"
		"cmp [edx],byte ptr 0;"
		"jz koniec;"
		"jmp sprawdz:"
		
		
		"wrocdopoczatku:"
		"mov eax,[ebp+8];"
		"inc cx;"
		"jmp przesunedx;"
		

		
		"sprawdz;"
		"mov bl,[eax];"
		"cmp bl,[edx];"
		"jz jeslirowne;"
		"jnz przesunedx:"

		
		
		
		
		
		"koniec:"
		
		"mov %2,cx;"
		"pop edx;"
		"pop eax;"
		"pop ebx;"
		"pop ecx;"
		"pop ebp;"
		
		"ret 8;"
		
		"wyjscie:"
		
        ".att_syntax prefix;"
        :"r" (i)
        :"r" (x),"r" (y)
        :"ebx","ecx"
        );     

       printf("y=%hd \n",i);
return 0;
}


0

Czym objawia się to, że program nie działa?

I dwa dodatkowe pytania:
Jak kompilujesz i na jakim systemie?
oraz:
Czy wybór inline asm gcc był Twój, czy takie są wymagania ćwiczeń?

0

Zmieniłem troche kod tak, żeby działał dla dowolnych łańcuchow ale nadal nie działa. A nie działa dokładnie to, ze sie w ogóle nie kompiluje...

0

Wklej plz jak kompilujesz oraz jakie błędy kompilatora dostajesz.
Oraz na jakim systemie kompilujesz (łącznie z architekturą CPU).

0

Kompiluje w Linuxie za pomocą edytora Geany (GCC) . A co do asm inline to takie wymagania mamy narzucone ;)

Co do architektury to nie mam pojęcia ale zapewne jest to x86.

Oto printscr;

1

Hehe masz zwyczaj ignorować część pytań ;)
Jaką masz architekturę CPU?
EDIT: OK, widzę, że wyedytowałeś swoją odp. Nvm więc ;)

Pytam o to ponieważ domyślnie na 64-bitowych x86 gcc kompiluje w 64-bitowym trybie, a kod Twojego programu jest w 32-bitowym assemblerze, więc w tym wypadku musisz dodać flagę -m32 przy kompilacji.

Generalnie z tego co widzę masz sporo literówek drobnych (konkretniej: czasem brakuje Ci ;, czasem masz za dużo :).
Poza tym w jednym miejscu starasz się wrzucić 16-bitową wartość do 32-bitowego rejestru używając mov. W takim wypadku trzeba użyć instrukcji movzx (jeśli to liczba naturalna, czyli unsigned) lub movsx (jeśli to liczba całkowita, czyli signed).

Kilka podpowiedzi jak to debugować:

  1. Zmień sobie wszystkie ; w kodzie assemblera na \n.

  2. Z konsoli, każ gcc wygenerować plik pośredni asemblera, czyli: gcc -m32 asdf.c -S (wygenerowany zostanie plik asdf.s)

  3. Sprawdź jak gcc stara się ten assembler skompilować: gcc -m32 -v asdf.c
    Powinna Ci wyskoczyć m.in. następująca linia:

as -v --32 -o /tmp/cc1is7QE.o /tmp/ccGttw6Z.s

as to kompilator asemblera. Istotne w powyższym jest tylko --32 dla nas.

  1. Otwórz plik asdf.s, i znajdź linie które wyglądaja tak:
# 9 "asdf.c" 1

i potem

# 0 "" 2

I je usuń (obie). To jest informacja o tym gdzie kod jest w pliku C i chwilowo będzie nam przeszkadzać.

  1. Skompiluj ten plik samym asemblerem:
as --32 asdf.s

Powinno pojawić Ci się trochę błędów, wraz z dokładną informacją gdzie błąd się znajduje, np.:

./asdf.s: Assembler messages:
./asdf.s:63: Warning: missing operand; zero assumed
./asdf.s:63: Error: can't handle non absolute segment in jmp' ./asdf.s:65: Error: operand type mismatch for mov'

W pliku asdf.s idź na konkretne linie i popraw literówki.
Te same zmiany od razu wprowadzaj w pliku .c który edytujesz, w analogicznych miejscach.

Jak już będzie się kompilować, daj znać. Przypuszczam, że program wtedy jeszcze działać nie będzie.

Ah, i tam w 102 linii w C brakuje Ci =, tak jak zresztą kod błędu Ci mówi. Tj powinno być: "=r" (i)

0

W ogóle nie chce mi wygenerować tego pliku za pomocą komendy gcc -m32 asdf.c -S
Wyskakują te same błędy co przy kompilacji

0

O ale teraz w ogóle mi pokazuje błędy w kodzie asemblera :D

0

Jak poprawiłeś ten = w 102 linii to powinien Ci już OK generować i powinieneś móc zrobić to co napisałem.

0
#include <stdio.h>
 
#include <stdio.h>
 
int main() {
        char *x="abcabab_xxabc";   //0
        char *y="ab";               //1
        int i=0;
		//char bufor[4];
      
        asm (
        ".intel_syntax noprefix;"  /*  składnia intel  */
       
        "mov ecx, %1\n" 
        "push ecx\n"  
		"mov ecx, %0\n"
		"mov ebx,%2\n"
		"call zadanie1\n"
		"jmp wyjscie\n"	
		"zadanie1:"
		
		
		"push ebp\n"
		"mov ebp,esp\n"
		"push ecx\n"
		"push ebx\n"
		"push eax\n"
		"push edx\n"
		
		"xor eax,eax\n"
		"xor edx,edx\n"
		
		"mov eax,[ebp+8]\n" //do rejestru wrzucamy wartosc y bo tak go ustawilismy na stosie
		"mov edx,[ebp-4]\n" //do edx wrzucamy wartosc x
		
		
		
		"cmp [edx],byte ptr 0\n"
		"jz koniec\n"
		"cmp [eax],byte ptr 0\n"
		"jz koniec\n"

		"xor cx,cx\n" //wyzerowanie licznika

		"jmp sprawdz\n"
		
		
		"jeslirowne:"
		"inc eax \n"
		"cmp [eax],byte ptr 0 \n"
		"jz wrocdopoczatku\n"

		"jmp przesunedx;"

		
		
		"przesunedx:"
		"inc edx\n"
		"cmp [edx],byte ptr 0\n"
		"jz koniec\n"
		"jmp sprawdz:"
		
		
		"wrocdopoczatku:"
		"mov eax,[ebp+8]\n"
		"inc cx\n"
		"jmp przesunedx\n"
		

		
		"sprawdz:"
		"mov bl,[eax]\n"
		"cmp bl,[edx]\n"
		"jz jeslirowne\n"
		"jnz przesunedx:"

	
		"koniec:"
		
		"mov %2,cx\n"
		"pop edx\n"
		"pop eax\n"
		"pop ebx\n"
		"pop ecx\n"
		"pop ebp\n"
		
		"ret 8\n"
		
		"wyjscie:"
		
        ".att_syntax prefix\n"
        :"=r" (i)
        :"r" (x),"r" (y)
        :"ebx","ecx"
        );     

       printf("y=%hd \n",i);
return 0;
}

Teraz wyskakują tylko 2 błędy ale za cholere nie mogę się pokapować o co w nich chodzi O_o

3

"jmp sprawdz:"
tutaj masz : za dużo, nie powinno go tam być (ale powinien być \n, którego nie ma)

    ".intel_syntax noprefix;"

tutaj (początek kodu) zmień sobie ; na \n
ew. dodaj też \n w liniach w których go nie ma (zazwyczaj przy labelach go pomijasz)

    "cmp [edx],byte ptr 0\n"

Ta linia powinna wygladac tak:
"cmp byte ptr [edx], 0\n"

analogicznie w innych miejscach; zazwyczaj ci się : zaplątuje w skoku ew brakuje \n
Po tych zmianach + tym o czym wspomniałem w poprzednim poście powinno Ci się kompilować OK

Póki co będę AFK, więc Ci napiszę kolejne kroki:

Jak już wszystko będzie się kompilować, skompiluj sobie kod najlepiej z opcją -g (tj. gcc -m32 -g asdf.c).

A potem, jeśli wynik nie będzie poprawny (a nie będzie) musisz znaleźć różnicę między tym jakie wyniki pośrednie generuje kod, a jakie ty (jako programista) sądzisz, że powinny być.
Użyj sobie gdb do tego, tj:

gdb ./a.out
(gdzie ./a.out to nazwa pliku wygenerowanego przez gcc ofc).

Kilka przydatnych poleceń:
b main - ustawienie breakpointu na main - zazwyczaj bęziesz to chciał zrobić na początku sesji debuggowania
r - uruchom aplikację
set disassembly-flavor intel - przełącz się na intelową składnię
a potem:
si - wykonaj instrukcję i się zatrzymaj
ni - wykonaj instrukcję, ale w przypadku call nie wchodź do funkcji, i się zatrzymaj
x/10i $eip - wypisz 10 instrukcji zaczynając od miejsca w którym aktualnie się zatrzymało wykonanie (instrukcja na górze to będzie to, co się wykona następne)
x/10c <$rejestr albo adres> - wypisz 10 bajtów (znaków) spod tego adresu
c - kontynuuj wykonanie do następnego breakpointu (jeśli takowy ustawiłeś)
info reg - wypisz wartości rejestrów

Na sieci znajdziesz więcej instrukcji jeśli Ci będą potrzebne.
Generalnie staraj się doprowadzić kod do takiej postaci, żeby robił to co chcesz.

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