Windows 内核中有多少 C++11 是可用的

How much of C++11 is usable in Windows Kernel

已交付最新的 WDK 以与支持 C++11 的 Visual Studio15 一起使用。

但是,我没有看到关于有多少功能可用的文档。

显然,我不会使用 std::threadstd::mutex,但不太清楚的是魔术静力学。

Class * function()
{
     static Class myInstance;

     return &myInstance;
}

现在在用户模式下是线程安全的,但尚不清楚此构造是否可以在内核中工作。

更令人担忧的是,内核是否可以接受 C++11 之前的代码(假设析构函数是微不足道的)。

除非您计划完全重写内核并部署一个全新的 标准化 导出名称(这意味着丢弃所有现有的可执行文件),我认为那将是几乎不可能。许多 C++ 功能实际上是 元函数 ,编译器必须将其转换为存在的东西。

std::thread 这样的东西可以作为内核资源的包装器实现(这很可能是“指向数据结构指针的指针:这就是 HANDLE 实际上是什么),通过让这些结构驻留在另一个进程中并且对客户端程序完全不透明。

函数调用这样的东西来保持这种不透明性需要一个标准的 ABI(应用程序二进制接口)所有语言都可以依赖,在生成必须 linked.

的目标代码时

现在,C ABI - 由于缺少重载 - 是微不足道的(只需将 _ 附加到函数名称:这是 windows 内核库采用的约定,并且每个编译器开发人员在制作它的 windows 版本时必须依赖它),但 C++ 名称修改是......专有的(没有关于必须如何在系统级别完成的定义,因此每个编译器都有自己的定义)。

因此,唯一可靠的内核将是仅导出的内核 extern "C"。 它可以在内部用 C++ 编写,但它的接口在任何情况下都必须是纯 C(这只是你的 class* function();,在语义上与 HANDLE CreateClass().

没有区别

请注意,即使在 C++ 规范级别定义标准 ABI 也无济于事:所有 C++ 编译器都将 link 相同,但不需要其他语言遵循。

并且系统级 ABI 必须足够简单,不需要客户端语言功能(如函数重载),并非所有语言都必须支持。

更复杂的是,C++ 也有模板,它在编译期间实例化代码并且不能跨进程边界或内核屏障可靠地实现:想象一下内核在内部有 vector<int>vector<double>:当我必须使用这些功能时,我可以依赖系统,但是 vecotr<foo> 呢?

在我的机器上编译我的软件时,如何让我所有用户的系统内核使 vector<foo> 存在?这可以在安装过程中进行,但同样需要通信接口更加标准化。

内核是存在于汇编程序级别的物理资源的管理器。在 C 中表示它们几乎是微不足道的。如果您使用 C++ 低级功能(与 C 基本相同),用 C++ 表示它们仍然是微不足道的,但是-一旦您上升到抽象-您会立即遇到标准化缺失和复杂的非平凡选择在哪里以及如何实现这将转化为未来对那些在内核级别的使用可能没有明确定义的事物的约束。


当然,原则上,没有什么禁止在内核实现内部使用 C++,但这会在跨资源使用的边界管理中产生问题。

实际协议是"give me access to a resource"和"keep your resource back"。

客户端程序可以将这两个调用包装在 RAII class 中并在其上应用所有 C++11 功能,但是将其移动到边界的另一边呢? 内核可以 return 一个 win::unique<something> 吗?好吧......不是真的,因为你不能破坏你自己不在你的进程中的东西:"samrt handle" 将因此有一个析构函数,导致对内核函数的另一个调用。 o 内核在任何情况下都会有一个单独的 Create/Get 和 Delete/Relese 函数。

我当然可以在智能句柄方面为您的 C++ 程序开发一个 API,但程序与内核通信仍将通过普通函数进行(因此智能句柄全部由客户端管理, 无论如何)

类似地,如果调用都是同步的,则堆栈展开会起作用,但 create/delete 本身不是同步的(它们不会在另一个内部调用)。它们是 "synchronized" RAII 模式,通过驻留在 YOUR 堆栈中的 LOCAL 对象。但是 *HPEN (注意取消引用)结构不在您的堆栈中:在另一个进程(GDI 驱动程序)中,因此 smart<HPEN> 必须在构造时调用 CreatePen 并且 DeletePen 在销毁时,因为内核本身无法知道您的 "unwinding"(那是您的,而不是内核)何时会到达正确的点。

C++ //in kernel// 可以存在于完全由内核本身在同一个内核调用中同步构造和销毁的对象,然后 - 因此 - 不会离开内核,以某种方式使用由客户。这当然是可能的,但由于内核的目的是导出功能并且导出需要平面 APIs,您很快就会使用 C++ 内核导出 C++ 包装器在客户端使用的纯 C 接口.

我怀疑这种努力是否合理。

我找到了一些关于开关 /kernel msdn : /kernel (Create Kernel Mode Binary) 的文档,其中描述了一个开关来告诉编译器 .obj 用于内核模式。

那描述了异常和 RTTI 的不同行为,但没有提到魔术静力学。

来自简单

的可见反编译
Class * GetInstance()
{
   static Class instance;
   return &instance;
}

和一些用户模式测试,编译器

  1. 不发出任何线程本地代码。
  2. 不提供用户模式的线程安全行为。

编辑

为清楚起见。当未指定 /kernel 时,魔术静态起作用并且静态初始化是线程安全的。该机制(使用 fs:)不适用于内核。

使用 /kernel 代码不是线程安全的,但与内核兼容。 (没有引用fs:)