1.1.6 内核的内存操作
Windows驱动程序使用的内存资源非常珍贵,分配内存时要尽量节约。和应用程序一样,局部变量是存放在栈( Stack)空间中的。但栈空间不会像应用程序那么大,所以驱动程序不适台递归调用或者局部变量是大型结构体。如果需要大型结构体,请在堆( Heap)中申请。
堆中申请内存的函数有以下几个,原型如下:
ExAllocatePool(
);
PVOID
ExAllocatePoolWithTag(
);
PVOID
ExAllocatePoolWithQuota(
);
PVOID
ExAllocatePoolWithQuotaTag(
参数PooIType是个枚举变量,如果此值为NonPagedPool,则分配非分页内存。如果此值为PagedPool,则分配内存为分页内存。Windows规定有些虚拟内存页面是可以交换到文件中的,这类内存被称为分页内存。而有些虚拟内存页永远不会交换到文件中,这些内存被称为非分页内存。
参数NumbelofBytes是分配内存的大小,注意最好是4的倍数。
函数返回分配的内存地址,一定是内核模式地址。如果返回NULL,则代表分配失败。
以上四个函数功能类似,函数以WithQuota结尾的代表分配的时候按配额分配。函数以WithTag结尾的函数,和ExAllocatePool功能类似,唯一不同的是多了一个Tag参数,系统在要求的内存外又额外地多分配了4个字节的标签。在调试的时候,可以找出是否有标有这个标签的内存没有被释放。
将分配的内存,进行回收的函数是ExFreePool和ExFreePoolWithTag,它们的原型是:
ExFreePool(
);
VOID
ExFreePoolWithTag(
参数P就是要释放的地址。
下面的代码为WinPcap中使用内核内存操作的实例:
PWCHAR getAdaptersList(void)
{
…
PWCHAR DeviceNames = (PWCHAR) ExAllocatePoolWithTag(PagedPool, BufLen,
'0PWA');
…
ExFreePool(DeviceNames);
1.1.7 内存操作的运行时函数
运行时函数是程序运行时必不可少的,由编译器提供。针对不同的操作系统,运行时函数的实现方法不同,但接口基本保持一致。例如,malloc函数就是典型的运行时函数,所有编译器厂商都必须提供这个函数,但在不同操作系统上的实现方法就不尽相同了。
1.1.7.1 内存间复制(非重叠的情况)
在驱动程序开发中,经常用到内存的复制。DDK为程序员提供了RtlCopyMemory函数。
IN VOID UNALIGNED *Destination,
IN CONST VOID UNALIGNED *Source,
IN SIZE_T Length
参数Destination表示要复制内存的目标地址。参数Source表示要复制内存的源地址。参数Length表示要复制的内存的长度,单位是字节。
1.1.7.2 内存间复制(可重叠的情况)
用RtICopyMemory可以复制内存,但其内部没有考虑目标内存与源内存重叠的情况。对可重叠的情况DDK提供了RtIMoveMemory函数。
RtlMoveMemory(
IN VOID UNALIGNED *Destination,
IN CONST VOID UNALIGNED *Source,
IN SIZE_T Length
参数Destination表示要复制内存的目标地址。参数Source表示要复制内存的源地址。参数Length表示要复制的内存的长度,单位是字节。
1.1.7.3 填充内存
驱动程序开发中,迹经常用到对某段内存区域用固定字节填充。DDK为程序员提供了RtIFillMemory函数。
RtlFillMemory(
IN VOID UNALIGNED *Destination,
IN SIZE_T Length,
IN UCHAR Fill
参数Destination为目标内存的地址。参数Length为待填的长度。参数Fill为需要填充的字节。
在驱动程序开发中,还经常要对某段内存填零,DDK提供了RtlZeroMemory函数。
RtlZeroMemory(
IN VOID UNALIGNED *Destination,
IN SIZE_T Length
参数Destination为目标内存的地址。参数Length为待填的长度。
1.1.7.4 内存比较
驱动程序开发中,还会用到比较两块内存是否一致,可采用RtICompareMemory函数。
RtlCompareMemory(
IN CONST VOID *Source1,
IN CONST VOID *Source2,
IN SIZE_T Length
参数Sourcel为比较的第一个内存地址。参数Sou:rce2为比较的第二个内存地址。参数Length为比较的长度,单位为字节。
函数返回相等的字节数。
函数RtIEquaIMemory通过判断返回值和Length是否相等,来判断两块内存是否完全一致。同时DDK还提供了RtlEqualMemory函数,直接判断两块内存是否一致。
RtlEqualMemory(
CONST VOID *Source1,
CONST VOID *Source2,
SIZE_T Length
函数RtlEquaIMemory在两块内存一致的情况下返回非零值,在不一致的情况下返回零。
本文出自 “千江月” 博客,请务必保留此出处http://eslxf.blog.51cto.com/918801/196914