为什么x86上的MS fastcall不使用EAX作为第一个参数?

为什么x86上的MS fastcall不使用EAX作为第一个参数?,x86,cpu-registers,fastcall,X86,Cpu Registers,Fastcall,根据维基百科:“微软或GCC的快速调用约定(也称为msfastcall)传递适合ECX和EDX的前两个参数(从左到右计算)。其余参数从右到左推送到堆栈上。” 为什么他们决定对arg0、arg1、arg2使用EAX、ECX、EDX?如果他们要把参数放入寄存器,为什么要停在2?我知道Borland的fast都能做到这一点,所以microsoft选择不使用EAX只是为了与众不同吗?由于x86命令集的限制,没有调用立即命令,有调用IP.offset,这是相对的。当然,编译器编写者希望保留具有绝对偏移量的

根据维基百科:“微软或GCC的快速调用约定(也称为msfastcall)传递适合ECX和EDX的前两个参数(从左到右计算)。其余参数从右到左推送到堆栈上。”


为什么他们决定对arg0、arg1、arg2使用EAX、ECX、EDX?如果他们要把参数放入寄存器,为什么要停在2?我知道Borland的fast都能做到这一点,所以microsoft选择不使用EAX只是为了与众不同吗?

由于x86命令集的限制,没有调用立即
命令,有调用IP.offset,
这是相对的。当然,编译器编写者希望保留具有绝对偏移量的内容,处理器制造商可能会要求这样做,因此我们有以下“折衷方案”:
MOV eax,绝对地址(标签)
呼叫eax
这将等于呼叫绝对地址(标签)
这种调用方法需要1个临时寄存器,仅用于调用,可以很容易地重用,EAX是用于此目的的最佳选择。
这些考虑的结果很有用,您可以在asm代码中使用它。基准测试表明,分支预测器至少在一定程度上可以与此类代码一起正常工作。 另一种可能性,但很少见,是在调用已在顶级缓存中的过程时,必须重置标志以避免依赖项惩罚或部分寄存器暂停。例如,如果在子程序的最开始使用mov-ah,1之类的东西,就会发生这种情况。为了避免这种情况,请使用EAX作为临时寄存器并放入
异或eax,eax

就在打电话之前。在某些罕见的情况下,它实际上可以节省几个时钟周期。但是这样做与使用它传递参数的实际好处是值得怀疑的,原因可能如上所述。

您想知道他们的实际原因还是一些合理的解释?我更喜欢实际原因。我理解可能有“大多数ms函数使用两个或更少的参数”或“EAX将始终存储返回值,因此如果需要使用参数,则必须保存它”之类的原因。然而,ARM的设计选择使用R0作为第一个参数。很高兴看到MS决定使用两个传入寄存器的原因。这是一段古老的历史,可以追溯到这些编译器有着完全不同的目标时。Borland编译器编译速度很快,GCC和Microsoft更关注他们的代码优化器。让EAX获得回报是相当困难的,它被用于太多的指令中。你需要一个备份存储来保存它,最好是便宜一点,否则代码一点也不快。Borland在历史上没有一个好的优化器知道如何有效地使用寄存器。因此,也不缺少支持存储。这读起来更像是一个咆哮,而不是一个专业/技术答案-请删除所有不必要的措辞,并将其简化为相关的技术细节。现在我想看看“政治错误”可能会持续多久,然后在反应变得极端时发布屏幕,然后改进,并可能将其作为证据发布到其他地方。由于特殊原因,什么是不正确的(虽然不是“政治上的”),任何反馈都是受欢迎的。