ARMV8 Procedure Call Standard
1.前言
2. 术语说明
| 
 Term  | 
 Note  | 
| 
 ABI  | 
 Application Binary Interface 应用程序二进制接口  | 
| 
 EABI  | 
 Embedded ABI 嵌入式ABI  | 
| 
 PCS  | 
 Procedure Call Standard 程序调用标准  | 
| 
 AAPCS  | 
 PCS for ARM Architecture ARM体系结构程序调用标准  | 
| 
 APCS  | 
 ARM Procedure Call Standard ARM程序调用标准(已经废弃)  | 
| 
 TPCS  | 
 Thumb Procedure Call Standard Thumb程序调用标准(已经废弃)  | 
| 
 ATPCS  | 
 ARM-Thumb Procedure Call Standard  | 
| 
 PIC,PID  | 
 Position-independent code, position-independent data 位置独立代码和数据  | 
| 
 Activation(call-frame) stack  | 
 程序调用记录栈  | 
| 
 Activation record(call frame)  | 
 用于程序保存寄存器和本地变量的内存(通常在栈上申请)  | 
| 
 Variadic routine  | 
 模板函数, 由调用程序决定它的参数个数和类型,而不是被调用函数  | 
| 
 Scratch register( temporary register)  | 
 草稿寄存器, 用来保存计算的中间值(通常在程序中未命名且有限的生命周期).  | 
| 
 Variable register  | 
 变量寄存器, 用来保存变量的值, 通常用于程序的本地变量  | 
| 
 Program State  | 
 程序状态, 程序的内存状态,包括寄存器的值  | 
3. AAPCS的范围
AAPCS64定义了各个子函数如何被汇编到一起协同工作。描述了调用者例程和被调用者例程或例程与它的执行环境间的约定,主要包括:
(1)在被调用程序(called)开始执行之前, 调用者(caller)负责创建一个程序状态 (一般是SP设置,以及参数传递)
(2)被调用程序保存调用者(caller)传递过来的程序状态
(3)被调用程序正确修改它的程序状态
(4)所有例程保持全局变量不变;
指定了一组PCS各个变体的一些比较重要的选择,包括:
(1)字节序;
(2)数据类型的大小和格式;
(3)浮点操作使用硬浮点还是软浮点;
AAPCS包括4个小节:
(1)Data的排布;
(2)栈的排布,函数之间的调用;
(3)处理器扩展的变化,或何时执行环境约束地址模型???
(4)C C++语言数据类型的绑定???
4. 数据类型与对齐
5. 寄存器的使用规则
5.1 通用目的的寄存器

5.2 SIMD和float point寄存器
(1) v0-v7, are used to pass argument values into a subroutine and to return result values from
(2) a function;
(3) Registers v8-v15 must be preserved by a callee across subroutine calls
(4) the remaining registers (v0-v7, v16-v31)do not need to be preserved (or should be preserved by the caller)
(5) only the bottom 64 bits of each value stored in v8-v15 need to be preserved1; it is the responsibility of the caller to preserve larger values
(6) The FPSR is a status register that holds the cumulative exception bits of the floating-point unit
It contains the fields IDC, IXC, UFC, OFC, DZC, IOC and QC. These fields are not preserved across a public interface and may have any value on entry to a subroutine.
The FPCR is used to control the behavior of the floating-point unit. It is a global register with the following properties.
o The exception-control bits (8-12), rounding mode bits (22-23) and flush-to-zero bits (24) may be modified by calls to specific support functions that affect the global state of the application.
o All other bits are reserved and must not be modified. It is not defined whether the bits read as zero or one, or whether they are preserved across a public interface
6. processes, Memory and Stack的使用规则
6.1 进程的组成部分
一个进程的memory通常可以分为5部分,除了栈要求是连续的,其它部分可以不连续;一个进程只有code和stack是必须的,其它可以没有。
| 
 categories  | 
 note  | 
| 
 code (the program being executed)  | 
 which must be readable, but need not be writable, by the process.  | 
| 
 read-only static data  | 
|
| 
 writable static data  | 
 进一步划分为initialized, zero-initialized and uninitialized data  | 
| 
 the heap  | 
 内存区域,由进程自己管理  | 
| 
 the stack  | 
 栈是连续的内存区域,用来存储本地变量,当参数寄存器不够用时,会通过栈传递参数给子函数; 栈是向下增长的,栈指针保存在特殊功能寄存器SP中; 栈可以动态增长也可以是定长的。 栈的通用约束: (1)SP只能访问stack base和stack limit之间的memory,即Stack-limit < SP <= stack-base (2)SP必须对齐在16个字节上,即SP mod 16 = 0 (3)函数只能访问自己能回溯的那些栈帧。例如f1调用f2,而f2函数又调用了f3,那么f3是可以访问自己的stack以及f2和f1的stack,也就是说,函数可以访问[SP, stack-base – 1]之间的内容; 调用外部接口的栈约束: SP必须对齐在16个字节上,即SP mod 16 = 0  | 
6.2 内存地址
1. 内存地址是由一个或多个互斥的区域组成的,任何一个区域都不会跨越地址0;
2. Tag 地址???
6.3 Stack
| 
 1.栈是连续的内存区域,用来存储本地变量,当参数寄存器不够用时,会通过栈传递参数给子函数; 栈是向下增长的,栈指针保存在特殊功能寄存器SP中; 栈可以动态增长也可以是定长的。 2. 栈的通用约束: (1)SP只能访问stack base和stack limit之间的memory,即Stack-limit < SP <= stack-base (2)SP必须对齐在16个字节上,即SP mod 16 = 0 (3)函数只能访问自己能回溯的那些栈帧。例如f1调用f2,而f2函数又调用了f3,那么f3是可以访问自己的stack以及f2和f1的stack,也就是说,函数可以访问[SP, stack-base – 1]之间的内容; 3. 调用外部接口的栈约束: SP必须对齐在16个字节上,即SP mod 16 = 0  | 
6.4 栈帧指针
每个被调用的函数都有一个栈帧结构(位于SP与FP之间),它存储在栈中,通过栈中两个64bit值链接在调用者函数的栈帧后面,高地址的64bit保存返回地址LR,低地址的64bit值保存调用者函数的栈帧指针FP,由于被调用函数的FP+4就是调用者函数的SP指针,因此不需要保存;被调用者FP指向保存调用者函数栈帧地址的低64bit的位置,表示被调用函数栈帧的开始,SP指向被调用函数栈帧的结束;
如下图:

7. Subroutine Calls
8. 参数传递规则
根据参数个数是否固定,可以将子程序分为参数个数固定的子程序和参数个数可变化的子程序,两者是同一的,参数固定的子程序可以认为可变参数是空的
| 
 Stage  | 
 Note  | 
|
| 
 Stage A---Initialization  | 
 A.1 The Next General-purpose Register Number (NGRN) is set to zero; A.2 The Next SIMD and Floating-point Register Number (NSRN) is set to zero; A.3 The next stacked argument address (NSAA) is set to the current stack-pointer value (SP).  | 
 This stage is performed exactly once, before processing of the arguments commences.  | 
| 
 Stage B – Pre-padding and extension of arguments  | 
 B.1 如果参数类型是组合类型,调用者和被调用者无法静态获取大小,参数会被拷贝到内存,参数会被拷贝到内存的指针取代。  | 
|
| 
 Stage C – Assignment of arguments to registers and stack  | 
 C.1 如果参数是Half-, Single-, Double- or Quad- precision Floating-point or Short Vector Type,并且NSRN<8,参数会分配给寄存器v[NSRN]; C.2 HFA和HVA?? C.3 HFA和HVA?? C.4 HFA和HVA?? C.5 如果参数是Half- or Single- precision Floating Point type,并且参数大小被设置为8字节,那么就像参数被保存到64bit寄存器一样,其它位会被不确定的数值填充??? C6. 如果参数类型是HFA, an HVA, a Half-, Single-, Double- or Quad- precision Floating-point or Short Vector Type,则参数被拷贝到NSAA,NSAA会加上参数的大小 C7. 如果参数类型是Integral or Pointer Type,参数大小小于等于8字节,如果NGRN<8,参数被拷贝到x[NGRN],NGRN增加1; C8. 如果参数有一个16字节的对齐,NGRN会up到偶数 C9. 如果参数类型是Integral Type,参数大小为16字节,如果NGRN<7,则参数被拷贝到x[NGRN]和x[NGRN+1], x[NGRN]包含的是地地址的数据,NGRN增加2; C10. 如果参数是Composite Type,如果按double-words的个数<8-NGRN, 参数会被拷贝到连续的通用寄存器,就好像LDR从连续的内存拷贝数据到连续的寄存器中。NGRN会加上使用的寄存器的个数; C11. NGRN被设置为8; C12. NSAA被up到8,或者参数自然对齐?? C13.如果参数是composite type, 参数被保存到NSAA, NSAA会增加参数的大小; C14. 参数大小小于8字节,会被设置为8字节,与参数拷贝到64bit寄存器是一样的 C15. 参数被拷贝到NSAA指示的内存,NSAA增加参数大小  | 
 For each argument in the list the rules are applied in turn until the argument has been allocated  | 
9. 返回结果的规则
返回结果的类型决定了返回的方式:
| 
 Items  | 
 Note  | 
| 
 If the type, T, of the result of a function is such that: void func(T arg)  | 
 Arg会按照参数传递原则传递给一个寄存器,结果也会返回到这个寄存器  | 
| 
 其它情况  | 
 调用者会保留一段内存,将内存地址存放到x8,传递给被调用者,被调用者根据运行情况随时更新内容  | 
10.参考文档
ARMV8 Procedure Call Standard的更多相关文章
- 如何在 arm 官网上找到合适的手册
		
http://infocenter.arm.com/help/advanced/help.jsp 在这里输入合适的版号即可 这样就可以不用去 CSDN 了 100000_0000_00_EN - AR ...
 - Cortex-M3中C与汇编的交互
		
以下内容摘自<ARM Cortex-M3权威指南> 概览 在CM3 上编程,既可以使用C 也可以使用汇编.可能还有其它语言的编译器,但是大多数人还是 ...
 - ATPCS和AAPCS
		
1. 基本概念 ATPCS (ARM-Thumb Procedure Call Standard) 规定了一些子程序间调用的基本规则,这些规则包括子程序调用过程中寄存器的使用规则,数据栈的使用规则,参 ...
 - arm汇编进入C函数分析,C函数压栈,出栈,传参,返回值
		
环境及代码介绍 环境和源码 由于有时候要透彻的理解C里面的一些细节问题,所有有必要看看汇编,首先这一切的开始就是从汇编代码进入C的main函数过程.这里不使用编译器自动生成的这部分汇编代码,因为编译器 ...
 - ARM中C和汇编混合编程及示例(转)
		
在嵌入式系统开发中,目前使用的主要编程语言是C和汇编,C++已经有相应的编译器,但是现在使用还是比较少的.在稍大规模的嵌入式软件中,例如含有OS,大部分的代码都是用C编写的,主要是因为C语言的结构比较 ...
 - 为何C语言(的函数调用)需要堆栈,而汇编语言不需要
		
转自:Uboot中start.S源码中指令级的详尽解析 green-waste为何 C 语言(的函数调用)需要堆栈,而汇编语言却需要堆栈之前看了很多关亍uboot的分析,其中就有说要为C语言的运行,准 ...
 - 在汇编代码中调用C函数
		
对于ARM体系来说,不同语言撰写的函数之间相互调用(mix calls)遵循的是 ATPCS(ARM-Thumb Procedure Call Standard),ATPCS主要是定义了函数呼叫时参数 ...
 - linux内核调试指南
		
linux内核调试指南 一些前言 作者前言 知识从哪里来 为什么撰写本文档 为什么需要汇编级调试 ***第一部分:基础知识*** 总纲:内核世界的陷阱 源码阅读的陷阱 代码调试的陷阱 原理理解的陷阱 ...
 - Cortex-M3 Context Switching
		
http://www.embedded.com/design/embedded/4231326/Taking-advantage-of-the-Cortex-M3-s-pre-emptive-cont ...
 
随机推荐
- 自学Zabbix4.1 zabbix监控web服务器访问性能
			
自学Zabbix4.1 zabbix监控web服务器访问性能 使用Zabbix实现对web性能的监控,通过它可以了解web站点的可用性以及性能.最终将各项指标绘制到图形中,这样我们可以了解到一个站点的 ...
 - 自学Zabbix7.1 IT services
			
自学Zabbix7.1 IT services 1. 概念IT Services 服务器或者某项服务.业务的可用率,不懂技术的上级领导会过问最近服务器可用率如何.所有api的状况怎么样?通常一些技术人 ...
 - json模块和pickle模块(二十二)
			
之前我们学习过用eval内置方法可以将一个字符串转成python对象,不过,eval方法是有局限性的,对于普通的数据类型, json.loads和eval都能用,但遇到特殊类型的时候,eval就不管用 ...
 - 3分钟学会sessionStorage用法
			
前言: 因最近移动端开发过程中遇到一个运营提出的所谓技术难点需求,对于原生APP来说轻而易举,毕竟自己的APP用户操作指哪打哪,但是H5该怎么做?H5就实现不了么?对于一个爱研究攻克这些前端棘手问题的 ...
 - linux driver ------ platform模型,通过杂项设备(主设备号是10)注册设备节点
			
注册完设备和驱动之后,就需要注册设备节点 Linux杂项设备出现的意义在于:有很多简单的外围字符设备,它们功能相对简单,一个设备占用一个主设备号对于内核资源来说太浪费.所以对于这些简单的字符设备它们共 ...
 - IntelliJ IDEA和Eclipse最常用的快捷键对应表:
			
描述 Eclipse Intellij 代码补全 Ctrl+space Ctrl+space 打开类或者接口 (两个IDE都支持使用“驼峰字符”前缀的方式来过滤查找列表,进而轻松完成搜索:比如:可 以 ...
 - 1032. Sharing (25)
			
To store English words, one method is to use linked lists and store a word letter by letter. To save ...
 - python---基于memcache的自定义session类
			
import config import hashlib import time import memcache import json conn = memcache.Client(["1 ...
 - Calendar add 方法 和set方法
			
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); Calendar c = Calendar. ...
 - vue中$mount与el区别
			
vue中的$mount和el两者在使用中没有什么区别,都是将实例化后的vue挂载到指定的DOM元素中 用法: 如果在实例化vue时指定el,则该vue将会渲染在el对应的DOM中 反之 没有指定el, ...