ЭЛЕКТРОННАЯ БИБЛИОТЕКА КОАПП
Сборники Художественной, Технической, Справочной, Английской, Нормативной, Исторической, и др. литературы.



 

Часть 25

Глава 24. Сочетание 16-разрядных и 32-разрядных программ
----------------------------------------------------------------
Процессор i486(TM), работающий в защищенном режиме, подобно
процессору 386(ТМ), основан на 32-разрядной архитектуре, но
поддерживает программы для 16-разрядной архитектуры ранних
процессоров Intel(R). Существуют три уровня поддержки:
1. Выполнение программ процессоров 8086 и 80286 при полной
   совместимости.
2. Сочетание 16-разрядных модулей с 32-разрядными модулями.
3. Сочетание 16-разрядных и 32-рязрядных адресов и данных в
   одном модуле.
Первый уровень обсуждался в Главе 21, Главе 22 и Главе 23.
Эта глава покажет, как 16-разрядные и 32-разрядные модули
могут взаимодействовать друг с другом, и как в одном модуле
могут  использоваться 16-разрядные и 32-разрядные операнды
и адреса.
Функции процессора i486 работают эффективнее, когда возможно
четкое разделение чисто 16-разрядных и чисто 32-разрядных
модулей. Чисто 16-разрядные модули обладают следующими
характеристиками:
- Все сегменты содержат не более 64 Кбайт.
- Элемент данных имеет размерность 8 или 16 бит.
- Указатели на коды и данные имеют 16-разрядное смещение.
- Управление передается только между сегментами, которые
  задаются при помощи 16-разрядного кода.
Чисто 32-разрядные модули обладают следующими характеристиками:
- Сегменты могут содержать более 64 Кбайт (от 0 байт до 4
  гигобайт).
- Элемент данных имеет размерность 8 или 32 бита.
- Указатели на коды и данные имеют 32-разрядное смещение.
- Управление передается только между сегментами, которые
  задаются при помощи 32-разрядного кода.
Программы, написанные для 16-разрядных процессоров, содержат
чистый 16-разрядный код. Новые программы, написанные для
защищенного режима процессора i486, содержат чистый 32-
разрядный код. При переносе прикладных програм с 16-разрядных
процессоров на 32-разрядный процессор i486 может возникнуть
ситуация, требующая сочетания 16-разрядных и 32-разрядных кодов.
Причины для сочетания кодов могут быть следующие:
- Модули будут преобразовываться один в один из 16-разрядной
  среды в 32-разрядную.
- Старые 16-разрядные компиляторы и средства разработки
  програмного обеспечения будут использоваться в 32-разрядной
  операционной среде, пока новые 32-разрядные средства
  разработки не станут доступны.
- Исходные тексты 16-разрядных модулей не доступны для
  модификации.
- Специфические для данного модуля структуры данных имеют
  фиксированный размер 16-разрядного слова.
- Естественный размер слова в исходном языке 16-бит.
24.1  Использование 16-разрядной и 32-разрядной сред.
----------------------------------------------------------------
Особенности архитектуры, которые позволяют процессору i486
сочетать 16-разрядные и 32-разрядные операнды и адреса
включают в себя:
- D-бит (бит по умолчанию) в дескрипторах сегмента кода,
  определяющий выбор по умолчанию размерности операндов
  и адресов для команд сегмента кодов. ( В режиме реальных
  адресов и виртуальном режиме процессора 8086, которые не
  используют дескрипторов, по умолчанию принято 16-разрядов).
  Если D-бит установлен, то сегмент кода - это 32-разрядный
  сегмент, если D-бит очищен, то сегмент кода - это 16-разрядный
  сегмент. D-бит задает размер операндов и адресов, когда все
  команды используют операнды и исполнительные адреса одного
  размера.
- Префиксы команд подавляют выбранные по умолчанию размерности
  операндов и адресов (доступны в защищенном режиме так же, как
  и в режиме реальных адресов и виртуальном режиме процессора
  8086).
- Разделение 16-разрядных и 32-разрядных шлюзов для передачи
  управления внутри сегмента (включая шлюзы вызова, шлюзы
  прерывания и шлюзы ловушки).
  Размер операнда для передачи управления определяется типом
  шлюза, но не D-битом или префиксом передаваемой команды.
- Регистры, которые могут быть использованы как для 16-
  разрядных так и для 32-разрядных операндов и вычисления
  исполнительных адресов.
- В-бит (большой бит) в дескрипторах сегментов данных,
  описывающий размер указателя стека ( 32-разрядный
  регист ESP или 16-разрядный регистр SP) используемый
  процессором для явных ссылок на стек.
24.2     Сочетание 16-разрядных и 32-разрядных операций.
----------------------------------------------------------------
Процессор i486 имеет два префикса команд, которые позволяют
сочетать 16-разрядные и 32-разрядные операции внутри одного
сегмента:
- Префикс размера операнда (66H)
- Префикс размера адреса   (67H)
Эти префиксы "обращают" установленный по умолчанию размер,
взятый из D-бита. Например процессор интерпретирует команду
MOV mem, reg (память, регистр) одним из четырех способов:
- В 32-разрядном сегменте:
  1. Перемещает 32 бита из 32-разрядного регистра в память
     с использованием 32-разрядного исполнительного адреса.
  2. Если используется префикс размера операнда,то перемещается
     16 бит из 16-разрядного регистра в память с испольванием
     32-разрядного исполнительного адреса.
  3. Если используется префикс размера адреса, то перемещается
     32 бита из 32-разрядного регистра в память с использованием
     16-разрядного исполнительного адреса.
  4. Если используется и префикс размера операнда и префикс
     размера адреса, то перемещается 16 бит из 16-разрядного
     регистра в память с использованием 16-разрядного
     исполнительного адреса.
- В 16-разрядном сегменте:
  1. Перемещает 16 битов из 16-разрядного регистра в память
     с использованием 16-разрядного исполнительного адреса.
  2. Если используется префикс размера операнда,то перемещается
     32 бита из 32-разрядного регистра в память с испольванием
     16-разрядного исполнительного адреса.
  3. Если используется префикс размера адреса, то перемещается
     16 бит из 16-разрядного регистра в память с использованием
     32-разрядного исполнительного адреса.
  4. Если используется и префикс размера операнда и префикс
     размера адреса, то перемещается 32 бита из 32-разрядного
     регистра в память с использованием 32-разрядного
     исполнительного адреса.
Этот пример показывает, что любую команду можно использовать с
любой комбинацией  размеров адресов и размеров операндов не
считаясь с тем, в 16-разрядном или в 32-разрядном сегменте
находится эта команда. Выбор 16- или 32-разрядного сегмента
кода по умолчанию базируется на следующих критериях:
1. Необходимость адресовать команды или данные в сегментах,
   больших 64 Кбайт.
2. Преобладающий размер операндов.
3. Желаемый режим адресации.
Биту умолчания должна быть дана установка, которая позволит
использование доступа к операндам преобладающего размера без
использования префиксов размера операнда.
24.3   Разделение данных между сегментами кода различной
       разрядности.
----------------------------------------------------------------
Поскольку выбор размерности операндов и адресов определяется
в сегментах кода и их дескрипторах, сегменты данных могут
свободно разделять между собой 16-разрядные и 32-разрядные
сегменты кода. Единственное ограничение налагается указателями
с 16-разрядным смещением, которые могут адресовать только
первые 64 Кбайт сегмента. Когда между 16-разрядными и
32-разрядными сегментами когда должен разделяться сегмент данных
длиннее чем 64 Кбайт, то данные, которые должны быть доступны
16-разрядным сегментам, должны быть помещены в первые 64 Кбайт.
Стек с диапазоном меньше 64 Кбайт может разделятся как
16-разрядными так и 32-разрядными сегментами кода. Этот класс
стеков включает:
- Стеки в сегментах, расширяемых вверх, с очищенными битами
  детализации и большими битами.
- Стеки в сегментах, расширяемых вниз, с очищенными битами
  детализации и большими битами.
- Стеки в сегментах, расширяемых вверх, с очищенным набором
  битов детализации и большим битом. В этих сегментах стек
  полностью содержится внутри младших 64 Кбайт. (Смещения,
  большие чем 0FFFFH, могут быть использованы для неразделяемых
  данных не входящих в стек).
В общем случае, B-бит сегмента стека нельзя использовать для
изменения размера стека, который используется 16-разрядным
сегментом кода. Размер указателя стека, используемый
процессором для неявных ссылок на стек, управляется
B-битом дескриптора сегмента данных стека. Неявными являются
ссылки, вызванные прерываниями, исключениями и такими командами,
как PUSH, POP, CALL и RET. Хотя кажется, что B-бит можно
использовать для увеличения сегмента стека 16-разрядных
программ сверх 64 Кбайт, делать этого нельзя. B-бит не
управляет явными ссылками стека, такими как ссылки на
параметры или локальные переменные. "Большой" стек может быть
использован 16-разрядным сегментом кода только в случае, если
код модифицирован таким образом, что все явные ссылки на стек
стоят перед префиксом размера адреса. Такая модификация вызывает
использование этими ссылками 32-разрядной адресации.
В больших сегментах, расширяемых вниз (установлены биты
детализации, большой и бит расширения вниз), все смещения
больше 64Кбайт, следовательно 16-разрядная программа не
может использовать сегмент стека этого типа, хотя сегмент
кода и модифицирован для использования 32-разрядной адресации.
(Более подробная информация о G, B и E битах содержится в
Главе 6).
24.4   Передача управления между сегментами кода различной
       разрядности.
----------------------------------------------------------------
При передаче управления между процедурами в 16-разрядных и
32-разрядных сегментах кода, программист должен знать
следующие три вещи:
- Границы адресации зависят от указателей с 16-разрядным
  смещением.
- Для корректного обращения со стеком необходимо правильно
  подбирать признаки размера операнда для командных пар
  CALL/RET, Прерывание/RET.
- Перевод параметров, и особенно параметров указателя.
Ясно, что 16-разрядные исполнительные адреса нельзя
использовать для адресации данных или кодов размещенных
за 0FFFFH в 32-разрядном сегменте, нельзя также "втискивать"
длинные 32-разрядные параметры в 16-разрядное слово. Хотя,
большая часть проблем интерфейса между 16-разрядными и
32-разрядными модулями, исключая выщеописанные исключения
вполне может быть решена. Некоторые решения проблем включают
помещение программы интерфейса между модулями.
24.4.1  Размер указателя сегмента кода
----------------------------------------------------------------
Для команд передачи управления, которые используют указатель
на следующую команду (т.е. тех, которые не используют шлюзы),
размер смещения указателя определяется атрибутом размера
операнда. Смысл использования указателя на два сегмента кода
разной размерностей:
- Команды JMP, CALL или RET из 32-разрядного сегмента в
  16-разрядный сегмент всегда возможны с использованием
  32-разрядного операнда.
- Команды JMP, CALL или RET из 16-разрядного сегмента с
  использованием 16-разрядного операнда, не могут адресоваться
  в 32-разрядный сегмент, если адрес назначения больше 0FFFFH.
Интерфейсные процедуры могут обеспечивать механизм, позволяющий
адресоваться из 16-разрядного сегмента в 32-разрядный сегмент
с адресом назначения превосходящим 64 Кбайта. Требования к
семейству интерфейсных процедур будет обсуждаться позже в
этой главе.
24.4.2    Управление стеком для передачи управления
----------------------------------------------------------------
Поскольку управление стеком различается для 16-разрядных и
32-разрядных команд CALL и RET, размер операнда в команде
RET должен соответствовать размеру операнда в команде CALL.
(Смотри Рисунок 24-1). 16-разрядная команда CALL заносит в
стек содержимое 16-разрядного регистра IP и (для вызовов между
разными уровнями привилегированности) 16-разрядного регистра SP.
Соответствующая команда RET также должна использовать
16-разрядный операнд для выборки этого 16-разрядного значения из
стека в 16-разрядный регистр. 32-разрядная команда CALL заносит
в стек содержимое 32-разрядного регистра EIP и (для
внутриуровневых вызовов) 32-разрядного регистра ЕSP.
Соответствующая команда RET также должна использовать
32-разрядный операнд для выборки этого 16-разрядного значения из
стека в 32-разрядный регистр. Если две части командной пары CALL
/RET имеют операнды различной длины, взаимодействие со стеком
будет некорректным, и значения указателя команды и указателя
стека не будут корректно восстановлены.
ЪДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД
ДДДДДДДї
і                     БЕЗ ПЕРЕНОСА ПРИВИЛЕГИРОВАННОСТИ           
       і
і                                                                
       і
і         После 16-разрядного вызова      После 32-разрядного выз
ова    і
і             31                    0         31                 
   0   і
і            ГДДДДДДДДДДДДДДДДДДДДДґ         ГДДДДДДДДДДДДДДДДДДД
ДДґ    і
інаправление і/////////////////////і         і///////////////////
//і    і
і заполнения ГДДДДДДДДДДВДДДДДДДДДДґ         ГДДДДДДДДДДДДДДДДДДД
ДДґ    і
і            і PARM2    і PARM1    і         і        PARM2      
  і    і
і     і      ГДДДДДДДДДДЕДДДДДДДДДДґ         ГДДДДДДДДДДДДДДДДДДД
ДДґ    і
і     і      і    CS    і  IP      і<ДД SP   і        PARM1      
  і    і
і     і      ГДДДДДДДДДДЕДДДДДДДДДДґ         ГДДДДДДДДДДВДДДДДДДД
ДДґ    і
і     і      і                     і         і//////////і   CS   
  і    і
і     V      ГДДДДДДДДДДЕДДДДДДДДДДґ         ГДДДДДДДДДДБДДДДДДДД
ДДґ    і
і            і                     і  ESP ДД>і         EIP       
  і    і
і            ГДДДДДДДДДДЕДДДДДДДДДДґ         ГДДДДДДДДДДВДДДДДДДД
ДДґ    і
і                                                                
       і
і                                                                
       і
і                   С   ПЕРЕНОСОМ  ПРИВИЛЕГИРОВАННОСТИ           
       і
і                                                                
       і
і         После 16-разрядного вызова      После 32-разрядного выз
ова    і
і             31                    0         31                 
   0   і
і            ГДДДДДДДДДДВДДДДДДДДДДґ         ГДДДДДДДДДДВДДДДДДДД
ДДґ    і
інаправление і    SS    і  SP      і         і//////////і   SS   
  і    і
і заполнения ГДДДДДДДДДДЕДДДДДДДДДДґ         ГДДДДДДДДДДБДДДДДДДД
ДДґ    і
і            і PARM2    і PARM1    і         і         ESP       
  і    і
і     і      ГДДДДДДДДДДЕДДДДДДДДДДґ         ГДДДДДДДДДДДДДДДДДДД
ДДґ    і
і     і      і    CS    і  IP      і<ДД SP   і        PARM2      
  і    і
і     і      ГДДДДДДДДДДЕДДДДДДДДДДґ         ГДДДДДДДДДДДДДДДДДДД
ДДґ    і
і     і      і                     і         і        PARM1      
  і    і
і     V      ГДДДДДДДДДДДДДДДДДДДДДґ         ГДДДДДДДДДДВДДДДДДДД
ДДґ    і
і            і                     і         і//////////і   CS   
  і    і
і            ГДДДДДДДДДДЕДДДДДДДДДДґ         ГДДДДДДДДДДБДДДДДДДД
ДДґ    і
і            і                     і  ESP ДД>і         EIP       
  і    і
і            ГДДДДДДДДДДЕДДДДДДДДДДґ         ГДДДДДДДДДДВДДДДДДДД
ДДґ    і
АДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД
ДДДДДДДЩ
     Рисунок 24-1. Стек после вызовов длинннх 16- и 32-разрядных
                    указателей.
Когда команда CALL и соответствующая ей команда RET находятся в
сегментах, имеющих одинаковые значения D-бита (т.е. обе по
умолчанию 32-разрядные или обе по умолчанию 16-разрядные),
могут быть использованы установки по умолчанию. Если же команда
CALL и соответствующая ей команда RET находятся в сегментах
имеющих различные значения D-бита , должны быть использованы
префиксы размера операнда.
Существует три способа выполнения 32-разрядного вызова
16-разрядной процедурой:
1. Использовать 16-разрядный вызов 32-разрядной интерфейсной
   процедуры, которая осуществит 32-разрядный вызов из
   заданного места.
2. Осуществить вызов через 32-разрядный шлюз вызова.
3. Изменить 16-разрядную процедуру, вставив перед вызовом
   префикс размер операнда, превращающий этот вызов в
   32-разрядный.
Точно так же существует и три способа выполнения 16-разрядного
вызова 32-разрядной процедурой:
1. Использовать 32-разрядный вызов 32-разрядной интерфейсной
   процедуры, которая осуществит 16-разрядный вызов из
   заданного места.
2. Осуществить вызов через 16-разрядный шлюз вызова.
3. Изменить 32-разрядную процедуру, вставив перед вызовом
   префикс размера операнда, превращающий этот вызов в
   16-разрядный. (Необходимо следить, чтобы возвращаемое
   смещение не превосходило 0FFFFH).
Программист может использовать любой из приведенных выше
методов выполнения команды CALL в 16-разрядном сегменте,
подобрав ей соответствующую команду RET в 32-разрядном
сегменте, или выполнить команду CALL в 32-разрядном сегменте,
подобрав ей соответствующую команду RET в 16-разрядном
сегменте.
24.4.2.1  Управление размером операнда при вызовах
----------------------------------------------------------------
Признак размера операнда  команды CALL в деиствительности
описывается битом D для сегмента, содержащего адресат, и
любого командного префикса размера операнда.
Когда на селектор указателя ссылается команда CALL, выбирающая
шлюз дескриптора, то тип вызова определяется типом шлюза вызова.
Вызов, идущий через шлюз вызова процессора 80286 (тип
дескриптора 4), имеет признак 16-разрядного размера операнда;
вызов, идущий через шлюз вызова центральных процессоров 286/
i486 (тип дескриптора 12), имеет признак 32-разрядного размера
операнда. Смещение относительно адресата берется из дескриптора
шлюза; таким образом, каждая 16-разрядная процедура может
вызывать процедуру расположенную в адресном пространстве больше
64 Кбайт в 32-разрядном сегменте, поскольку 32-разрядный шлюз
вызова содержит 32-разрядное смещение.
Немодифицированный 16-разрядный сегмент кода, который успешно
запускается на процессоре 8086 или в режиме реальных адресов
на процессоре 80286, имеет очищенный D-бит и не использует
префикса замены размера операнда; таким образом, он будет
использовать 16-разрядную версию команды CALL. Единственная
модификация, которая требуется для того, чтобы 16-разрядная
процедура смогла сделать 32-разрядный вызов - это перемещение
вызова в шлюз вызова процессора 386/i486.
24.4.2.2  Изменение размера вызова
----------------------------------------------------------------
При добавлении 32-разрядных шлюзов к 16-разрядным процедурам,
необходимо учитывать число параметров. Поле счета дескриптора
шлюза определяет размер строки параметров, копируемой из
текущего стека в стек более привилегированной процедуры. Поле
счета 16-разрядного шлюза определяет число копируемых слов,
тогда как поле счета 32-разрядного шлюза определяет число
копируемых двойных слов; поэтому 16-разрядная процедура должна
использовать четное число слов в качестве параметров.
24.4.3  Передача прерывания управления
----------------------------------------------------------------
Передача управления при прерываниях и исключениях происходит
с использованием шлюза. Признак размера операнда для
прерывания определяется дескриптором шлюза в таблице
дескрипторов прерываний (IDT). Шлюз прерывания или ловушки
центрального процессора 386/i486 (тип дескриптора 14 или 15),
выбирающий 32-разрядный обработчик прерываний, можно
использовать для прерывания как 16- так и 32-разрядных
процедур. Однако, иногда невыгодно предпочитать прерывание
или искючение вызову 16-разрядного обработчика при запущенном
32-разрядном коде, поскольку 16-разрядная процедура прерывания
сохраняет в стеке только 16 бит возвращаемого смещения. Если
32-разрядная процедура запущена в адресах превышающих 0FFFFH,
то 16-разрядная процедура прерывания не может обеспечить
адрес возврата.
24.4.4    Перевод параметра
----------------------------------------------------------------
Когда смещения сегмента или указатели сегмента (которые содержат
смещения сегмента) передаются как параметры между 16- и
32-разрядными процедурами, необходим некоторый перевод. Если 32-
разрядная процедура передает указатель на данные, расположенные
в адресах превосходящих 64 Кбайт, 16-разрядной процедуре,
последняя не может их использовать. За исключением этого
ограничения, интерфейсная программа может выполнять любые
необходимые преобразования форматов между 32-разрядными и 16-
разрядными указателями.
24.4.5  Интерфейсные процедуры
----------------------------------------------------------------
С размещением интерффейсных программ между 32-разрядными и
16-разрядными процедурами разрешаются некоторые интерфейсные
проблемы, такие как:
- Возможность процедурам в 16-раззрядных сегментах вызывать
  процедуры в 32-разрядных сегментах, имеющие смещение
  большее 0FFFFH.
- Устанавление соответствия между размерами операндов команд
  CALL и RET .
- Перевод параметров (данных).
Интерфейссная программа упрощается, когда есть нижеследующие
ограничения.
- Интерфейсная программа располагается в сегменте с
  установленным D-битом, означающим размер операнда по
  умолчанию 32 бита.
- Все процедуры, которые могут вызываться 16-разрядными
  процедурами, имеют смещение не более 0FFFFH.
- Все возвращаемые адреса, сохраняемые 16-разрядными
  процедурами, также имеют смещение не более 0FFFFH.
Если какое либо из этих ограничений нарушается, то программа
интерфейса становится более сложной. Например, если
16-разрядная процедура вызывает 32-разрядную процедуру с
точкой входа за 0FFFFH, программа интерфейса должна обеспечить
смещение к точке входа. Отображение между 16-разрядными и
32-разрядными адресами осуществляется автоматически только при
использовании шлюза вызова, поскольку дескриптор шлюза вызова
содержит 32-разрядный адрес. Если шлюз вызова не используется,
то 32-разрядный адрес должен обеспечить дескриптор.
Программа интерфейса вызывает процедуры из других сегментов.
Возможно два типа интерфейсов:
- Когда 16-разрядные процедуры вызывают 32-разрядные процедуры.
  Процедура интерфейса вызывается 16-разрядной командой CALL
  и использует префикс размера операнда перед командой RET для
  выполнения 16-разрядной команды RET. Вызовы 32-разрядных
  сегментов - это 32-разрядные команды CALL (по умолчанию,
  поскольку установлен D-бит), а 32-разрядная программа
  производит возврат с помощью 32-разрядной команды RET.
- Когда 32-разрядные процедуры вызывают 16-разрядные процедуры.
  Процедура интерфейса вызывается 32-разрядной командой CALL
  и возвращается 32-разрядной командой RET (по умолчанию,
  поскольку установлен D-бит). Команда CALL для 16-разрядных
  процедур использует префикс размера операнда; возврат
  16-разрядной процедуры осуществляется с помощью 16-разрядной
  команды RET.


Яндекс цитирования