Programowanie niskopoziomowe / Moduł 4: Programowanie hybrydowe

From Studia Informatyczne


Grafika:PNP_M4_S01.png

...


Grafika:PNP_M4_S02.png

...


Grafika:PNP_M4_S03.png

...


Grafika:PNP_M4_S04.png

Rejestr 1 jest używany prze asembler MIPS do rozwijania pseudoinstrukcji asemblera w sekwencje 2..3 instrukcji procesora. Rejestr ten zawiera tymczasową wartość, przekazywaną pomiędzy instrukcjami składającymi się na jedną pseudoinstrukcję.

Rejestry k0 i k1 są zarezerwowane do użytku systemu operacyjnego. Z punktu widzenia aplikacji są one ulotne, gdyż wykonanie programu może zostać w każdej chwili przerwane, a w tym czasie system operacyjny może zmienić zawartość tych rejestrów.

Rejestr 28 ułatwia dostęp do danych statycznych.

Rejestr 30 może być użyty jako wskaźnik ramki, zwykle jednak kompilatory dlła MIPS adresują obiekty ramki sou względem wskaźnika stosu, a rejestr 30 służy jako dziewiąty rejestr zachowywany.


Grafika:PNP_M4_S05.png

Konwencja wołania – to zestaw reguł rządzących zachowaniem programów, w tym użyciem przez nie rejestrów i innych zasobów procesora, użyciem stosu systemowego, sposobem przekazywania argumentów do procedur, wywoływania procedur, alokacji zmiennych lokalnych, przekazywania wartości i powrotów z procedur.

Konwencja wołania może być zdefiniowana na różnych poziomach – zależy to od stopnia kontroli podmiotu definiującego konwencję wołania nad obszarem zastosowań tej konwencji.

W komputerach zbudowanych na bazie procesorów MIPS obowiązuje jedna konwencja wołania, zdefiniowana przez projektantów procesora i opisana w dokumentacji procesora. Jest ona stosowana w e wszystkich środowiskach – wszystkich systemach operacyjnych, językach programowania i kompilatorach.

W implementacjach systemów rodziny Unix dla procesorów innych niż MIPS przyjęto, że system operacyjny narzuca konwencję wołania, z której korzysta całe oprogramowania działające w systemie operacyjnym. Konwencja jest wspólna dla wszystkich systemów rodziny Unix/Linux, co daje w efekcie pełną przenośność oprogramowania pomiędzy tymi systemami operacyjnymi. Konwencje te są opisane w dokumentach Unix System V Applicatiion Binary Interface dla poszczególnych rodzin procesorów.

Jeśli konwencja wołania nie została zdefiniowana na poziomie systemu operacyjnego, definiuje ją twórca kompilatora. Jest to sytuacja niekorzystna, gdyż każdy dostawca kompilatora może zdefiniować konwencję wołania odmiennie, co powoduje niemożność łączenia modułów pisanych w tym samym języku programowania i kompilowanych przez różne kompilatory. Sytuacja taka miała miejsce w systemie operacyjnym DOS i częściowo we wczesnych systemach rodziny Windows.

Należy zauważyć, że istnieją środowiska, w których różne języki programowania używają różnych konwencji wołania, chociaż sytuacje takie należą już raczej do przeszłości.


Grafika:PNP_M4_S06.png

Sama architektura procesora (np. x86) lub konwencja wołania (np. MIPS) określają, które z rejestrów procesora pełnią rolę wskaźnika stosu w pamięci i wskaźnika ramki. W niektórych konwencjach wołania można nie używać wskaźnika ramki.

Pozostałe funkcje rejestrów w ramach konwencji wołania są przypisane wyłącznie przez samą konwencję.

Rejestry argumentów służą do przekazywania argumentów wywołania. Konwencja wołanie określa dokładnie ile i jakich argumentów można przekazać w rejestrach.


Grafika:PNP_M4_S07.png

Bardzo istotny jest podział rejestrów na zachowywane i tymczasowe. Większość błędów w programach hybrydowych ma swoje źródło w zignorowaniu przez programistę tego podziału.

Rejestry przechowywane służą do alokacji zmiennych lokalnych. ich zawartość nie może być zmieniona przez żadną procedurę. Oznacza to, że albo procedura nie używa tych rejestrów, albo używa ich dla zmiennych lokalnych, ale w tym przypadku zawartość każdego używanego rejestr musi być w prologu procedury zapamiętana na stosie w pamięci, a w epilogu (przed powrotem) – odtworzona.

Rejestry tymczasowe mogą być dowolnie modyfikowane prze każdą procedurę, co oznacza, że nie ma gwarancji przechowania ich zawartości przez procedurę wywoływaną. Rejestry te są zwykle używane do przechowywania danych tymczasowych w dowolnych procedurach (pomiędzy wywołaniami procedur) albo do przechowywania zmiennych lokalnych w procedurach nie wywołujących innych procedur.

Jeżeli rejestry tymczasowe miałyby być używane do przechowywania zmiennych lokalnych w innych przypadkach, procedura musi zapamiętać ich zawartość na stosie przed każdym wywołaniem innej procedura i odtworzyć ich zawartość po wywołaniu.


Grafika:PNP_M4_S08.png

Czynności wykonywane w prologu procedury są zdefiniowane przez konwencję wołania.

W niektórych środowiskach na początku procedura wywołana wyrównuje stos do określonej granicy (np. 16 bajtów).

Jeżeli procedura korzysta ze wskaźnika ramki, musi ona zachować wskaźnik ramki procedury wywołującej.

Kolejnymi czynnościami są: alokacja miejsca na stosie na wartości argumentów przekazane przez rejestry (o ile konwencja nie określa, że czynność tę wykonuje procedura wołająca) i opcjonalne składowanie rejestrów argumentów na stosie.

Następnie procedura ustanawia własną wartość wskaźnika ramki, po czym następuje alokacja zmiennych lokalnych i składowanie rejestrów.

Konwencja wołania może inaczej ustalić kolejność wymienionych czynności.


Grafika:PNP_M4_S09.png

W epilogu procedury następuje odwrócenie efektów wykonania prologu.

Ostatnią czynnością wykonywaną w epilogu jest powrót według śladu wywołania.


Grafika:PNP_M4_S10.png

Konwencja wołania MIPS została określona przez projektantów procesora. 30 z 32 rejestrów architektury MIPS nie ma funkcji przypisanych przez sam model programowy. Ustalenie ich funkcji jest jednym z elementów konwencji wołania. Konwencja nadaje rejestrom alternatywne nazwy mnemoniczne.


Grafika:PNP_M4_S11.png

Tabela przedstawia funkcje rejestrów MIPS w konwencji wołania.

Rejestr 0 nie jest rejestrem, lecz lokacją zwracającą 0 przy odczycie.

Instrukcje skoku ze śladem pozostawiają ślad w rejestrze numer 31.


Grafika:PNP_M4_S12.png

Rejestr 1 jest używany przez asembler MIPS do rozwijania metainstrukcji asemblera w sekwencje 2..3 instrukcji procesora. Rejestr ten zawiera tymczasową wartość, przekazywaną pomiędzy instrukcjami składającymi się na jedną metainstrukcję.

Rejestry k0 i k1 są zarezerwowane do użytku systemu operacyjnego. Z punktu widzenia aplikacji są one ulotne, gdyż wykonanie programu może zostać w każdej chwili przerwane, a w tym czasie system operacyjny może zmienić zawartość tych rejestrów.

Rejestr 28 ułatwia dostęp do danych statycznych.

Rejestr 30 może być użyty jako wskaźnik ramki, zwykle jednak kompilatory dla MIPS adresują obiekty ramki stosu względem wskaźnika stosu, a rejestr 30 służy jako dziewiąty rejestr zachowywany.


Grafika:PNP_M4_S13.png

...


Grafika:PNP_M4_S14.png

...


Grafika:PNP_M4_S15.png

...


Grafika:PNP_M4_S16.png

...


Grafika:PNP_M4_S17.png

...


Grafika:PNP_M4_S18.png

...


Grafika:PNP_M4_S19.png

...


Grafika:PNP_M4_S20.png

...


Grafika:PNP_M4_S21.png

...


Grafika:PNP_M4_S22.png

...