W jaki sposób „obiekty” i „klasy” OOP są zorganizowane w pamięci pod względem języka asemblera?

13

Jak zorganizowane są obiekty w pamięci?

Na przykład wiem, że funkcja to fragment kodu w pamięci, który oczekuje parametrów przez stos i / lub rejestry i obsługuje własną ramkę stosu.

Ale obiekty są znacznie bardziej skomplikowaną strukturą. Jak są zorganizowani? Czy każdy obiekt ma „linki” do metod i przekazuje adres do tej metody?

Byłoby wspaniale zobaczyć dobre wyjaśnienie tego tematu.

UPD. Uściśliłem pytanie i interesuje mnie głównie statyczne pisanie języków.

Mikołaj Golub
źródło
4
Może różnić się bardzo między różnymi językami, zwłaszcza między językami wpisywanymi dynamicznie i statycznie. Czy możesz zawęzić swoje pytanie do języków OO, które najbardziej Cię interesują?
Bart van Ingen Schenau
Zaktualizowałem pytanie, więc myślę, że dynamicznie pisane języki są trudniejsze do zrozumienia.
Nikolai Golub

Odpowiedzi:

17

Jeśli nie ma dynamicznej wysyłki (polimorfizm), „metody” są tylko funkcjami cukierkowymi, być może z niejawnym dodatkowym parametrem. Odpowiednio, instancje klas bez zachowania polimorficznego są zasadniczo Cs structdo celów generowania kodu.

Dla klasycznej dynamicznej wysyłki w systemie typu statycznego istnieje zasadniczo jedna dominująca strategia: vtables. Każda instancja otrzymuje jeden dodatkowy wskaźnik, który odnosi się do (ograniczonej reprezentacji) jego typu, a przede wszystkim vtable: tablica wskaźników funkcji, po jednej na metodę. Ponieważ pełny zestaw metod dla każdego typu (w łańcuchu dziedziczenia) jest znany w czasie kompilacji, można przypisywać kolejne indeksy (0..N dla N metod) do metod i wywoływać metody, patrząc na wskaźnik funkcji w vtable przy użyciu tego indeksu (ponownie przekazując odwołanie do instancji jako dodatkowy parametr).

W przypadku bardziej dynamicznych języków opartych na klasach zazwyczaj same klasy są obiektami pierwszej klasy, a każdy obiekt zamiast tego ma odniesienie do swojego obiektu klasy. Z kolei obiekt klasy jest właścicielem metod w pewien sposób zależny od języka (w Rubim metody są podstawową częścią modelu obiektowego, w Pythonie są tylko obiektami funkcyjnymi z niewielkimi opakowaniami wokół nich). Klasy zwykle przechowują również odniesienia do swoich nadklas (klas) i delegują wyszukiwanie odziedziczonych metod do tych klas, aby wspomóc metaprogramowanie, które dodaje i zmienia metody.

Istnieje wiele innych systemów, które nie są oparte na klasach, ale różnią się znacznie, więc wybiorę tylko jedną ciekawą alternatywę projektową: kiedy możesz dodawać nowe (zestawy) metod do wszystkich typów w dowolnym miejscu w programie ( np. klasy typów w Haskell i cechy w Rust), pełny zestaw metod nie jest znany podczas kompilacji. Aby rozwiązać ten problem, tworzy się tabelę vt na cechę i przekazuje ją, gdy wymagana jest implementacja cechy. Oznacza to, że kod taki jak ten:

void needs_a_trait(SomeTrait &x) { x.method2(1); }
ConcreteType x = ...;
needs_a_trait(x);

sprowadza się do tego:

functionpointer SomeTrait_ConcreteType_vtable[] = { &method1, &method2, ... };
void needs_a_trait(void *x, functionpointer vtable[]) { vtable[1](x, 1); }
ConcreteType x = ...;
needs_a_trait(x, SomeTrait_ConcreteType_vtable);

Oznacza to również, że informacje vtable nie są osadzone w obiekcie. Jeśli chcesz odwoływać się do „instancji cechy”, która zachowa się poprawnie, gdy na przykład będzie przechowywana w strukturach danych zawierających wiele różnych typów, możesz utworzyć gruby wskaźnik (instance_pointer, trait_vtable) . To właściwie uogólnienie powyższej strategii.


źródło
5

Jest to odpowiedź w sensie przysłowie „jeśli dasz człowiekowi rybę, karmisz go na jeden dzień, a jeśli nauczysz go łowić, karmisz go na całe życie”, ponieważ twoje pytanie jest bardzo szerokie

1. badać otwarte źródła informacji

Google dla „programowania obiektowego w asemblerze” wymienia wiele różnych istotnych zasobów.

np. Object Oriented Programming in Assembly, Ethan J. Eldridge, 15 grudnia 2011 r. znalazł się na trzecim miejscu i wygląda dobrze

2. uczyć się na podstawie istniejącego odręcznego kodu

Możesz zobaczyć, jak to działa, studiując kody źródłowe napisane w niektórych popularnych językach asemblera z jawnie zadeklarowanym OOP np

3. uczyć się na wzorcach kodu generowanych przez kompilatory

Możesz zobaczyć, jak to działa, studiując pliki języka asemblera tworzone przez wybrane kompilatory OOP. Kompilatory C ++ i FreePascal można skonfigurować tak, aby można było zobaczyć, jak wygląda transkrypcja wysokopoziomowego kodu OOP do kodu języka asemblera

4. rozwiąż zagadkę zdrowym rozsądkiem

Teraz jest już za późno, ponieważ znasz już wskazówki z innych odpowiedzi. Ale zanim internet był tak łatwy do przeszukania i zanim pojawiły się strony, na których można uzyskać odpowiedź bez wysiłku w ciągu kilku godzin za darmo od wolontariusza, który nauczył się tego na własnej skórze, jedyną dostępną metodą dla każdego była

Zadaj sobie pytanie: „jak bym to wdrożył?”

Bardzo często po kilku dniach procesu myślenia w tle i po wyrzuceniu kilku projektów szkiców papierowych okazało się, że rozwiązanie, które wymyśliłeś, jest bardzo podobne do rozwiązania, które inni programiści wymyślili i już wdrożyli


Teraz moja odpowiedź oparta jest na opinii, nie odpowiada bezpośrednio na pytanie OP, a starsi użytkownicy o wysokiej reputacji mogą swobodnie głosować za mną

xmojmr
źródło