Интерфейс программирования Linux показывает макет виртуального адресного пространства процесса. Является ли каждый регион на диаграмме сегментом?
Из понимания ядра Linux ,
Верно ли, что следующее означает, что модуль сегментации в MMU отображает сегменты и смещения в сегментах в адрес виртуальной памяти, а модуль поискового вызова затем отображает адрес виртуальной памяти в адрес физической памяти?
Блок управления памятью (MMU) преобразует логический адрес в линейный адрес с помощью аппаратной схемы, называемой блоком сегментации; впоследствии вторая аппаратная схема, называемая пейджинговым модулем, преобразует линейный адрес в физический адрес (см. рисунок 2-1).
Тогда почему говорится, что Linux не использует сегментацию, а только пейджинг?
Сегментация включена в микропроцессоры 80x86, чтобы побудить программистов разделить свои приложения на логически связанные объекты, такие как подпрограммы или глобальные и локальные области данных. Однако Linux использует сегментацию очень ограниченным образом. Фактически, сегментация и разбиение по страницам несколько избыточны, потому что оба могут использоваться для разделения физических адресных пространств процессов: сегментация может назначать различное линейное адресное пространство каждому процессу, в то время как разбиение по страницам может отображать одно и то же линейное адресное пространство в разные физические адресные пространства , Linux предпочитает сегментацию подкачки по следующим причинам:
• Управление памятью упрощается, когда все процессы используют одни и те же значения регистров сегмента, то есть когда они совместно используют один и тот же набор линейных адресов.
• Одной из целей проектирования Linux является переносимость на широкий спектр архитектур; В частности, архитектуры RISC имеют ограниченную поддержку сегментации.
Версия Linux 2.6 использует сегментацию только тогда, когда этого требует архитектура 80x86.
Ответы:
Архитектура x86-64 не использует сегментацию в длинном режиме (64-битный режим).
Четыре из регистров сегмента: CS, SS, DS и ES принудительно устанавливаются в 0, а предел в 2 ^ 64.
https://en.wikipedia.org/wiki/X86_memory_segmentation#Later_developments
Операционная система больше не может ограничивать доступные диапазоны «линейных адресов». Поэтому он не может использовать сегментацию для защиты памяти; он должен полностью полагаться на пейджинг.
Не беспокойтесь о деталях процессоров x86, которые применимы только при работе в устаревших 32-битных режимах. Linux для 32-битных режимов используется не так часто. Это даже можно считать "в состоянии доброго пренебрежения в течение нескольких лет". См. 32-разрядную поддержку x86 в Fedora [LWN.net, 2017].
(Бывает, что 32-битный Linux тоже не использует сегментацию. Но вам не нужно доверять мне, вы можете просто проигнорировать это :-).
источник
mov eax, [fs:rdi + 16]
). Ядро использует GS (послеswapgs
), чтобы найти стек ядра текущего процесса вsyscall
точке входа. Но да, сегментация не используется как часть основного механизма управления памятью / защиты памяти ОС.Поскольку в x86 есть сегменты, их невозможно использовать. Но оба
cs
(сегмент кода) иds
(сегмент данных) базовые адреса установлены на ноль, поэтому сегментация на самом деле не используется. Исключением являются локальные данные потока, один из обычно неиспользуемых регистров сегмента указывает на локальные данные потока. Но это главным образом для того, чтобы избежать резервирования одного из регистров общего назначения для этой задачи.Это не говорит о том, что Linux не использует сегментацию на x86, поскольку это было бы невозможно. Вы уже отметили одну часть, Linux использует сегментацию очень ограниченным образом . Вторая часть - Linux использует сегментацию только тогда, когда этого требует архитектура 80x86.
Вы уже процитировали причины, пейджинг проще и более переносим.
источник
Нет.
Хотя система сегментации (в 32-разрядном защищенном режиме на платформе x86) предназначена для поддержки отдельных сегментов кода, данных и стека, на практике все сегменты устанавливаются в одну и ту же область памяти. То есть они начинаются с 0 и заканчиваются в конце памяти (*) . Это делает логические адреса и линейные адреса равными.
Это называется «плоской» моделью памяти, и она несколько проще, чем модель, в которой у вас есть отдельные сегменты, а затем указатели внутри них. В частности, сегментированная модель требует более длинных указателей, поскольку селектор сегмента должен быть включен в дополнение к указателю смещения. (16-битный селектор сегмента + 32-битное смещение для общего 48-битного указателя; вместо 32-битного плоского указателя.)
64-битный длинный режим на самом деле даже не поддерживает сегментацию, кроме модели с плоской памятью.
Если бы вы программировали в защищенном 16-битном режиме на 286, вам бы больше нужны сегменты, поскольку адресное пространство составляет 24 бита, а указатели - только 16 бит.
(* Обратите внимание, что я не могу вспомнить, как 32-битный Linux обрабатывает разделение ядра / пользовательского пространства. Сегментация позволила бы это путем установки пределов сегментов пользовательского пространства, чтобы они не включали пространство ядра. Пейджинг позволяет это, поскольку он обеспечивает уровень защиты на странице.)
В x86 все еще есть сегменты, и вы не можете их отключить. Они просто используются как можно меньше. В 32-битном защищенном режиме сегменты должны быть настроены для плоской модели, и даже в 64-битном режиме они все еще существуют.
источник
wrfsbase
является недопустимым в защищенном режиме / режиме Compat, только в длинном режиме, поэтому в пользовательском пространстве 32-битного ядра не может установить базовую базу FS высокой.Linux x86 / 32 не использует сегментацию в том смысле, что инициализирует все сегменты одним и тем же линейным адресом и пределом. Архитектура x86 требует, чтобы программа имела сегменты: код может выполняться только из сегмента кода, стек может быть расположен только в сегменте стека, данные могут обрабатываться только в одном из сегментов данных. Linux обходит этот механизм, устанавливая все сегменты одинаковым образом (за исключением исключений, которые ваша книга не упоминает в любом случае), так что один и тот же логический адрес действителен в любом сегменте. Это фактически эквивалентно отсутствию сегментов вообще.
источник
Это 2 практически совершенно разных использования слова «сегмент»
Обычаи имеют общее происхождение: если вы были с использованием сегментированной модели памяти (особенно без страничной виртуальной памяти), вы можете иметь данные и BSS адрес быть относительно сегмента базы DS, стек по отношению к основанию SS и кода по отношению к Базовый адрес CS.
Таким образом, несколько разных программ могут быть загружены на разные линейные адреса или даже перемещены после запуска без изменения 16- или 32-битных смещений относительно баз сегментов.
Но тогда вы должны знать, к какому сегменту относится указатель, поэтому у вас есть «дальние указатели» и так далее. (Фактическим 16-битным x86-программам часто не требуется доступ к своему коду в качестве данных, поэтому они могут где-то использовать сегмент кода в 64 КБ и, возможно, еще один блок размером 64 КБ с DS = SS, с ростом стека из-за высоких смещений и данными в дно. Или крошечная модель кода с равными основами всех сегментов).
Как сегментация x86 взаимодействует с подкачкой
Отображение адреса в 32/64-битном режиме:
Таблицы страниц (кэшируемые с помощью TLB) отображаются на линейный физический адрес 32 (устаревший режим), 36 (устаревший PAE) или 52-битный (x86-64). ( /programming/46509152/why-in-64bit-the-virtual-address-are-4-bits-short-48bit-long-compared-with-the ).
Этот шаг не является обязательным: подкачка должна быть включена во время загрузки, установив бит в регистре управления. Без пейджинга линейные адреса являются физическими адресами.
Обратите внимание, что сегментация не позволяет использовать более 32 или 64 бит виртуального адресного пространства в одном процессе (или потоке) , потому что плоское (линейное) адресное пространство, на которое все отображается, имеет столько же битов, сколько и сами смещения. (Это не относится к 16-разрядным версиям x86, где сегментация действительно полезна для использования более 64 КБ памяти с 16-разрядными регистрами и смещениями.)
CPU кэширует дескрипторы сегментов, загруженные из GDT (или LDT), включая базу сегментов. Когда вы разыменовываете указатель, в зависимости от того, в каком регистре он находится, в качестве сегмента по умолчанию используется либо DS, либо SS. Значение регистра (указатель) рассматривается как смещение от базы сегмента.
Поскольку база сегмента обычно равна нулю, процессоры делают это в особом случае. Или с другой стороны, если вы делаете имеете ненулевую базу сегмента, нагрузки имеют дополнительную задержку , потому что «специальный» (нормальный) случай обхода добавления базовый адрес не применяется.
Как Linux настраивает регистры сегментов x86:
База и предел CS / DS / ES / SS равны 0 / -1 в 32- и 64-битном режиме. Это называется плоской моделью памяти, поскольку все указатели указывают на одно и то же адресное пространство.
(Архитекторы процессоров AMD стерилизовали сегментацию, применяя модель плоской памяти для 64-битного режима, потому что основные операционные системы все равно не использовали ее, за исключением защиты без exec, которая была обеспечена гораздо лучшим способом с помощью подкачки с помощью PAE или x86- 64 таблицы формата таблицы.)
TLS (Thread Local Storage): FS и GS не фиксируются на базе = 0 в длинном режиме. (Они были новыми с 386, и не использовались неявно никакими инструкциями, даже
rep
инструкциями -string, которые используют ES). x86-64 Linux устанавливает базовый адрес FS для каждого потока в адрес блока TLS.Например,
mov eax, [fs: 16]
загружает 32-битное значение из 16 байтов в блок TLS для этого потока.дескриптор сегмента CS выбирает, в каком режиме находится CPU (16/32/64-битный защищенный режим / длинный режим). Linux использует одну запись GDT для всех 64-битных процессов в пользовательском пространстве и другую запись GDT для всех 32-битных процессов в пользовательском пространстве. (Чтобы процессор работал правильно, DS / ES также должен быть настроен на допустимые записи, как и SS). Он также выбирает уровень привилегий (ядро (кольцо 0) по сравнению с пользователем (кольцо 3)), поэтому даже при возврате в 64-битное пространство пользователя ядру все равно приходится организовывать изменение CS, используя
iret
илиsysret
вместо обычного прыжок или повтор инструкции.В x86-64
syscall
точка входа используетswapgs
для переключения GS из GS пользовательского пространства в ядро, которое она использует, чтобы найти стек ядра для этого потока. (Специализированный случай локального хранилища потоков).syscall
Инструкция не меняет указатель стека на точку в стеке ядра; он все еще указывает на стек пользователя, когда ядро достигает точки входа 1 .DS / ES / SS также должны быть настроены на допустимые дескрипторы сегментов, чтобы ЦП мог работать в защищенном режиме / длинном режиме, даже если база / лимит этих дескрипторов игнорируются в длинном режиме.
Таким образом, в основном сегментация x86 используется для TLS и для обязательного x86 osdev, что требует от вас аппаратное обеспечение.
Сноска 1: Забавная история: есть архивы списков рассылки сообщений между разработчиками ядра и архитекторами AMD за пару лет до выпуска кремния AMD64, что привело к изменениям в дизайне,
syscall
чтобы его можно было использовать. Смотрите ссылки в этом ответе для деталей.источник