Ли Linux не использует сегментацию, а только подкачку?

Интерфейс программирования Linux показывает расположение виртуального адресного пространства процесса. Является ли каждая область диаграммы сегментом?

 введите описание изображения здесь>> </a> </p>

<p> От  Понимание ядра Linux , </p>

<p> Правильно ли это, что единица сегментации в MMU отображает сегменты и смещения внутри сегментов в адрес виртуальной памяти, а блок пейджинга затем отображает адрес виртуальной памяти на адрес физической памяти? </p>

<blockquote>
  <p> Модуль управления памятью (MMU) преобразует логический адрес в линейный
  адрес с помощью аппаратной схемы, называемой единицей сегментации; впоследствии вторая аппаратная схема, называемая блоком поискового вызова, преобразует линейный адрес в физический адрес (см. рис. 2-1). </p>
</blockquote>

<p> <a href= введите описание изображения здесь>> </a> </p>

<p> Тогда почему он говорит, что Linux не использует сегментацию, а только пейджинг? </p>

<blockquote>
  <p> Сегментация была включена в микропроцессоры 80x86 для поощрения
  программистов разделить свои приложения на логически связанные
  таких как подпрограммы или глобальные и локальные области данных. Однако,
  <strong> Linux использует сегментацию очень ограниченным образом. </strong> На самом деле сегментация и пейджинг несколько избыточны, поскольку оба могут быть
  используемый для разделения физических адресных пространств процессов:
  сегментация может назначать различное линейное адресное пространство для каждого
  процесс, в то время как пейджинг может отображать одно и то же линейное адресное пространство в
  различные физические адресные пространства. Linux предпочитает подкачку
  сегментации по следующим причинам: </p>
  
  <p> • Управление памятью проще, когда все процессы используют один и тот же сегмент
  регистрируют значения, т. е. когда они имеют один и тот же набор линейных
  адреса. </p>
  
  <p> • Одна из целей проектирования Linux - переносимость в широком диапазоне
  архитектуры; Архитектуры RISC, в частности, ограничены
  поддержка сегментации. </p>
  
  <p> 2.6 версия Linux использует сегментацию только тогда, когда требуется
  80x86. </p>
</blockquote></body></html>

25 голосов | спросил Tim 15 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowSat, 15 Sep 2018 18:34:17 +0300 2018, 18:34:17

6 ответов


26

Короткий ответ: Ядро Linux в некоторой степени способно обрабатывать сегменты и пейджинг. Каждый из этих методов предлагает несколько преимуществ, например, сегментация обеспечивает лучшую безопасность, поскольку сегменты предопределены, и мы можем избежать ложных чтений /записей во время переходов адреса и т. Д. С другой стороны, пейджинг помогает уменьшить фрагментацию (поскольку не будет отверстия памяти, оставшиеся от меньших отверстий) и обеспечивает лучшее управление памятью. Таким образом, ядро ​​Linux и большинство современных операционных систем используют комбинацию обоих этих методов для управления их памятью.

Теперь давайте впихнемся в него! Сначала мы должны уточнить разницу между paging и сегментацией на уровне процессора, а затем в системе Linux. Сегментация и пейджинг были включены в микропроцессоры Intel, чтобы побудить программистов разделить свои приложения на логически связанные объекты, такие как подпрограммы или глобальные и локальные области данных.

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

Во-первых, есть сегмент, который представляет собой массив памяти с определенным размером. Первый указатель просто указывает на этот сегмент и этим обращается ко всему сегменту. Чтобы указать, что означает байт в этом сегменте, необходим второй указатель, который является только локальным для сегмента. Таким образом, эти два комбинированных могут обращаться к одному байту. Например, у вас может быть 16-разрядный указатель для сегментов для адресации 65536 разных сегментов и 16-разрядного локального указателя в них для обращения к байтам. Недостатком этого является то, что локальный указатель определяет максимальный размер блока непрерывной памяти. Возможно, вы сможете использовать всю память, но каждый используемый вами блок может составлять только часть максимальной памяти, которую вы можете использовать. Это особенно важно для программ, работающих на больших наборах данных (перемещение кодировщиков, 3D-рендеринга, баз данных и т. Д.). Это серьезная проблема.

 введите описание изображения здесь>> </a> </p>

<p>  Пейджинг  представляет собой комбинацию преимуществ модели с плоской памятью (только один указатель, адресующий все пространство памяти) и возможность определять блоки памяти, которые несколько изолированы от других. В пейджинговой системе у вас есть один указатель, адресующий всю память. Таким образом, 32-разрядная система с 32-разрядным указателем способна адресовать 4 ГБ памяти с каждым адресом, указывающим ровно на один байт. Но эта область памяти по-прежнему разбита на «страницы». Страница - это всего лишь блок памяти определенного размера. И здесь начинается «волшебство». Процессор имеет второе отображение, которое точно определяет, как каждая из этих страниц отображается в «плоское» пространство памяти. Программа, использующая память, воспринимает ее как полностью плоскую. Он может адресовать каждый байт только одним указателем. Но ядро ​​может переместить блоки памяти, определить для них специальные атрибуты и т. Д. Например, ядро ​​может определить такой блок памяти «только для чтения» и завершать каждую программу, которая пытается ее записать. Кроме того, подкачка основана на следующем: предположим, что программа пытается получить доступ к адресу памяти вне диапазона физически доступной памяти. Ядро может поймать это, выбрать один блок памяти, который не использовался в течение некоторого времени, и записать его в пространство подкачки, затем взять эту страницу памяти и сопоставить ее с местом, в которое приложение попыталось написать, и магически больше памяти для доступных приложений, чем машина. </p>

<p> Все это очень низкоуровневое и что подразумевается, когда ядро ​​Linux предпочитает разбиение на страницы по сегментации. Но, говоря только об этом, ядро ​​Linux может в какой-то мере иметь дело и иногда даже комбинировать подходы (32-разрядный Linux <a href = PAE , например).

 введите описание изображения здесь>> </a> </p>

<p> Теперь давайте поговорим о сегментах  в программах . Хотя этот уровень по-прежнему довольно низкий, он намного выше, чем сегменты на уровне процессора, и снова все упростилось просто, чтобы дать идею. Когда у вас есть исполняемый файл, это в основном просто дамп памяти, который необходимо загрузить обратно в память и затем выполнить. Но не все в исполняемом файле - это код. Исполняемые файлы могут содержать данные, а также текст на кнопках и т. Д. Поэтому, чтобы сделать это проще, программы делятся на сегменты, для кода, для данных. Когда исполняемый файл загружен, те его части попадают в разные части памяти с разными способностями. Чтобы сделать программы более безопасными, например, хорошая практика позволяет разрешать только код в сегменте кода. Это предотвращает любые атаки, которые пытаются манипулировать данными программы до действительного двоичного кода, а затем каким-то образом исполняется. Ядро заметит, что что-то в сегменте данных должно быть выполнено и будет предотвращать это. </p>

<p> Более подробные данные приведены здесь: <a href= 1 , 2 , 3 и 4 .

ответил Goro 15 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowSat, 15 Sep 2018 18:52:03 +0300 2018, 18:52:03
21

Архитектура x86-64 не использует сегментацию в длинном режиме (64-разрядный режим).

Четыре из сегментных регистров: CS, SS, DS и ES принудительно равны 0, а предел равен 2 ^ 64.

https://en.wikipedia.org/wiki/X86_memory_segmentation#Later_developments

OS не позволяет ограничить, какие диапазоны «линейных адресов» доступны. Поэтому он не может использовать сегментацию для защиты памяти; он должен полностью полагаться на пейджинг.

Не беспокойтесь о деталях процессоров x86, которые будут применяться только при запуске в 32-разрядных режимах. Linux для 32-битных режимов не используется так сильно. Его можно даже считать «в состоянии мягкого пренебрежения в течение нескольких лет». См. 32-разрядная поддержка x86 в Fedora [LWN.net, 2017].

(Случается, что 32-разрядная Linux тоже не использует сегментацию, но вам не нужно доверять мне, вы можете просто игнорировать ее: -).

ответил sourcejedi 15 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowSat, 15 Sep 2018 18:50:58 +0300 2018, 18:50:58
10

Поскольку x86 имеет сегменты, их невозможно использовать. Но оба cs (сегмент кода) и ds (сегмент данных) базовые адреса установлены на ноль, поэтому сегментация на самом деле не используется. Исключение составляют локальные данные потока, один из обычно неиспользуемых регистров сегмента указывает на локальные данные потока. Но это в основном заключается в том, чтобы избежать резервирования одного из регистров общего назначения для этой задачи.

Он не говорит, что Linux не использует сегментацию на x86, поскольку это было бы невозможно. Вы уже выделили одну часть, Linux использует сегментацию очень ограниченным образом . Вторая часть Linux использует сегментацию только тогда, когда это требуется архитектурой 80x86

Вы уже указали причины, пейджинг проще и портативнее.

ответил RalfFriedl 15 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowSat, 15 Sep 2018 18:52:28 +0300 2018, 18:52:28
7
  

Является ли каждая область диаграммы сегментом?

Нет.

В то время как система сегментации (в 32-битном защищенном режиме на x86) предназначена для поддержки отдельных сегментов кода, данных и стека, на практике все сегменты настроены на одну и ту же область памяти. То есть они начинаются с 0 и заканчиваются в конце памяти (*) . Это делает логические адреса и линейные адреса равными.

Это называется «плоской» моделью памяти и несколько проще, чем модель, в которой у вас есть отдельные сегменты, а затем указатели внутри них. В частности, сегментированная модель требует более длинных указателей, поскольку селектор сегмента должен быть включен в дополнение к указателю смещения. (16-битный сегментный селектор + 32-битное смещение для всего 48-битного указателя, а всего 32-разрядный плоский указатель.)

64-битный длинный режим на самом деле даже не поддерживает сегментацию, отличную от модели с плоской памятью.

Если вы должны были запрограммировать в 16-битном защищенном режиме на 286, у вас будет больше потребности в сегментах, поскольку адресное пространство составляет 24 бита, но указатели - всего 16 бит.

(* Обратите внимание, что я не могу вспомнить, как 32-разрядная Linux обрабатывает разделение ядра /пользовательского пространства. Сегментация позволит это путем установки пределов сегментов пользовательского пространства, чтобы они не включали пространство ядра. для него, поскольку он обеспечивает уровень защиты для каждой страницы.)

  

Тогда почему говорится, что Linux не использует сегментацию, а только подкачку?

У x86 все еще есть сегменты, и вы не можете их отключить. Они просто используются как можно меньше. В 32-битном защищенном режиме сегменты должны быть настроены для плоской модели, и даже в 64-битном режиме они все еще существуют.

ответил ilkkachu 16 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowSun, 16 Sep 2018 19:59:37 +0300 2018, 19:59:37
2
  

Является ли каждая область диаграммы сегментом?

Это два почти полностью разных слова «сегмент»

  • x86 сегментирование /сегментные регистры: современные x86 операционные системы используют модель с плоской памятью, где все сегменты имеют одинаковое значение base = 0 и limit = max в 32-битном режиме, то же самое, что и аппаратное обеспечение, которое используется в 64-битном режиме , что делает сегментированный вид рудиментарным. (За исключением FS или GS, используется для локального хранилища потоков даже в режиме 64-разрядной версии.)
  • Секции /сегменты компоновщика /программ-загрузчика. ( В чем разница раздела и сегмента в формате файлов ELF )

Употребления имеют общее происхождение: если вы были с использованием сегментированной модели памяти (особенно без выгружаемой виртуальной памяти), у вас могут быть данные и адреса BSS относительно базы сегмента DS, к базе SS и коду относительно базового адреса CS.

Таким образом, несколько разных программ могут быть загружены на разные линейные адреса или даже перемещены после запуска без изменения 16 или 32-битных смещений относительно базовых сегментов.

Но тогда вам нужно знать, к какому сегменту относится указатель, поэтому у вас есть «дальние указатели» и т. д. (Фактические 16-разрядные x86-программы часто не нуждались в доступе к их коду в качестве данных, поэтому могли бы использовать сегмент кода 64k где-то и, возможно, еще один 64-килобайтный блок с DS = SS, причем стек, растущий из-за высоких смещений, и данные на нижняя. Или крошечная модель кода со всеми базовыми сегментами).


Как сегментирование x86 взаимодействует с пейджингом

Отображение адреса в 32/64-битном режиме:

  1. сегмент: смещение (база сегментов, подразумеваемая регистром, содержащим смещение, или переопределенная префиксом команды)
  2. 32 или 64-битный линейный виртуальный адрес = базовый + смещение. (В модели с плоской памятью, такой как Linux, используются указатели /смещения = линейные адреса. За исключением случаев, когда вы получаете доступ к TLS относительно FS или GS.)
  3. таблиц страниц (кэшированных TLB) отображаются линейные до 32 (устаревший режим), 36 (устаревший PAE) или 52-битный (x86-64) физический адрес. ( https :. //stackoverflow.com/questions/46509152/why-in-64bit-the-virtual-address-are-4-bits-short-48bit-long-compared-with-the )

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

Обратите внимание, что сегментация not позволяет использовать более 32 или 64 бит виртуального адресного пространства в одном процессе (или потоке) , поскольку плоская (линейная) адресное пространство, на которое отображается все, содержит только то же количество бит, что и сами смещения. (Это было не так для 16-разрядного x86, где сегментация была действительно полезна для использования более 64 тыс. Памяти с преимущественно 16-разрядными регистрами и смещениями.)


ЦП кэширует дескрипторы сегментов, загруженные из GDT (или LDT), включая базу сегментов. Когда вы разыскиваете указатель, в зависимости от того, в каком регистре он находится, по умолчанию используется либо DS, либо SS как сегмент. Значение регистра (указатель) рассматривается как смещение от базы сегмента.

Так как база сегментов обычно равна нулю, CPU делают это в особом случае. Или с другой точки зрения, если вы do имеете ненулевую базу сегментов, нагрузки имеют дополнительную задержку, потому что «специальный» (обычный) случай обхода добавления базового адреса не применяется.


Как Linux устанавливает регистры сегментов x86:

Основание и предел CS /DS /ES /SS - все 0 /-1 в 32 и 64-битном режиме. Это называется плоской моделью памяти, поскольку все указатели указывают на одно и то же адресное пространство.

(архитекторы AMD процессоров экранировали сегментацию с помощью обеспечения модели плоской памяти для 64-битного режима, потому что основные операционные системы не использовали ее в любом случае, за исключением защиты от отсутствия exec, которая была предоставленав гораздо лучшем виде, используя пейджинг с форматом страницы PAE или x86-64.)

  • TLS (локальное хранилище потоков): FS и GS not фиксированы в base = 0 в длинном режиме. (Они были новыми с 386 и не используются неявно с помощью каких-либо инструкций, даже инструкции ---- +: = 0 =: + ----, которые используют ES). x86-64 Linux устанавливает базовый адрес FS для каждого потока на адрес блока TLS.

    например. rep загружает 32-битное значение из 16 байтов в блок TLS для этого потока.

  • дескриптор сегмента CS выбирает, в каком режиме находится процессор (16/32/64-битный защищенный режим /длительный режим). Linux использует единую запись GDT для всех 64-разрядных процессов в пространстве пользователя и другую запись GDT для всех 32-разрядных процессов в пространстве пользователя. (Для того, чтобы CPU работал правильно, DS /ES также должны быть установлены на допустимые записи, а также SS). Он также выбирает уровень привилегий (ядро (кольцо 0) против пользователя (кольцо 3)), поэтому даже при возврате в 64-разрядное пользовательское пространство ядро ​​все же должно организовать изменение CS, используя mov eax, [fs: 16] или iret вместо обычного перехода или команды ret.

  • В x86-64 точка ввода sysret использует syscall, чтобы перевернуть GS из пользовательского пространства GS в ядро, которое оно использует для поиска стека ядра для этого потока. (Специализированный случай локального хранилища потоков). Инструкция swapgs не меняет указатель стека на стек ядра; он все еще указывает на стек пользователя, когда ядро ​​достигает точки входа 1 .

  • DS /ES /SS также необходимо установить на допустимые дескрипторы сегментов для работы ЦП в защищенном режиме /длительном режиме, даже если база /предел из этих дескрипторов игнорируется в длинном режиме.

Таким образом, в основном для сегментации TLS используется сегментация x86, а для обязательного содержимого x86 osdev, которое требуется для аппаратного обеспечения.


Сноска 1: История припусков: есть архив списков рассылки сообщений между разработчиками ядра и архитекторами AMD за пару лет до того, как был выпущен кремний AMD64, что привело к изменениям дизайна syscall, чтобы он был полезен. См. Ссылки в этот ответ для деталей.

ответил Peter Cordes 17 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowMon, 17 Sep 2018 14:08:26 +0300 2018, 14:08:26
2

Linux x86 /32 не использует сегментацию в том смысле, что он инициализирует все сегменты одним и тем же линейным адресом и лимитом. Архитектура x86 требует, чтобы программа имела сегменты: код может выполняться только из сегмента кода, стек может находиться только в сегменте стека, данные могут обрабатываться только в одном из сегментов данных. Linux обходит этот механизм, устанавливая все сегменты одинаково (с исключениями, которые ваша книга не упоминает в любом случае), так что один и тот же логический адрес действителен в любом сегменте. Это фактически эквивалентно отсутствию сегментов.

ответил Dmitry Grigoryev 17 thEurope/Moscowp30Europe/Moscow09bEurope/MoscowMon, 17 Sep 2018 15:56:38 +0300 2018, 15:56:38

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132