大多数操作系统的问题在于它们遵循特定的“调用约定”。此约定要求将函数参数放在堆栈上,这是 C 风格调用约定的某种派生。您必须使用此约定以实现与该操作系统的 ABI(应用程序二进制接口)兼容性。因此,如果没有操作系统支持,您只能将此功能用于在应用程序中进行的调用。
这会使编译器相当复杂,并且可能需要大量的工作。简而言之,如果你有一个支持这种调用约定的编译器,你可以保护你自己的程序,但是当你必须做诸如读/写文件等事情时,你仍然会受到操作系统的支配。缓冲区溢出例如,在 DLL 中,不能通过更改调用约定来修复。
其次,直到最近,随着虚拟化的出现,像这样建立一个单独的区域确实是不可行的,因为分段很昂贵,而内存虚拟化更是如此。今天,这实际上不是问题,但由于我们必须处理历史软件(例如十年前编写的仍然需要传统调用方法的东西),操作系统将被迫在一段时间内无限期支持这两种模型的时间。
如果编写了一个没有兼容性问题的新操作系统,它当然可以这样做,但它可能不会发生,因为有更多可行的方法。微软自己的Singularity操作系统完全不受缓冲区溢出的影响(根据他们的说法),因为操作系统静态地验证每个程序不可能行为不端。有趣的是,该操作系统不使用 Windows、Linux、Mac OS 等所使用的“内存保护”。程序在运行之前经过验证是否正确行为,而不是在运行时。当然,如果病毒能够感染这个系统,那么由于缺乏硬件级别的保护,它将拥有无限的系统控制权。
简而言之,即使没有对该主题进行任何认真的研究,这种方法显然也有可能奏效,但在 FOSS(免费和开源软件)之外,从财务角度来看,这种方法不可能奏效。Linux 可以从内核向上重写以支持新模型,为其推出一个编译器,然后可以重新编译那里的所有软件而无需太多努力(注意:“太多”相对于,比如说,微软)。
微软、苹果等没有这个好处,因为代码已经被数百万不同的开发者编译,所以任何无法更新的东西都会立即过时,或者他们必须编写模拟器来支持旧的软件。基本上,直到有人想出一个内置此功能的操作系统,并具有兼容的编译器(至少 C 和 C++,可能还有 Cocoa 和 Win32 C++),并且它获得了足够的支持以成为与 Linux、Microsoft 和Mac OS,很难证明转向新模型的合理性。Linux 将是最容易转移的,尽管所有软件都必须编译,直到 RPM 和其他包类型支持新的调用模型。
最后,DEP(数据执行保护)在大多数情况下几乎解决了这个问题,使得执行不应执行的代码变得更加困难。这也减少了切换到新模型的需要,尽管正如 Singularity 所展示的那样,如果硬件不经常被迫保护免受程序员的错误和他们提出的漏洞利用,它可能会快得多。