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

x86-64的寄存器使用规则

前言

本篇文章介绍通用寄存器的使用规则,x86-64的通用寄存器就那么十几个,寄存器的说明参考文章x86-64汇编指令支持的通用目的寄存器,而我们的函数调用却可以嵌套很多层,也可以处理很复杂的逻辑,所以,每个寄存器都有他的作用和使用规则

写在前面

  • 函数的调用者和被调用者:
    函数A中调用函数B,我们说A是调用者,B是被调用者
  • 栈帧
    栈帧是在函数调用过程中函数负责维护的自己执行过程中使用到的栈空间,在函数A调用函数B的时候,有下列几种情况需要在运行时栈上分配空间保存数据:
    1. 函数调用过程中,如果寄存器无法全部保存参数数据,就会在运行时栈上分配空间来保存参数数据
    2. 如果函数存在非静态局部变量,并且无法用寄存器保存,或者使用到了变量的地址,就会在运行时栈上分配空间
    3. 如果函数存在数组或者结构联合的局部变量,需要分配栈空间保存数据

%rax寄存器

该寄存器最常用的就是作为函数调用的返回值,一个函数如果有返回值,该返回值一定是通过rax寄存器或者他的低位寄存器返回的,当然,在函数执行过程中也可以存储别的数据。

%rdi %rsi %rdx %rcx %r8 %r9

这六个寄存器是作为函数传递参数使用的,并且使用规则很简单,如果一个参数能够保存到寄存器,一定是按照标题寄存器的顺序列表依此保存的,当然参数可能无法使用寄存器保存,比如参数超过了寄存器能保存的数量
看下面的例子:

int add_scale(int a1,int* a2,int a3,int a4,int a5,int a6,int a7,int a8);
int main()
{int a2 = 2;add_scale(1,&a2,3,4,5,6,7,8);return 0;
}
int add_scale(int a1,int* a2,int a3,int a4,int a5,int a6,int a7,int a8)
{int s = 2.0;return a1 + (*a2) * s + a3 + a4 + a5 + a6 +a7 + a8;
}

在x86-64机器上生成的main函数的汇编代码如下:

main:pushq	%rbpmovq	%rsp, %rbpsubq	$32, %rspmovl	$2, -4(%rbp)leaq	-4(%rbp), %raxmovl	$8, 8(%rsp)	// 第八参数保存到栈movl	$55, (%rsp)	// 第七参数保存到栈顶,第七个参数占用八个字节movl	$6, %r9d	// 第六参数保存到%r9的低位movl	$5, %r8d	// 第五个参数保存到%r8的低位movl	$4, %ecx	// 第四个参数保存到%rcx的低位movl	$3, %edx	// 第三个参数保存到%rdx的低位	movq	%rax, %rsi	// 第二个参数的地址保存到%rsimovl	$1, %edi	// 第一个参数保存到%rdi的低位call	add_scale

可以看到

  • 参数保存的顺序就是按照标题列出的顺序依次保存的
  • 超出6个参数后保存到栈里,并且从栈顶依次往后保存
  • 通过栈传递参数时,所有的数据大小都向8的倍数对齐

%rbx %rbp %r12 %r13 %r14 %r15

这六个寄存器被称为被调用者保存寄存器,意思就是被调用函数必须保证调用该函数之前和从该函数返回之前这几个寄存器的值是不变的
一般情况下,如果函数中用到哪个寄存器的话,会在函数开始的时候先把该寄存器的值入栈,函数返回之前在把寄存器出栈,这样,函数返回后就能保证寄存器的值没有发生变化。

%rsp

运行时栈顶指针,与其说rsp保存的是运行时栈顶的位置还不如说,运行时栈顶的位置随着rsp寄存器的值的改变而改变

%r10 %r11

这两个寄存器是被称为调用者保存的寄存器,意思就是比如函数A调用函数B,函数A中使用了这两个寄存器,但是函数B可以随便修改这两个寄存器的值而不用考虑任何问题,函数A调用函数B之后,需要确保这两个寄存器的值依然可用。

相关文章:

  • 管理类联考——数学——真题篇——按知识分类——代数
  • 【产品经理】需求池和版本树
  • Mybatis是如何进行分页的?
  • 入职字节外包一个月,我离职了。。。
  • Leetcode 2957. Remove Adjacent Almost-Equal Characters
  • 开源CDN软件GoEdge —— 筑梦之路
  • 常用的C语言宏定义
  • 阿里云国际版无法远程连接Windows服务器的排查方法
  • ACMMM 2024 ACM International Conference on Multimedia
  • 前端知识(十三)——JavaScript监听按键,禁止F12,禁止右键,禁止保存网页【Ctrl+s】等操作
  • 【Qt5】QVersionNumber
  • Mysql分布式集群部署---MySQL集群Cluster将数据分成多个片段,每个片段存储在不同的服务器上
  • 基于FPGA的视频接口之高速IO
  • Android渲染-AHardwareBuffer
  • 【Go-自学版】03-即时通信系统1
  • [分享]iOS开发 - 实现UITableView Plain SectionView和table不停留一起滑动
  • [原]深入对比数据科学工具箱:Python和R 非结构化数据的结构化
  • 【391天】每日项目总结系列128(2018.03.03)
  • 【407天】跃迁之路——程序员高效学习方法论探索系列(实验阶段164-2018.03.19)...
  • 30秒的PHP代码片段(1)数组 - Array
  • gf框架之分页模块(五) - 自定义分页
  • iOS | NSProxy
  • JavaScript设计模式之工厂模式
  • java中的hashCode
  • js
  • leetcode386. Lexicographical Numbers
  • Netty源码解析1-Buffer
  • PHP那些事儿
  • TCP拥塞控制
  • 从PHP迁移至Golang - 基础篇
  • 反思总结然后整装待发
  • 复杂数据处理
  • 极限编程 (Extreme Programming) - 发布计划 (Release Planning)
  • 将回调地狱按在地上摩擦的Promise
  • 聊聊sentinel的DegradeSlot
  • 如何抓住下一波零售风口?看RPA玩转零售自动化
  • 山寨一个 Promise
  • 视频flv转mp4最快的几种方法(就是不用格式工厂)
  • 一个SAP顾问在美国的这些年
  • 移动端唤起键盘时取消position:fixed定位
  • 硬币翻转问题,区间操作
  • SAP CRM里Lead通过工作流自动创建Opportunity的原理讲解 ...
  • TPG领衔财团投资轻奢珠宝品牌APM Monaco
  • 教程:使用iPhone相机和openCV来完成3D重建(第一部分) ...
  • 数据库巡检项
  • ​人工智能之父图灵诞辰纪念日,一起来看最受读者欢迎的AI技术好书
  • (3)Dubbo启动时qos-server can not bind localhost22222错误解决
  • (初研) Sentence-embedding fine-tune notebook
  • (二)hibernate配置管理
  • (附源码)ssm经济信息门户网站 毕业设计 141634
  • (六)Hibernate的二级缓存
  • (七)微服务分布式云架构spring cloud - common-service 项目构建过程
  • (小白学Java)Java简介和基本配置
  • (转)我也是一只IT小小鸟
  • (转载)(官方)UE4--图像编程----着色器开发