Moja praca inżynierska

Pierwszy semestr działań związanych z pracą inżynierską za mną, pora więc na małe podsumowanie. Tak jak narzekam na wiele aspektów związanych z moimi studiami, to tym razem zdecydowanie są powody do zadowolenia. Poniżej skrótowy opis rozwój „sytuacji” w moim wypadku.

Prolog

Na koniec poprzedniego semestru należało zadeklarować opiekuna i temat pracowni inżynierskiej. Zadanie zdecydowanie niełatwe, szczególnie gdy ma się tylko garstkę własnych doświadczeń i cudzych opinii na temat poszczególnych ludzi. Temat też należy dobrać z głową, jednak tu już prościej – zwykle wiadomo co kogo interesuje :). Ja szczęśliwie nie miałem problemu z doborem prowadzącego – oczywiście chciałem, aby opiekunem pracy został dr inż. Tomasz Jordan Kruk. Wiązało się to z niemałym, papierkowym rajdem po dziekanatach i sekretariatach, jednak bez większych problemów. Problem był natomiast z precyzyjnym tematem pracy. Wiedziałem tylko, że chcę aby dotyczył on zagadnień niskopoziomowych, związanychz  systemami operacyjnymi. Od słowa do słowa, dostałem propozycję zajęcia się systemem Google Chrome OS… i zgodziłem się bez większych oporów :). Pełne brzmienie tematu zostało wybrane jako Budowa systemu Chrome OS – uroczo prawda? Temat zdecydowanie nieoklepany tzn. nieznany, co mogło się wiązać z pewnymi trudnościami.

Zawiązanie akcji

Kolejne tygodnie po wybraniu tematu wiązały się z przekopywaniem Internetu w poszukiwaniu informacji na temat tegoż tworu. Martwiące było to, iż odnalazłem pełno marketingowego bełkotu, a rzetelnych informacji – jak na lekarstwo. W zasadzie jedyne sensowne źródło wiedzy, to strona projektu z dosyć ubogą dokumentacją. Wyzwania – to lubię! Długa i dokładna analiza materiałów przekonały mnie, że najciekawszym elementem systemu Chrome OS są mechanizmy bezpieczeństwa. Za namową Prowadzącego, przez kolejne tygodnie pracowałem nad pierwszym rozdziałem mojej pracy, który nosi tytuł Mechanizmy bezpieczeństwa systemu Google Chrome OS. Muszę przyznać, że to dopiero było wyzwanie! Myśli i treści wiele, jednak ubranie ich w techniczno-naukowy język to prawdziwa sztuka. Uważam się za osobę, która dba o język polski, dlatego każde zdanie składałem z wielkim namaszczeniem. To nie to samo, co blog, gdzie mogę czasem strzelić emotkę, tudzież całkiem kolokwialne stwierdzenie, czy ohydny anglicyzm ;). Ostatecznie, tempo pisania sięgało jednego (sic!) słowa na minutę. Rewelacyjnie, prawda? Efektem tygodni pracy było 16 stron tekstu, z którego naprawdę jestem zadowolony. Mój Opiekun również docenił moją pracę i podsunął mi pomysł, aby zrobić z tego rodziału materiał konferencyjny bądź artykuł – czemu nie!

W tym miejscu wtrącę słówko na temat składania tekstu. Na mojej uczelni (jak zapewne na wielu innych) lansuje się system składu tekstu o intrygującej nazwie LaTeX. Przeczytanie książeczki o tym narzędziu zajęło mi 2 dni, które przepełniły mnie lekką obawą przed czymś z goła innym niż Word ;). Ostatecznie jednak, praca z LateXem okazała się prawdziwą przyjemnością i zdecydowanie ułatwiła mi pracę. Po prostu mogłem skoncentrować się na samym pisaniu, a  nie na ustawianiu marginesów. Z całego serca polecam wszystkim, do każdego rodzaju pisania (prace, dokumentacje, korespondencja, a nawet CV).

Rozwój akcji

Po napisanym rozdziale przyszła pora na wybranie części praktycznej (bo i z tego powinna się składać praca inżynierska). Tu zaczęły się niemałe problemy, bo rozszerzanie Chrome OS może być trudne i niewykonalne w przewidzianym czasie inżynierki. Szczęśliwie, podczas pisania poprzedniego rozdziału natrafiłem na bardzo ciekawą rzecz: koncepcję kontenerów procesów (jest to mechanizm parawirtualizacji o którym niebawem napiszę więcej). Zrodził się więc pomysł, aby rozszerzyć części składowe kontenerów. Ucieszyło mnie to niezmiernie, gdyż oznacza to dużo grzebania w Linuksie! Kolejne 4 tygodnie spędziłem na poznawaniu budowy Linuksa i oswajaniu się z procesem rozwoju jądra. Temat mnie naprawdę wciągnął i z trudem mogłem oderwać się od czytania artykułów i kodu oraz oglądania nagrań z różnych konferencji o tematyce jądra Linuksa. Finalnie, udało mi się zdecydować na rozwijanie mechanizmu cgroups i nad tym będę pracował w najbliższych tygodniach.

Uważny czytelnik może zauważyć, że od chwili wymyślenia tematu zacząłem dosyć mocno się od niego oddalać – i to jest właśnie najlepsza część mojej pracy inżynierskiej – mogę dowolnie zmieniać jej kształt i prowadzić rzeczywiste, odkrywcze badanie, a nie odtwórcze kompilowanie XX źródeł wiadomości. Aktualnie, wygląda na to, że temat będzie brzmiał Mechanizmy zabezpieczeń w nowoczesnych dystrybucjach Linuksa na przykładzie Chrome OS , ale kto wie co przyniesie przyszłość.

I co dalej?

Tak jak pisałem, będę teraz pracował nad praktyczną częścią pracy. Później przyjdzie pora na kolejne rozdziały – jakie? To się jeszcze okaże.

Mała porada

Wszystkim osobom, które dopiero szykują się do pisania pracy inżynierskiej polecam bardzo dobrze zastanowić się nad doborem opiekuna. Nieważne jak zdolni jesteście, dobry mentor może Wam wiele pomóc. Nie chodzi przecież o to, aby prowadził za rękę i pokazywał co, kiedy i ile napisać, tylko o to, aby odpowiednio kierunkował, podpowiadał i ostrzegał przed potencjalnymi zagrożeniami. Temat natomiast, przy współpracy z odpowiednią osobą, wyklaruje się sam.

Cudowna (?) odmiana

Nie spodziewałem się, że kiedyś taki dzień nastanie, ale jednak! Miniony semestr był.. dosyć przyzwoity! To prawda, że masakrycznie zaniedbałem bloga – bo jak zwykle było multum roboty, a sił i minut w dobie nadal tyle samo. Mam jednak silne wrażenie, że nie cały ten czas zmarnowałem.

Zło

Jako urodzony optymista zacznę od tego, co było kiepskie, złe bądź fatalne. Jest na kierunku przedmiot o hucznej nazwie Bezpieczeństwo systemów i sieci. Sama nazwa budzi skojarzenia z medialnymi tematami hackerów i cyberwojen. Czego można więc spodziewać się po tym przedmiocie? Rzućmy kilkoma przykładami… Studenci zabezpieczający serwery, a następnie włamujący się do nich po to, aby poznać stosowane w praktyce techniki (zarówno dobrych jak i złych „gości”) – może nawet drużynowe potyczki, tak aby zwiększyć zaangażowanie? Analiza fizycznych jak i programowych zabezpieczeń sieci – poznawanie budowy i działania, a może nawet programowanie takich rozwiązań? Podstawy social engineeringu? Przykłady zagospodarowania czasu można mnożyć w zasadzie bez końca – potencjał przedmiotu ogromny! A wykonanie..? Wykład ma taką złą sławę, że moja frekwencja wyniosła okrągłe 0%. Tak, po prostu pojawiłem się tam jeden jedyny raz – na egzaminie zerowym. Co jest z nim nie tak? Materiał tam prezentowany jest bezdennie głupi i nudny. Co wykład, to nowy algorytm kryptograficzny do wkucia na pałę. Oprócz ciągu przekleństw do głowy przychodzi mi jeszcze jedno pytanie: dlaczego tak brutalnie zgwałcono, przedmiot z ogromnymi możliwościami? Czy bezpieczeństwo to rzeczywiście tylko kryptografia? Czy znajomość przebiegu algorytmów jest informatykom w ogóle potrzebna (tym chyba się zajmują się ludzie od kryptologii, tj. matematycy)? Żale możnaby wylewać jeszcze przez 3 ekrany tekstu, ale chyba po prostu szkoda słów. Na zakończenie tematu dodam, że laboratoria są dostosowane poziomem do wykładu. Polegają one na napisaniu sprawozdania z klikania w różnych, niedopracowanych programach, które chyba mają za zadanie ilustrować zagadnienia takie jak szyfrowanie czy podpis cyfrowy. Zgroza!

Oferta edukacyjna mojego wydziału jest tak bogata, że musiałem dokonać wyboru najmniejszego zła – padło na przedmiot o nazwie Programowanie aplikacji interakcyjnych, o jakże uroczym skrócie PAIN (który wszystko tłumaczy). Nie ma co się chyba rozwodzić zanadto nad brakiem sensowności tego przedmiotu, jako że aplikacje interakcyjne (tzn. okienkowe) są od jakiegoś czasu w zaniku. Biorąc ten przedmiot miałem nadzieję, że nauczę się nieco technik i dobrych praktyk programowania aplikacji z widokiem okienkowym, że przy okazji poznam parę trendów w tej dziedzinie i co nieco dowiem się o istniejących rozwiązaniach. Tymczasem (prawie) każdy wykład dotyczył tego, jak rozmieszcza się guziki i pola tekstowe w frameworkach/środowiskach takich jak: X, WinAPI, MFC, Qt, .NET (WinForms). Rewelacja, nie? Czy komukolwiek potrzebna jest wiedza o tym, jak wyświetlić menu w WinAPI, albo o tym na ile okien może dzielić splitter dynamiczny z MFC? Totalna bzdura! Nie muszę chyba dodawać, że potem trzeba było to odtwarzać na kolokwium… Najwstrętniejszą częścią tego przedmiotu były jednak laboratoria. Każde z nich polegało na zrobieniu większego, bądź mniejszego programu w każdej z ww. technologii – kupa zmarnowanego czasu na bieganie po dokumentacji i sklejanie kilkunastu okienek. Oczywiście, jakość kodu i zastosowane techniki absolutnie nie miały żadnego znaczenia i nie były sprawdzane. Liczyło się tylko to, jak ładnie dane okienko wygląda. Jako, że jest to przedmiot obieralny, to z całego serca życzę mu szybkiej śmierci przez brak chętnych.

Dobro

Po wyszczególnieniu tego co złe, przechodzimy do rzeczy przyzwoitych, dobrych i genialnych. Nie będę się rozpisywał o przedmiotach takich jak Prawo własności intelektualnej czy Procesory sygnałowe. Powiem tylko, że były one bardzo lekkie i przyjemne i skutecznie zasiliły konto moich cennych ECTS-ów.

Warto jednak napisać coś więcej o przedmiocie o tajemniczej nazwie Języki przetwarzania symbolicznego. Przedmiot ten przedstawia dwa sztandardowe języki przetwarzania symbolicznego – LISP i Prolog. O ile Lisp był mi trochę znany za sprawą Emacsa, o tyle Prolog był całkowitą nowością. Jako język deklaratywny prezentuje całkiem nowe podejście do programowania – podejście bardzo ciekawe. Przedmiot zaliczam na duży plus, ze względu na pokzanie mi czegoś nowego, na co wcześniej nie zwracałem uwagi. Nie mówię, że było prosto, czy też, że Prolog stał się moją nową pasją, jednak moje horyzonty myślowe zostały poszerzone. I o to w studiowaniu chodzi!

Techniki kompilacji to przedmiot wobec którego miałem duże oczekiwania. Głównie ze względu na to, iż zawsze chciałem podjąć się napisania kompilatora i zobaczenia, jak ta cała magia się dzieje. Moje oczekiwania zostały częściowo spełnione. Wykład był naprawdę przyzwoitym wstępem do parsowania, zabrakło na nim jednak czegoś o optymalizacji kodu i o budowaniu samych kompilatorów. Braki wykładu nadrobił jednak projekt, na którym miałem możliwość napisania interpretera podzbioru języka Python. Projekt był naprawdę bardzo duży (zdecydowanie największy jaki robiłem na studiach) i niezwykle ciekawy. Końcowy efekt był dla mnie bardzo zadawalający, niestety nie miałem jednak czasu, aby dopracować kod, aby jego jakość zaspakajała moje osobiste potrzeby ;). Coś za coś, jak widać. Nie jest to może to samo co kompilator, jednak moja ciekawość i ambicja została w 100% zaspokojone. Zastanawiam się czy by przypadkiem nie upublicznić efektu mojej pracy w celach edukacyjnych, jednak niektóre programistyczne potworki, które się tam kryją mogłyby być bardzo antyedukacyjne ;>.

Przechodząc do tego, co na tym semestrze było najlepsze, zacznę od przedmiotu Systemy wbudowane. Przedmiot ten ze względu na niezwykle rozległą tematykę był bardzo przeglądowy. Udało mi się zdobyć przekrojową wiedzę na wiele tematów związanych z systemami wbudowanymi oraz systemami czasu rzeczywistego. Wykład był prowadzony dobrze i otwarcie a mnogość tematów pozwoliła mi po raz kolejny poszerzyć swoją wiedzę ogólną. Czy to dobrze? Zdecydowanie tak! Po co miałbym się uczyć o charakterystyce sygnałów sterujących w sieci polowej PROFIBUS – wystarczy mi wiedza, że taka sieć jest i co mogę dzięki niej osiągnąć! Laboratoria i projekt polegały na zapoznaniu się z systemem operacyjnym VxWorks – muszę przyznać, że to bardzo ciekawe, jednak niekiedy męczące, doświadczenie. Przedmiot na duuuuuuuuuży plus!

Na sam koniec, tradycyjnie – wisienka na torcie: Sterowniki urządzeń – podstawy programowania. Mógłbym długo „ochać” i „achać” na temat tego przedmiotu, ale może po prostu opiszę o czym on jest ;). Przedmiot jest o tworzeniu sterowników do urządzeń wszelkiej maści (mocno w kontekście systemów wbudowanych) w systemie Linux. Myślę, że ciężko byłoby mówić ogólnie, w oderwaniu od konkretnej implementacji, a więc wybór konkretnego systemu jest jak najbardziej słuszny. Wybór Linuksa też jest jak najbardziej na plus, gdyż ma to dużą wartość edukacyjną – przede wszystkim można przejrzeć jak coś jest zrobione, a nie polegać ślepo na dokumentacji. Przedmiot więc koncentruje się na grzebaniu głęboko w jądrze systemu – czyli to, co lubię najbardziej :). Wysoki poziom komplikacji materii i slajdy z kodem mogły niektórych przerażać, ale na tym polega przecież praktyczne podejście do sprawy. Do świetnego wykładu niezwykle ważnym dodatkiem jest projekt, który polega na stworzeniu sterownika do dowolnego urządzenia, na dowolnej platformie (niekoniecznie Linux, mógłbyć też np. dowolny mikrokontroler). Mojemu projektowi poświęce oddzielnego posta, bo myślę, że jest tego wart :).

Świetność tego przedmiotu należy w 100% przypisać prowadzącemu, panu dr inż. Wojciechowi Zabołotnemu. Pan doktor Zabołotny, dzięki swojej niezwykle rozległej, wszechstronnej i praktycznej wiedzy uczynił z wykładu prawdziwe widowisko, na które pomimo piątku i późnej pory przychodziłem z ogromną przyjemnością. Wszystkim studentom, z całego serca życzę takich prowadzących.

Reasumując, dzięki temu przedmiotowi dowiedziałem się masę ciekawych rzeczy związanych z jądrem Linux, systemami wbudowanymi i problemami jakie można napotkać podczas pracy ze sprzętem. Dokładnie to, czym chciałbym się zajmować. Dziękuję!

Ostatni semestr

W końcu udało mi się ukończyć semestr, w którym większość rzeczy zaliczyć mogę na plus. 6 semestr z 7 semestrów studiów inżynierskich – wynik niezbyt imponujący – coż, podobno lepiej późno niż wcale. To, czego jednak znów mi zabrakło, to więcej wolnego czasu na rozwój własnych zainteresowań.

Na zakończenie wspomnę, że przede mną ostatni semestr studiów inżynierskich, który poświęcę w zasadzie w całości (został mi tylko jeden przedmiot – algorytmy heurystyczne) pisaniu pracy dyplomowej. Ze względu na uczelniane wymogi pisanie inżynierki zacząłem już w minionym semestrze – i o tym napiszę w następnej notce.

I znowu porażka

To uczucie gdy…

Zapewne nieobce każdemu jest uczucie, gdy wydaje się, że „już gorzej być nie może”, a potem okazuje się, że no właśnie – wydawało się. Po semestrze numer cztery wydawało mi się, że gorzej być nie może – a tu proszę, taka niespodzianka! Semestr piąty przekroczył wszelkie granice beznadziejności, które ustanowili poprzednicy. Słyszałem pogłoski, że po dwóch pierwszych latach jest już luźno i przyjemnie – akurat!

To złe

Długo „stygłem” zanim napisałem tego posta. Gdybym napisał go od razu po zakończeniu sesji, byłoby w nim zbyt wiele nieprzyzwoitych określeń ;>. W ciągu tych 15 tygodni semestru „zaliczyłem” około 20 bezsennych nocy, spędzonych na roztrząsaniu rozmaitych „mądrości”. Wynika stąd, że średnio w każdym tygodniu nie spałem ponad jedną noc! Być może jestem zbyt ambitny, ale ja po prostu staram się wykonać zlecone mi zadania dobrze. Jak widać w prosty sposób odbija mi się to na zdrowiu, a także kontaktach towarzyskich, zainteresowaniach no i blogu. Do pierwszej fali kolokwiów udawało mi się pisać regularnie i to z nawet dobrym skutkiem. Potem odpadłem. Każdą wolną chwilę, którą jakimś cudem udawało mi się wyrwać szkole wolałem poświęcić na sen, spotkanie z ludźmi i niestety – na blog, czy też rozwijanie zainteresowań czasu już nie było. Czy studia tu są tego warte? Przemyślenia na ten temat pozostawię sobie na oddzielną notkę.

Teraz może wspomnę o garstce (z baaaaardzo wielu) absurdów, które spotkały mnie w tym semestrze. Przede wszystkim wyjątkowo dokuczliwa okazała się tzw. profesorska duma. Niestety, wiele osób pracujących na uczelni w roli wykładowcy/laboranta w ogóle nie przykłada się do swojej pracy. Ich stosunek do prowadzenia zajęć jest delikatnie mówiąc olewczy. Materiał jest przygotowany niedbale, czesto jest bardzo mizerny merytorycznie, albo mówiąć wprost – zawiera rażące błędy. Nie jest to jednak najbardziej denerwująca cecha – bardziej wkurzające jest to, że często właśnie te osoby nie potrafią się przyznać do swojego błędu czy też niewiedzy. Warto być przecież prawdziwym, nieomylnym twardzielem, nie? Dodajmy do tego poniżające odniesienie do studenta (bo co takiemu pro-fesorowi student, pff!) i katastrofa gotowa. Przykłady z życia wziętę? Jeden z prowadzących postanowił przepisać na slajdy tłumaczenie książki, a następnie na wykładzie pracowicie, przez dwie godziny odczytywał je nużącym głosem. To ma być wykład? Jeśli tak, to wykładowcą może być absolutnie każdy, kto potrafi czytać, bo to jedyne, co ten prowadzący zaprezentował swoją osobą. Inny wykładowca z kolei prowadził wykład chaotycznie i niedbale, a żeby zaliczyć przedmiot zalecał przeczytanie książki.. którą oczywiście sam napisał (to, że lansuje tam własny, często rozbieżny z rzeczywistością, ogląd tematu – przemilczę). Dodatkowo oceny z tego przedmiotu wydawały się pochodzić wprost z /dev/random, a liczba „uwalonych” po pierwszej turze przekraczała 50%. Czyja to wina? To chyba oczywista sprawa. Na innym przedmiocie spotkałem się z kolei z laborantem, który nie potrafił się przyznać do swojej niewiedzy – a była ona ogromna, bo niestety wydaje mi się, że został do przedmiotu wybrany przez przypadek. Oczywiście – mógł się przygotować, ale komu by się chciało? A może po prostu nie można zbyt wiele oczekiwać od programistów Javy ;>?

Nuda, nuda, nuda. Tak można scharakteryzować wykład z przedmiotu, który wydawał mi się ciekawy – z tytułu i opisu. Nużący, monotonny głos, patrzenie w podłogę, zerowy kontakt ze studentem – tak można scharakteryzować prowadzącego ten wykład. Człowiek ten na dobre obrzydził mi dziedzinę informatyki, którą kiedyś bardzo lubiłem. Szkoda.

Merytoryka – a raczej jej brak – najbardziej mnie boli. Zdarza się to dosyć często, a koronnym przykładem na moich studiach jest przedmiot o grafice komputerowej. O ile wykład był znośny (może nawet dobry dla kogoś zainteresowanego jakkolwiek tematem?), to już laboratoria zdecydowanie nie. Jak myślicie, co można robić na laboratoriach z przedmiotu o tytlue „grafika komputerowa”? Gdy sam sobie zadałem to pytanie miałem kilka pomysłów – podstawy silników graficznych (budowanie/modyfikacje/analiza), projektowanie/implementowanie algorytmów związanych z grafiką, pisanie sterowników graficznych. Tymczasem okazuje się, że na laboratoriach rysuje/edytuje się obrazki w programch graficznych i modeluje obiekty 3D! Prawdziwy absurd! To jest informatyka na Politechnice Warszawskiej, czy może ASP, tudzież grafika na PWSFTViT? Może warto jeszcze zrobić jakiś przedmiot z nauką Excela i Worda, przecież to też robi się na komputerze! Wydaje mi się, że osoba, która układała materiał na te laboratoria kompletnie nie miała pomysłu na czym mogą polegać albo brakowało ludzi z odpowiednimi umiejętnościami (i lepiej, żeby to był ten pierwszy powód…).

Na dobre zakończenie semestru spotkała nas studentów jeszcze bardzo „miła” niespodzianka. Mianowicie, na 6 semestrze mamy do zrobienia 4-6 przedmiotów, które sami wybieramy. W kwietniu zeszłego roku została przedstawiona oferta programowa liczącą kilkanaście przedmiotów. Okej, niezbyt bogata, ale można już było się zastanowić, co warto wybrać. Przyszedł moment wyboru i… okazało się, że połowy z tych przedmiotów nie ma – części nie można wziąć, a inne w ogóle nie zostały utworzone. Wszelkie skargi i pretensje zostały odrzucone metodą przerzucania odpowiedzialności na kogoś innego – i tak studenci zostali na lodzie. Cały „szeroki” wybór przedmiotów został ograniczony do wybierania „mniejszego zła”, czyli przedmiotów, które cieszą się lepszą sławą od pozostałych. I to mają być studia elastyczne – kpina! Nie wątpię oczywiście, że odpowiedzialni za ten bałagan się nie znajdą.

Podobna, miła sytuacja „administracyjna” miała miejsce na początku semestru, gdy to dziekanat dobroczynnie dał stypendia studentom, a nieco później okazało się, że trzeba je odebrać. Sprawa była moim zdaniem mocno skandaliczna, ale powiedzmy, że postarałem się już o tym zapomnieć.

I to dobre

Szczęśliwie, semestr ten miał kilka miłych akcentów. Przede wszystkim udało mi się dostać do najlepszego z możliwych opiekunów pracy inżynierskiej! Niezmiernie mnie to cieszy, bo wiem że pisanie jej, będzie dzięki temu prawdziwą przyjemnością. Postaram się o tym wspomnieć na blogu w niedługim czasie :).

Dodatkowo na semestrze tym miałem przyjemność uczestniczyć w 3 niezłych wykładach, które jakoś wzbogaciły moją wiedzę. Pierwszy z nich dotyczył technik internetowych – przekrojowo o różnych sprawach związanych z aplikacjami internetowymi; drugi był o systemie UNIX (nota bene, ten sam prowadzący co techniki internetowe) – opis API, a także wewnętrznych mechanizmów; trzeci natomiast dotyczył sztucznej inteligencji – co prawda pierwsza połówka dotyczyła wnioskowania i była naprawdę paskudna (zarówno pod względem materiału jak i prowadzącego), ale druga była naprawdę ciekawa i zainteresowała mnie tematem.

Ostatnim miłym elementem semestru były projekty – doskonała okazja, żeby posiedzieć z kolegami, napić się piwa, zjeść pizzę, a przy tym rozwiązać ciekawe zagadnienia :)! Kod, to jest jednak to, co cieszy programistów najbardziej :P.

Plany?

Nie. Kiedyś pisałem, o tym jakie przedmioty będę robić w nadchodzącym semestrze i czego od nich oczekuję, jednak po przeszłych doświadczeniach wiem, że należy wyłącznie oczekiwać, że będą one mało upierdliwe. O dobry, wysoki poziom jest bardzo ciężko, niech więc chociaż nie przeszkadzają w mojej własnej edukacji.

Koncepcja pamięci wirtualnej

Pamięć

Jednym z zadań systemu operacyjnego jest zarządzanie zasobami – tzn. przydzielanie ich i odbieranie wykonywającym się programom. Pamięć, zaraz po czasie procesora, jest najważniejszym i zarazem najpopularniejszym zasobem, który używany jest przez procesy. Jak pokazuje historia, rozwój pamięci jest bardzo szybki – IBM 7094 z 1962 roku miał standardowo około 150 KiB pamięci, a sam komputer kosztował 3.5 mln USD. Na dzień dzisiejszy, przeciętny komputer ma 10000 razy więcej pamięci i kosztuje 10000 razy mniej :). Z drugiej strony, programy rozrastają się jeszcze szybciej niż dostępna pamięć – 1 MiB wystarczał kiedyś, żeby polecieć w kosmos, natomiast Windows Vista ledwo zipie na komputerze z 1 GiB pamięci ;).

Pamięci powinno być dużo – najlepiej nieskończenie dużo. Do tego jeszcze warto, aby była ona nieskończenie szybka, nieulotna i tania. Niestety – nie da się! W ramach rozwiązania tego problemu wprowadzono koncepcję hierarchii pamięci. Zgodnie z nią komputery wyposażone są w nieco bardzo szybkiej, małej i drogiej pamięci (rejestry, cache); w dużo szybkiej i niedrogiej pamięci (RAM) oraz w ogromnie dużo, bardzo wolnej, ale bardzo taniej pamięci (HDD, DVD itd.). Do wygodnej pracy z taką hierarchią niezbędne jest stworzenie pewnej abstrakcji, która pozwalałaby nie przejmować się tym, czy operujemy na cache’u, RAM-ie, czy wczytujemy wymiecione programy z dysku – ale o tym za chwilę, na razie zajmijmy się najprostszym przypadkiem.

Brak abstrakcji

W tym modelu zarządzania pamięcią, każdy wykonywający się program operuje bezpośrednio na pamięci fizycznej (RAM) – wykonanie instrukcji mov [0x9000], 24 spowoduje wpisanie wartości 24 pod adres 0x9000. Wydaje się to intuicyjnie oczywiste, jednak pociąga to za sobą wiele skomplikowanych problemów. Przede wszystkim ciężko tu zapewnić ochronę – procesy mogą odczytywać i zapisywać pamięć, która nie należy do nich. Do tego, każdy proces musi wiedzieć gdzie został załadowany tak aby instrukcje odwoływania się do pamięci były poprawne. Każdy proces musi również znać i przestrzegać limitów pamięci, które raczej powinny być sztywne. Wszystkie te problemy starano się jakoś rozwiązać i tak np. wprowadzono podział pamięci na pewne zakresy, które przypisywane były procesom poprzez odpowiednie znaczniki. Inny sposób zakłada natomiast wymiatanie całej pamięci na dysk, wybranie kolejnego procesu do wykonania, a następnie wczytanie całej jego pamięci z dysku – jest to rozwiązania wyjątkowo nieefektywne. Dokładniejsze studium przypadku ujawnia wiele kolejnych problemów – np. alokacja dużej tablicy (ciągłej!) w pofragmentowanej przestrzeni może się okazać niemożliwe – potrzebny jest wtedy mechanizm relokacji. Na wiele problemów związanych z brakiem abstrakcji znajdziemy pewne (lepsze lub gorsze) remedium, niestety niektórych rzeczy obejść się nie uda – np. potrzeby powiększenia przestrzeni adresowej ponad dostępna pamięć fizyczną. Na koniec warto jednak dodać, iż całkowity brak abstrakcji na pamięci jest wciąż popularny i uzasadniony – w systemach wbudowanych. Procesy działające w takich systemach są zwykle małe i zaufane – nie potrzebna jest im szczególna ochrona, czy wygoda programowania.

Pamięć wirtualna

Wirtualny – słowo często używane w informatyce, nie zawsze poprawnie, nie zawsze świadomie :). Ciekawy tego co mówi na ten temat słownik języka polskiego – sprawdziłem i zdziwiłem się co nie miara. Nic więc dziwnego, że dezinformacja się szerzy :D. Mówiąc wymijająco (ale za to prawdziwie) – to co znaczy wirtualny – zależy od kontekstu :). Wracając jednak do tematu…

Pamięć wirtualna to mechanizm zapewniający wykonywającemu się programowi dostęp do pełnej, niezależnej od innych procesów przestrzeni adresowej. Przestrzeń ta w szczególności nie musi odpowiadać pamięci fizycznej (co jest sytuacją typową) – może być nieciągła, pofragmentowana i przechowywana na nośnikach trwałych (dysku). Zachodzi więc pewne mapowanie adresu wirtualnego (na którym operuje proces) na adres w pamięci fizycznej. To podejście rozwiązuje nam wszystkie problemy związane z ochroną (oddzielne przestrzenie adresowe = brak możliwości „wchodzenia sobie w drogę”), ładowaniem do pamięci (procesy mogą być np. ładowane pod stały adres), nieciągłością przy alokacji tablic (sprawę załatwia mapowanie – ciągły obszar mapowany jest na nieciągły, który był aktualnie dostępny). Nie ma rzeczy idealnych, więc łatwo się domyślić, że muszą być jakieś wady. Tak jest i tym razem. Pamięć wirtualna znacząco komplikuję budowę architektur (potrzebna jest jednostka zarządzania pamięcią), a także powodują pewien narzut związany z pośredniością, co może mieć znaczenie np. w systemach czasu rzeczywistego.

Dla uzupełnienia dodam, że pamięć wirtualną buduje się w oparciu o pamięć RAM i urządzenia dyskowe. Wspomniany wcześniej cache jest w zasadzie dla programisty i systemu operacyjnego przezroczysty (podsystemy architektury decydują o tym, co ma być cache’owane), a rejestrami zajmują się kompilatory i programiści assemblera (i tak nie przydałyby się w budowaniu pamięci wirtualnej).

Praktycznie

Praktycznie rzecz ujmując pamięć wirtualna jest jak najbardziej pożądana (oprócz wspomnianych systemów czasu rzeczywistego) i w zasadzie nie spotyka się w dużych komputerach jej braku. Pamięć wirtualną realizować można na dwa sposoby – za pomocą segmentacji oraz za pomocą stronicowania (o którym w następnym wpisie), z czego tak jak pisałem, ta druga metoda jest zdecydowanie popularniejsza.

„Daj się poznać” – pierwsze miejsce! Dziękuję!

Konkurs zorganizowany przez Maćka Aniserowicza dobiegł końca. Wg oficjalnych wyników zająłem w głosowaniu pierwsze miejsce! Cóż tu dużo pisać – ogromnie się cieszę, że praca wykonana przez te 3 miesiące spodobała się Czytelnikom. Tak jak już wspominałem jest to najlepsze motywacja, aby dalej aktywnie pracować nad projektem i blogiem – i tak w rzeczy samej będzie :).

Bardzo dziękuję Maćkowi i chylę czoła za trud i zaangażowanie, które włożył w przygotowanie konkursu. Ta inicjatywa to świetny pomysł na rozruszanie polskiego środowiska programistów. W moim wypadku, konkurs sprawił, że mój blog ożył, zyskał wielu nowych czytelników i osiągnał poziom, z którego w końcu jestem zadowolony.

Dziękuję również Czytelnikom – to w końcu dzięki Wam udało mi się zdobyć tak dobry wynik :). Szczerze powiedziawsz, nie spodziewałem się, że projekt nie .NETowy ma szanse na miejsce choćby w pierwszej piątce!

Dziękuję i gratuluję wszystkim Współzawodnikom, bez których konkurs nie byłby taki ciekawy. Sporo nowych, niezwykle ciekawych blogów dołączyło do mojego czytnika RSS :).

Teraz, po zakończeniu konkursu, powstało całkiem nowe zadanie – nie zawieść oczekujących na kolejne wpisy. Tak sobie myślę, że może być to trudniejsze niż sam udział w konkursie, bo jak wiadomo bez „bata nad głową” pracuje się ciężej :). Zrobię jednak wszystko co w mojej mocy, żeby nie rozczarować!

PS. Kolejny post na temat systemów operacyjnych już w przyszłym tygodniu! Natłok rozmaitych zajęć sprawił, że o wynikach konkursu dowiedziałem się od kolegi, a ten post ukazał się 3 dnia po ogłoszeniu wyników – proszę więc o wyrozumiałość ;).

„Daj się poznać” – finał!

Udało się! Dostałem się do finałowej siedemnastki konkursu Daj się poznać. Dziękuje wszystkim współzawodnikom, którzy oddali na mnie swój głos :) Jednocześnie zwracam się do wszystkich Czytelników, którym moje posty przypadły do gustu, z prośbą o oddanie na mnie głosu. Możecie to zrobić tutaj. Wasze uznanie dla mojej pracy, to najlepsza zachęta do dalszego, intensywnego pisania. Z góry dzięki! :)

„Daj się poznać” – sukces!

Statystyka

W zeszłym tygodniu minął 10 tydzień pracy nad moim projektem. Na blogu, łącznie z tym, wiszą 23 posty otaggowane „daj się poznać”. 20 z wymienionych, to posty stricte konkursowe, 6 z nich to posty dotykające projektu bezpośrednio, pozostałe 14, to potężna dawka wiedzy przydatnej podczas tworzenia systemu operacyjnego. 3 posty trafiły na dotnetomaniaka, generując znaczny ruch :) Najbardziej popularnym postem, był nieco kontrowersyjny wpis Edytor tekstu zamiast wypasionego IDE?. Skandalizowanie zawsze w cenie? ;>

Kod?

Zabrzmi to śmiesznie, ale projekt ma w obecnym stadium poniżej 100 linii. To dużo i mało jednocześnie. Dużo, gdyż wiedza potrzebna i zalecana do napisania tych <100 linii jest naprawdę obszerna. Mało, gdyż to wciąż tylko <100 linii, gdy inne projekty konkursowe mają ich tysiące. Tak jak wspominałem, projekt nie stanowi pełnoprawnego „produktu”, a jest przedmiotem swoistych badań – i w takiej formie idealnie się sprawdza.

Słodki smak sukcesu

Swój udział w konkursie uważam za ogromny sukces, niezależnie od miejsca, które zajmę. Dzięki Maćkowi, zmobilizowałem się do regularnego pisania postów (choć bywało ciężko). Pokazałem sam sobie, że się da. Jak się okazało – najtrudniej jest zacząć. Bolączką mojego bloga były naprawdę sporadyczne i nietematyczne posty – teraz to się zmieniło. Kolejnym aspektem sukcesu jest pozytywna informacja zwrotna, którą dostałem. Wszystkim, którzy pozytywnie wyrazili się na temat mojej pracy serdecznie dziękuję – to niesamowita motywacja do dalszego działania.

Co dalej?

Projekt i seria postów na temat tworzenia systemu operacyjnego na pewno nie skończy się wraz z konkursem. Całość mam zamiar jeszcze dłuuuuugo kontynuować. Nie mogę zagwarantować, że posty dalej będą pojawiać się tak regularnie, jak przez czas trwania konkursu, postaram się jednak pisać jak najczęściej.

Na koniec

Jeśli seria postów konkursowych przypadła Ci do gustu drogi Czytelniku, nie zapomnij zagłosować na mnie po 15 listopada! Tak czy inaczej, zachęcam do subskrypcji mojego bloga i regularnego zaglądania tutaj! Będzie coraz lepiej – gwarantuję!

Tworzenie systemu operacyjnego – część 0×05: Multiboot Specification

Multiboot Specification

Multiboot Specification jest próbą stworzenia ustandaryzowanego sposobu bootowania systemów operacyjnych. Chodzi o to, aby każdy bootloader zgodny z Multiboot Specification był w stanie bootować każdy system operacyjny również zgodny z Multiboot Specification. Ma to ułatwić tworzenie środowisk z wieloma systemami operacyjnymi.

Multiboot Specification nie definiuje tego, jak ma być napisany bootloader, a jedynie odpowiedni interfejs. Referencyjną implementacją Multiboot Specifciation jest GNU GRUB. Wiele systemów operacyjnych (np. Linux), bootloaderów i maszyn wirtualnych (np. QEMU) jest zgodnych z tą specyfikacją, więc nie jest ona tylko teoretycznym dokumentem. Niezwykle istotną cechą bootloaderów zgodnych z Multiboot Specification jest to, że są one w stanie bootować kernel skompilowany do popularnych formatów plików wykonywalnych np. ELF. Dzięki temu możemy korzystać ze wszelkich dobrodziejstw, które formaty oferują.

O konkretnych cechach Multiboot Specification wspomnę przy okazji kodu, poniżej.

Multiboot Specification mam i ja!

W swoim projekcie systemu operacyjnego postanowiłem porzucić własny bootloader na rzecz bootloadera zgodnego z Multiboot Specification. Może się to wydawać dziwne, bo napisanie całego kodu związanego z bootowaniem zajęło mi sporo czasu, ale tak naprawdę ma to głębokie uzasadnienie. Przede wszystkim, mój bootloader jest bardzo ubogi i prosty – nie potrafi bootować żadnych formatów plików wykonywalnych, a jedynie płaskie binarki, co jest niezwykle uciążliwe, gdyż muszę polegać na magicznych stałych. Ponadto nie dostarcza on żadnych informacji systemowi operacyjnemu – wszystko trzeba zrobić samodzielnie. Oczywiście, można napisać ten kod samodzielnie… Jednak uważam, że nie jest on wystarczająco pasjonujący, aby się nim zajmować :). Dzięki Multiboot Specification będziemy mogli przestać zajmować się szczegółami, a przejść do rzeczy :).

Kod – czyli co my musimy zrobić dla Multiboot Specification, a co on zrobi dla nas?

Na chwilę musimy powrócić do assemblera, aby dostarczyć kilku informacji wymaganych przez bootloader i od razu możemy skoczyć do kodu w C.

global loader				; set visible to linker
extern main				; main from main.c
 
; some useful macro values
FLAGS		equ	0		; this is the multiboot 'flag' field
MAGIC		equ	0x1BADB002	; 'magic number' lets bootloader find the header
CHECKSUM	equ	-(MAGIC + FLAGS); checksum required
STACKSIZE	equ	0x4000		; 16 KiB for stack
 
section .text
align 4
; setting multiboot header
multiboot_header:
	dd	MAGIC
   	dd	FLAGS
   	dd	CHECKSUM
 
loader:
	mov	esp, stack + STACKSIZE	; set up the stack
	push	eax			; pass multiboot magic number as second parameter
	push	ebx			; pass multiboot info structure as first parameter
 
	call	main			; call C code
 
section .bss
align 4
stack:
   	resb 	STACKSIZE		; reserve stack space

Najbardziej istotne są makra z linii 5-7. Pierwsze z nich określa flagi, które informują bootloader, czego od niego oczekujemy. Wśród możliwych opcji jest: wyrównanie modułów do rozmiaru strony, dołączenie mapy pamięci oraz dostępnych trybów video. Po więcej informacji zapraszam tu. Póki co, nie potrzebujemy niczego, stąd wartość 0. Drugie to wartość magiczna, która pozwala bootloaderowi zidentyfikować nagłówek. Liczba 0x1BADB002 jest urocza, prawda? :) Trzecia wartość, to suma kontrolna, która powinna mieć wartość, taką że dodana do pól: FLAGS i MAGIC daje zero.

Kolejne linijki są oczywiste. W sekcji kodu musimy zamieścić kolejno wartość magiczną, flagi oraz sumę kontrolną, co dzieje się w liniach 14-16. Etykieta loader to rzeczywisty punkt wejściowy naszego jądra. W wierszu 19 ustalamy początek stosu, na którego miejsce rezerwujemy w sekcji bss (linia 28). Istotne jest, aby miejsce rezerwowane było w sekcji bss, bo inaczej rezerwacja będzie polegała na stworzeniu dużego pliku z wieloma zerami, a przecież nie o to nam chodzi. Etykieta bss załatwia sprawę – kompilator „wie”, że tylko rezerwujemy przestrzeń w odpowiednim miejscu w pamięci. Następnie w liniach 20 i 21 odkładamy zawartość dwóch rejestrów na stos (istotna jest kolejność – jeśli masz wątpliwości czemu pierwsza instrukcja odpowiada drugiemu parametrowi, spójrz do konwencji wołania) tak, aby przekazać je do funkcji main, którą wołamy w linii 23. Znaczenie przekazanych parametrów omówię poniżej.

Spójrzmy teraz na kod jądra w C:

char hello[] = "Hello from kernel!";

int main(void* mbd, unsigned int magic)
{
	int count = 0;
	int i = 0;
	unsigned char *videoram = (unsigned char *) 0xB8000; /* 0xB0000 for monochrome monitors */

	if ( magic != 0x2BADB002 )
	{
		/* something went wrong.. */
		while(1); /* .. so hang! :) */
	}

	/* clear screen */
	for(i=0; i<16000; ++i)
	{
		videoram[count++] = 'A';
		videoram[count++] = 0x00; /* print black 'A' on black background */
	}

	/* print string */
	i = 0;
	count = 0;
	while(hello[i] != '\0')
	{
		videoram[count++] = hello[i++];
		videoram[count++] = 0x07; /* grey letters on black background */
	}

	while(1); /* just spin */

	return 0;
}

Widzimy, że tym razem do funkcji main przekazane są dwa parametry, które włożyliśmy na stos. Pierwszy z nich to struktura informacyjna dostarczona przez bootloader, która zawiera informacje zarządane za pomocą flag. Druga, to kolejna wartość magiczna, infomująca nas o tym, czy wszystko poszło prawidłowo. Tym razem jest to 0x2BADB002. W liniach 41-45 widzimy bardzo prymitywną :) obsługę sytuacji błędnej. Reszta kodu jest taka, jak w odcinku poprzednim.

Co tak właściwie się stało? Specyfikacja Multiboot zapewnia nam że:

  • rejestr EAX będzie zawierał magiczną wartość 0x2BADB002, jeśli jądro zostało prawidłowo załadowane (stąd wkładanie rejestru EAX na stos w pierwszym przedstawionym kodzie)
  • rejestr EBX będzie zawierał adres struktury informacyjnej z danymi zażądanymi we fladze (stąd wkładanie rejestru EBX na stos w pierwszym przedstawionym kodzie)
  • linia A20 będzie aktywowana
  • rejestry segmentowe będą ustawione tak, aby realizowany był płaski model pamięci
  • będzie aktywowany tryb chroniony procesora
  • bit 17 i 9 rejestru EFLAGS będzie zgaszony

Jak widać, Multiboot Specification zapewnia nam wszystko, co poprzedni bootloader oraz sporo więcej. Więcej na temat struktur i gwarantowanego stanu tutaj.

Skrypt linkera pozostaje prawie bez zmian. Istotne jest, że tym razem musimy zdefiniować punkt wejściowy naszego programu (jądra), czyli etykietę loader oraz to, że możemy zażądać, aby nasz kernel został załadowany daleeeeeko za granicą 1MiB! Ja ładuję go zaraz za tą granicą:

ENTRY (loader)

SECTIONS {
    . = 0x00100000;

    .text : {
        *(.text)
    }

    .rodata ALIGN (0x1000) : {
        *(.rodata)
    }

    .data ALIGN (0x1000) : {
        *(.data)
    }

    .bss : {
        *(.bss)
    }
}

Uważny czytelnik zauważy ustawienie wyrównań (polecenia ALIGN), które jednak aktualnie nie mają dużego znaczenia, więc nie będę ich omawiał.

Pozostała nam kompilacja do formatu elf w wariancie dla architektury i386 (x86):

nasm -f elf -o ./bin/loader.o loader.asm
gcc -o ./bin/main.o -c main.c -m32 -nostdlib -nostartfiles -nodefaultlibs
ld -melf_i386 -T linker.ld -o ./bin/kernel.bin ./bin/loader.o ./bin/main.o

Oraz uruchamianie:

qemu -kernel ./bin/kernel.bin

Użycie QEMU może być zdziwieniem, gdyż nie używamy tu żadnego bootloadera typu GRUB. QEMU jednak, tak jak wspominałem, posiada wbudowany bootloader zgodny z Multiboot Specification. Włącza się go za pomocą przełącznika -kernel. Jeśli ktoś jednak bardzo chce może użyć GRUBa.

To tyle, nasz stuningowany kernel powinien działać.

NIH

Jestem zwolennikiem unikania syndromu NIH, stąd decyzja o użyciu dobrze napisanego i przetestowanego bootloadera zgodnego z Multiboot Specification. Stan naszej wiedzy nie ucierpiał na tej decyzji, gdyż mamy już za sobą napisanie prostego bootloadera :). W przyszłości będzie można do niego wrócić i wzbogacić go o ładowanie plików w formacie ELF i jeszcze kilka ficzerów. Na razie jednak, zajmijmy się tym co najważniejsze, czyli jądrem naszego systemu operacyjnego.

Tradycyjnie, pełen kod odcinka można pobrać tak:

git clone git://github.com/luksow/OS.git --branch 0x05

Lub obejrzeć go tu.

Pliki wykonywalne/obiektowe

Co to?

Uruchomienie programu to czynność oczywista, która polega, z grubsza (w zależności od systemu operacyjnego), na dwukliku na ikonę „pliczek.exe”, wykonania w terminalu polecenia „./kodzik” lub wybrania odpowiedniej pozycji z menu telefonu. Niewiele osób zastanawia się, co tak naprawdę kryje się za wspomnianymi plikami, które powodują uruchomienie programu – nie jest to też wcale takie oczywiste.

Pliki te nazywa się najczęściej wykonywalnymi. Niestety, jak to często bywa, nie ma ogólnoprzyjętego zestawu nazewnictwa i definicji, stąd liczne nieporozumienia między określeniem „plik wykonywalny”, a „plik obiektowym” (polska nazwa jest dla mnie dziwna, po angielsku to object file) – spróbujmy to jakoś ogarnąć. Plikiem obiektowym, najwygodniej jest nazywać każdy plik, który zawiera uporządkowane sekcje kodu maszynowego (składającego się z instrukcji). Dodatkowo, w takim pliku mogą, ale nie muszą, znajdować się dane oraz metadane. Plik wykonywalny, to natomiast rodzaj pliku obiektowego, który może być bezpośrednio wykonany pod kontrolą systemu operacyjnego. Innym przykładem pliku obiektowego może być np. biblioteka dynamiczna/współdzielona.

Wszystkie pliki obiektowe są zapisane na dysku w pewnym ustalonym formacie, zależnym od systemu operacyjnego, w którym mają być uruchamiane. Format ten definiuje w jaki sposób w pliku zapisane są instrukcje, dane i metadane. Instrukcje to po prostu kod maszynowy, dane to wszelkie zmienne i struktury, które są zdefiniowane bezpośrednio w źródle (np. zmienne statyczne, łańcuchy znaków). Metadane to natomiast bardziej skomplikowana sprawa. To, co wchodzi w ich skład zależy przede wszystkim od samego formatu – jego przeznaczenia. Metadanymi są np.: identyfikator formatu (który często jest po prostu „magicznymi liczbami”) umieszczony w nagłówku, wskazówki na temat relokacji, informacje dla debuggera, tablica symboli. To na podstawie metadanych pliku wykonywalnego system operacyjny „wie”, jak rozmieścić kod i dane programu w pamięci i skąd w zasadzie zacząć jego wykonywanie. Metadane pliku wykonywalnego powinny być kompletne, tzn. powinny zawierać pełen opis, pozwalający na uruchomienie programu tak, aby przeniesienie go na analogiczny system operacyjny nie wymagało dodatkowych czynności. Można powiedzieć, iż metadane są instrukcją obsługi do załączonego kodu i danych, dla systemu operacyjnego.

Przykłady

Jak to w życiu bywa – standardy – każdy ma własne ;) Stąd formatów plików obiektowych jest bardzo wiele, może nawet tyle co formatów audio, czy obrazów. Poniżej przedstawiłem króciótką charakterystykę kilku z nich:

  • a.out – pierwotny format plików wykonywalnych UNIXa, który pojawił się tam już w pierwszej wersji, jeszcze na komputery PDP-7. Jest niezwykle prosty i popularny, ale w nowych rozwiązaniach raczej nieużywany. Teraz nietrudno zgadnąć, skąd wzięła się domyślna nazwa programów kompilowanych pod UNIXem :)
  • COFF (Common Object File Format) – format COFF zastąpił a.out na pozycji domyślnego formatu plików  obiektowych (sam został już jednak zastąpiony przez format ELF). W formacie COFF można przechowywać pojedyncze funkcje, symbole, fragmenty programów, biblioteki oraz może być on bezpośrednio wykonywany.
  • ELF (Executable and Linking Format) – ELF zastąpił natomiast COFF na pozycji lidera w systemach uniksopodobnych (i nie doczekał się jeszcze zdetronizowania). Mimo kilku wad, jest dobrze udokumentowany i bardzo popularny. Został opracowany w Unix System Laboratories podczas prac nad sławnym Systemem V R4.
  • COM – wyjątkowo prosty format używany przez MS-DOS. Można powiedzieć, że jest on „płaską binarką” – nie zawiera żadnych nagłówków. W związku z tym, iż pliki o formacie COM wykonywane były w trybie rzeczywistym, są ograniczone co do rozmiaru do wielkości jednego segmentu trybu rzeczywistego.
  • MZ – format MZ zastąpił COM w MS-DOS 2.0 i jest zdecydowanie bardziej zaawansowany ;) Na uwagę zasługuje fakt, że jego nazwa (i jednocześnie identyfikator zawarty w pierwszych dwóch bajtach pliku – 0x4D (M) 0x5A (Z)) wzięła się od inżyniera Marka Zbikowskiego – rodzimo brzmiące nazwisko, prawda? :)
  • NE (New Executable) – format NE zastąpił natomiast MZ i został wprowadzony w Windowsie 3.x. Niestety posiada on limity rozmiaru takie jak MZ oraz również jest 16 bitowy.
  • PE (Portable Executable) – w końcu, współczesny format plików wykonywalnych dla systemu Windows, wprowadzony wraz z wersją 95. Oczywiście jest on 32 bitowy i posiada wiele udogodnień w stosunku do poprzedników. Warto też wspomnieć, iż jest on kontenerem dla binarek .NETa.

Podsumowanie

Celem stosowania formatów jest ustandaryzowanie pewnych kwestii. Jak widać na powyższych przykładach, nie jest to łatwe – każdy chce mieć coś do powiedzenia :) Stosowanie różnych formatów plików obiektowych na różnych systemach operacyjnych sprawia iż „binarki” (pliki wykonywalne) nie są przenośne – uruchomienie skompilowanego, nawet prostego programu typu hello world, nie jest możliwe na obu systemach. Stąd powstały koncepcje wielu emulatorów, jak choćby WINE czy liczne klony „pegasusa” :), które starają się ten problem usunąć.

Nawiązując do projektowania systemów operacyjnych z formatami plików obiektowych spotkać można się np. przy tworzeniu interfejsu binarnego aplikacji czy też kompilując jądro do formatu łatwego do przeczytania przez konkretny bootloader.

Emacs dla C/C++

Co się przydaje?

To czego potrzebuję do pełni szczęścia podczas programowania w C/C++ to:

  • Szybkie działanie edytora
  • Kolorowanie składni
  • Automatyczne formatowanie kodu
  • Inteligentne uzupełnianie kodu
  • Wsparcie dla debuggera
  • Przeglądanie kodu
  • Możliwość rozszerzenia IDE o własne snippety, generację kodu

Wydaje mi się, że moje wymagania nie jest zbyt wygórowane. Niestety, nie jest łatwo o edytor spełniający wszystkie powyższe życzenia. Na szczęście Emacs, po odpowiednim tuningu spełnia wszystkie moje wymagania.

Out of the box

Świeża instalacja Emacsa, w miarę nowej wersji (co do starszych nie mam rozeznania) zapewnia kolorwanie składni, automatyczne formatowanie kodu, wsparcie dla debuggera (gdb) oraz możliwość tworzenia własnych rozszerzeń. Przyzwoicie prawda? Oczywiście wszystko to jest, do granic możliwości, konfigurowalne. Począwszy od zmiany kolorów, poprzez wybór predefiniowanych/własnych stylów formatowania kodu aż do tworzenia własnych skrótów i (mini)skryptów – wszystko to jest oczywiście możliwe! Ponadto, Emacs doskonale integruje się z powłoką systemu, pozwalając na obsługę buildów nie opuszczając edytora.

Na oddzielny akapit zasługuje wspomnienie o tym, że Emacs działa naprawdę szybko, nawet na starych komputerach. Mówiąc szybko, mam na myśli SZYBKO, a nie tak jak Eclipse, czy VS :)

Jest jeszcze kilka cech, których brakuje, ale to załatwiają zgrabne pluginy, o których poniżej.

CEDET

CEDET, czyli Collection of Emacs Development Environment Tools, to kombajn, który obowiązkowo należy doinstalować do Emacsa. Niezależnie jakiego języka programowania używasz, zawsze znajdziesz tu coś dla siebie. Aktualnie, wsparcie dla C/C++ jest najlepiej rozwinięte. Wtyczka oferuje m. in. uzupełnianie kodu, które spokojnie może konkurować z Intellisense z Visual Studio (np. w szybkości działania). Nie są to „naiwne” ctags (dostępne np. w vimie), tylko uzupełnianie z prawdziwego zdarzenia! Niestety, C++ nie jest językiem stworzonym do łatwej analizy, stąd CEDET czasem się myli, ale to raczej wyjątki, niż reguły. Wtyczka posiada również wsparcie dla „code templates” oraz szukanie odniesień w kodzie (do funkcji, metod, klas itd.), które działają całkiem przyzwoicie.

Inne ficzery, których jednak nie używam na co dzień to generacja diagramów UML (!) oraz wsparcie dla zarządzania projektami. Wśród obsługiwanych (lepiej lub gorzej) języków znajdują się: C, C++, Java, Emacs Lisp, Make, Scheme, Erlang, Texinfo, HTML, CEDET, Awk,  Simula, JavaScript, Python, C#, PHP, Ruby, SRecode Templates, Bourne Shell, Scala, dot. Niestety, wsparcie dla wielu z nich, pozostawia wiele do życzenia.

ECB

ECB – Emacs Code Browser, to wtyczka, wymagająca do działania wspomnianego wyżej dodatku CEDET, która zapewnia wygodne i sprawne przeglądanie kodu. Dzięki ECB zyskujemy, okienko (oczywiście w pełni konfigurowalne) umożliwiające nawigację po strukturze katalogów. Niby to nic takiego, ale jeśli rozważymy dowolną możliwość konfiguracji, to da się dzieki temu pluginowi uzyskać naprawdę ciekawe efekty.

Dla wymagających

Jeśli powyższy zestaw funkcjonalności to dla Was za mało, możecie poszperać i znaleźć tysiące, setki tysięcy rozszerzeń do Emacsa wszelkiej maści. Wszak legenda głosi, że do Emacsa napisano już wszstko :) Będzie więc bardzo łatwo o narzędzia dodające obsługę systemów kontroli wersji, czy generacje dokumentacji na podstawie kodu. Szukanie można rozpocząć np. tu.

Na koniec

Mój poprzedni post o edytorach tekstu wzbudził bardzo duże zainteresowanie, można więc spodziewać się więcej postów w tym temacie. W przyszłości m. in. zaprezentuję swój config i ujawnię cały zestaw dodatków, których używam :)

Poniżej zamieszczam screena prezentującego trio Emacs + CEDET + ECB w akcji:

Po lewej widać okienko ECB, z drzewem katalogów. Górne okienko zawiera kod, natomiast dolne – propozycje uzupełnienia kodu. Oczywiście okienko z kodem podczas pisania nie jest takie małe. Normalnie okienka ECB oraz „code completion” są ukryte. Screen natomiast nie oddaje nawet połowy pozytywnych wrażeń z użytkowania dobrze skonfigurowanego Emacsa. Polecam spróbować!