Каковы сегмент и смещение в реальном режиме адресации памяти?

memory assembly operating-system x86 real-mode

12187 просмотра

6 ответа

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

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

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

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

Автор: narayanpatra Источник Размещён: 12.11.2019 09:24

Ответы (6)


13 плюса

Решение

В x86 Real-Mode Memory физический адрес имеет длину 20 бит и вычисляется:

PhysicalAddress = Segment * 16 + Offset

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

Автор: GJ. Размещён: 07.11.2010 08:35

17 плюса

Когда 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, если моя математика верна).

Автор: cHao Размещён: 07.11.2010 08:36

1 плюс

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

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

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

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

Автор: Thraka Размещён: 17.12.2012 06:56

1 плюс

Я вижу, что вопросу и ответам уже несколько лет, но есть неверное утверждение, что в реальном режиме существуют только 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 мы можем найти следующее утверждение: «Эти префиксы можно использовать в режиме реального адреса как а также в защищенном режиме и режиме виртуального 8086 ».)

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

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

кортик

Автор: Dirk Wolfgang Glomp Размещён: 06.02.2014 12:56

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 с необходимым шаблоном для его запуска.

Автор: Ciro Santilli 新疆改造中心法轮功六四事件 Размещён: 07.11.2015 09:07

-1 плюса

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

Любой логический проект просто объединял бы два 16-разрядных регистра для создания 32-разрядного адресного пространства (например 0xFFFF : 0xFFFF = 0xFFFFFFFF), но неаааа ... 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 наняла немых инженеров, и мы должны жить с этим.

Автор: James M. Lay Размещён: 22.03.2017 08:11
Вопросы из категории :
32x32