• 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.

            

     

            

     

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

  • 相关阅读:
    校园微社区微信小程序源码/二手交易/兼职交友微信小程序源码
    复盘归因,提高交付质量的秘诀
    MATLAB中的矩阵的重构和重新排列
    C语言复习笔记7----二维数组
    骨传导耳机哪个牌子好?骨传导好用的品牌推荐
    使用canal解决Mysql和Redis数据同步(TCP)
    Java函数式编程(Lambda表达式、方法引用)详解
    Python学习之CSDN21天学习挑战赛计划之14
    【21-业务开发-基础业务-商品模块-分类管理-商品系统三级分类的新增类别前后端代码实现-商品系统三级分类的更新类别前后端代码实现-之前错误的Bug修正】
    物联网AI MicroPython学习之语法UART通用异步通信
  • 原文地址:https://blog.csdn.net/cxsjabcabc/article/details/127739540