Чому (не) сегментація?


42

Я вивчаю операційні системи та архітектуру x86, і, коли я читав про сегментацію та пейджинг, мені, природно, було цікаво, як сучасні ОС керують управлінням пам'яттю. З того, що я виявив, Linux та більшість інших операційних систем по суті уникають сегментації на користь пейджингу. Декілька причин цього, які я знайшов, - це простота та портативність.

Які практичні можливості існують для сегментації (x86 чи іншим способом) і чи зможемо ми коли-небудь побачити надійні операційні системи, що використовують її, чи вони надалі надаватимуть перевагу системі, що базується на пейджингу.

Тепер я знаю, що це навантажене питання, але мені цікаво, як сегментація буде оброблятися за допомогою нових розроблених операційних систем. Чи має такий сенс віддавати перевагу пейджингу, що ніхто не вважатиме більш «сегментований» підхід? Якщо так, то чому?


І коли я кажу про "сегментацію", я маю на увазі, що Linux використовує її лише наскільки це потрібно. Лише 4 сегменти для сегментів коду / даних ядра користувача та ядра. Читаючи документацію Intel, я просто відчув, що сегментація розроблена з більш надійними рішеннями. Потім мені неодноразово говорили, наскільки складним може бути х86.


Цей цікавий анекдот я знайшов після того, як він був пов'язаний з оригінальним "оголошенням" для Linux Torvald для Linux. Про це він сказав кілька публікацій пізніше:

Просто я б сказав, що перенесення неможливо. Це здебільшого на C, але більшість людей не називатиме те, що я пишу C. Він використовує всі можливі функції 386, які я міг би знайти, оскільки це був також проект, який навчає мене про 386. Як уже згадувалося, він використовує MMU , як для підкачки (ще не на диску), так і для сегментації. Саме сегментація робить її НАДАЛЬНО 386 залежною (кожне завдання має 64Mb сегмент для коду та даних - максимум 64 завдання в 4Gb. Кожен, кому потрібно більше 64Mb / завдання - жорсткі файли cookie).

Я думаю, що власні експерименти з x86 змусили мене задати це питання. У Лінуса не було StackOverflow, тому він просто реалізував його, щоб спробувати його.


Яку книгу ви прочитали?

1
Я читаю ряд книг. Я почав розпитувати про це, читаючи посібник із програмування Intel Systems (т. 3), але трохи прочитав про управління пам'яттю Linux у "Розуміння ядра Linux" та інших джерелах в Інтернеті.
Містер Шикаданс

Зокрема, я читав розділ «Місцеві таблиці дескрипторів», і мені було цікаво, як ці операційні системи використовують це.
Містер Шикаданс

1
OpenBSD поєднує сегментацію x86 та пейджинг для отримання бітового моделювання NX (функція захисту, яка забороняє виконання сторінок даних). Можливо, PaX також використовував це.

Я майже нічого не знаю з цього приводу. Я просто набрав пошукове запитання, щоб побачити відповіді на скарги на всі використовувані зараз операційні системи. Переглядаючи скарги, більшість людей використовують ПК і зараз планшети для виконання декількох конкретних завдань. То чому б не виділити більше обсягу використання пам'яті, щоб виконувати ці завдання швидше, на відміну від надання всіх периферійних лайнів, які мають доступ до нього.

Відповіді:


31

При сегментації можна було б, наприклад, помістити кожен динамічно виділений об'єкт (malloc) у свій власний сегмент пам'яті. Обладнання перевірило б обмеження сегментів автоматично, і весь клас помилок безпеки (перевиконання буфера) буде усунутий.

Крім того, оскільки всі зміщення сегмента починаються з нуля, весь складений код автоматично буде незалежним від позиції. Виклик в іншу DLL зводиться до далекого виклику з постійним зміщенням (залежно від викликаної функції). Це значно спростить компонувачі та навантажувачі.

За допомогою 4-х захисних кілець можна розробити більш тонкий контроль доступу (під час підкачки у вас є лише два рівні захисту: користувач та керівник) та більш надійні ядра ОС. Наприклад, лише кільце 0 має повний доступ до обладнання. Розділяючи основні драйвери ядра ОС та драйвери пристроїв на кільця 0 і 1, ви можете зробити більш надійну і дуже швидку операційну систему мікроядра, де більшість відповідних перевірок доступу здійснюватиме HW. (Драйвери пристроїв могли отримати доступ до обладнання через растровий доступ вводу / виводу в TSS.)

Однак .. x86 трохи обмежений. Він має лише 4 «вільних» регістри даних; перезавантажити їх досить дорого, і можна одночасно отримати доступ лише до 8192 сегментів. (Якщо припустити, що ви максимізуєте кількість доступних об'єктів, тому GDT містить лише системні дескриптори та дескриптори LDT.)

Тепер, за допомогою 64-бітного режиму сегментація описується як "спадщина", а перевірка обмежень апаратних засобів проводиться лише в обмежених обставинах. ІМХО, ВЕЛИЧНА помилка. Насправді я не звинувачую Intel, я здебільшого звинувачую розробників, більшість з яких вважають, що сегментація є "надто складною" і прагнула плоского адресного простору. Я також звинувачую письменників з ОС, яким не вистачало уяви, щоб добре застосувати сегментацію. (AFAIK, OS / 2 була єдиною операційною системою, яка повною мірою використовувала функції сегментації.)


1
Ось чому я залишив це відкритим. У цьому питанні, безумовно, є кілька різних питань ...
Містер Шикаданс

1
@zvrba: Яке чудове пояснення !!! Дякую за це. Тепер у мене виникають сумніви: ви не думаєте, що INTEL міг би виграти великий приз, зробивши сегменти, що не перекриваються, та 4 Гб, здатні допомогти під час пейджингу? Я маю на увазі, як я зрозумів, "сегментація з пейджингом" здатна адресувати максимум 4 Гб адресного простору віртуальної пам'яті. І це «арахіс» !!! Уявіть, що ви можете мати сегменти даних з кодом, стеком, розміром до 4 ГБ кожен і не перекриватись, а не перекриватись, як вам потрібно! І це було б на той час великим успіхом, не вимагаючи повної 64-бітової архітектури як сьогодні.
фантер

1
Фантастичне пояснення того, чому сегментація хороша. Страшно соромно, що воно впало обочиною. Ось розробка з більш детальною інформацією для тих, кому цікаво дізнатися більше.
ВВП2

1
Недарма я любив ОС / 2! Яка сумна втрата справді цінної технології завдяки незнанню та маркетингу.
іллюмінат

Кожен, хто вважає, що сегментація є гарною ідеєю, не повинен бути достатньо дорослим, щоб пам’ятати, яка жахлива сегментація. Це жахливо. Практично весь C-код, коли-небудь написаний, передбачає рівний адресний простір. Зручно бути в змозі подивитися на вказівник і просто побачити його адресу, не потрібно копатися в базі сегмента, припускаючи, що це навіть можливо, що це не в сегментації захищеного режиму x86, якщо тільки ядро ​​не дозволяє бачити це якось, швидше за все, з дуже дорогим системним викликом. Заміна неможлива за допомогою сегментів, якщо ви не замінюєте цілі сегменти. Пейджинг - це далеко, набагато вище.
doug65536

25

Коротка відповідь полягає в тому, що сегментація - це хак, який використовується для того, щоб процесор з обмеженою здатністю адреси пам'яті перевищував ці межі.

У випадку з 8086 на чіпі було 20 рядків адреси, що означає, що він може фізично отримати доступ до 1 Мб пам'яті. Однак внутрішня архітектура базувалася на 16-бітовій адресації, ймовірно, через бажання зберегти узгодженість з 8080. Отже, набір інструкцій включав сегментні регістри, які поєднувалися б з 16-бітовими індексами, щоб дозволити адресацію повного 1 Мб пам'яті. . 80286 поширив цю модель на справжній MMU, щоб підтримати сегментний захист та адресацію більшої кількості пам'яті (iirc, 16Mb).

Що стосується PDP-11, більш пізні моделі процесора забезпечили сегментацію в просторах Інструкції та Дані, знову підтримуючи обмеження 16-бітного адресного простору.

Проблема з сегментацією проста: ваша програма повинна явно обходити обмеження архітектури. У випадку з 8086, це означало, що найбільший суміжний блок пам'яті, до якого ви могли отримати доступ, був 64k. якщо вам потрібно було отримати більше доступу до цього, вам доведеться змінити регістри сегментів. Що означало для програміста C, що вам потрібно було сказати компілятору C, які саме вказівники він повинен генерувати.

Набагато простіше було програмувати MC68k, який мав 32-бітну внутрішню архітектуру та 24-бітний фізичний адресний простір.


5
Добре, що все має сенс. Однак, читаючи документи Intel, можна схилити думати, що сегменти можуть бути використані для більш високого захисту апаратного рівня від програмних помилок. Зокрема, розділ 3.2.3 Посібника із системного програмування - чи є переваги для багатосегментної моделі? Чи правильно було б сказати, що Linux використовує захищену плоску модель? (розділ 3.2.2)
Містер Шикаданс

3
Минуло багато часу, коли я звернув увагу на деталі архітектури пам'яті Intel, але не думаю, що сегментована архітектура забезпечила б більший апаратний захист. Єдиний реальний захист, який може вам надати MMU, - це відокремлення коду та даних, запобігаючи атакам перевищення буфера. І я вважаю, що це можна керувати без сегментів, за допомогою атрибутів на рівні сторінки. Теоретично можна обмежити доступ до об'єктів, створивши окремий сегмент для кожного, але я не вважаю це розумним.

1
Спасибі, ви повернули всі пригнічені спогади про обробку зображень на сегментованій пам’яті - це означатиме більше терапії!
Мартін Бекетт

10
Ви повністю зрозуміли сегментацію. У 8086 році це могло бути хаком; 80286 запроваджено захищений режим, коли це було вирішальним для захисту; у 80386 р. він ще більше розширився, і сегменти можуть бути більшими, ніж 64 кБ, все ж за рахунок перевірки обладнання. (BTW, 80286 НЕ мав MMU.)
zvrba

2
Ще в 1985 році, коли було представлено 386, адресний простір 4 Гб вважався величезним. Пам’ятайте, що жорсткий диск на 20 МіБ був на той час досить великим, і система все ще не була рідкістю для систем, які оснащувалися лише дисководами. 3,5-дюймовий FDD був представлений у 1983 році, він має форматовану ємність з величезних 360 КБ. (1,44 МБ 3,5-дюймових FDD-дисків стали доступними в 1986 році.) В рамках експериментальної помилки всі тоді думали про 32-бітовий адресний простір, як ми думаємо зараз з 64 біт: фізично доступний, але настільки великий, щоб бути практично нескінченним.
CVn

15

Для 80x86 є 4 варіанти - "нічого", тільки сегментація, лише підказка, і сегментація, і підкачка.

Для "нічого" (без сегментації чи підкачки) у вас є не простий спосіб захистити процес від себе, ні простий спосіб захистити процеси один від одного, ні спосіб обробляти такі речі, як фізична фрагментація адресного простору, ніяким способом уникнути позиції незалежний код і т. д. Незважаючи на всі ці проблеми, він (теоретично) може бути корисним у деяких ситуаціях (наприклад, вбудований пристрій, який працює лише в одному додатку; або, можливо, щось, що використовує JIT і все-таки віртуалізує все).

Тільки для сегментації; він майже вирішує проблему "захистити процес від себе", але потрібно багато роботи, щоб зробити його корисним, коли процес хоче використовувати більше 8192 сегментів (припускаючи один LDT за процес), що робить його в основному порушеним. Ви майже вирішуєте проблему "захистити процеси один від одного"; але різні частини програмного забезпечення, що працюють на одному рівні привілеїв, можуть завантажувати / використовувати сегменти один одного (є способи обійти це - змінити записи GDT під час передачі керування та / або використання LDT). Крім того, він здебільшого вирішує проблему "незалежного від позиції коду" (це може спричинити проблему "кодового сегмента", але це набагато менш важливо). Це нічого не робить для проблеми "фізичної фрагментації адресного простору".

Тільки для пейджингу; це не вирішує проблему "захистити процес від себе" сильно (але будьмо чесними тут, це справді проблема лише для налагодження / тестування коду, написаного на небезпечних мовах, і в будь-якому випадку є набагато більш потужні інструменти, такі як valgrind). Він повністю вирішує проблему "захистити процеси один від одного", повністю вирішує проблему "код незалежно від позиції" і повністю вирішує проблему "фрагментація простору фізичного адресного простору". Як додатковий бонус, він відкриває кілька дуже потужних прийомів, які ніде не є практичними без пейджингу; включаючи такі речі, як "копіювати при записі", файли з картографічною пам'яттю, ефективна обробка місцями обміну і т.д.

Тепер ви подумаєте, що використання як сегментації, так і пейджингування дасть вам переваги обом; і теоретично це може, за винятком того, що єдиною вигодою, яку ви отримуєте від сегментації (що не робиться краще під час пейджингу), є рішення проблеми "захистити процес від себе", про яку ніхто насправді не хвилює. На практиці те, що ви отримуєте, - це складності і обох, і обох витрат, за дуже малу користь.

Ось чому майже всі ОС, розроблені для 80x86, не використовують сегментацію для управління пам’яттю (вони використовують її для таких речей, як per-CPU і зберігання за завданням, але це переважно для зручності, щоб уникнути використання більш корисного реєстру загального призначення для них речі).

Звичайно, виробники процесорів не дурні - вони не збираються витрачати час і гроші, оптимізуючи те, що вони, як відомо, ніхто не використовує (вони замість цього оптимізують те, що використовують майже всі). З цієї причини виробники процесорів не оптимізують сегментацію, що робить сегментацію повільнішою, ніж це могло бути, що змушує розробників ОС хотіти уникати її ще більше. Здебільшого вони зберігали сегментацію лише для зворотної сумісності (що важливо).

Врешті-решт, AMD розробила довгий режим. Старого / існуючого 64-бітного коду для занепокоєння не було, тому AMD (для 64-бітного коду) позбулася стільки сегментації, скільки могли. Це дало розробникам ОС ще одну причину (не простий спосіб перенести код порту, розроблений для сегментації до 64-розрядних), щоб продовжувати уникати сегментації.


13

Я досить приголомшений тим, що за весь час, коли це питання було розміщено, ніхто не згадував про джерела архітектури сегментованої пам'яті та справжню силу, яку вони можуть собі дозволити.

Оригінальною системою, яка була або придумана, або вдосконалена у корисній формі, усі функції, пов’язані з дизайном та використанням сегментованих систем віртуальної пам’яті (разом із симетричними багатообробними та ієрархічними файловими системами) була Multics (див. Також сайт Multicians ). Сегментована пам’ять дозволяє Multics запропонувати користувачеві переконатися, що все знаходиться у (віртуальній) пам'яті, і це дозволяє на остаточному рівні спільного використання всьогоу прямій формі (тобто безпосередньо адресується в пам'яті). Файлова система стає просто картою всіх сегментів пам'яті. При правильному використанні систематично (як і в Multics) сегментована пам'ять звільняє користувача від багатьох обтяжень управління вторинним зберіганням даних, обміну даними та комунікацій між процесами. Інші відповіді висловлювали деякі хвилеподібні твердження, що сегментовану пам’ять важче використовувати, але це просто не відповідає дійсності, і Multics довів це з величезним успіхом десятиліття тому.

Intel створила версію сегментованої пам’яті 80286, яка хоч і є досить потужною, але її обмеження не дозволяють використовувати її для чогось справді корисного. 80386 покращився завдяки цим обмеженням, але на той час ринкові сили значною мірою заважали досягти успіху будь-якої системи, яка справді могла б скористатися цими вдосконаленнями. За роки, як здається, занадто багато людей навчилися ігнорувати уроки минулого.

Intel також спробувала на початку створити більш здатний супер-мікрофон під назвою iAPX 432, який би набагато перевершив будь-що інше на той момент, і він мав сегментовану архітектуру пам'яті та інші функції, сильно орієнтовані на об'єктно-орієнтоване програмування. Початкова реалізація була занадто повільною, і жодних подальших спроб не було зроблено.

Більш детальне обговорення того, як сегментація та пейджинги, що використовуються в мультимедіа, можна знайти у статті Поля Гріна Віртуальна пам'ять Multics - Навчальний посібник та роздуми


1
Чудова інформація та чудові аргументи. Спасибі за посилання, вони безцінні !!!
фантер

1
Дякуємо за посилання на Multics та за дуже інформативну відповідь! Очевидно, що сегментація багато в чому переважала те, що ми робимо зараз.
ВВП2

1
Ваша відповідь - справжній дорогоцінний камінь у грубій формі. Дуже дякую вам за те, що ви поділилися цією інформацією, яку ми втратили. Змушує мене прагнути повернутись до сегментації через розробку належної ОС, яка може спонукати до вдосконалення обладнання. Справді так багато питань можна було б покращити таким підходом! Це навіть звучить так, ніби ми могли отримати справжні мови OOP на набагато вищих рівнях продуктивності та на голому металі з сегментацією.
іллюмінат

6

Сегментація була злому / подолання, щоб дозволити до 1 МБ пам'яті вирішуватись 16-бітовим процесором - зазвичай лише 64 Кб пам'яті було б доступним.

Коли 32-бітові процесори прийшли до вас, ви могли звернутись до 4 Гб оперативної пам’яті з плоскою моделлю пам'яті і більше не було потреби в сегментації - сегментні регістри були повторно призначені як селектори для GDT / пейджингу в захищеному режимі (хоча ви можете захищений режим 16-розрядних).

Також режим з плоскою пам'яттю набагато зручніший для компіляторів - ви можете писати 16-бітні сегментовані програми на C , але це дуже громіздко. З плоскою моделлю пам'яті все простіше.


Чи багато чого можна сказати про «захист», що забезпечується сегментацією, коли ми можемо просто використовувати пейджинги замість цього?
Містер Шикаданс

1
@Містер. Shickadance сегментація не забезпечує будь-якого захисту пам’яті - для захисту пам’яті вам потрібен захищений режим, у якому ви можете захистити пам’ять, використовуючи або GDT, або пейджинговий виклик.
Джастін

5

Деякі архітектури (наприклад, ARM) взагалі не підтримують сегменти пам'яті. Якби Linux залежав від джерел від сегментів, його не можна було б легко перенести на ці архітектури.

Дивлячись на більш широку картину, провал сегментів пам'яті пов'язаний із постійною популярністю арифметики С та покажчика. Розробка C більш практична для архітектури з плоскою пам'яттю; і якщо ви хочете отримати рівну пам'ять, ви вибираєте підкачку пам'яті.

Був час на рубежі 80-х, коли Intel, як організація, передбачала майбутню популярність Ада та інших мов програмування вищого рівня. В основному, звідси випливали деякі їх більш ефектні збої, такі як жахлива сегментація APX432 та 286 пам'яті. З 386 вони капітулювали перед програмістами з плоскою пам'яттю; Пейджинг та TLB додано, і сегменти зробили розміром до 4 Гб. А потім AMD в основному видалив сегменти з x86_64, зробивши базовий рег-центр догляду / мається на увазі 0 (крім fs? Для TLS, я думаю?)

Сказавши це, переваги сегментів пам'яті очевидні - перемикання адресних просторів без необхідності перенаселення TLB. Можливо, коли-небудь хтось зробить конкурентоспроможний процесор, який підтримує сегментацію, ми можемо запрограмувати на нього орієнтовану на сегментацію ОС, а програмісти можуть зробити Ada / Pascal / D / Rust / other-langage-that-not-need-flat -пам'ятні програми для цього.


1

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

Цікаво, що я часто задаюся питанням, наскільки кращим може бути i86, якщо Intel викреслить усю підтримку цих старих режимів. Тут краще передбачає меншу потужність і, можливо, більш швидку експлуатацію.

Думаю, можна стверджувати, що Intel розводив молоко з 16-ти бітовими сегментами, що призводить до бунту сортів розробників. Але давайте визнаємо, що адресний простір на 64 кб - це не особливо, якщо дивитися на сучасний додаток. Врешті-решт, їм довелося щось зробити, оскільки конкуренція могла і ефективно реалізовувала ринок проти проблем, що стосуються простору i86.


1

Сегментація призводить до уповільнення перекладу сторінок і заміни

З цих причин сегментація значною мірою випала на x86-64.

Основна відмінність між ними полягає в тому, що:

  • підкачка розбиває пам'ять на шматки фіксованого розміру
  • сегментація дозволяє різну ширину для кожного шматка

Хоча це може бути розумнішим мати настроювані ширини сегментів, оскільки ви збільшуєте розмір пам'яті для процесу, фрагментація неминуча, наприклад:

|   | process 1 |       | process 2 |                        |
     -----------         -----------
0                                                            max

з часом стане те, що процес 1 зростає:

|   | process 1        || process 2 |                        |
     ------------------  -------------
0                                                            max

поки розкол неминучий:

|   | process 1 part 1 || process 2 |   | process 1 part 2 | |
     ------------------  -----------     ------------------
0                                                            max

На даний момент:

  • єдиний спосіб перекладу сторінок - це здійснення двійкового пошуку на всіх сторінках процесу 1, що займає неприйнятний журнал (n)
  • Зміна процесу 1, частина 1 може бути величезною, оскільки цей сегмент може бути величезним

Однак із сторінками фіксованого розміру:

  • кожен 32-розрядний переклад виконує лише 2 зчитування пам'яті: каталог та сторінка сторінки
  • кожен своп - прийнятний 4 Кбіт

Частини пам'яті з фіксованим розміром просто більш керовані та домінували в поточному дизайні ОС.

Дивіться також: https://stackoverflow.com/questions/18431261/how-does-x86-paging-work

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.