Какие сегменты использует скомпилированная программа C? - PullRequest
3 голосов
/ 02 мая 2010

Я читал в вики OSDev, что защищенный режим архитектуры x86 позволяет вам создавать отдельные сегменты для кода и данных, тогда как вы не можете писать в раздел кода. Эта Windows (да, это платформа) загружает новый код в сегмент кода, и данные создаются в сегменте данных. Но, если это так, как программа знает, что она должна переключать сегменты в сегмент данных? Поскольку, если я правильно понимаю, все адресные инструкции указывают на сегмент, из которого вы запускаете код, если вы не переключите дескриптор. Но я также читал, что модель с плоской памятью с такими ограничениями позволяет запускать код и данные в одном сегменте. Но я читаю это только в связи с ассемблером. Итак, пожалуйста, как обстоят дела с скомпилированным кодом C в Windows? Спасибо.

Ответы [ 2 ]

3 голосов
/ 02 мая 2010

Информация, которую вы прочитали, устарела. Версии Windows с 1993 года используют 32-битное пространство виртуальной памяти. Значения регистров сегментов CS и DS больше не имеют значения и не могут быть изменены. До сих пор существует понятие кода против данных, которое теперь реализуется атрибутами страницы памяти. Просмотрите допустимые значения, переданные в аргументе flNewProtect для API-функции VirtualProtectEx () .

Вы очень редко используете этот API самостоятельно, атрибуты устанавливаются загрузчиком исполняемого образа и менеджером кучи.

2 голосов
/ 02 мая 2010

Существует два значения для сегмента в объяснении:

  • сегмент памяти 8086
  • сегмент программной части объектного модуля

Первый относится к тому, что загружено в регистр сегмента 80386+; он содержит начальный адрес физической памяти, длину выделения памяти, разрешенный доступ на чтение / запись / выполнение, а также рост от низкого до высокого или наоборот (плюс еще несколько неясных флагов, таких как «копирование по ссылке»).

Второе значение является частью языка объектного модуля. В основном, есть сегмент с именем code, сегмент с именем data (который содержит инициализированные данные) и сегмент для неинициализированных данных с именем bss (названный в честь псевдоинструкций ассемблеров 1960-х, означающих Блок, начинающийся с символа ). Когда компоновщик объединяет объектные модули, он объединяет все сегменты кода вместе, все сегменты данных вместе в другом месте, а также bss вместе. Когда загрузчик отображает адреса памяти, он просматривает общее кодовое пространство и выделяет выделение памяти ЦП, по крайней мере, такого размера, и отображает сегмент в код (в ситуации виртуальной памяти) или считывает код в выделенную память, для чего он должен временно установить память как доступную для записи данных. Защита от записи осуществляется через механизм подкачки ЦП, а также регистр сегмента. Это необходимо для защиты попыток записи кода, например, через ошибочный адрес данных. Загрузчик также выполняет аналогичную настройку для двух групп сегментов данных. (Помимо этого, существует настройка сегмента стека и его распределение, а также отображение общих изображений.)

Что касается инструкций выполнения x86, у каждого операнда есть связанный регистр сегмента. Иногда они явные, а иногда неявные. Доступ к коду неявным образом осуществляется через CS, через стек SS, который подразумевается, когда задействован регистр ESP или EBP, и DS подразумевается для большинства других операндов. ES, FS и GS должны быть указаны в качестве переопределения во всех других случаях, за исключением некоторых строковых инструкций, таких как movs и cmps. В плоской модели все регистры сегментов отображаются в одно и то же адресное пространство, хотя CS не позволяет писать.

Итак, чтобы ответить на ваш последний вопрос, ЦПУ имеет четыре (или более) сегментных регистра, настроенных одновременно для доступа к плоскому пространству виртуальной памяти процесса. Доступ каждого операнда проверяется на соответствие инструкции (например, не увеличивается адрес CS), а также проверяется модулем защиты подкачки на предмет его допустимости.

...