• Windows内核--读懂源代码的特殊“标志“(1.4)


       Windows内核代码严谨而富有逻辑,毕竟Kernel不是简单的Hello World,为了让代码更易于阅读和维护,加入了不少具有编译器特性和协助程序员的代码,同时对于错误和异常,内核必须合适处理,保证稳定和安全。

    • 似乎没有实际意义(对于生成二进制指令)的宏

             

              

            编译器根据"__in/__out/OPTIONAL"的标志知道它代表输入/输出/可选参数。

            程序员根据这些符号清晰地了解参数的特性,避免误用。

                    

    • 函数开始的"PAGED_CODE"

            

            内核不像普通应用程序,不用太关心硬件和操作系统内部状态,OS本身就需要管理这些。抽象出了IRQ和IRQL, 支援分页内存,任何内核API都必须清晰地确认当前处于哪种中断级别。 

            PAGED_CODE宏就在判断当前代码是否可运行于可分页内存,否则,debug版本就会抛出异常发现问题。

            

    Windows内核只有PASSIVE和APC使用分页内存 ,更高IRQL只能跑在非分页内存。

    APC类似于Unix的Signal, DPC代表线程调度级别。

    • 到处可见的"NT_SUCCESS"

                    

    内核把大于等于0定义为成功的返回值。

    内核必须要处理任何Fail返回值以保证内核正确和安全。

            创建Object失败:

                    

            从句柄找指针失败:

                     

             创建内存地址空间失败:

                    

            等等,数不胜数。

    Windows定义了4种不同的NT Status, 用高位Bit简洁地用一个数值代表不同状态类型。

                    NT_SUCCESS          (最高两个bit: 00)

                    NT_INFORMATION   (最高两个bit: 01)     

                    NT_WARNING           (最高两个bit: 10)          

                    NT_ERROR                (最高两个bit: 11) 

                            使用 NTSTATUS 值 - Windows drivers | Microsoft Learn

                            

    • 使用全局变量

            比如进程工作集Min/Max变量。

            

    经常写上层应用的可能会疑惑,全局变量不是不推荐的吗? 为什么Kernel还明目张胆地使用? 事实上,当你理解内核为何是内核时,就会懂得全局变量其实是内核的基本属性, 用全局变量来表达也许是唯一或最恰当的选项。     

            

             #pragma代表编译器指令,可以"指导"编译器做处理。

                    Pragma 指令与 __pragma 和 _Pragma 关键字 | Microsoft Learn (Pragma大全)

                    #pragma alloc_text(PAGE, ...)表示代码段加入到分页内存。

                    #pragma alloc_text(INIT, ...)表示初始化后就不需要了,可以移除。

                    #pragma data_seg("PAGEDATA")表示data放入分页内存。

                            data_seg pragma | Microsoft Learn

    • 系统调用开始调用KeGetPreviousMode和Probe操作

            

             一般来说,系统调用会接收用户模式的参数,内核当然默认不信任用户模式,所以会有ProbeXXXX确认参数真的合法。

            为什么还要判断是否之前Mode是否是KernelMode呢? 因为此系统调用函数很可能被Kernel或Driver直接调用,默认内核空间是可信赖的,此时就会忽略参数检查,以提高性能。

    内核内部使用和私有API

            有些API以i后缀代表是内部使用,以p后缀代表是私有不可为外部调用。比如,Ki代表内核管理内部API, Psp代表进程/线程私有API.

            

     

            

     

           内核中还有很多有趣的语言或编译器特性,以后带大家不断领略。

  • 相关阅读:
    频率域滤波
    北航投资携核心医疗获2023年度十佳投资案例
    程序员团队如何做好项目管理?十年管理经验,真实案例分享
    荧光染料CY3/CY5/CY5.5聚已内酯PLA载药纳米粒CY3-PLA|CY5-SS-PEG-PLA|CY5.5-PLA(定制供应)
    langchain 加载各种格式文件读取方法
    Java Socket 循环接收数据readLine()阻塞问题解决办法
    (部署服务器系列三)eclipse远程调试springboot项目代码
    Uniapp矩阵评分组件
    【Linux】一万七千字详解 —— 基本指令(二)
    CSS画圆以及CSS实现动态圆
  • 原文地址:https://blog.csdn.net/cxsjabcabc/article/details/127739540