Как ООП «объекты» и «классы» организованы в памяти на языке ассемблера?

13

Как объекты организованы в памяти?

Например, я знаю, что функция - это фрагмент кода в памяти, который ожидает параметры через стек и / или регистры и обрабатывает свой собственный кадр стека.

Но объекты - это гораздо более сложная структура. Как они организованы? Имеет ли каждый объект «ссылки» на методы и передает адрес самому себе этому методу?

Было бы здорово увидеть хорошее объяснение этой темы.

UPD. Я уточнил вопрос, и в основном меня интересует статическая типизация языков.

Николай Голуб
источник
4
Он может сильно различаться между разными языками, особенно между динамически типизированными и статически типизированными языками. Можете ли вы сузить свой вопрос до наиболее интересующих вас ОО-языков?
Барт ван Инген Шенау
Я обновил вопрос, поэтому я думаю, что динамически типизированные языки труднее понять.
Николай Голуб

Ответы:

17

Если динамическая диспетчеризация отсутствует (полиморфизм), «методы» - это просто сладкие функции, возможно, с неявным дополнительным параметром. Соответственно, экземпляры классов без полиморфного поведения по существу являются C structs для генерации кода.

Для классической динамической диспетчеризации в системе статического типа существует в основном одна доминирующая стратегия: vtables. Каждый экземпляр получает один дополнительный указатель, который ссылается на (ограниченное представление) своего типа, наиболее важно vtable: массив указателей на функции, по одному на метод. Поскольку полный набор методов для каждого типа (в цепочке наследования) известен во время компиляции, можно присвоить методам последовательные индексы (0..N для N методов) и вызывать методы, просматривая указатель на функцию в vtable, использующий этот индекс (снова передавая ссылку на экземпляр как дополнительный параметр).

Для более динамических языков на основе классов сами классы обычно являются первоклассными объектами, и каждый объект вместо этого имеет ссылку на свой объект класса. Объект класса, в свою очередь, владеет методами в зависимости от языка (в Ruby методы являются основной частью объектной модели, в Python они являются просто функциональными объектами с крошечными обертками вокруг них). Классы обычно хранят ссылки на свои суперклассы и делегируют поиск унаследованных методов этим классам, чтобы помочь метапрограммированию, которое добавляет и изменяет методы.

Есть много других систем, которые не основаны на классах, но они существенно различаются, поэтому я выберу только одну интересную альтернативу разработки: когда вы можете добавлять новые (наборы) методов ко всем типам по желанию в любом месте программы ( например, классы типов в Haskell и traits в Rust), полный набор методов не известен при компиляции. Чтобы решить эту проблему, каждый создает vtable для черты и передает их, когда требуется реализация черты. Код такой:

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

компилируется до этого:

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);

Это также означает, что информация vtable не встроена в объект. Если вам нужны ссылки на «экземпляр свойства», который будет вести себя корректно, например, когда он хранится в структурах данных, содержащих много разных типов, можно создать толстый указатель (instance_pointer, trait_vtable) . На самом деле это обобщение вышеуказанной стратегии.


источник
5

Это ответ в смысле пословицы «если вы даете человеку рыбу, вы кормите его в течение дня, а если вы учите его ловить рыбу, вы кормите его на всю жизнь», поскольку ваш вопрос очень широк

1. исследование открытых источников информации

Google для "ассемблерного объектно-ориентированного программирования" перечисляет довольно много разных релевантных ресурсов

напр., объектно-ориентированное программирование в сборке, Итан Дж. Элдридж, 15 декабря 2011 г. - это третье звено и выглядит хорошо

2. учиться на существующем рукописном коде

Вы можете увидеть, как это работает, изучив исходные коды, написанные на некоторых популярных языках ассемблера с явно объявленным ООП, например:

3. учиться на шаблонах кода, сгенерированных компиляторами

Вы можете увидеть, как это работает, изучив файлы на языке промежуточной ассемблера, созданные компиляторами ООП по вашему выбору. Компиляторы как C ++, так и FreePascal можно настроить так, чтобы вы могли видеть, как выглядит транскрипция кода ООП высокого уровня в код на языке ассемблера

4. решить головоломку со своим здравым смыслом

Сейчас уже слишком поздно, так как вы уже знаете подсказки из других ответов. Но до того, как в интернете было так легко искать, и до того, как появились сайты, где можно без каких-либо усилий получить ответ в течение нескольких часов от добровольца, который усвоил его трудным способом, единственным рабочим методом, доступным бесплатно для всех, был

Спросите себя: «Как бы я это реализовал?»

Очень часто, после нескольких дней фонового мышления, запущенного в вашей памяти, и после того, как вы выбросили несколько черновиков, вы обнаружите, что решение, которое вы придумали, очень похоже на решение, которое другие программисты придумали и уже реализовали.


Теперь мой ответ основан на мнении, прямо не отвечает на вопрос OP, и старшие пользователи с высоким уровнем репутации могут свободно понизить меня

xmojmr
источник