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 ...
随机推荐
- 自学Zabbix3.11-宏Macros
点击返回:自学Zabbix之路 点击返回:自学Zabbix4.0之路 点击返回:自学zabbix集锦 自学Zabbix3.11-宏Macros zabbix宏变量让zabbix变得更灵活,它根据一系列 ...
- CodeForces 464E The Classic Problem | 呆克斯歘 主席树维护高精度
题意描述 有一个\(n\)点\(m\)边的无向图,第\(i\)条边的边权是\(2^{a_i}\).求点\(s\)到点\(t\)的最短路长度(对\(10^9 + 7\)取模). 题解 思路很简单--用主 ...
- __AFO
博主已退役高考,博客基本就很少回复了 NOI2018的游记也没时间写了,以后补上吧[其实是自己懒] 嗯就这样,高三加油!
- 51nod1236 序列求和 V3 【数学】
题目链接 51nod1236 题解 用特征方程求得斐波那契通项: \[f(n) = \frac{(\frac{1 + \sqrt{5}}{2})^{n} - (\frac{1 - \sqrt{5}}{ ...
- SPI接口扫盲 SPI定义/SPI时序(CPHA CPOL)
SPI接口扫盲 douqingl@gmail.com 为何要写这篇文档?百度上找出来的SPI接口中文描述都说的太过简略,没有一篇文档能够详尽的将SPI介绍清楚的.wikipedia英文版[注释 ...
- 在windows上部署使用redis出现的问题及解决方法
在windows上部署使用Redis出现问题的解决方法 原文链接:https://www.cnblogs.com/herry52/p/5938902.html 下载Redis 在Redis的官网下载 ...
- 【推荐】使用Ultrapico Expresso学习正则表达式
Ultrapico Expresso是我工作中经常使用的一个非常强大的正则表达式构建.测试以及代码生成工具.它能够对你构建的正则表达式进行解析.验证,并输出解析结果,提供性能测试工具,支持C#.VB等 ...
- Makefile ------ := ?= += =的区别
Makefile 中:= ?= += =的区别 新建一个Makefile,内容为: ifdef DEFINE_VRE VRE = “Hello World!” endif ifeq ($(OPT),d ...
- Docker简介以及安装
Docker简介以及安装 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.什么是容器 1.一种虚拟化方案 与传统的虚拟机不同,传统的虚拟机是通过中间层将一台或多台独立的机器虚拟运 ...
- GO语言的进阶之路-协程和Channel
GO语言的进阶之路-协程和Channel 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 看过我之前几篇博客小伙伴可能对Golang语言的语法上了解的差不多了,但是,如果想要你的代码 ...