Всем доброй ночи. Извините, конечно, если название темы не совсем скромное, но я уверен, что вопросов при изучении этого интерестного языка программирования у меня будет предостаточно. Поэтому, чтобы не захламлять форум, каждый раз создавая новую тему по какой-то проблеме, решил поступить именно так... Очень надеюсь, что с вашей помощью, многие "тёмные пятна" в моём понимании языка Assembler'а прояснятся.
Итак, поехали. Помогите мне, пожалуйста, разобраться вот в чём. Существуют следующие понятия/утверждения:
1) Процессор воспринимает оперативную память как сплошной набор байтов, каждый из котрых имеет свой порядковый номер.
2) При включении питания процессор начинает работать в реальном режиме (правда, потом почти все ОС переводят его в защищённый, но это пока нам не нужно).
3) Есть такой тип памяти FLAT.
А теперь ответьте, пожалуйста, что из этих понятий тождественно, синонимично, а что нет? То есть, значит ли, например, что в первом утверждении тип памяти FLAT, а процессор работает в реальном режиме?
Вопросы от noname Incognito.
Модератор: Andy
Действительно, процессор начинает работу в реальном режиме. Адрессация памяти - плоская несегментированная модель - или FLAT. В этом режиме сегменты кода, данных и стека лежат в пределах одного линейного НЕЗАЩИЩЕННОГО пространства, адрессуемого 20-ю битами. Т.е. любой резидент в памяти, либо сама неграмотно написанная программа может без труда изменить любой участок памяти. Фактически адрессуется более 1М памяти, а точнее 1М+64К - благодаря системе формирования линейного адреса из сегмента и смещения. Я думаю ни для кого не секрет, как этот адрес формируеться. Возможность доступа к этому участку регулируется уровнем Gate A20. Начиная с адрессов A0000 находятся системные области, которые являются окнами видеоадаптера, BIOSa, EMS - либо других устройств (например ТВ-тюнера), если удается на низком уровне переключить окно его видеобуффера в нужный участок памяти.
-
- Сообщения: 4
- Зарегистрирован: 04 дек 2006, 02:59
somewhere, спасибо. Действительно, всё немножко стало на свои места... Хотелось бы ещё поднять тему сегментных регистров. В чём смысл селектора ( в чём его удобство ) если мы по сути меняем "шило на мыло", преобразовывая, определённым образом, новый адрес начала сегмента в 16-ти розрядное число? Почему ОС перемещая какой-то участок памяти в другое место, просто не "запоминает" новый адрес начала этого участка?
noname Incognito, немного не понял смысл вопроса, но вкратце объясню смысл сегментных регистров:
- В реальном режиме их смысел ясен - определение участка памяти, с которым предстоит (или выполняется) работа. Максимально адрессуемый размер этого участка - 64К. В РР для определения адреса памяти, на который указывает сегментный регистр служит его значение*16.
- В защищенном режиме каждый сегм. регистр есть селлектор, а точнее содержит номер в GDT (Global Description Table) или LDT (Local ...). Иными словами ссылаются на дескрипторы. Дескрипторы содержат базовый адрес, границу и права доступа. Т.е. память таким образом делиться на защищенные участки. Местоположение самой таблицы дескрипторов определяет регистр GDTR. Есть еще и локальная таблица дескрипторов, но суть ее одна и таже. По большому счету сегментые регистры 48-разрядные, но доступно только 16 (потому как другие загружаються автоматически и служат для кеширования дескриптора сегмента). Поэтому даже в реальном режиме тоже есть базовый адрес, граница и права доступа. Только они у всех одинаковые, а вот GDT нет. Заместо нее принято дескриптор сегмента умножать на 16 и тем самым получать базовый адрес.
Все это сделано для того чтобы защитить доступ одной программы к другой в мультизадачном режиме. Да и в принципе для отладки тоже большой плюс. Существует даже возможность постраничного доступа с механизмом подкачки используя аппаратные исключения и на основе их выполнять какие-либо действия по перемещению страниц.
Если я правильно понял, то ты хочешь узнать, почему в РР сегментов так много, почему бы не сделать одни статические сегменты (ровно по 64К). Если это так, то:
- Память будет делиться на участки по 64К, итого 1М/64К=16 сегментов. Линейный адрес памяти тогда есть СегРег*64К + смещение.
- Допустим прога запросила два участка памяти по 16К... ну вот очень надо ей... Тогда диспетчер выделения памяти должен передать ей два адреса выделенной памяти. Что тогда передать? Сегмент или смещение? Можно конечно и то и другое, но будет ли удобно работать с таким представлением? Регистров то у нас всего 8, один из них (SP) уже забит. Обычно еще и BP забит, т.к. обычно указывает на стек в процедуре. И еще два надо хранить, чтобы узнать базовый адрес выделенной памяти. А если еще и с индексированными массивами работать будем, то регистры у нас кончатся. В случае если ДВП будет давать дескриптор сегмента, он загрузиться в свободный сег. регистр и доступ к участку упрощается. А в реальном режиме у нас сейчас всего 16 сегментов и выделиться фактически не 32, а 128К. Для реального режима память просто громаднейшая.
- В реальном режиме их смысел ясен - определение участка памяти, с которым предстоит (или выполняется) работа. Максимально адрессуемый размер этого участка - 64К. В РР для определения адреса памяти, на который указывает сегментный регистр служит его значение*16.
- В защищенном режиме каждый сегм. регистр есть селлектор, а точнее содержит номер в GDT (Global Description Table) или LDT (Local ...). Иными словами ссылаются на дескрипторы. Дескрипторы содержат базовый адрес, границу и права доступа. Т.е. память таким образом делиться на защищенные участки. Местоположение самой таблицы дескрипторов определяет регистр GDTR. Есть еще и локальная таблица дескрипторов, но суть ее одна и таже. По большому счету сегментые регистры 48-разрядные, но доступно только 16 (потому как другие загружаються автоматически и служат для кеширования дескриптора сегмента). Поэтому даже в реальном режиме тоже есть базовый адрес, граница и права доступа. Только они у всех одинаковые, а вот GDT нет. Заместо нее принято дескриптор сегмента умножать на 16 и тем самым получать базовый адрес.
Все это сделано для того чтобы защитить доступ одной программы к другой в мультизадачном режиме. Да и в принципе для отладки тоже большой плюс. Существует даже возможность постраничного доступа с механизмом подкачки используя аппаратные исключения и на основе их выполнять какие-либо действия по перемещению страниц.
Если я правильно понял, то ты хочешь узнать, почему в РР сегментов так много, почему бы не сделать одни статические сегменты (ровно по 64К). Если это так, то:
- Память будет делиться на участки по 64К, итого 1М/64К=16 сегментов. Линейный адрес памяти тогда есть СегРег*64К + смещение.
- Допустим прога запросила два участка памяти по 16К... ну вот очень надо ей... Тогда диспетчер выделения памяти должен передать ей два адреса выделенной памяти. Что тогда передать? Сегмент или смещение? Можно конечно и то и другое, но будет ли удобно работать с таким представлением? Регистров то у нас всего 8, один из них (SP) уже забит. Обычно еще и BP забит, т.к. обычно указывает на стек в процедуре. И еще два надо хранить, чтобы узнать базовый адрес выделенной памяти. А если еще и с индексированными массивами работать будем, то регистры у нас кончатся. В случае если ДВП будет давать дескриптор сегмента, он загрузиться в свободный сег. регистр и доступ к участку упрощается. А в реальном режиме у нас сейчас всего 16 сегментов и выделиться фактически не 32, а 128К. Для реального режима память просто громаднейшая.
-
- Сообщения: 4
- Зарегистрирован: 04 дек 2006, 02:59
Должен признать, мне, довольно-таки, сложно что-то комментировать: знания мои практически нулевые. Честно говоря, читал твои ответы по несколько раз. Поэтому, с твоего позволения, "разбор" последнего поста ( да и предыдущего тоже, я сначала как-то пропустил это) начну, наверное, з самого простого.
Смещение у нас 16-ти битное. То есть максимально большое число которое туда можно записать 2^16=65536, а это и есть те 64К про которые ты говорил. Всё сходится. В предыдущем ответе было сказано, что полный адрес состоит из 20 бит. Вычитаем 16 бит смещение и получаем, что наш участок памяти максимум, грубо говоря, ещё можно "опустить" на 4 бита. Это максимум 2^4=16 "позиций". То есть полная, наибольшая площадь этого "прямоугольничка" равна 64К х 16=1024К=1М. Опять-же таки - всё сходится. Но меня интересует следующее: данные "размеры", это, что, так сложилось исторически, или здесь какие-то инженерно-аппаратные причины?somewhere писал(а):...максимально адрессуемый размер этого участка - 64К.
Можно сказать - и так, и так. Когда-то давным-давно, в 198Х-лохматых годах была такая техника i80286 - по тем временам крутая вещь была, сейчас же любой нормальный мобильник имеет куда более совершенную структуру. У этой вещи была 16-разрядная адресация, НО 20 разрядная адресная линия, переключение которой и управляеться воротами (Gate) A20. А это значит, что надо было адрессовать 2^20 байт имея лишь 16 битные регистры. Вот и придумали люди такую вот схему формирования адреса. Даже сейчас в БИОСе есть опция Gate A20 Option которая управляет скоростью переключения этой линии. После переключения устанавливаеться родная винде и многим другим ОС 36 разрядная адресная линия. Такие вот дела...
-
- Сообщения: 4
- Зарегистрирован: 04 дек 2006, 02:59
Ясно. Только вот запутаться можно, что было первично, а, что вторично. Или 1М Ram и 16-ти битный регистр, исходя из которых и придумали данный формат, или же изначально был 20-ти битный адрес, из которго следует, что адресовывать можна не более 1М памяти. Но это уже какой-то софистикой попахивает...
Поэтому потихоньку поедем дальше. Хотелось-бы задать 2 небольших вопросика:
1) Размер сегмента памяти уже аппаратно определён ( и как я понимаю, наверное, это 64К ) или пользователь вручную может его изменить? ( говорим пока только про реальный режим )
2) Может-ли сегмент памяти быть 2-ух мерным, или же это всегда "строка" байтов?
Поэтому потихоньку поедем дальше. Хотелось-бы задать 2 небольших вопросика:
1) Размер сегмента памяти уже аппаратно определён ( и как я понимаю, наверное, это 64К ) или пользователь вручную может его изменить? ( говорим пока только про реальный режим )
2) Может-ли сегмент памяти быть 2-ух мерным, или же это всегда "строка" байтов?
Да, в реальном режиме размер сегмента не более 64К. Даже если использовать 32-разрядное смещение, то оно должно быть не больше чем 0FFFFh, иначе можно схлопотать по аппаратному исключению №13 или №12." писал(а):1) Размер сегмента памяти уже аппаратно определён ( и как я понимаю, наверное, это 64К ) или пользователь вручную может его изменить? ( говорим пока только про реальный режим )
Память - это всегда одномерный набор байтов. А как его представлять - это уже дело программиста. Это может быть даже 10-мерное пространство, которое визуально представить невозможно, но в разрезе какой-то группы данных вполне представимо." писал(а):2) Может-ли сегмент памяти быть 2-ух мерным, или же это всегда "строка" байтов?
Сегмент - это лишь кусочек памяти с размером не более 64К. Никаких средств для задания размера сегмента в РР нет, он ограничивается только аппаратно. Есть специальные средства ОС MS DOS для контроля за выделением и освобождением памяти. Причем если попросишь 20К у ДОСа, а запишешь 50К с диска, то конца света не будет. Главное, чтобы что-то важное не затронул. Т.е. программер должен сам следить, чтобы программа не скакнула куда не надо. В принципе и в защищенном режиме это тоже надо делать, но за тобой уже будут следить.