RDI作为第一个参数的“潜规则”

作者:Vesper Vei
1 分钟阅读

目录

  1. RDI作为第一个参数的“潜规则”
  2. 1. 硬件遗产:为了“零成本”调用系统指令
  3. 2. 性能革命:从“内存时代”进化到“寄存器时代”
  4. 3. 实际意义:对 Pwn 和逆向的影响
    1. 总结对照表

RDI作为第一个参数的“潜规则”

这个问题问到了底层设计的核心。为什么要专门规定 RDI 是第一个参数、RSI 是第二个参数?为什么不随机选两个寄存器(比如 R8 和 R9)?

这背后的原因主要可以归结为两点:硬件遗产的延续 和 极致的性能优化


1. 硬件遗产:为了“零成本”调用系统指令

在 C 语言中,很多基础函数的操作逻辑是 “目标 \leftarrow 来源”。最典型的例子就是 memcpy(dest, src, size)

设计的巧妙之处:

x86 架构内置了一些非常强大的“字符串指令”(如 movsb),这些指令是硬编码(Hard-wired)在 CPU 电路里的,它们强制要求使用 RSI 作为源,RDI 作为目标。

如果调用约定(ABI)规定第一个参数进 RDI,第二个进 RSI,那么当你写 memcpy(dest, src, n) 时:

  1. dest 已经在 RDI 里了。

  2. src 已经在 RSI 里了。

  3. CPU 不需要再花时间写 mov 指令去交换寄存器的值,直接执行一条硬件指令就能开始搬运。

结论: 这种设计是为了让 C 语言的高频函数(如字符串处理、内存拷贝)能直接对接 CPU 的硬件加速指令。


2. 性能革命:从“内存时代”进化到“寄存器时代”

在老旧的 32 位(x86)时代,函数参数是放在**栈(Stack)**里的。

到了 64 位(x86-64)时代,寄存器变多了。工程师们制定了一套规则(System V ABI),规定前 6 个参数必须通过寄存器传递。

为什么要排这个顺序?

这就像一种“标准协议”。如果没有这个规定:

统一规定 RDI, RSI… 的目的,是让编译器、操作系统和不同语言编写的代码能够互相无缝通信。这就像大家约定好在公路右侧行驶一样。


3. 实际意义:对 Pwn 和逆向的影响

作为学习二进制安全(Pwn)的同学,理解这个原因对你至关重要:


总结对照表

维度旧时代 (32位/x86)新时代 (64位/x86-64)带来的好处
存放位置内存栈 (Stack)寄存器 (RDI, RSI…)速度快(寄存器访问是纳秒级)
指令数量需要多次 push/pop简单的 mov 即可代码体积小,执行效率高
逻辑一致性随意严格遵循 Dest/Source 逻辑硬件级优化,减少数据搬运成本

你想看看当参数超过 6 个(寄存器不够用)时,CPU 是如何“被迫”动用内存栈来处理的吗?

—> 参数超过6个时,“被迫”动用内存栈处理 —> 参数从右往左压栈道”设计心机”


关系图谱

Loading graph...