Я знаю цель каждого сегмента, но мне было интересно, кто на самом деле реализует их на таких языках, как c или c++?
Они написаны программистами компилятора c/c++, когда они пишут реализацию языка? Или эти сегменты реализованы на уровне ОС/аппаратных средств (возможно, когда ОС выбирает адресное пространство для программы)?
Я представляю себе стек стека как простую структуру c, которая вставляется в стек для каждого вызова функции. Я представляю кучу как динамический массив и так далее...
Они написаны программистами компилятора c/c++, когда они пишут реализацию языка? Или эти сегменты реализованы на уровне ОС/аппаратных средств (возможно, когда ОС выбирает адресное пространство для программы)?
Точки входа сегмента в основном управляются на этапе компоновки (и программы компоновщика) инструментальной цепочки.
В этом смысле Да, они реализованы разработчиками компилятора.
Вы можете предоставить собственный скрипт компоновщика, хотя вы можете указать, на каком конкретном адресе памяти должны быть адресованы эти сегменты, и если эти адреса памяти относятся к ПЗУ или ОЗУ.
Я представляю себе стек стека как простую структуру c, которая вставляется в стек для каждого вызова функции. Я представляю кучу как динамический массив и так далее...
Это совсем не так просто, я боюсь:
Это немного отрывочно - архитектуры HW, модели памяти и т.д. Все влияют на то, как реализация C/C++ может содержать "сегменты". У более старых процессоров были ограничения, в результате чего появился более сложный набор "сегментов" (iAPX 286 - помните?). Просто возьмите это как грубое введение, google для слов buzz,...
Код объекта содержит код, полученный в результате исполняемых инструкций: байты, полученные из собранных машинных инструкций. Это перейдет в сегмент кода, который (как правило) приведет к сегменту памяти, который защищен от записи.
Код объекта содержит данные: байты, полученные из собранных операторов определения данных, с некоторой инициализацией (или по умолчанию, ноль в случае C/C++). Это перейдет в сегмент данных без ограничений доступа.
Стек, который требуется вашему процессору, требуется стек: нажатие обратного адреса в стеке, причем наиболее эффективное согласование передачи параметров осуществляется путем нажатия параметров функции. "Кадр стека" частично "по соглашению", но обычно он состоит из адреса возврата и параметров; дополнительное пространство зарезервировано для локальных переменных: один набор для каждого экземпляра (что важно, если функция рекурсивна).
Куча - это только область памяти, из которой обслуживаются распределения (malloc, new). Обычно он выделяется за пределы сегментов кода и данных. Стеки могут быть выведены из кучи - здесь это зависит от того, есть ли у вас только один сегмент стека или несколько (мыслить потоки).
Кроме того, обратите внимание, что существует несколько объектных кодов "форматы" или "языки", то есть способы определения этих сегментов в объектном коде. Это зависит от того, что может обработать системный загрузчик: один такой формат известен как "a.out", другой - "ELF". Компиляторы должны придерживаться формата и возможностей.