pragma alloc_text的用途及支持的段列表
1、背景
在使用KWDF框架的时候,无意中看到这样的代码:
本着不知者无畏的勇气,我非得搞清楚这是做什么用 的。 让我们以来来回忆下 #pragam 都有那些常见用法?
(1)、链接库、函数入口
// 自动链接库
#pragma comment(lib, "user32.lib")// 链接器选项
#pragma comment(linker, "/ENTRY:main")
(2)、编译器警告控制
// 禁用特定警告
#pragma warning(disable: 4996) // 禁用不安全函数警告// 临时禁用警告
#pragma warning(push)
#pragma warning(disable: 4244)
// 代码块
#pragma warning(pop)// 将警告视为错误
#pragma warning(error: 4013)
(3)、防止头文件重复引用
#pragma once
(4)、结构体内存对齐(C++11中有:alignas 关键字用来对结构体指定字节对齐)
// 1字节对齐
#pragma pack(1)
struct PackedStruct {char c;int i;
};
#pragma pack() // 恢复默认对齐// 或使用 push/pop
#pragma pack(push, 1)
struct AnotherStruct {char c;int i;
};
#pragma pack(pop)
(5)、代码优化控制
// 禁用优化
#pragma optimize("", off)
void debug_function() {// 不优化的代码
}
#pragma optimize("", on)// 内联控制
#pragma auto_inline(off)
(6)、自定义消息
#pragma message("Debug mode enabled")
(7)、代码生成控制
// 指定函数不抛出异常
#pragma function_no_except(function_name)// 指定函数为纯函数
#pragma function_pure(function_name)
(8)、多线程同步
// OpenMP 并行处理
#pragma omp parallel for
for (int i = 0; i < 100; ++i) {// 并行执行
}// 临界区
#pragma omp critical
{// 临界区代码
}
暂时想到这么多(欢迎各位Coder补充),但是这个pragma alloc_tex初次相遇,下面将我对它的用途理解介绍如下:
在 Windows 驱动程序中,代码和数据被组织在不同的内存段中,每个段有不同的特性和用途:
(1)INIT 段
#pragma alloc_text (INIT, DriverEntry)
特点:
• 一次性执行:只在驱动程序初始化时执行一次
• 自动释放:执行完成后,系统会自动释放这个段的内存
• 节省内存:避免长期占用内存资源
• 适用函数:DriverEntry 和其他只在初始化时调用的函数
(2)PAGE段
#pragma alloc_text (PAGE, QueueSampleEvtDeviceAdd)
#pragma alloc_text (PAGE, QueueSampleEvtDriverContextCleanup)
特点:
• 可分页内存:可以被换出到磁盘(虚拟内存)
• IRQL 限制:只能在 PASSIVE_LEVEL 或 APC_LEVEL 下调用
• 内存优化:不常用的代码可以被换出,节省物理内存
• 必须使用 PAGED_CODE():运行时检查 IRQL 级别
(3)、NONPAGED 段
#pragma alloc_text (NONPAGED, MyInterruptHandler)
特点:
• 明确指定为非分页内存
• 可在高 IRQL 级别调用
(4)、POOLCODE 段
#pragma alloc_text (POOLCODE, MyUtilityFunction)
特点:
• 用于辅助函数
• 通常是分页的
通常使用的也就上面的这4个段,当然也还有其它的段。他们的使用规则:
应该放在 INIT 段的函数:
• DriverEntry
• 只在驱动加载时调用一次的初始化函数
应该放在 PAGE 段的函数:
• PnP 事件处理函数(EvtDeviceAdd, EvtDevicePrepareHardware 等)
• 电源管理函数
• 大部分 WDF 回调函数(除了中断和定时器)
• 文件操作处理函数
应该保持在默认段(非分页)的函数:
• 中断服务例程 (ISR)
• DPC 例程
• 定时器回调函数
• I/O 完成回调(在高 IRQL 执行的)
经过分析DDK的文档,我们可以知道比较全面的段如下:
1. 标准预定义段
初始化段:
• INIT - 初始化代码段,执行后会被释放
• INITDATA - 初始化数据段
分页段:
• PAGE - 可分页代码段
• PAGEDATA - 可分页数据段
• PAGEBMRK - 分页基准标记段
• PAGEKD - 内核调试器分页段
• PAGEHDLS - 句柄分页段
• PAGELK - 锁分页段
• PAGEVRFY - 验证分页段
非分页段:
• NONPAGED - 非分页代码段
• NONPAGEDDATA - 非分页数据段
池代码段:
• POOLCODE - 池代码段
• POOLDATA - 池数据段
2. 系统服务段
• SYSSTUBS - 系统存根段
• SYSINIT - 系统初始化段
• SYSDATA - 系统数据段
3. 驱动特定段
WDF 框架段:
• WDFINIT - WDF 初始化段
• WDFPAGE - WDF 分页段
电源管理段:
• PWRINIT - 电源初始化段
• PWRPAGE - 电源分页段
PnP 段:
• PNPINIT - PnP 初始化段
• PNPPAGE - PnP 分页段
4. 内存管理段
• MISYSINIT - 内存初始化段
• MMINIT - 内存管理初始化段
• MMPAGE - 内存管理分页段
5. I/O 管理段
• IOINIT - I/O 初始化段
• IOPAGE - I/O 分页段
6. 调试和跟踪段
• DEBUGCODE - 调试代码段
• TRACEDATA - 跟踪数据段
• KDBG - 内核调试段
7. 安全相关段
• SECINIT - 安全初始化段
• SECPAGE - 安全分页段
8. 缓存段
• CCACHE - 缓存代码段
• CACHEDATA - 缓存数据段
9. 自定义段
你还可以使用自定义段名,只要符合以下规则:
• 段名长度不超过 8 个字符
• 可以包含字母、数字和下划线
• 例如:MYINIT、MYPAGE、CUSTOM1 等
10. 架构特定段
x86 特定:
• INITX86 - x86 初始化段
• PAGEX86 - x86 分页段
AMD64 特定:
• INITAMD64 - AMD64 初始化段
• PAGEAMD64 - AMD64 分页段
ARM 特定:
• INITARM - ARM 初始化段
• PAGEARM - ARM 分页段