第3章 Windows运行机理-3.1 内核分析(4)

3.1.2 LE文件的格式

VxD采用线性可执行文件格式(LE)。这种文件格式是为OS/2 2.0版设计的。它同时包含16位和32位代码,这也是VxD程序的需要。回想VxD在Windows 3.x的时代,从DOS启动Windows,Windows在把机器转到保护模式之前,需要在实模式下做一些初始化。实模式的16位代码必须和32位代码一起放在可执行文件中。所以,LE文件格式成为理所当然的选择。Windows NT驱动程序不必在实模式下初始化,所以它们不必使用LE文件格式。它们用的是PE文件格式。

在LE文件中,代码和数据被存放在几类运行属性不同的段中。以下是一些可用的段类。

 LCODE:页面锁定的代码和数据段。这种段被锁定在内存里。换句话说,它永远不会被放在硬盘上,所以一定要谨慎地使用这种段类,以免浪费宝贵的内存。但那些每时每刻都必须放在内存中的代码和数据应该放在这个段里。尤其是那些硬件中断处理程序。

 PCODE:可调页代码段。VMM可以对这种段实行调页处理,在这种段里的代码不必时刻放在内存里,当VMM需要物理内存的时候,它就会把这段放到硬盘上去。

 PDATA:可调页数据段。

 ICODE:仅用于初始化段。这种段里的代码仅仅用来进行VxD的初始化。当初始化完成后,VMM就把这段从内存中释放。

 DBOCODE:仅用于调试的代码数据段。当你要调试VxD程序时,就要用到这种段里的代码和数据,例如,它包含要调试的消息的处理代码。

 SCODE:静态代码和数据段。这种段时刻存在于内存中,即使VxD已经卸载,这种段对某些动态的VxD程序也很有用。这些VxD程序需要在某一Windows进程里不停地加载/卸载,而又要记录上次的环境和状态。

 RCODE:实模式初始化代码数据段。这种段包含实模式初始化需要的16位代码和数据。

 16ICODE:16ICODE USE16保护模式初始化数据段。这是一个16位的段,它包含VxD要从保护模式拷贝到V86模式的代码。例如,如果要把一些V86的代码拷贝到一个虚拟机上时,想拷贝的代码就要放在这里。如果你把它放在其他的段里,编译程序就会产生错误的代码,例如,它会产生32位代码而不是16位代码。

 MCODE:锁定的消息字串。这种段包含了由VMM消息宏帮助编译的消息字串,这有助于构造驱动程序的国际版本。

VxD程序并不意味着必须包含以上所有的段,可以选择VxD程序需要的段。例如,如果VxD程序不进行实模式初始化,那么就不必包含RCODE段。

大多数时候,要用到LCODE,PCODE和PDATA段。作为一个VxD程序编写者,为代码和数据选择合适的段取决于自己的判断。总的来说,应该尽可能多地使用PCODE和PDATA。因为这样,VMM就可以在需要的时候把段调入调出内存。另外,硬件中断程序及其所用到的服务必须放在 LCODE段里。

注意,不能直接地使用这些段类,你要用这些段类来定义段,这些段的定义被存放在模块定义文件(.def)中。下面是一个标准的模块定义文件:

VxD SthVxD DYNAMIC

DESCRIPTION

'SthVxD (C) Beijing Herosoft Computer Technology Ltd.1996-2002'

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

_ITEXT CLASS 'ICODE' DISCARDABLE

_IDATA CLASS 'ICODE' DISCARDABLE

_PTEXT CLASS 'PCODE' NONDISCARDABLE

_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

SthVxD_DDB @1

第一个声明定义了VxD的名称,一个VxD的名称必须是全部大写的。

接下来是段的定义,段的定义包括三个部分:段的名称、段类和要求的段的运行属性。可以看到,很多段都基于相同的段类,例如,_LPTEXT,_LTEXT,_LDATA都是基于LCODE段类,而且属性也完全一样。这样定义段有利于让代码更容易被理解。如,LCODE可以包含代码和数据,对于一个程序员来说,如果他能把数据放到_LDATA段里,把代码放到_LTEXT 段里,代码就会显得很容易理解。最后,这两个段都会被编译到最后的可执行程序的同一个段内。

一个VxD程序导出且仅导出一个标记:它的设备描述块(DDB)。DDB实际上是一个结构,它包含了VMM需要知道的所有的VxD信息。必须在模块定义文件中导出DDB。

在大多数时候,可以把上面的.DEF文件用到新建的VxD项目中去。只要把.DEF文件里第一行和最后一行的VxD名字改掉就可以了。在一个汇编的VxD项目中,段的定义是不必要的,段的定义主要用于C的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

相关推荐
智者知已应修善业2 小时前
【蓝桥杯单词分析最多字母次数并列字典最小输出】2025-4-15
c语言·c++·经验分享·笔记·算法·蓝桥杯
爱编码的小八嘎7 小时前
第3章 Windows运行机理-3.1 内核分析(2)
c语言
v_for_van11 小时前
力扣刷题记录7(无算法背景,纯C语言)
c语言·算法·leetcode
白太岁12 小时前
通信:(3) 高并发网络通信:epoll + 边沿触发 + 非阻塞 IO + tcp
c语言·网络·c++·网络协议·tcp/ip
白太岁15 小时前
Redis:(2) hiredis 使用、C++ 封装与连接池
c语言·c++·redis·缓存
代码改善世界16 小时前
【C语言】线性表之顺序表、单链表、双向链表详解及实现
c语言·网络·链表
m0_5312371718 小时前
C语言-分支与循环语句练习2
c语言·开发语言·算法
Once_day18 小时前
GCC编译(3)常见编译选项
c语言·c++·编译和链接
爱编码的小八嘎19 小时前
第3章 Windows运行机理-3.1 内核分析(3)
c语言