• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Assembler - problem z zadaniem

VPS Starter Arubacloud
0 głosów
374 wizyt
pytanie zadane 18 czerwca 2019 w Assembler przez lycwid46 Nowicjusz (120 p.)
otagowane ponownie 18 czerwca 2019 przez Patrycjerz

Cześć. Mam program do napisania w assemblerze jednak jestem zupełnie zielony w tym temacie. Jakby ktoś mógł poratować odpowiedzią i ewentualnie wytłumaczyć co się tam dzieje. Ponoć zadanie nie jest, aż tak bardzo trudne.

Uzupełnić poniższy kod o treść procedury policz. Procedura ta ma pobierać ze stosu argument będący adresem łańcucha znaków i ma zwracać przez rejestr EAX liczbę znaków ’#’ w łańcuchu. Argumenty do procedury policz mają być przekazane przez stos, za usuwanie argumentów ze stosu ma odpowiadać wywołujący funkcję. Przykładowo, po uruchomieniu poniższego kodu na ekranie powinna zostać wypisana liczba 4.

    .intel syntax no prefix
    .text
    .global main

main :
    mov eax , offset messg
    push eax
    call policz
    add esp , 4
    // wypisanie wyniku
    push eax
    mov eax , offset printf arg1
    push eax
    call printf
    add esp , 8

exit:
    // kod powrotu z programu
    xor eax , eax
    ret

policz:
    [ TUTAJ POWINNO BYC UMIESZCZONE ROZWIAZANIE ]
.data

messg :
    .asciz ”Prz∗ykla#do###wy∗tekst”
printf arg1:
    .asciz ”%i "
komentarz 18 czerwca 2019 przez Eryk Andrzejewski Mędrzec (164,260 p.)
Domyślam się, że to asm na architekturę x86. Ale czy możesz podać nazwę asemblera? (program asemblujący kod do binarek, np. FASM, NASM, TASM, MASM, GNU-AS...).
komentarz 18 czerwca 2019 przez lycwid46 Nowicjusz (120 p.)
Tak, jest to asm na architekture x86. Program asemblujący to NASM.
komentarz 18 czerwca 2019 przez Eryk Andrzejewski Mędrzec (164,260 p.)

Jesteś pewien? Pisałem właśnie w NASM i składnia wyglądała nieco inaczej. Poza tym NASM domyślnie korzysta ze składni Intela, wobec czego nie widzę powodu dla którego miałoby być to deklarowane na początku tego pliku.

Z tego co wyszukałem, to podobną instrukcję ma w sobie GNU AS (u niego domyślną składnią jest AT&T), ale ma ona podkreślnik zamiast spacji:

.intel_syntax noprefix
 

 

komentarz 18 czerwca 2019 przez lycwid46 Nowicjusz (120 p.)
Możliwe że to GNU AS. Napewno Nie jest to FASM, ani MASM. Jednak wydaje mi się, że to NASM.

1 odpowiedź

0 głosów
odpowiedź 18 czerwca 2019 przez Eryk Andrzejewski Mędrzec (164,260 p.)

Najprościej będzie to chyba zrobić poprzez pętlę (zrealizowaną za pomocą etykiety, skoku i skoku warunkowego).

Przed pętlą zerujesz jakiś licznik (np. rejestr EAX). Przy każdym obiegu sprawdzasz, czy aktualny znak jest znakiem #. Jeżeli tak, to inkrementujesz licznik. Po wykonaniu pętli umieszczasz w EAX wartość (jeżeli od początku tam zliczałeś znaki, to nic więcej nie musisz robić). I na końcu dajesz ret i wracasz w miejsce wywołania funkcji. wink

Rozumiesz? Postaram się ogarnąć na szybko jakieś środowisko i spróbuję to napisać - dawno nie pisałem nic w j. asemblera. cheeky Ale fajnie by było, jakbyś sam jednak spróbował to napisać.

komentarz 18 czerwca 2019 przez lycwid46 Nowicjusz (120 p.)
edycja 18 czerwca 2019 przez Eryk Andrzejewski

Jakiś czas temu udało mi się napisać coś takiego

policz:
     mov ebx, [esp+4]

petla:
    mov cl, [ebx]
    cmp cl, 0
    je koniec1:
    cmp cl, '#'
    je koniec2:
    inc ebx
    jmp petla

koniec1:
     mov eax, -1
     ret

koniec2:
      mov eax, [esp+4]
      sub ebx, eax
      mov eax, ebx
      ret

 Czy coś z tego kawałku kodu jest poprawne ? :P

komentarz 18 czerwca 2019 przez Eryk Andrzejewski Mędrzec (164,260 p.)
edycja 18 czerwca 2019 przez Eryk Andrzejewski

Udało mi się zrobić chyba działający kod. Poprawiłem też jakieś tam błędy, czy niespójność składniową w kodzie, który przedstawiłeś w treści pytania. Ale najpierw odniosę się do Twojego kodu w komentarzu wyżej.

Pobierasz do rejestru EBX parametr funkcji ze stosu. Dalej wrzucasz do CL aktualny znak i prawidłowo porównujesz, czy jest on równy zero. Jeżeli jest - przerywasz pętlę skacząc pod jakiś tam adres. I to do tej pory jest prawidłowe. Nie rozumiem tylko dlaczego pod etykietką koniec1 do rejestru EAX wrzucasz -1. EAX to wartość zwracana, powinna zawierać liczbę znaków # w łańcuchu.

Gdy obecnym znakiem jest #, skaczesz do koniec2. Pamiętaj, że robiąc skok (zamiast call) nie jest wrzucany na stos adres powrotu, wobec czego instrukcja ret nie wróci w miejsce skoku warunkowego. Musiałbyś pewnie ręcznie wrzucić tam push EIP.

No i ogólnie w Twoim kodzie brakuje mi tego licznika znalezionych znaków #. Jedyne co inkrementujesz przy każdym obiegu pętli to rejestr EBX, który przechowuje adres kolejnej litery.

Wracając do mojego kodu - raczej staram się nie dawać gotowców, ale widzę że coś próbujesz działać samodzielnie, więc tym razem mogę dać. cheeky

Za chwilę go tutaj wrzucę.

.intel_syntax noprefix

.text
    .global main
    .extern printf
    
    main:
        mov eax, offset message
        push eax
        call policz
        add esp, 4
    
        // wypisanie wyniku
        push eax
        mov eax, offset printf_arg1
        push eax
        call printf
        add esp, 8
 
        // kod powrotu z programu
        xor eax, eax
        ret
 
    policz:
        // EAX to licznik
        xor eax, eax

        mov ebx, [esp + 4]
        policz_loop:
            mov ecx, [ebx]
            inc ebx
            
            // Interesuje nas tylko najmniej znaczacy bajt w rejestrze ECX
            // Bajt ten "siedzi" w rejestrze CL            
            cmp cl, 0
            je policz_end

            // # = 35
            cmp cl, 35
            jne policz_loop
            
            // Jezeli znak to #
            inc eax
        jmp policz_loop        

        policz_end:
            ret

.data
    message:
    	.asciz "P#rzyk#ladowy # t#ekst"

    printf_arg1:
    	.asciz "%d "

Komendy do zbudowania i uruchomienia programu:

as plik.asm -o plik.o
gcc plik.o -o plik
./plik

Powinno działać - przetestuj u siebie. Działa tak, jak to opisałem wyżej. wink

komentarz 18 czerwca 2019 przez lycwid46 Nowicjusz (120 p.)
edycja 18 czerwca 2019 przez Eryk Andrzejewski

Nie mogę uruchomić. Po wpisaniu 2 linijki wyskakuje "undefined reference to printf". Używam windowsa, ma to znaczenie? Ale wykombinowałem jeszcze inny fragment kodu, tym razem inne trochę podejście, jeśli mógłbyś poradzić czy on zadziała :P
 


    .intel_syntax noprefix
    .text
    .global main

main:
    mov eax, offset messg
    push eax
    call policz
    add esp, 4
    // wypisanie wyniku
    push eax
    mov eax, offset printf_arg1
    push eax
    call printf
    add esp, 8
exit:
    // kod powrotu z programu
    xor eax, eax
    ret
policz:
    mov ebx, [esp+4]
    xor ecx, ecx
petla:
    mov al, [ebx]
    cmp al, 0
    jne dalej
    mov eax, ecx
    ret
dalej:
    inc ebx
    cmp al, '#'
    jne petla
    inc ecx
    jmp petla

    .data
messg:
    .asciz "Prz*ykla#do###wy_*tekst"
printf_arg1:
    .asciz "%i\n"

 

komentarz 18 czerwca 2019 przez Eryk Andrzejewski Mędrzec (164,260 p.)

Upewnij się, czy konsolidujesz program z biblioteką standardową języka C (opcja -lc).

Twojego kodu nie uruchomiłem, ale po szybkiej analizie wygląda, że jest w porządku. yes

A, jeszcze taka prośba - kod źródłowy wrzucaj w przystosowany do tego bloczek, dużo przejrzyściej się w niego zagląda. Niestety nie ma w tej chwili kolorowania składni dla j. asemblera, ale postaram się ją dodać. wink

komentarz 19 czerwca 2019 przez lycwid46 Nowicjusz (120 p.)
Ok, Dostosuję się następnym razem :P Kod działa. Dziękuję Bardzo za pomoc i poświęcony czas :) Temat do zamknięcia.
komentarz 19 czerwca 2019 przez Eryk Andrzejewski Mędrzec (164,260 p.)

Nie ma za co. laugh

Temat możesz zamykać samodzielnie, jeżeli uznasz że Twoje wątpliwości zostały rozwiane.

Podobne pytania

0 głosów
0 odpowiedzi 933 wizyt
+1 głos
0 odpowiedzi 209 wizyt
0 głosów
0 odpowiedzi 61 wizyt
pytanie zadane 24 stycznia w Assembler przez koro33 Nowicjusz (120 p.)

92,452 zapytań

141,262 odpowiedzi

319,085 komentarzy

61,854 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Akademia Sekuraka 2024 zapewnia dostęp do minimum 15 szkoleń online z bezpieczeństwa IT oraz dostęp także do materiałów z edycji Sekurak Academy z roku 2023!

Przy zakupie możecie skorzystać z kodu: pasja-akademia - użyjcie go w koszyku, a uzyskacie rabat -30% na bilety w wersji "Standard"! Więcej informacji na temat akademii 2024 znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...