asembler zajawka

Czy warto się uczyć asemblera?

Jak wiadomo języki programowania można pogrupować ze względu na ich „poziom”. Mamy języki wysokopoziomowe takie jak Java czy C#. Pisany w nim kod wystarczy skompilować raz, a potem można go uruchamiać na każdej platformie z odpowiednim środowiskiem wykonawczym. Trochę niżej są języki takie jak C++ czy C (zerknij też na mój wpis „Czy warto się uczyć języka C”). Napisany w nich kod trzeba kompilować ponownie na każdy system operacyjny czy procesor, ale sam kod nie zależy od urządzenia na jakim będzie uruchamiany. No i najniżej znajduje się asembler, czyli język polegający na samodzielnym określaniu jakie instrukcje ma wykonać procesor. Oczywiście zmiana typu procesora na inny wymaga pisania kodu od nowa. No i samo programowanie jest bardzo żmudne. Czy w związku z tym warto w ogóle się uczyć asemblera? Zależy czym się zajmujesz. Dla mnie nie ulega jednak wątpliwości, że jest duża grupa inżynierów, która powinna poznać asembler procesorów, z którymi pracuje. I za chwilę wyjaśnię Ci dlaczego.

Historia 1 - Po co wam ten asembler?

Przypomina mi się taka historia z czasów studiów. Na pierwszym roku w ramach przedmiotu „Architektury komputerów i systemy operacyjne” jako zadanie domowe mieliśmy napisać jakąś funkcję matematyczną w asemblerze dla procesorów z rodziny x86 (czyli powszechnie stosowanych 32 bitowych procesorów Intela). 

Rozmawialiśmy sobie na temat tego projektu w jakiejś grupie znajomych, a rozmowie przysłuchiwał się starszy, bardziej „doświadczony” kolega. Był to człowiek, który chyba jakieś pięć lat wcześniej skończył studia na politechnice i pracował aktualnie jako menedżer kierujący różnymi inżynierskimi projektami.

Słysząc nasze dyskusje na temat zadania domowego i w ogóle całego przedmiotu skwitował temat jednym zdaniem:

„Po co wam w ogóle te wszystkie asemblery”.

asembler sceptyk

Wtedy, mając perspektywę studenta pierwszego roku mogłem tylko spuścić głowę i uznać, że skoro „doświadczony” inżynier ma taką opinię to faktycznie na studiach uczą nas kompletnie nieprzydatnych rzeczy.

Dzisiaj zareagowałbym pewnie inaczej. Ale najpierw historia numer dwa.

Historia 2 - Kłamliwy debugger

Któregoś wieczoru zadzwonił do mnie kolega. Pracował właśnie nad jakimś projektem urządzenia bazującego na mikrokontrolerze STM32 z rdzeniem ARM Cortex M4. To taki dość popularny 32-bitowy procesor z już całkiem dużymi możliwościami jak na małe urządzenia (chociaż Linuxa na nim nie postawisz). Kolega potrzebował pomocy bo jego program nie działał tak jak należy. Jeżeli chcesz poznać trochę szczegółów to czytaj dalej (musisz znać się trochę na programowaniu w C), a jeżeli chcesz przejść do puenty do zapraszam do sekcji „Co się stało?”.

Jak asembler pomógł zrozumieć problem?

Konkretnie chodziło o mniej więcej taki kod:

void lcdBuf_drawText(uint16_t x0, uint16_t y0, uint16_t heightPixels, uint16_t* pBufWidth, const char* text)
{
	int i,j;
	int bitCnt = 0;
	uint16_t x0Tmp = x0;
	uint16_t y0Tmp = y0;

	uint16_t bufWidthTmp = lcd_getStringSize((char*)text);
	uint16_t bufWidth = 0;

	if(bufWidthTmp > (*pBufWidth)) {
		bufWidth = bufWidthTmp;
	}else{
		bufWidth = *pBufWidth;
	}
	*pBufWidth = bufWidthTmp;

	uint16_t bufNoOfPixels = heightPixels * bufWidth;

	/*I coś tam dalej - nieistotne dla nas w tym momencie*/
}

Problem polegał na tym, że w powyższej funkcji po wykonaniu instrukcji:

uint16_t bufWidthTmp = lcd_getStringSize((char*)text);

W zmiennej bufWidthTmp znajdowała się długość tekstu na wyświetlaczu. Była to np. wartość 89. Kolega testował kod przy pomocy debuggera i gdy procesor wykonał instrukcję:

bufWidth = bufWidthTmp;

to do zmiennej bufWidth nie trafiała wartość 89, ale np. 65500. Ewidentnie nie był to błąd w kodzie, więc zaczęliśmy przeglądać kod skompilowany właśnie do poziomu asemblera żeby zobaczyć co się tam właściwie dzieje.

Szybko odkryliśmy, że zmienna bufWidth znajduje się na stosie funkcji lcdBuf_drawText pod adresem 12 bajtów wyższym niż początek stosu. Było to widać np. po tym, że instrukcja:

bufWidth = bufWidthTmp;

została skompilowana do asemblera jako:

str r0, [r7, #12]

i podobny kod tj. [r7, #12znajdował się przy każdym odwołaniu do bufWidth. Znając asembler łatwo mogliśmy dojść do tego, gdzie znajduje się w pamięcie zmienna bufWidth. Przyjmijmy, że był to adres 0x200ff00C.

W kolejnym kroku kazaliśmy wyświetlić debuggerowi adres zmiennej bufWidth czyli wartość instrukcji:

&bufWidth

W efekcie otrzymaliśmy całkiem inny adres dajmy na to, że było to 0x200ff100. Debugger myślał, że zmienna znajduje się w innym miejscu niż kompilator. Po sprawdzeniu zawartości poprawnego adresu okazało się, że jest tam właściwa wartość czyli nasz 89.

Co się stało?

Okazało się, że program działał poprawnie, ale z jakiegoś powodu debugger szukał jednej ze zmiennych w niewłaściwym miejscu pamięci. Dlaczego tak było – nie wiem. W każdym razie udało nam się znaleźć problem tylko dzięki znajomości asemblera dla tego konkretnego procesora. Bez tego nie mielibyśmy szansy rozwiązania tej zagadki.

Warto znać asembler

Warto zwrócić uwagę, że w historii, którą opisałem nie chodziło o jakiś skomplikowany projekt. Nikt nie pisał systemu operacyjnego ani jakiegoś superwydajnego kodu (zwykle z tymi tematami kojarzy się stosowanie asemblera). Problem dotyczył jak najbardziej standardowego projektu systemu opartego na popularnym mikrokontrolerze.

Mam w zanadrzu jeszcze kilka innych sytuacji, w których sięgałem do kodu asemblerowego żeby zrozumieć dlaczego program napisany w C nie działa tak jak należy. Możesz mie wierzyć – od czasu do czasu się to zdarza.

Znajomość tego co kompilator języka C robi pod maską, czyli do jakich instrukcji asemblerowych kompilują się poszczególne instrukcje pozwoli Ci uniknąć wielu niespodzianek.

Jak więc widzisz warto znać asembler nawet wtedy gdy nie planujesz pisać w nim żadnych programów. A jeżeli programujesz małe mikrokontrolery w języku C to poświęcenie odrobiny czasu na zapoznanie się z asemblerem dla konkretnej rodziny procesorów jest moim zdaniem bezsprzecznie dobrym pomysłem.

No i na koniec pozwolę sobie na małą autoreklamę. Jeżeli chcesz zrozumieć dobrze jak działa język C to koniecznie zainteresuj się kursami z naszej platformy: „Podstawy programowania. Język C„, „Zaawansowane programowanie w języku C” oraz „Język C. Poziom ekspert„. Zwłaszcza w tym ostatnim pokazuję jaki jest związek między językiem C a asemblerem i jak wykorzystać tę wiedzę do unikania różnego rodzaju pułapek.

Maciej Kraszewski

Maciej Kraszewski

Inżynier, menedżer R&D i nauczyciel akademicki. Uwielbiam zajmować się tworzeniem nowych technologii, zdobywaniem nowej wiedzy i dzieleniem się swoim doświadczeniem z innymi. Specjalizuję się w zagadnieniach przetwarzania obrazu i widzenia maszynowego.
Szukasz dobrych materiałów o projektowaniu elektroniki?

Załóż darmowe konto na naszej platformie i odbierz pakiet materiałów edukacyjnych.

Zakładając konto zgadzasz się na przesyłanie Ci treści marketingowych przez IT20 sp. z o.o. zgodnie z dostępną na stronie Polityką Prywatności. Możesz wycofać zgodę w każdej chwili.

2 komentarze do “Czy warto się uczyć asemblera?

  • 7 maja 2021 o 17:55
    Permalink

    Dlaczego warto uczyć się asemblera?

    Bo jest po prostu fajny. Super jest mieć 100% kontroli nad tym co się dzieje. Choć należy pamiętać, że to nie znaczy, że nasz kod będzie szybszy niż ten napisany w C.

    Odpowiedz
    • 12 maja 2021 o 19:58
      Permalink

      Świetna uwaga. To prawda – często się skupiamy nad tym czy coś jest praktyczne, a tak naprawdę z takim niskopoziomowym programowaniem jest też świetna zabawa. Co do szybkości kodu to pełna zgoda. Trzeba naprawdę sporej wiedzy o algorytmach i działaniu procesorów żeby napisać w asemblerze kod lepszy niż ten, który wygeneruje kompilator w C. W większości przypadków opinia, że asembler pozwala tworzyć bardziej wydajny kod jest mocno na wyrost.

      Odpowiedz

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *

Szukasz dobrych materiałów o projektowaniu elektroniki?

Załóż darmowe konto na naszej platformie i odbierz pakiet materiałów edukacyjnych.

Zakładając konto zgadzasz się na przesyłanie Ci treści marketingowych przez IT20 sp. z o.o. zgodnie z dostępną na stronie Polityką Prywatności. Możesz wycofać zgodę w każdej chwili.

Zapisz się na listę mailową i odbierz swoje bonusy!

Więcej treści na temat elektroniki i robotyki, darmowe e-booki i dostęp do minikursów on-line. Otrzymasz to wszystko zapisując się na naszą listę mailową.