Elektroda.pl
Elektroda.pl
X

Search our partners

Find the latest content on electronic components. Datasheets.com
Elektroda.pl
Please add exception to AdBlock for elektroda.pl.
If you watch the ads, you support portal and users.

[ARM] Alokacja pamięci - Wielowątkowość.

xŁolesxxx 09 Apr 2012 21:19 3649 29
Computer Controls
  • #1
    xŁolesxxx
    Level 14  
    Witam.
    Zastanawiam się nad realizacją wielowątkowości. Che napisać taki mini system zarządzający procesami, lądował by je z karty i uruchamiał. Ale nie za bardzo wiem czy to się uda i nie wiem jak szukać informacji o tym. Mianowicie czy da się uruchamiać jakiś skompilowany program z pod rożnych adresów. W sensie że raz jest gdzieś tam załadowany a innym razem gdzieś kawałek dalej ? Bo problem chyba ze skokami się pojawi, bo wydaje mi się że w momencie kompilacji jest to ustawione na sztywno ? Proszę o wyjaśnienie mi tego lub o jakiś link gdzie mogę o tym poczytać. Jeśli dubluje jakiś temat to przepraszam ale nie udało mi się nic znaleźć.
    Dzięki.
    Kamery 3D Time of Flight - zastosowania w przemyśle. Darmowe szkolenie 16.12.2021r. g. 10.00 Zarejestruj się
  • Computer Controls
  • #2
    tmf
    Moderator of Microcontroller designs
    Wbrew pozorom instrukcje skoków nie są problemem. Każdy procesor ma skoki względne, dzięki czemu można program dowolnie przemieszczać w pamięci. Problemem są struktury danych - program w C zakłada pewną strukturę segmentów pamięci i trzyma tam m.in. zmienne globalne. Także twój program musiałby korzystać wyłącznie ze zmiennych lokalnych (i nie wykorzystywać zmiennych statycznych), dodatkowo musiałby być pozbawiony kodu startowego, za odwiednią inicjalizację procesora i struktur danych odpowiedzialny byłby program wywołujący. Temat jest oczywiście szerszy.
  • #3
    Freddie Chopin
    MCUs specialist
    Skoki względne skokami względnymi, ale funkcje wywoływane są po adresie... Też się zastanawiałem nad tym tematem i też mnie on bardzo ciekawi. Opcja kompilatora -fPIC niewiele zmienia, albo ja nie umiem jej obsługiwać <:

    4\/3!!
  • Computer Controls
  • #4
    gaskoin
    Level 38  
    Bo nie wywołuje się funkcji od nowa. Skok z i do funkcji może nastąpić w jej połowie. Wygląda to tak, że robi się gdzieś zrzut PC, rejestrów, czegoś tam jeszcze, dla każdego taska i potem na tej podstawie się skacze gdzieś z powrotem.

    Jest to oczywiście dużo bardziej skomplikowane niż takie sobie. Gość który wymyślił uC/OS pierwszą podstawową wersję pisał chyba rok.
  • #5
    xŁolesxxx
    Level 14  
    Trzeba jakiś zegar który będzie generował przerwania. W momencie przerwania trzeba zapisać stany rejestrów w wydzielonej pamięci procesu, załadować inne związywane z kolejnym procesem i uruchomić od momentu zatrzymania. Każdy proces miałby swój stos i pozostaje tylko kwestia adresowania. Chaba że może da się jakieś adresy wirtualne, to by sprawę załatwiło całkowicie ?
  • #6
    tmf
    Moderator of Microcontroller designs
    Freddie Chopin wrote:
    Skoki względne skokami względnymi, ale funkcje wywoływane są po adresie... Też się zastanawiałem nad tym tematem i też mnie on bardzo ciekawi. Opcja kompilatora -fPIC niewiele zmienia, albo ja nie umiem jej obsługiwać <:

    4\/3!!


    A nie ma w ARM instrukcji wywołania funkcji z adresem względnym? Powinna być. A jeśli nie ma to wystarczy dodawać adres początku programu do offsetu wyliczonego przez linker.
  • #7
    Byron
    Level 11  
    Witam.

    Oczywiscie ze fpic dziala.
    Drodzy koledzy poczytajcie sobie o Global offset table (sekcja .got)
    Wystaczy ja przerelokowac i problem rozwiazany.

    Pozdrawiam
    Marcin
  • #8
    Freddie Chopin
    MCUs specialist
    tmf wrote:
    A nie ma w ARM instrukcji wywołania funkcji z adresem względnym? Powinna być. A jeśli nie ma to wystarczy dodawać adres początku programu do offsetu wyliczonego przez linker.

    Wszystko jest, tylko kompilator i linker generuje kod w którym adresy wywoływania funkcji są na sztywno...

    Byron wrote:
    Oczywiscie ze fpic dziala.
    Drodzy koledzy poczytajcie sobie o Global offset table (sekcja .got)
    Wystaczy ja przerelokowac i problem rozwiazany.

    Sprawdziłeś? Bo ja sprawdziłem. Dodanie tej opcji (albo -fpie) nie zmienia generalnie NIC... Funkcje w każdym przypadku wywoływane są "na sztywno" po adresie. Kiedyś udało mi się zrobić tak, że stałe i zmienne są wywoływane przez rejestr R12, ale teraz nie mogę tego powtórzyć.

    4\/3!!
  • #9
    User removed account
    User removed account  
  • #10
    gaskoin
    Level 38  
    Freddie a nie można gdzieś w tablicy przechowywać tychże adresów do funkcji jako wskaźników do nich ?

    Jeśli chodzi o używanie zmiennych lokalnych, to do komunikacji między wątkami z takowymi można zaimplementować kolejkę.
    Btw, jeśli ktoś napisze system operacyjny, to jego pierwsza wersja będzie pewnie migała diodami a nie wymieniała dane między wątkami :)
  • #11
    Freddie Chopin
    MCUs specialist
    gaskoin wrote:
    Freddie a nie można gdzieś w tablicy przechowywać tychże adresów do funkcji jako wskaźników do nich ?

    No ale zapanujesz nad WSZYSTKIM? Nad funkcjami wywoływanymi "z ukrycia" (np. konwersja z liczby całkowitej na floata, dzielenie na architekturze która nie ma do tego rozkazu, ...) też? Nie chodzi mi o funkcje które sobie wywołuję ja, bo wtedy sprawa jest dosyć prosta, ale właśnie o takie funkcje biblioteczne - a przecież zwykle każda z nich wywołuje ze sto innych...

    4\/3!!
  • #12
    gaskoin
    Level 38  
    Wydaje mi się, że ważny będzie tylko start tych funkcji, ponieważ potem przeskakując pomiędzy taskami wystarczyło by zapisać sobie PC + resztę rejestrów i stos, po czym je odtwarzać w odpowiedniej kolejności (taski).

    Niektóre ARMy mają specjalne timery, instrukcje i przerwania pod systemy operacyjne, ale tyle, to pewnie też wiecie :)
  • #14
    User removed account
    User removed account  
  • #15
    Freddie Chopin
    MCUs specialist
    Najbardziej interesującą opcją byłoby mieć mozliwość wrzucenia funkcji gdziekolwiek, funkcje "systemowe" żeby sobie były zupełnie gdzie indziej - taki system operacyjny jak na PC (; Gdyby faktycznie udało się zmusić GCC do korzystania z jumptable przy każdym wywołaniu funkcji i np tego offsetu do stałych to byłoby idealnie, ale chyba nie da rady tego zrobić...

    4\/3!!
  • #16
    User removed account
    User removed account  
  • #17
    gaskoin
    Level 38  
    Bo Freddie chciał pokonać system i mieć system operacyjny, do którego pewnie wrzuca taski, jako osobne pliki wykonywalne, choćby z np karty SD, wtedy nie może znać adresu. Jednak jest to o tyle trudne, że będziesz musiał najpierw sobie napisać taki system "taskowy" o którym piszę :) Generalnie jest tak, że trzeba zająć odpowiednią ilość pamięci i wrzucić w nią cały program. Coś jak malloc dla zmiennej - od razu masz adres gdzie jest program, a reszta wygląda już tak samo, więc też możesz sobie dorzucić start programu do tablicy :)
  • #18
    Freddie Chopin
    MCUs specialist
    albertb wrote:
    Jeśli tak, to nie rozumiem zastrzeżeń z #11 do metody gaskoina.
    Na etapie tworzenia "appletu" znasz przecież adresy wszystkich funkcji systemowych.
    Więc czemu nie mogą być wywołane na sztywno po adresie?
    A wszystkie swoje, które mogą trafić w nieznane miejsce poprzez tablicę jak pisał gaskoin?

    No ale jak zmusić kompilator, do wywołania funkcji "ukrytych" spod jakiegoś konkretnego adresu?

    4\/3!!
  • #19
    tmf
    Moderator of Microcontroller designs
    Freddie Chopin wrote:
    No ale wtedy każdy "task" musiałbyś mieć w postaci kompletnej aplikacji, ładowanej tylko i wyłącznie pod JEDEN (wybrany na etapie linkowania) adres.

    4\/3!!


    No niekoniecznie. Aplikację można przecież zlinkować z własnymi bibliotekami, w szczególności z wersją libc użytą przez OS, wtedy będziesz miał automatycznie wszystkie wywołania funkcji bibliotecznych poprawne. W ramach programu z definicji wszystkie wywołania będą poprawne, bo o to zadba linker. A poszczególne taski przecież wzajemnie nie wywołują funkcji z innego tasku. Jedyne co trzeba zapewnić to zamianę wszystkich wywołań na wywołania względne, no albo ładować elfa i robić translację adresów. To w sumie nie jest takie trudne o ile mówimy o C, jeśli to będzie C++ to sprawa się znacznie komplikuje.
    Swoją drogą, nie lepiej przeanalizować kod jakiegoś RTOS, będzie widać jak to jest zrobione.
  • #20
    Freddie Chopin
    MCUs specialist
    Pewnie jest to robione pamięcią wirtualną, bo niby jak inaczej zrobić to prosto i wydajnie? (; No i na takie "duże" systemy operacyjne kod jest faktycznie "PIC" i "PIE", a jakoś na bare-metal ARM niezbyt wychodzi taka kombinacja...

    4\/3!!
  • #21
    User removed account
    User removed account  
  • #22
    tmf
    Moderator of Microcontroller designs
    albertb wrote:

    tmp wrote:

    Aplikację można przecież zlinkować z własnymi bibliotekami, w szczególności z wersją libc użytą
    ...


    W szczególności podoba mi się tyle printf -ów ile tasków ;-)

    Albert


    A niby dlaczego miałby ich tyle być? Przecież linkuje z biblioteką, która jest już w tym "OSie", a nie dołącza jej do każdego tasku.
  • #23
    User removed account
    User removed account  
  • #24
    tmf
    Moderator of Microcontroller designs
    A kto mówi o dynamicznym linkowaniu? Na etapie kompilacji tego "tasku" się linkuje z biblioteką. Tyle, że zostawia się sam kod "tasku", a bibliotekę wywala, będzie ona w OS i linkowanie ciągle będzie poprawne, o ile ktoś nie zmieni miejsca samej biblioteki, co nie jest problemem, bo segmenty można ustawiać na sztywno. Nie wiem z czym tu masz problem.

    albertb wrote:
    Napisz jak w tasku zlinkować dynamicznie bibliotekę z systemu, a ci odpuszczę grzechy,
    Albert


    Ksiądz, czy co?
  • #25
    User removed account
    User removed account  
  • #26
    tmf
    Moderator of Microcontroller designs
    Akurat sposób działa doskonale, nie testowałem tego z ARM , ale z AVR (myślę, że procesor nie ma tu nic do rzeczy). Zresztą opisałem go z działającymi przykładami w swojej książce. Ale po kolei. Linker nie stanowi problemu - on ma za zadanie uzupełnić adresy wywołań funkcji bibliotecznych w aplikacji. Może z biblioteki wywalać funkcje, ale nie musi. Linker w ogóle samej biblioteki ma "nie dotykać", jedynie ma zająć się kodem aplikacji. Jak to zrobić? Ano wywalanie funkcji jest opcjonalne, dwa, że nadając funkcji atrybut used zablokujemy możliwość jej wywalenia. Mamy bibliotekę - zmieniając adresy segmentu .text możemy spowodować, że zostanie umieszczona pod konkretnym adresem. Ok, mamy już stałe adresy funkcji bibliotecznych. Linkujemy teraz aplikację z taką biblioteką. W efekcie mamy plik wynikowy składający się z dwóch części - pierwsza to biblioteka (dla wszystkich aplikacji umieszczona pod tym samym adresem - relokowaliśmy segment .text). Będzie ona identyczna dla wszystkich aplikacji i ją wywalamy. Druga - to właściwa aplikacja, zawierająca kod odwołujący się do biblioteki. Aby to zadziałało ten "OS" musi umieścić bibliotekę pod adresem pod którym się jej spodziewa aplikacja. Ale biblioteka będzie współdzielona przez wszystkie aplikacje. Po wczytaniu kodu aplikacji wszystko wygląda dla niej tak jak powinno. Z kolei do samych funkcji aplikacji (o ile zachodzi taka potrzeba) można się odwołać poprzez tablicę wektorów, którą też można wygenerować automatycznie (jak to odsyłam znowu do książki, bo za długo by pisać). Jedyny kłopot jest z funkcjami bibliotecznymi, które nie są reentrant (niektóre funkcje IO i alokacja pamięci dynamicznej). Trzeba jeszcze zadbać aby aplikacja nie bruździała w pamięci - ale nie ma problemu o ile nie używamy zmiennych globalnych.
  • #27
    User removed account
    User removed account  
  • #28
    tmf
    Moderator of Microcontroller designs
    Problem leży w tym jak standardowo zbudowana jest libc, a właściwie to jest kilka problemów. Pierwszy - przykłady z mnożeniem i innymi prostymi operacjami nie są najlepsze, bo odpowiedni kod może nie pochodzić z libc tylko być generowany bezpośrednio przez kompilator. Tak jest np. na AVR w przypadku operacji na liczbach long, wtedy każda aplikacja i tak będzie miała swoją wersję, chyba, że odpowiednie symbole pojawią się w linkowanej bibliotece. Ale to akurat małoistotne dla naszych rozważań. Drugi problem jest poważniejszy. Libc, podobnie jak wiele innych bibliotek ma każdą funkcję w osobnym pliku obj, w efekcie linker wywala niepotrzebne funkcje w całości, co powoduje przesunięcie adresu innych funkcji. I tu niestety dotykamy tematu kopilatorospecyficznego lub musimy stworzyć własne libc. To drugie jest bardziej uniwersalne, ale i kłopotliwe. Trzeba przekompilować całe libc tak, aby wszystkie funkcje znalazły się w jednym pliku obj, dzięki temu linker (bez specjalnych opcji - data-sections, function-sections) ich nie usunie, co zapewni stałe adresy dla wszystkich aplikacji. To o ile się nie mylę zapewnia atrybut gcc combine. Możemy też usunąć linkowanie z libc (-nodefaultlibs) i zapewnić własną bibliotekę mającą potrzebne funkcje. To jest fajne jeśli tworzysz własny OS, bo możesz podmienić funkcje, potencjalnie problematyczne (np. malloc, free itd). Kolejna możliwość to parametr linkera --relocatable - umożliwia połączenie wielu polików obj w jeden, w ten sposób libc możesz przerobić na jeden plik obj, co zapobiegnie wywalaniu nieużywanych funkcji. Co ważne, nie wymaga rekompilacji libc, a jedynie częściowego linkowania libc.a. Inna możliwość to rekompilacja libc tak, aby każda funkcja była skompilowana z atrybutem used - w ten sposób zawsze znajdzie się w kodzie wynikowym i będziesz miał stałe adresy. IMHO akurat libc nie warto ruszać, bo jest krótka i często używana, lepiej więc pozwolić kompilatorowi na cyrki, kosztem nawet zwiększenia długości aplikacji. Natomiast warto się z pewnością w ten sposób zabawić z libprintf czy libm (jeśli nie mamy FPU).
  • #29
    User removed account
    User removed account  
  • #30
    przemekbary
    Level 16  
    Witam
    A koprocesor CP15 i tablica translacji w ARM9?