Уроки Iczelion'а

Формат LE


VxD использует формат линейных исполняемых файлов (linear executable file format - LE). Этот формат был спроектирован для OS/2 вверсии 2.0. Он может содержать как 16-битный, так и 32-битный код, что является одним из требований к VxD. Помните, что VxD начали свою историю еще в эпоху Windows 3.x. В то время Windows загружалась из DOS'а, поэтому VxD должны были выполнять определенные действия в реальном режиме, прежде чем Windows переключала машину в защищенный режим. 16-битный код реального режима должен был находиться в том же файле, что и 32-битный код защищенного режима. Поэтому файловый LE-формат был очевидным выбором. Драйвера Windows NT не имеют дела с pеальным pежимом, поэтому им не надо использовать LE-формат. Вместо этого они используют PE-формат.

Код и данные в LE-файле хранятся в сегментах с различными аттрибутами выполнения. Они приводятся ниже.

  • LCODE - 'рage-locked' код и данные. Этот сегмент "заперт" в памяти. Иными словами, этот сегмент не может быть выгружен на диск, поэтому этот класс сегментов целесообразно использовать тогда, когда нельзя тратить попусту драгоценное системное время. Код и данные должны всегда присутствовать в памяти. Особенно это нужно для обработчиков хардварных прерываний.
  • PCODE - выгружаемый код. Выгрузка на диск и загрузка кода в память регулируется VMM. Код в этом сегменте может не присутствовать все время в памяти (например, если VMM срочно понадобилась физическая память, он может выгрузить этот сегмент на время).
  • PDATA - то же самое, только это сегмент с данными, а не с кодом.
  • ICODE - код только для инициализации. Код в этом сегменте используется только во время инициализации VxD. После инициализации, этот сегмент будет выгружен из памяти, чтобы освободить физическую память.
  • DBCODE - код и данные только для отладки. Код и данные в этом сегменте используются только тогда, когда вы запускает VxD под отладчиком. Hапример, код может содержать обработчик для контрольного сообщения Debug_Query.
  • SCODE - статические код и данные. Этот сегмент будет всегда присутствовать в памяти, даже когда VxD будет выгружен. Этот сегмент особенно полезен для динамических VxD, так как они могут выгружаться много раз во время рабочей Windows-сессии, в то время как требуется, чтобы сохранялось их конфигурация/состояние.
  • RCODE - инициализационные код и данные pеального pежима. Этот сегмент содержит 16-битные код и данные для инициализации в реальном pежиме.
  • 16ICODEUSE16 - инициализационные данные защищенного pежима. Этот сегмент содержит код, который VxD скопирует из защищенного режима в V86-режим. Hапример, если вы хотите скопировать какой-то код V86-режима, этот код должен находиться в этом сегменте. Если вы поместите код в другой сегмент, ассемблер сгенерирует неправильный код, так как он будет генерировать 32-битный код вместо полагающегося 16-битного.
  • MCODE - "запертые" строки сообщений. Этот сегмент содержит строки сообщений, которые скомпилированны с помощью макросов сообщений VMM. Это поможет вам создать интернациональные версии вашего драйвера.


Все это не значит, что ваш VxD обязан иметь все эти сегменты. Вы можете выбрать те сегменты, которые вы хотите использовать в вашем VxD. Hапример, если ваш VxD не имеет инициализации pеального pежима, у него не будет секции RCODE. Как правило, вы будете использовать LCODE, PCODE и PDATA. За вами, как за создателем VxD, остается выбоp нужных сегментов. Обычно вам следует использовать PCODE и PDATA так часто, как это возможно, потому что тогда VMM сможет выгружать сегменты из памяти и загружать их обратно, когда им это понадобится. Вы должны использовать LCODE для обработчиков хардварных прерываний и сервисов, которые будут вызываться этими обработчиками.

Вам не нужно использовать эти классы сегментов напрямую. Вы должны объявить сегменты на основе этих классов. Объявления сегментов находятся в файле определения модуля. (.def). Вот пример такого файла для VxD:

VXD FIRSTVXD

SEGMENTS _LPTEXT CLASS 'LCODE' PRELOAD NONDISCARDABLE _LTEXT CLASS 'LCODE' PRELOAD NONDISCARDABLE _LDATA CLASS 'LCODE' PRELOAD NONDISCARDABLE

_TEXT CLASS 'LCODE' PRELOAD NONDISCARDABLE _DATA CLASS 'LCODE' PRELOAD NONDISCARDABLE CONST CLASS 'LCODE' PRELOAD NONDISCARDABLE _TLS CLASS 'LCODE' PRELOAD NONDISCARDABLE

_BSS CLASS 'LCODE' PRELOAD NONDISCARDABLE _LMGTABLE CLASS 'MCODE' PRELOAD NONDISCARDABLE IOPL _LMSGDATA CLASS 'MCODE' PRELOAD NONDISCARDABLE IOPL _IMSGTABLE CLASS 'MCODE' PRELOAD DISCARDABLE IOPL

_IMSGDATA CLASS 'MCODE' PRELOAD DISCARDABLE IOPL _ITEXT CLASS 'ICODE' DISCARDABLE _IDATA CLASS 'ICODE' DISCARDABLE _PTEXT CLASS 'PCODE' NONDISCARDABLE

_PMSGTABLE CLASS 'MCODE' NONDISCARDABLE IOPL _PMSGDATA CLASS 'MCODE' NONDISCARDABLE IOPL _PDATA CLASS 'PDATA' NONDISCARDABLE SHARED _STEXT CLASS 'SCODE' RESIDENT

_SDATA CLASS 'SCODE' RESIDENT _DBOSTART CLASS 'DBOCODE' PRELOAD NONDISCARDABLE CONFORMING _DBOCODE CLASS 'DBOCODE' PRELOAD NONDISCARDABLE CONFORMING _DBODATA CLASS 'DBOCODE' PRELOAD NONDISCARDABLE CONFORMING

_16ICODE CLASS '16ICODE' PRELOAD DISCARDABLE _RCODE CLASS 'RCODE' EXPORTS FIRSTVXD_DDB @1



Первое утверждение задает имя VxD. Имя VxD должно быть заданно в верхнем регистре. Я экспериментировал с именами в нижнем регистре, и VxD отказывался делать что-либо кроме как загрузки самого себя в память. Затем идут определения сегментов. Определение состоит из трех частей: имя сегмента, класс сегмента и желаемые свойства выполнения сегмента. Вы можете видеть, что многие сегменты основываются на одном классе, например, _LPTEXT, _LTEXT, _LDATA основываются на классе LCODE и имеют одни и те же свойства. Эти сегменты объявлены для того, чтобы сделать программирование легче. Hапрмер, LCODE может содержать и код и данные. Программисту будет проще поместить данные _LDATA, а код в _LTEXT. В конце концов, оба сегмента будут объединены в один при компиляции исполняемого файла.

VxD экспортирует один и только один символ - это device descriрtor block (DDB). Фактически, DDB - это структура, которая содержит все, что VMM должна знать о VxD. Вы должны экспортировать DDB в файле определения модуля. Большую часть времени вы будете использовать вышеприведенный .DEF файл в своих новых VxD-проектах. Вам следует только изменить имя VxD в первой и последней линиях .DEF-файла. Определения сегментов - это перегиб в asm'овском VxD-проекте. Вы получите много предупреждений, но это будет компилироваться.

Вы можете избавиться от назойливых предупреждений, удалив те определения сегментов, которые вы не используете в своих проектах.

vmm.inc содержит множество макросов для объявления сегментов в вашем исходнике.

_LTEXT VxD_LOCKED_CODE_SEG

_PTEXT VxD_PAGEABLE_CODE_SEG _DBOCODE VxD_DEBUG_ONLY_CODE_SEG

_ITEXT VxD_INIT_CODE_SEG

_LDATA VxD_LOCKED_DATA_SEG

_IDATA VxD_IDATA_SEG

_PDATA VxD_PAGEABLE_DATA_SEG

_STEXT VxD_STATIC_CODE_SEG

_SDATA VxD_STATIC_DATA_SEG

_DBODATA VxD_DEBUG_ONLY_DATA_SEG

_16ICODE VxD_16BIT_INIT_SEG

_RCODE VxD_REAL_INIT_SEG

У каждого макроса есть необходимая завершающая часть. Например, если вы хотите объявить сегмент _LTEXT в вашем исходнике, вам нужно это сделать так:

VxD_LOCKED_CODE_SEG <поместите сюда свой код> VxD_LOCKED_CODE_ENDS


Содержание раздела