Страничная организация памяти

stm7868162

Как записываются виртуальные адреса в скомпилированной (для ОС со страничной организацией памяти) программе?
Т.е. следующее: размер страницы = 1024
1) В программе виртуальные адреса линейные. На процессор подаём адрес 1028. Он сам вычисляет, что это 1-я страница, смещение 4
Или же
2) В программе виртуальные адреса сразу имеют форму 1:4 (1-я страница, смещение 4)
?

bastii

в х86 1ое

rosali

размер страницы 4k обычно.

katrin2201

По-моему, оба пункта - одно и то же.
Если последовательно записать 1, а потом 4, выделив на оба числа пральное количество бит, получится как раз 1028.

rosali

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

bastii

смотря что считать правильным

sollariss

Вроде бы там есть Выражения, которые дефайнятся нужным образом (тип ОС, тип процессора, адресация, размер страницы) ? Так что компилятор как бы знает а на деле все потом доопределяется.

agaaaa

гы
Товарищи! Вы путаете страницы с сегментами!
Страничная адресация в ОС или не страничная, програма всегда работает с сегментами (чей размер, кстати, задаётся на этапе компиляции а не со страницами. В 32-ух битной ОС длинный указатель имеет формат селектор_сегмента(16):смещение(32). какие тут вопросы?

bleyman

>>32-ух битной ОС длинный указатель имеет формат селектор_сегмента(16):смещение(32). какие тут вопросы?
Ты когда-нибудь видел ненулевой селектор сегмента? Я - нет. Чо за прогон вообще?

kamputer

>Ты когда-нибудь видел ненулевой селектор сегмента? Я - нет. Чо за прогон вообще?
[offtop]
Чуве, селектор - это сегментный регистр. Можешь запустить любую из своих поделок, и посмотреть в отладчике, чему равны значения CS, DS, ES и т.д. Так что ты, наверно, про дескрипторы сегментов говоришь. Они тоже с ненулевой базой бывают, в винде, например, это то, на что ссылаецо FS. (Всюду говорим о 32-битном случае).
[/offtop]

bleyman

Я говорил именно про сегментные регистры - CS, DS и всё такое.
Упс. И вправду ненулевые.
А мне всегда казалось, что нулевые. Мб они в дебажных версиях плюсовых прог нулевые, конечно.
Только я не пойму никак, в чём их смысл. А ещё они на сколько сдвигают - по прежнему на 16 байт? Тогда их правильнее называть не сегментными =)

katrin2201

В программе есть линейный адрес, и есть таблица страниц для процесса.

katrin2201

а это от ОСи зависит. Линукс вот вроде не работает. Там вообще страничная адресация преобладает. А сегментов там по дефолту четыре на всю ось что ли. И у всех смещение сегмента нулевое, а размер - на все 4 гига.

bastii

кстати случайно натолкнулся:
On x86 machines, Windows chooses a page size of 4K because that was the only page size supported by that architecture at the time the operating system was designed. (4MB pages were added to the CPU later, in the Pentium as I recall, but clearly that is too large for everyday use.)
For the ia64, Windows chose a page size of 8K. Why 8K?
It's a balance between two competing objectives. Large page sizes allow more efficient I/O since you are reading twice as much data at one go. However large page sizes also increase the likelihood that the extra I/O you perform is wasted because of poor locality.
Experiments were run on the ia64 with various page sizes (even with 64K pages, which were seriously considered at one point and 8K provided the best balance.
Note that changing the page size creates all sorts of problems for compatibility. There are large numbers of programs out there that ly assume that the page size is 4K. Boy are they in for a surprise.

shlyumper

А ещё они на сколько сдвигают - по прежнему на 16 байт? Тогда их правильнее называть не сегментными =)
Вообще, речь же про protected mode? Там "все не так", и название "сегментный регистр" скорее получается историческим. Почитай, например, здесь.

Marinavo_0507

Меня вот всегда интересовало, зачем интеловцы в 80286 сделали служебными младшие биты селектора, а не старшие? Можно было бы создавать подряд несколько дескрипторов, и работать с массивами длиннее 64K с помощью простой адресной арифметики.

bleyman

Ммм. Попытался почитать. Возникло стойкое ощущение, что речь всё-таки про flat mode. Нет?

Ivan8209

А чем этот flat mode сильно отличается от protected?
---
...Я работаю антинаучным аферистом...

bleyman

Ммм. Ну он типа плоский. 4 гига адресуются при помощи адресных регистров. Процессор сам превращает виртуальные адреса в физические и вызывает методы ОС чтобы вытащить страницу из свопа.
Зачем дополнительные сложности какие-то?
ЗЫ: Я вообще этим не развлекался никогда, мб и фигню несу =)

Ivan8209

Я не помню, чтобы ты был приверженцем ОС без средств защиты памяти.
> Зачем дополнительные сложности какие-то?
Например, для того, чтобы ни один ненормальный root
не получал доступа к памяти ядра, минуя последнее.
---
...Я работаю антинаучным аферистом...

bleyman

>> Я не помню, чтобы ты был приверженцем ОС без средств защиты памяти.
эээ типа. Ну, типа. Как бы Виртуальная Память. Вот!
>> Цытата меня>> Процессор сам превращает виртуальные адреса в физические и вызывает методы ОС чтобы вытащить страницу из свопа.
Каждый процесс сидит в своём 4-х гиговом адресном пространстве. Логические адреса транслируются в физические процессором под контролем ядра. В чём проблема-то?

agaaaa

Каждый процесс сидит в своём 4-х гиговом адресном пространстве. Логические адреса транслируются в физические процессором под контролем ядра. В чём проблема-то?
Поддерживаю! Кто хочет полных объяснений, могу одолжить на 30 минту книжку под названием "Процессоры Pentium 4, Athlon и Duron" Гука и Юрова, изд. Питер. Советую приобрести или скачать в эл. варианте (если найдёте)

Ivan8209

Логические адреса совпадают с физическими?
Партия учит нас, что защищённый режим --- это когда работает механизм защиты памяти.
---
...Я работаю антинаучным аферистом...

vall

>Логические адреса совпадают с физическими?
где это тут написано?
сегментная адресация давно нигде не используется. х86_64 её уже нет совсем.

Ivan8209

Защищённый режим и сегментная адресация не одно и то же.
---
...Я работаю антинаучным аферистом...

vall

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

agaaaa

Она как раз организуется сегментацией. Страничное управление памятью предназначено только для свопинга

bastii

Не только для свопинга. Идея в том, что для двух процессов один и тот же линейный адрес отображается в разные физические. При чем по умолчанию два процесса работают с непересекающимися фрагментами памяти. Эта трансляция выполняется постранично и реализуется аппаратно процессором. По верх линейной адресации реализован механизм сегментной адресации. Здесь логический адрес представляет собой пару селекторов дескриптора сегмента (он сидят в сегментных регистрах и смещения в этом сегменте. На практике оказалось, что этот механизм лишний, поэтому в большинстве систем все сегменты указывают на начало линейного пространства адресов, и соответствующие им селекторы заносятся в сегментные регистры и дальше их не трогают. Такой режим адресации называется flat mode.
Так что Fj все правильно говорит.

agaaaa

Хрен! Один и тот же линейный адрес всегда отображается в один и тот же физический, если не производит замену страниц (например при свопинге)

bastii

Нет, в х86 ты можешь настроить отображения 4мб блока линейного адресного пространства на произвольный 4мб блок физического пространства, и дальше в рамках этого отображения в пределах этих блоков можно задавать отображения произвольных страниц линейного адресного пространства в страницы физического адресного пространства.
Короче как у нас тут говорят -- ботай матчасть.

vall

а ты знаешь что у каждой задачи своя таблица виртуальной памяти?

agaaaa

Ты не прав, не каждая задача имеет свой каталог страниц - он один и им управляет ОС, ботай матчасть. Цитата: "...Страницы не имеют прямой связи с логической структурой данных или програм... Страничная переадресация может использоваться с сегментацией без каких-либо требований по согласованию границ сегментов и страниц..."

vall

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

agaaaa

Так, товарищи. Давайте уж всё-таки разберёмся, о чём идёт речь.
После включения 32bit protected mode появляется возможность управления защищёнными сегментами, которые располагаются в пространстве физических адресов. Это управление обеспечивается глобальной и локальной таблицей дескрипторов сегментов (GDT и LDT соотв.). Сегменты, доступные всем программам ОС помещает в GDT, плюс у кажой программы наличествует LDT к элементам которго может обращаться только эта программа (если конечно копии этого элемента нет ни в GDT, ни в LDT другой задачи). Не это ли имеется ввиду под "таблицей у каждого процесса"?
Теперь ОС может включить ( а может и не включить ) блок страничной переадресации и занести физический адрес таблицы страниц в спец. регистр. После этого все обращения к памяти проходят через блок страничной переадресации.
Пример после включения Protected Mode и Paging:
ОС запускает процесс и отдаёт ему сегмент линейной памяти в 4 Гб начиная с линейного адреса 0x0001:0x00000000 (режим, когда программе выделяется сегмент максимального размера называется "плоским"). В упрощённом варианте в таблицу страниц при этом ОС заносит нужное кол-во страниц и пишет, что они ещё не выделены. Затем при обращении программы в пределах сегмента с селектором 1 по адресу скажем 0x00010000 ОС видит, что такому линейному адресу не соответствует ни одна страница физ. памяти и выделяет её для программы по тому физ. адресу, по которому пожелает. После чего все вызовы в пределах 0x0001xxxx (зависит от размера страницы) аппаратно и прозрачно для процесса перенаправляются на выбранный ОС физический адрес. Ну и т. д.

vall

дочитай ты наконец книжку которую читаешь, а не флуди тут.
в твоей замечательной модели с одним каталогом страниц и flat моделью как решается проблема что два процесса могут захотеть один адрес?
регистр cr3 сохраняется в tss, интересно для чего же это сделано?
при операциях с памятью сначала работает сегментный механизм, а потом страничный.

agaaaa

в твоей замечательной модели с одним каталогом страниц и flat моделью как решается проблема что два процесса могут захотеть один адрес?
Легко: на уровне сегментов дать доступ к одному и тому же сегменту, например разместив его в GDT
регистр cr3 сохраняется в tss, интересно для чего же это сделано?
Зы... и правда сохряняется
Сорри за флуд, мы уже давно оффтоп. Но изначальный вопрос некорректен, имхо
Надо бы вынести в отдельную тему. Тогда мне интересно, а собственно зачем нужно сохранять cr3 и присваивать его каждой задаче? up

bastii

Для того, чтобы каждый процесс имел свою трансляцию при страничной адресации.
Короче, сделай простенькую консольную программу с одной переменной, которой присваивается, например, номер процесса. Программа выводит адрес и значение переменной. Запусти ее в двух экземплярах и убедись, что в обоих программах переменные будут иметь один адрес, но разные значения. Дальше можно добавить еще одну переменную в разделяемую секцию.
Короче вот прога:

#include <stdio.h>
#include <tchar.h>
#include <windows.h>
#pragma section("secA", read, write, shared)
DWORD a;
__declspec(allocate("secA"
DWORD b;
int _tmain(int argc, _TCHAR* argv[])
{
b = a = ::GetCurrentProcessId;
while(1) {
printf("&a = %p\na = %d\n&b = %p\nb = %d\n\n", &a, a, &b, b);
::Sleep(2000);
}
return 0;
}

Запусти сначала один экземпляр, потом в второй -- и втыкай до просветления. Попробуй придумать, как такое можно реализовать без использования страничной адресации, где каждый процесс имеет свои каталоги страниц.
Причем из диссама можно убедится, что для работы обеими переменными используется один сегмент (т.е. значение DS не меняется):

b = a = ::GetCurrentProcessId;
004113AE mov esi,esp
004113B0 call dword ptr [__imp__GetCurren0 (4181A0h)]
004113B6 cmp esi,esp
004113B8 call @ILT+310(__RTC_CheckEsp) (41113Bh)
004113BD mov dword ptr [a (417178h)],eax
004113C2 mov eax,dword ptr [a (417178h)]
004113C7 mov dword ptr [b (419000h)],eax

agaaaa

А не вариант, что одно и то же значение DS в разных LDT указывает на разные сегменты?

vall

>Легко: на уровне сегментов дать доступ к одному и тому же сегменту, например разместив его в GDT
адрес один но память разная нужна.
а теперь представь что у тебя замаплено в память пара гигабайт файлов.
и такой процесс не один.
вперёд.
>Зы... и правда сохряняется
открытие блин.
>Тогда мне интересно, а собственно зачем нужно сохранять cr3 и присваивать его каждой задаче?
как ни странно - чтоб у каждой задачи было своё адресное пространство.

vall

все стандартные сегменты идут с 0 и размером 4гб. они все одинаковые.

agaaaa

>адрес один но память разная нужна.
Что значит адрес один? Зачем тебе надо совпадение в разных программах одного линейного адреса?
>открытие блин.
И правда не знал. Приму к сведению
>как ни странно - чтоб у каждой задачи было своё адресное пространство.
Как уже было сказано это прекрасно работает с одной только сегментацией

bastii

 
А не вариант, что одно и то же значение DS в разных LDT указывает на разные сегменты?
Вариант конечно, но для этого примера не годится. Если посмотришь на адреса переменных, то увидишь, что они сидят в соседних страницах. Причем одна общая у процессов, а втрорая нет. С учетом, того что работа с ними через один сегмент (селектор в регистре DS в коде не меняется).

agaaaa

Эх... говорило мне что-то "ботай SoftICE", дык нет...
>Если посмотришь на адреса переменных, то увидишь, что они сидят в соседних страницах.
Как ты определяешь, что они в соседних страницах?

bastii

004113BD mov dword ptr [a (417178h)],eax
004113C2 mov eax,dword ptr [a (417178h)]
004113C7 mov dword ptr [b (419000h)],eax
Адреса у а -- 417178h, у b -- 419000h.

agaaaa

Вопрос был "зачем это нужно?"

vall

например чтоб утилизировать больше чем 4гб адрессного пространстава суммарно всеми процессами.

kamputer

Афтар, не пиши больше.

bleyman

А ты можешь ответить мне на парочку вопросов? Читать книжку как-то ломает =)
1) Зачем вообще нужны сегментные регистры в 32-х битном режиме? Насколько я понимаю, в real mode они выполняли две задачи: а) можно было зашивать смещение адресов переменных/джампов прямо в код, б) можно было адресовать аж целый мегабайт памяти. В системе с виртуальной памятью (а) выполняется автоматически, под виндой любая прога видит себя сидящей по адресу 0х40000000 (по дефолту (если я ничего не путаю (б) ну и так четырёх гигов адресного пространства пока вполне хватает.
2) А как они работают? Ну то есть эффективный адрес в real mode получался как offset + segment * 16; а если у тебя оффсет 32битный, а сегмент всего 16, то как-то очень странно всё выглядит - 65536 четырёхгиговых страниц и все начинаются в первом мегабайте. А всё адресное пространство получается 4гб + 1мб. Неаккуратненько!

vall

в защищённом режиме сегмент это номер записи в спец таблице. (LDT или GDT)
а там уже записано смещение, размер и права на доступ и тд.
сейчас их никто не использует, и в x84_86 их почти полностью выкосили.
только лишние опреации при каждом вычислении адреса и
проверке прав доступа - всё равно везде поголовно flat mode.
точнее не помню, доставать книжку тоже лень.
что-то подумалось.
вроде с помощью сегментов можно было бы реализовать один не исполняемый стэк без лишенего гемороя - просто cs не натягивать на всё адресное пространство. но наверно и тут есть какие-то проблемы.

bastii

В винде в регистре FS сидит селектор дескриптора сегмента, в котором сиди Thread Information Block. Например, FS:[0] указывает на список SEH, а FS:[2C] указывает массив TLS.

shlyumper

вот упорный
ну прочитай ты статью, на которую я ссылку давал - там как раз подробный ответ на оба вопроса (хотя, в большей степени все же на второй).

shlyumper

Кстати, сильно подозреваю, что ответ на вопрос №1 примерно такой:
Систему селекторов/дескрипторов придумали еще для 80286, и там они были реально необходимы, т.к. регистры были 16-разрядными, и адресовать ими без пачки дексрипторов все 16 мегов, доступных 80286 было невозможно. А дальше оставили все как есть немного подправив в 80386 исходя из главной проблемы всей архитектуры x86 - обратной совместимости.

Marinavo_0507

А на мой вопрос есть что-нибудь?

shlyumper

не, не знаю. Где-то дома (не в Москве) валяется старая книжка по OS/2 2.0, в которой примерно половина книги посвящена объяснению что такое protected mode, как оно работает и насколько оно круто, книжка была написана как раз про 80286 еще. Возможно, там был ответ на твой вопрос, но я не помню ни названия этой книжки, ни автора.
Оставить комментарий
Имя или ник:
Комментарий: