Каковы сегмент и смещение в реальном режиме адресации памяти? - PullRequest
12 голосов
/ 07 ноября 2010

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

В реальном режиме регистры имеют только 16 битов, поэтому вы можете адресовать только до 64к. Чтобы разрешить адресацию большего объема памяти, адрес קד рассчитывается по сегменту * 16 + смещение.

Здесь я могу понять первую строку. У нас 16 бит, поэтому мы можем адресовать до 2 ^ 16 = 64 КБ.

Но что это за вторая строка? Что представляет собой сегмент? Почему мы умножаем это на 16? почему мы добавляем смещение. Я просто не могу понять, что это за смещение? Кто-нибудь может объяснить мне или дать мне ссылку на это, пожалуйста?

Ответы [ 6 ]

16 голосов
/ 07 ноября 2010

Когда Intel собирала 8086, имелось обоснованное обоснование наличия в машине более 64 КБ, но не было способа использовать 32-разрядное адресное пространство. Тогда даже мегабайт был огромным объемом памяти. (Помните печально известную цитату «640K должно хватить на всех»? По сути, это неверный перевод того факта, что в те времена 1МБ был чертовски огромный .) Слово «гигабайт» не использовалось в течение еще 15-20 лет, и это не будет относиться к ОЗУ в течение еще 5-10 лет после этого.

Таким образом, вместо реализации настолько огромного адресного пространства, что оно "никогда" не будет полностью использовано, они реализовали 20-битные адреса. Они по-прежнему использовали 16-битные слова для адресов, потому что, в конце концов, это 16-битный процессор. Верхнее слово было «сегмент», а нижнее слово было «смещение». Однако эти две части значительно перекрываются - «сегмент» - это фрагмент памяти размером 64 КБ, который начинается с (segment) * 16, и «смещение» может указывать на любое место в этом блоке. Чтобы вычислить фактический адрес, вы умножаете сегментную часть адреса на 16 (или сдвигаете ее влево на 4 бита ... тоже самое), а затем добавляете смещение. Когда вы закончите, у вас есть 20-битный адрес.

 19           4  0
  +--+--+--+--+
  |  segment  |
  +--+--+--+--+--+
     |   offset  |
     +--+--+--+--+

Например, если сегмент был 0x8000, а смещение было 0x0100, фактический адрес получается равным ((0x8000 << 4) + 0x0100) == 0x80100.

   8  0  0  0
      0  1  0  0
  ---------------
   8  0  1  0  0

Математика редко бывает такой аккуратной, хотя - 0x80100 можно представить буквально тысячами различных комбинаций сегмент: смещение (4096, если моя математика верна).

12 голосов
/ 07 ноября 2010

В x86-памяти реального режима физический адрес имеет длину 20 бит и вычисляется:

PhysicalAddress = Segment * 16 + Offset

Проверьте также: Управление памятью в реальном режиме *

1 голос

Минимальный пример

С:

  • смещение = msg
  • сегмент = ds
mov $0, %ax
mov %ax, %ds
mov %ds:msg, %al
/* %al contains 1 */

mov $1, %ax
mov %ax, %ds
mov %ds:msg, %al
/* %al contains 2: 1 * 16 bytes forward. */

msg:
.byte 1
.fill 15
.byte 2

Итак, если вы хотите получить доступ к памяти выше 64 КБ:

mov $0xF000, %ax
mov %ax, %ds

Обратите внимание, что это позволяет использовать адреса шириной более 20 бит, если вы используете что-то вроде:

0x10 * 0xFFFF + 0xFFFF == 0x10FFEF

На более ранних процессорах, которые имели только 20 адресных проводов, он был просто урезан, но позже все усложнилось с линией A20 (21-й адресный провод): https://en.wikipedia.org/wiki/A20_line

На репозитории GitHub с необходимым шаблоном для его запуска.

1 голос
/ 06 февраля 2014

Я вижу, что вопросу и ответу уже несколько лет, но есть неверное утверждение, что в реальном режиме существует только 16-битные регистры.

В реальном режиме регистры не только 16бит, потому что есть также 8-битные регистры тоже.Каждый из этих 8-битных регистров является частью 16-битного регистра, который разделен на нижнюю и верхнюю части 16-битного регистра.

И, начиная реальный режим с 80386+, мы становимся 32-битными регистрамии дополнительно также два новых префикса команд, один для переопределения / обратного размера операнда по умолчанию и один для переопределения / обратного размера адреса по умолчанию одной инструкции внутри сегмента кода.

Эти префиксы команд могут бытьиспользуется в комбинации для обратного изменения размера операнда и размера адреса для одной инструкции.В реальном режиме размер операнда и размер адреса по умолчанию составляет 16 бит.С этими обоими префиксами команд мы можем использовать пример 32-битного операнда / регистра для вычисления 32-битного значения в одном 32-битном регистре или для перемещения 32-битного значения в и из ячейки памяти.И мы можем использовать все 32-битные регистры (возможно, в сочетании с базой + индекс * масштаб + смещение) в качестве адреса-регистра, но сумма эффективного адреса не должна превышать предел размера сегмента 64 КБ.

(На странице OSDEV-Wiki в таблице «Префикс размера операнда и размера адреса» можно найти, что «префикс операнда 0x66» и «префикс адреса 0x67» равны N /A (недоступно) для реального режима и виртуального режима 8086. http://wiki.osdev.org/X86-64_Instruction_Encoding
Но это совершенно неверно, поскольку в руководстве Intel мы можем найти следующее утверждение: «Эти префиксы могут использоваться в режиме реального адреса кака также в защищенном режиме и режиме virtual-8086 ".)

Начиная с Pentium MMX, мы становимся восемью 64-битными MMX-регистрами.
Начиная с Pentium 3, мы становимся восемью 128-битными XMM-регистрами.
..

Если я не ошибаюсь, то 256-битный регистр YMM и 512-битный ZMM-регистр и 64-битный регистр общего назначения x64 не могут использоваться в реальном режиме.

Dirk

1 голос
/ 17 декабря 2012

Я хочу добавить здесь ответ только потому, что я рыскал в интернете, пытаясь это понять.Другие ответы опускали ключевую информацию, которую я получил по ссылке, представленной в одном из ответов.Однако я почти полностью пропустил это.Читая связанную страницу, я все еще не понимал, как это работает.

Проблема, с которой я, вероятно, столкнулся, заключалась в том, что я действительно только понимал, как Commodore 64 (процессор 6502) распределяет память.Он использует аналогичные обозначения для адресации памяти.Он имеет 64 КБ общей памяти и использует 8-битные значения PAGE: OFFSET для доступа к памяти.Каждая страница имеет длину 256 байт (8-разрядное число), и смещение указывает на одно из значений на этой странице.Страницы расположены в памяти один за другим.Итак, страница 2 начинается там, где заканчивается страница 1.Я собирался в 386, думая в том же стиле.Это не так.

В реальном режиме используется похожий стиль, даже если он имеет другую формулировку SEGMENT: OFFSET.Сегмент размером 64 КБ.Однако сами сегменты не располагаются вплотную, как Коммодор.Они разнесены на 16 байт друг от друга.Смещение по-прежнему работает так же, указывая, сколько байтов с начала страницы \ сегмента.

Я надеюсь, что это объяснение поможет любому, кто найдет этот вопрос, оно помогло мне написать его.

0 голосов
/ 22 марта 2017

16-битный регистр может адресовать только до 0xFFFF (65 536 байт, 64 КБ).Когда этого было недостаточно, Intel добавила сегментные регистры.

Любой логический проект просто объединял бы два 16-разрядных регистра для создания 32-разрядного адресного пространства (например, 0xFFFF : 0xFFFF = 0xFFFFFFFF), но nooooo ... Intel пришлось запутаться в нас.

Исторически передняя шина (FSB) имела только 20 адресных линий и, следовательно, могла передавать только 20-битные адреса.Чтобы «исправить» это, Intel разработала схему, в которой сегментные регистры расширяют ваш адрес только на 4 бита (16 бит + 4 = 20, в теории).

Для достижения этой целиСегментный регистр смещен влево от своего первоначального значения на 4 бита, а затем добавлен к адресу в общем регистре (например, [es:ax] = ( es << 4 ) + ax) . Примечание. Сдвиг влево на 4 бита эквивалентен умножению на 16 .

Вот и все.Вот несколько иллюстративных примеров:

;; everything's hexadecimal

[ 0:1 ] = 1

[ F:1 ] = F1

[ F:0 ] = F0

[ F:FF] = 1EF ; [F becomes F0, + FF = 1EF]

[ F000 : FFFF ] = FFFFF (max 20-bit number)

[ FFFF : FFFF ] = 10FFEF (oh shit, 21-bit number!)

Итак, вы все равно можете адресовать более 20 бит.Что просходит?Адрес «оборачивается», как модульная арифметика (как естественное следствие аппаратного обеспечения).Итак, 0x10FFEF становится 0xFFEF.

И вот оно у вас!Intel наняла немых инженеров, и мы должны с этим жить.

...