Альтернатива FP_SEG и FP_OFF ​​для преобразования указателя в линейный адрес - PullRequest
0 голосов
/ 06 сентября 2011

На 16-битной машине DOS есть опции, такие как FP_SEG и FP_OFF ​​для преобразования указателя в линейный адрес, но, поскольку этот метод больше не существует в 32-битном компиляторе, какие еще функции могут делать то же самое на 32-битной машине ??

1 Ответ

2 голосов
/ 06 сентября 2011

К счастью, они не нужны, так как 32-битный режим не сегментирован, и, следовательно, адреса всегда линейны (упрощение, но давайте будем простыми).

РЕДАКТИРОВАТЬ: Первая версия сбивала с толку, давайте попробуем еще раз.

В 16-битном сегментированном режиме (здесь я имею в виду исключительно устаревшие программы для DOS, вероятно, для других-битные x86-ОС) адреса даются в 32-битном формате, состоящем из 16-битного сегмента и 16-битного смещения.Они объединяются, чтобы сформировать 20-битный линейный адрес (отсюда исходит печально известный барьер 640K, 2**20 = 1MB и 384K зарезервированы для системы, а bios оставляют ~ 640K для пользовательских программ) путем умножения сегмента на 16 = 0x10 (эквивалентно смещению влево на 4) и добавлению смещения.Т.е.: linear = segment*0x10 + offset.

Это означает, что 2**12 сегмент: указатели типа адреса будут ссылаться на один и тот же линейный адрес, поэтому в общем случае нет способа получить 32-разрядное значение, используемое для формирования линейного адреса.

В старых программах DOS, в которых использовались указатели с дальним сегментированием (в отличие от указателей с близким указателем, которые содержали только смещение и неявно использовался ds регистр сегмента), они обычно рассматривались как 32-разрядные целочисленные значения без знака, где 16 наиболее значимыхбиты были сегментом, а 16 младших разрядов - смещением.Это дает следующие определения макросов для FP_SEG и FP_OFF (с использованием типов из stdint.h):

#define FP_SEG(x) (uint16_t)((uint32_t)(x) >> 16) /* grab 16 most significant bits */ 
#define FP_OFF(x) (uint16_t)((uint32_t)(x)) /* grab 16 least significant bits */

Чтобы преобразовать 20-битный линейный адрес в сегментированный адрес, у вас есть много вариантов (2**12).Одним из способов может быть:

#define LIN_SEG(x) (uint16_t)(((uint32_t)(x)&0xf0000)>>4)
#define LIN_OFF(x) (uint16_t)((uint32_t)(x))

Наконец, краткий пример того, как все это работает вместе:

Сегментированный адрес: a = 0xA000:0x0123
Как 32-битный дальний указатель b = 0xA0000123
20-битный линейный адрес: c = 0xA0123

FP_SEG(b) == 0xA000
FP_OFF(b) == 0x0123
LIN_SEG(c) = 0xA000
LIN_OFF(c) = 0x0123
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...