当前位置: 首页 > news >正文

函数调用寄存器规则

所有 CPU 通用函数调用寄存器规则

不管是 Intel、AMD、ARM,全部遵守这 4 条规则

  1. 参数规则前 N 个参数用约定寄存器传递,超出部分用

  2. 返回值规则函数返回值必须放在固定的约定寄存器中。

  3. 易失寄存器规则(调用者保存)

    • 函数可以随便修改
    • 调用者如果要保留值,必须自己提前保存
  4. 非易失寄存器规则(被调用者保存)

    • 函数不能破坏原有值
    • 如果使用,必须先保存、后恢复
    • 调用者可以放心使用,不用担心被改

x86 (32 位,IA-32)

32 位 x86几乎不用寄存器传参,全部用传参。

核心规则

  1. 传参:全部通过 ** 栈(stack)** 传递
  2. 返回值EAX存返回值(64 位返回值用EDX:EAX
  3. 调用者保存寄存器(被调用函数可以随便改,调用前需自己保存):EAX, ECX, EDX
  4. 被调用者保存寄存器(被调用函数必须原样返回):EBX, ESI, EDI, EBP
  5. 栈帧EBP用作栈基址,ESP是栈顶指针

x86_64 (amd64,64 位 x86)

优先用寄存器传参,速度远快于栈,是现代 Linux/macOS/Windows 主流。

整数 / 指针寄存器规范(标准标注)

寄存器标准名称官方用途定义保存方说明
%raxReturn Value函数返回值;临时寄存器Caller Saved(调用者保存)函数返回值存在这里;函数可随意修改
%rbxBase Pointer被调用者保存寄存器Callee Saved(被调用者保存)函数必须保护,返回前恢复原值
%rcx4th Argument第 4 个函数参数;临时寄存器Caller Saved函数可随意修改
%rdx3rd Argument第 3 个函数参数;临时寄存器Caller Saved函数可随意修改
%rsi2nd Argument第 2 个函数参数;临时寄存器Caller Saved函数可随意修改
%rdi1st Argument第 1 个函数参数;临时寄存器Caller Saved函数可随意修改
%rbpFrame Pointer栈帧基址;被调用者保存寄存器Callee Saved函数必须保护
%rspStack Pointer栈顶指针-硬件维护,不可随意修改
%r85th Argument第 5 个函数参数;临时寄存器Caller Saved函数可随意修改
%r96th Argument第 6 个函数参数;临时寄存器Caller Saved函数可随意修改
%r10Temporary临时寄存器Caller Saved函数可随意修改
%r11Temporary临时寄存器Caller Saved函数可随意修改
%r12Callee Saved被调用者保存寄存器Callee Saved函数必须保护
%r13Callee Saved被调用者保存寄存器Callee Saved函数必须保护
%r14Callee Saved被调用者保存寄存器Callee Saved函数必须保护
%r15Callee Saved被调用者保存寄存器Callee Saved函数必须保护

标准调用规则(官方定义)

  1. 参数传递
    • 6 个整数 / 指针参数RDI → RSI → RDX → RCX → R8 → R9
    • 第 7 个及以上参数:栈传递
  2. 返回值
    • 整数 / 指针:RAX
    • 128 位返回值:RDX:RAX
  3. 保存规则
    • Caller Saved(调用者保存)RAX, RCX, RDX, RSI, RDI, R8-R11(函数可直接修改,调用者需自行备份)
    • Callee Saved(被调用者保存)RBX, RBP, R12-R15(函数使用前必须入栈保存,返回前出栈恢复)

ARM64 (AArch64) AAPCS64 官方标准

文档:ARM Architecture Reference Manual AAPCS64(ARM 官方过程调用标准)适用:iOS/Android 手机、Mac M 系列、ARM 服务器

通用寄存器(X0~X31)标准标注

寄存器标准别名官方用途定义保存方约束
X0Argument/Result第 1 个参数;函数返回值Caller Saved(Volatile)函数可修改
X1Argument第 2 个参数Caller Saved函数可修改
X2Argument第 3 个参数Caller Saved函数可修改
X3Argument第 4 个参数Caller Saved函数可修改
X4Argument第 5 个参数Caller Saved函数可修改
X5Argument第 6 个参数Caller Saved函数可修改
X6Argument第 7 个参数Caller Saved函数可修改
X7Argument第 8 个参数Caller Saved函数可修改
X8Indirect Result间接返回地址寄存器Caller Saved函数可修改
X9-X15Temporary临时寄存器Caller Saved函数可修改
X16IP0内部过程调用寄存器Caller Saved函数可修改
X17IP1内部过程调用寄存器Caller Saved函数可修改
X18Platform Register平台保留寄存器-不可随意使用
X19-X28Callee Saved被调用者保存寄存器Callee Saved(Non-volatile)函数必须保护原值
X29FP (Frame Pointer)栈帧基址寄存器Callee Saved函数必须保护
X30LR (Link Register)函数返回地址寄存器Callee Saved存储返回地址,必须保护
X31SP / Zero Register栈指针 / 零寄存器-硬件维护

标准调用规则(官方定义)

  1. 参数传递
    • 8 个整数 / 指针参数X0 ~ X7
    • 第 9 个及以上参数:栈传递
  2. 返回值
    • 整数 / 指针:X0
    • 128 位返回值:X0 + X1
  3. 保存规则
    • Volatile(Caller Saved)X0-X15, X16-X17(函数可直接修改,调用者自行备份)
    • Non-volatile(Callee Saved)X19-X29, LR(X30)(函数必须入栈保存,返回前恢复)
  4. 特殊寄存器
    • LR (X30):存储函数返回地址(无需像 x86 一样压栈)
    • SP (X31):栈指针,硬件自动维护

权威标准总结

x86_64

  • 参数:RDI, RSI, RDX, RCX, R8, R9(前 6 个)
  • 返回:RAX
  • 易失:RAX, RCX, RDX, RSI, RDI, R8-R11
  • 非易失:RBX, RBP, R12-R15

ARM64

  • 参数:X0~X7(前 8 个)
  • 返回:X0
  • 易失:X0~X15
  • 非易失:X19~X29, LR(X30)

LoongArch64(龙芯 64 位)

1. 参数传递

8 个整数 / 指针参数用寄存器:

R4 → R5 → R6 → R7 → R8 → R9 → R10 → R11第 9 个及以后 →

2. 返回值

  • 普通返回值:R0
  • 128 位返回值:R0 + R1

3. 临时寄存器(调用者保存 / 易失)

函数可直接修改,调用前需自己保存:R0 ~ R11,R23 ~ R31

4. 被调用者保存寄存器(非易失)

函数使用必须保存并恢复R12 ~ R22

5. 特殊寄存器

  • R1 (RA):返回地址寄存器(存函数返回地址)
  • R2 (SP):栈指针
  • R3 (FP):栈帧基址指针

完整标准表

寄存器用途定义保存方
R0返回值 / 临时调用者
R1 (RA)返回地址被调用者
R2 (SP)栈指针硬件
R3 (FP)帧指针被调用者
R4-R11函数参数 1~8调用者
R12-R22被调用者保存寄存器被调用者
R23-R31临时寄存器调用者

申威 64 位(SW64)

1. 参数传递

6 个整数 / 指针参数用寄存器:R3 → R4 → R5 → R6 → R7 → R8第 7 个及以后 →

2. 返回值

  • 普通 64 位返回值:R0
  • 128 位返回值:R0 + R1

3. 临时寄存器(调用者保存 / 易失)

函数可直接修改,调用前需自己保存:R0 ~ R9, R15, R26 ~ R31

4. 被调用者保存寄存器(非易失)

函数使用必须入栈保存、返回恢复R10 ~ R23, R25 (FP)

5. 特殊寄存器

  • R26 (RA):返回地址寄存器(存函数返回地址)
  • R24 (SP):栈指针
  • R25 (FP):栈帧基址指针
寄存器别名用途定义保存方
R0RV函数返回值调用者
R1-R2TMP临时寄存器调用者
R3-R8ARG第 1~6 个函数参数调用者
R9TMP临时寄存器调用者
R10-R23SAV被调用者保存寄存器被调用者
R24SP栈指针硬件
R25FP栈帧指针被调用者
R26RA返回地址调用者
R27-R31TMP临时寄存器调用者

应用场景

场景:自己写汇编函数、写系统调用、写启动代码

必须严格遵守 ABI 规则,否则调用会崩溃。

具体用法:

  • 调用函数前,把参数放到约定寄存器
  • 函数返回后,从约定寄存器拿返回值
  • 保存 / 恢复非易失寄存器,避免破坏调用者数据

例子:写 Linux 系统调用必须用:

rax放系统调用号

rdi、rsi、rdx、r10、r8、r9放参数

场景:写编译器、动态翻译、虚拟机

编译器生成函数调用代码必须严格遵守寄存器规则

具体用法:

  • 函数传参用哪些寄存器
  • 哪些寄存器可以当临时变量
  • 哪些寄存器必须保存恢复

所有编译器(GCC、Clang、MSVC)都按这套规则生成代码。

场景:优化高频调用函数

寄存器比内存快 100 倍以上,优化核心就是尽量用寄存器

具体用法:

  • 尽量让函数参数 ≤6 个(x86_64)或 ≤8 个(arm64)
  • 减少栈使用,提升速度
  • 内联函数减少调用开销

场景:C 调用汇编、Python 调用 C、Java JNI、Go 调用 C

跨语言调用100% 依赖寄存器调用规则

具体用法:

  • 参数按规则放入寄存器
  • 调用后从约定寄存器取返回值

JNI、FFI、ctypes 底层全是这套规则。

场景:栈溢出、ROP、劫持控制流

必须精准控制寄存器,才能完成利用。

具体用法:

  • 控制RDI/X0传参
  • 控制RAX/X0返回值
  • 构造调用栈与寄存器布局

PWN 入门第一课:背寄存器调用规则。

场景:函数挂钩、监控、日志、篡改参数

Hook 必须修改寄存器里的参数 / 返回值。

具体用法:

  • 进入函数时修改RDI/X0篡改参数
  • 函数返回时修改RAX/X0篡改返回值

所有 Frida、Xposed、Inline Hook 都依赖这套规则。

http://www.jsqmd.com/news/512766/

相关文章:

  • 美妆品牌,快速搭建小程序商城
  • 基于单片机无线防丢报警器设计 [单片机]-计算机毕业设计源码+LW文档
  • 佳维视工控一体机在水质检测仪中的应用
  • 如何在ESP32上构建你的AI伙伴:Xiaozhi-ESP32开源项目深度探索
  • Git误操作急救手册:拯救代码必备
  • 写代码 vs 拖模块:1949AI拆一个自动化流程的两种实现
  • 桌面温湿度天气时钟 原理图设计 (SchDoc)
  • 如何备份红米手机短信(6 种行之有效的方法)
  • 2013-2024年各省级数字经济指数数据+Stata代码
  • [特殊字符] 重磅!智慧港口评级落地!AI硬核技术,助力港口冲击一级(引领型)标杆!
  • A 股 Level-2 行情数据 API 实战指南
  • 告别Appium!用Python+facebook-wda搞定iOS自动化测试(保姆级环境搭建与实战)
  • 【Keepalived】主备模式MASTER/BACKUP的vrrp实例配置详解
  • 新能源汽车电池壳体孔深光学3D轮廓测量-激光频率梳3D轮廓技术
  • OSI七层模型实战解析:从理论到网络通信的完美落地
  • 3月必看!防雨布行业内口碑好的品牌分析情况,市场防雨布企业推荐优质品牌选购指南 - 品牌推荐师
  • 单例模式(懒汉式)
  • C语言学习与未来规划
  • 高效HR的AI工具箱:21个精准提示词,重塑核心工作流(即拿即用版)
  • RDMA-InfiniBand和RoCEv2
  • 电动船舶在线监测管理系统方案
  • 3.21小测
  • 告别模型部署踩坑!Transformers 权威验证模型完整性全流程(通用版)
  • CSS进阶指南:深入解析选择器优先级与继承机制
  • 逆向工程师必备:用Frida动态分析AES/DES/RSA的N种姿势
  • 基于离散余弦变换的感知哈希算法:原理、实现与工程实践
  • MySQL 中 InnoDB 存储引擎与 MyISAM 存储引擎的区别是什么?
  • 实验二 网络信息收集
  • Mysql锁机制与优化实践以及MVCC底层原理剖析--重点笔记
  • CTF刷题神器大比拼:在线工具vs本地软件哪个更适合你?