Asembler - analiza kodu NASM (zliczanie literek 'a' w zdaniu)

Asembler - analiza kodu NASM (zliczanie literek 'a' w zdaniu)
CE
  • Rejestracja:prawie 12 lat
  • Ostatnio:ponad 7 lat
  • Postów:124
0

Witam. Jakiś czas temu rozpoczęliśmy na studiach naukę asemblera i zostaliśmy rzuceni z marszu na głęboką wodę. Nie jestem zwolennikiem nauki przez analizę cudzego kodu, wolę krok po kroku sprawdzić treści w książce, ale tym razem niestety nie mam wyboru - goni mnie czas.
Poniżej przedstawię kawałek kodu pod linuxa w formacie NASM. Bardzo prosiłbym o pomoc w analizie wybranych przeze mnie fragmentów.

Kopiuj
section. text
global _start

_start:

		mov		eax, 3
		mov		ebx, 0
		mov		ecx, tekst
		mov		edx, [dlugosc]
		int		80h
		xor		ecx, ecx ; dlaczego ecx i ebx są zerowane w miejscu, kiedy linijkę wcześniej wprowadzaliśmy do nich podstawowe wartości? czy to nie powinno spowodować błędów w kompilacji?
		xor		ebx, ebx

_add:
		inc		ebx ; nawet, jeśli nie podalibyśmy żadnej litery a, program powinien wejść do tego miejsca i zinkrementować ebx. Czy nie będzie w takim razie w przekroju całego programu o jedną literę a za dużo, czy popełniam gdzieś błąd myślowy? 

_petla:
		mov		sil, [tekst+ecx]
		inc		ecx
		cmp		sil, 97
		je		_add
		cmp		ecx, 19 ; największa czarna magia dla mnie - 19 to komenda XOFF, mająca pauzować transmisję. Jakie ma to powiązania z instrukcją porównania?
		jne		_petla

_end:
		add		ebx, 47 ; co to ma wywołać? 47 to w kodzie ASCII zwykły slash, jaki ma cel sumowanie tego z zawartością rejestru bazowego?
		mov		[tekst],ebx
		mov		eax, 4
		mov		ebx, 1
		mov		ecx, tekst
		mov		edx, 1
		int		80h

		mov		eax, 1
		int		80h

section .data

tekst		TIMES	20	db	0 ; dlaczego zmienna tekst jest deklarowana jako dwudziestokrotne zero?
dlugosc	dd		$-tekst ; prosiłbym jeszcze o wyjaśnienie zapisu $-tekst

To wszystko. Program niemal w całości jest dla mnie niezrozumiały, więc jeśli ktoś byłby w stanie, oprócz odpowiedzi na moje pytania, krok po kroku przedstawić działanie kodu, byłbym bardzo wdzięczny. Pozdrawiam.

edytowany 2x, ostatnio: Ceplusplus
Shalom
  • Rejestracja:około 21 lat
  • Ostatnio:prawie 3 lata
  • Lokalizacja:Space: the final frontier
  • Postów:26433
1
  1. int to wywołanie przerwania którego "parametry" są zwykle ustalane rejestrami. Siłą rzeczy w kodzie masz ustawienie parametrów, wywołanie przerwania a potem zerowanie parametrów żeby zrobić z nimi coś innego. Nie rozumiem skad błąd kompilacji. To tak jakbyś miał:
Kopiuj
int a = 10;
int b = 20;
funkcja(a,b);
a = 0;
b = 0;

Czemu wg ciebie taki kod miałby jakieś błędy generować? o_O
2. Nie pisałeś że kod jest poprawny ;] Faktycznie będzie o 1 literkę za dużo, ale nie do końca, patrz 4.
3. Ty chłopie W OGÓLE nie rozumiesz co się w tym kodzie dzieje. Czeski film. ecx to jest licznik którym idziemy po tablicy ze stringiem. Porównanie go z 19 oznacza że doszlismy do KOŃCA STRINGA (bo tablica ma 20 znaków, patrz 5.). To jest zwykła LICZBA a nie znak ascii. W ogóle za używanie liczb zamiast po prostu znaków ascii powinna być chłosta.
4. Dodanie 47 zapewne służy do tego żeby np. liczbę 3 zamienić na znak 3 którego to kod ascii wynosi 51, czyli właśnie 47+1+3. Ale idiota który to wymyślił powinien zawisnąć. Normalny człowiek inkrementowałby po ludzku a potem dodał ZNAK 0 żeby uzyskać odpowiednią liczbę. Poza tym kod zakłada że literek jest mniej niż 10 ;]
5. tekst jest po prostu tablicą 2 bajtów, że wyzerowanych to akurat mało istotne, a ten $ na końcu oznacza po prostu "koniec stringa"


"Nie brookliński most, ale przemienić w jasny, nowy dzień najsmutniejszą noc - to jest dopiero coś!"
edytowany 2x, ostatnio: Shalom
CE
  • Rejestracja:prawie 12 lat
  • Ostatnio:ponad 7 lat
  • Postów:124
0

W porządku, dziękuję za pomoc. Jak w takim razie rozpoznać, czy działamy na bitach, czy na znakach ASCII? W jednym z programów porównywał wszystko ze 107, przy czym linker interpretował to jako po prostu "k".

Kopiuj
cmp sil,107

Jeśli byłaby możliwość, bardzo prosiłbym o przerobienie kodu na najbardziej prawidłowy sposób, żebym miał dalsze podstawy do przerobienia pozostałych wymaganych programów.

edytowany 1x, ostatnio: Ceplusplus
Shalom
  • Rejestracja:około 21 lat
  • Ostatnio:prawie 3 lata
  • Lokalizacja:Space: the final frontier
  • Postów:26433
0

Jak w takim razie rozpoznać, czy działamy na bitach, czy na znakach ASCII

Jeśli autor kodu był idiotą to niestety się nie da. Trzeba po prostu rozumieć co się w kodzie dzieje, wtedy dość oczywiste staje się jak traktować pewne wartości.

Jeśli byłaby możliwość, bardzo prosiłbym o przerobienie kodu na najbardziej prawidłowy sposób

:D :D :D


"Nie brookliński most, ale przemienić w jasny, nowy dzień najsmutniejszą noc - to jest dopiero coś!"
CE
  • Rejestracja:prawie 12 lat
  • Ostatnio:ponad 7 lat
  • Postów:124
0

Czy w takim razie uzyskałbym pomoc odnośnie dobrego poradnika do assemblera? Korzystam z wikibooksa, ale tam nauczyłem się jedynie przeznaczenia instrukcji "na sztywno", i to póki co cała moja wiedza. Czytałem jeszcze książkę Drozdowskiego, ale zupełnie nie przypadła mi do gustu.

Shalom
  • Rejestracja:około 21 lat
  • Ostatnio:prawie 3 lata
  • Lokalizacja:Space: the final frontier
  • Postów:26433
0

Ale właściwie czego oczekujesz? Bo rozumiesz że programowanie w asemblerze jest proste jak budowa cepa? To nie ma żadnych wysokopoziomowych mechanizmów, polimorfizmów, genericów, wzorców projektowych ;]
Musisz po prostu znać kilka podstawowych instrukcji (mov, xor, cpm, skoki, etykiety, int, call, ret) i mieć pod ręką zestaw przerwań z parametrami i w sumie tyle. Nic więcej tam nie ma do nauki. Reszta to jest po prostu głowa na karku i umiejętne dzielenie kodu na sensowne kawałki.


"Nie brookliński most, ale przemienić w jasny, nowy dzień najsmutniejszą noc - to jest dopiero coś!"
CE
  • Rejestracja:prawie 12 lat
  • Ostatnio:ponad 7 lat
  • Postów:124
0

Może i proste, ale najpierw się tego trzeba nauczyć, a tego za proste nie uważam. Stąd kluczem jest dobry poradnik, którego nie mam. Co z tego, że znam kilka instrukcji, akurat większość z tych, które wymieniłeś, skoro nie pojmuję "logiki" rejestrowej.

Shalom
  • Rejestracja:około 21 lat
  • Ostatnio:prawie 3 lata
  • Lokalizacja:Space: the final frontier
  • Postów:26433
0

Ale czego dokładnie nie pojmujesz? Rejestry to takie "zmienne" wielokrotnego użytku i tyle. Z czym konkretnie masz problem?


"Nie brookliński most, ale przemienić w jasny, nowy dzień najsmutniejszą noc - to jest dopiero coś!"
Azarien
  • Rejestracja:ponad 21 lat
  • Ostatnio:około 2 godziny
1

Dla procesora nie ma różnicy między np. liczbą 48 a znakiem 0. Różnica jest tylko w kodzie źródłowym. Dlatego powinno się trzymać zasady, że piszemy 48 jeśli chodzi o liczbę czterdzieści osiem, a '0' jeśli chodzi o znak - cyfrę zero.
Jeżeli programista tego nie przestrzegał, to zostaje tylko zastanawianie się co poeta chciał powiedzieć.

edytowany 1x, ostatnio: Azarien
CE
  • Rejestracja:prawie 12 lat
  • Ostatnio:ponad 7 lat
  • Postów:124
0

Korzystamy cały czas z rejestrów EAX, EBX,ECX oraz EDX. Wiem, że pierwszy to akumulator, drugi baza, itd., ale przy jakich konkretnych instrukcjach powinniśmy wybierać który konkretny? Autor tego programu korzystał jeszcze z indeksu źródłowego SIL - dlaczego akurat ten?
No i nie rozumiem podziału na długość i tekst - jedno ma odpowiadać za adres, drugie za wpisane do niego bajty. Z tymże już 20 komórek używamy na samą etykietę, co totalnie mi utrudnia zrozumienie całości. Póki co to tyle, jak zrozumiem to, to przejdę dalej ze swoimi pytaniami :).

edytowany 2x, ostatnio: Ceplusplus
Azarien
  • Rejestracja:ponad 21 lat
  • Ostatnio:około 2 godziny
1

Więc przede wszystkim: czy faktycznie nie da się określić, czy odwołujemy się do konkretnych bitów, czy znaków ASCII?

Z analizy kodu źródłowego można wywnioskować, w jakim kontekście użyto danej wartości - czy określa ilość czegoś, czy jest numerem telefonu, czy wskaźnikiem do pamięci, czy kodem ASCII. Dla komputera to tylko liczby.

Druga sprawa: korzystamy cały czas na rejestrach EAX, EBX,ECX oraz EDX. Wiem, że pierwszy to akumulator, drugi baza, itd.,
Są to rejestry ogólnego przeznaczenia i w większości zastosowań są zupełnie zamienne.

Autor tego programu korzystał jeszcze z indeksu źródłowego SIL - dlaczego akurat ten?
Bo miał takie widzimisię, gdy eax, ebx, ecx i edx już przeznaczył na co innego.
Zresztą rejestr sil jako dolna 8-bitowa połówka rejestru si jest dostępny tylko w trybie 64-bitowym, i to jest jedyny element w kodzie świadczący o tym że jest to tak naprawdę kod x86-64 a nie x86. Cała reszta kodu operuje na rejestrach 32-bitowych.

Shalom
  • Rejestracja:około 21 lat
  • Ostatnio:prawie 3 lata
  • Lokalizacja:Space: the final frontier
  • Postów:26433
1

Korzystamy cały czas z rejestrów EAX, EBX,ECX oraz EDX. Wiem, że pierwszy to akumulator, drugi baza, itd., ale przy jakich konkretnych instrukcjach powinniśmy wybierać który konkretny?

Pytanie jest dość głupie, bo instrukcje ograniczają ci wybór ;] Po prostu niektóre instrukcje automatycznie wymuszają uzycie danego rejestru. Poza tymi wymuszeniami nie musisz się ty przejmować i możesz stosować rejestry zamiennie, jak ci wygodnie.

Autor tego programu korzystał jeszcze z indeksu źródłowego SIL - dlaczego akurat ten?

Bo mu brakło innych? Jakbyś kiedyś spróbował NAPISAĆ jakiś kod a nie tylko "analizować" (w cudzysłowie, bo marna ta twoja analiza) to byś szybko zrozumiał w czym rzecz. Rejestry bardzo szybko się "kończą" ;] Gdyby ten kod był trochę większy to trzeba by pewnie wrzucać rejestry na stos / zdejmować ze stosu. Spróbuj sobie napisać analogiczny kod w C ale stosując tylko 1 albo 2 zmienne typu int. Może wtedy zrozumiesz gdzie jest problem ;)

No i nie rozumiem podziału na długość i tekst - jedno ma odpowiadać za adres, drugie za wpisane do niego bajty.

A ja nie rozumiem o czym ty piszesz. Masz w tym kodzie zwykłą pętlę "for" w której jeden rejestr robi ci za odczytany znak a inny rejestr za licznik pętli. Twój ecx to jest licznik pętli po prostu a sil to dany znak. Coś w stylu:

Kopiuj
for (int i=0;i<19;i++){
    char znak = tablica[i];
}

Gdzie odpowiednikiem i jest ecx a odpowiednikiem zmiennej znak jest sil.
Czy ty masz jakiekolwiek pojęcie o programowaniu że asembler to jest pierwszy język jaki wam pokazali? o_O

Z tymże już 20 komórek używamy na samą etykietę, co totalnie mi utrudnia zrozumienie całości.

Tego to już zupełnie nie rozumiem. Jaką etykietę? WTF? Masz tablicę na 20 elementów i tyle. Etykieta tej tablicy wskazuje tylko na to gdzie się ona zaczyna. Podobnie jak w C gdzie "nazwa tablicy może być zrzutowana do wskaźnika na 1 element". Tu jest identycznie. tekst to adres pierwszego elementu tej tablicy (bloku pamięci), [tekst] to wartość z tego adresu. To tak jakbyś miał tam:

Kopiuj
char* tekst = malloc(20*sizeof(char));

A operator [] robił dereferencje tak jak * w C. Więc odpowiednikiem asemblerowego [tekst] jest *tekst z C. Analogicznie [tekst+5] to *(tekst+5).


"Nie brookliński most, ale przemienić w jasny, nowy dzień najsmutniejszą noc - to jest dopiero coś!"
edytowany 1x, ostatnio: Shalom
0

Sory ale musze to powiedzieć nie każdy jak Shalom wyssał asemblera z mlekiem matki. To że ktoś próbuje zrozumieć ten dość specyficzny język programowania tak różny jak obecny nie zobowiązuje cię do śmieszkowania z poziomu iq delikwenta tylko na podesłaniu jakiś materiałów czy łopatologicznym wytłumaczeniu problemu. Jeśli nie możesz tego zrobić to nie pisz bo burak z ciebie wychodzi

Shalom
A czy ja gdzieś coś o jakimś IQ pisalem? o_O Poza tym nic mnie tu do niczego nie zobowiązuje. Wydaje mi się że wyjaśniłem problem na tyle łopatologicznie że bardziej się już nie da.
Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)