К счастью, они не нужны, так как 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