呼叫门和陷阱门之间有速度差异吗?

Is there a speed difference between call gates and trap gates?

我明白调用门和陷阱门的区别。我想知道是否有人知道两个门之间的速度有显着差异。

如果将 DwordCount 字段保留为 0(意味着没有参数从外部堆栈复制到内部堆栈),速度也会有差异吗?

一般;调用门仅访问 GDT,而陷阱门访问 IDT,然后访问 GDT。由于局部性较差(TLB 未命中和高速缓存未命中的可能性更高),这使得中断陷阱门“在实践中可能更慢,而不管 CPU”。请注意,这相对重要,因为它们通常用于内核 API,您可以假设 CPU 在 user-space 中花费了足够的时间,导致所有内核的东西都变成“最近未使用”并且被驱逐出 caches/TLBs.

对于特定的速度,很久以前我在 Pentium 4 上的一个循环(所有内容都缓存)中进行了基准测试,发现陷阱门比“没有参数的调用门”慢了大约 15%,但不记住周期中的确切成本。我还没有测试过任何其他微拱门。

我还希望使用参数会增加调用门的成本(由于从一个堆栈复制到另一个堆栈的成本)并且可能使其比陷阱门慢。

然而,“int n”软件中断是 2 个字节的代码,而使用调用门(远调用)的指令要大得多(7 个字节?),部分原因是偏移量甚至没有使用。原始执行速度并不是影响性能的唯一因素——从磁盘加载程序、动态链接、指令缓存占用等因素也很重要。考虑到这一点,最快的策略可能同时支持这两者,并在很少使用的代码(“执行一次”初始化代码、错误处理)中使用软件中断,并在频繁执行的代码中使用调用门。

请注意,通常(对于内核 API)调用者将函数编号放入寄存器 (EAX);并且调用门处理程序或陷阱处理程序做一些初步工作(设置调用约定等),然后执行“call [table + eax*4]”将控制权转移到请求的函数(或“无效函数号”函数)。这意味着(假设参数在寄存器中传递)内核支持两者是微不足道的(并且对两者使用相同的 table 函数指针)。进一步;同样的策略可以扩展到支持 SYSCALLSYSENTER,它们更快(如果 CPU 支持)并且可以在无效操作码异常处理程序中模拟(如果不支持CPU).

终于;对于内核 API,绝对最快的方法是通过为每个特定函数设置调用门(或陷阱)来摆脱“call [table + eax*4]”(这可能会导致 TLB 和缓存未命中以及分支预测错误)。这不适用于 SYSCALLSYSENTER;对于陷阱,它受限于可用 IDT 条目的数量;所以它真的只对调用门有意义。