這篇文章是對AAPCS文檔的簡單翻譯, 因以前要講課又沒在網上找到中文版, 就決定嘗試本身翻譯一下, 我的理解不保證翻譯正確性.
全部拿捏不許的地方所有保留英文(一來方便讀者對上下文理解, 二來防止前面翻譯出錯引發後面誤導), 部分不重要章節省略翻譯, 一些有疑惑的術語列舉以下:
variant 我的理解是符合基本標準的一種具體實現, 直接按字面意思翻譯爲變型.
conformance 直接翻譯成遵循守則, 對翻譯有異議的讀者建議看原文以防我誤導.
Aggregate 翻譯爲集合彷佛更通順點, 反正就當結構體理解就對了.
public interface 我的理解是對外可見的接口, 翻譯爲公共接口(public interface).
veneer 見[ARM Compiler toolchain Using the Linker]的overview of veneers一節. 含義是爲支持32位空間跳轉而由連接器生成的額外代碼. 暫時翻譯爲膠合代碼. html
文檔編號: ARM IHI 0042F current through ABI release 2.10
日期: 2015/11/24 git
引言:
ARM架構程序調用標準(Procedure Call Standard for the ARM Architecture, AAPCS)描述了ARM架構下應用程序二進制接口(Application Binary Interface, ABI)程序調用的標準.
如何獲取最新的釋出標準: 登陸http://infocenter.arm.com/獲取最新版本(若是你的手冊超過一年以上)(對於ARM軟件開發工具部分, ARM架構ABI部分無需更新). github
1. 關於此文檔 算法
1.1. 修改歷史
略. 編程
1.2. 參考書籍
AAPCS Procedure Call Standard for the ARM Architecture ARM架構程序調用標準.
AAELF ELF for the ARM Architecture ARM架構ELF.
BSABI ABI for the ARM Architecture(Base Standard) ARM架構ABI(基本標準).
CPPABI C++ ABI for the ARM Architecture ARM架構C++ ABI.
ARM ARM The ARM Architecture Reference Manual 2nd ARM架構參考手冊 ARM DDI 0100E, ISBN 0 201 737191.
登陸http://infocenter.arm.com/help/index.jsp獲取ARMv5 Architecture Reference Manual.
ACLE ARM C Language Extensions ARM C語言擴展 ARM IHI 0053A.
登陸http://infocenter.arm.com/help/index.jsp獲取ARM C Language Extensions.
GC++ABI Generic C++ ABI 通用C++ ABI.
登陸http://mentorembedded.github.com/cxx-abi/abi.html. 數組
1.3. 術語與縮略語
ABI 應用程序二進制接口.
1. 在指定的運行環境下可執行文件必須遵循的執行規範. 如the Linux ABI for the ARM Architecture.
2. 單獨生成的可重定位文件爲可以被靜態連接及可執行所需遵循的規範.
如the C++ ABI for the ARM Architecture / the Run-time ABI for the ARM Architecture / the C Library ABI for the ARM Architecture.
EABI 適用於嵌入式程序的ABI.
PCS 程序調用標準.
AAPCS ARM架構程序調用標準(本標準).
APCS ARM程序調用標準.
TPCS Thumb程序調用標準.
ATPCS ARM-Thumb程序調用標準.
PIC 位置無關代碼.
PID 位置無關數據.
routine / subroutine 一個控制權能夠被轉移, 且當其任務完成時將控制權返回給它的調用者的程序片斷.
routine用來在出現複雜調用時明確關係: routine是調用者(caller), subroutine是被調用者(calllee).
Procedure 一個無返回值的routine.
Function 一個帶返回值的routine.
Activation stack 當前記錄的routine的棧(AKA call-frame stack).
Activation record 被routine用來存儲寄存器值與本地變量的內存, 一般分配在棧上(AKA call-frame).
Argument / Parameter 這兩個術語是能夠相互替代的. 它們能夠表明程序被調用時傳入參數的形參或實參自己, 根據上下文來決定.
Externally visible [An interface] between separately compiled or separately assembled routines.
Variadic routine 若是程序的參數個數與類型是由調用者而非被調用者自己決定的, 那麼該程序是變長程序.
Global register 一個寄存器它的值在程序運行時從不保存或銷燬, 它的值只可能經過一種運行環境指明的方式被更新.
Program state 程序內存的狀態, 包括寄存器值.
Scratch register 被用來在一次計算中存儲一個當即數(一般這些值在程序源代碼中沒有名字且只有有限的生命週期)的寄存器(AKA temporary register).
Variable register 被用來存儲變量的值(一般是程序的局部變量, 在程序源代碼中有名字)的寄存器(AKA v-register). 架構
更多的術語將在第一次出現時進行定義. app
1.4. 使用許可
略. less
1.5. 鳴謝
略. jsp
2. 概要
AAPCS定義了單獨編寫, 編譯, 彙編的子程序如何組合工做. 它描述了調用程序與被調用程序間的協議:
(1). 調用方有義務建立program state來保證被調用程序能夠執行.
(2). 被調用方有義務在調用過程當中保護該program state.
(3). 被調用方有權利修改該program state.
本標準指定了一系列PCS變型(variant)的基礎, 這些變型(variant)由如下項不一樣優先級決定:
(1). 代碼大小.
(2). 性能.
(3). 功能(i.e. 調試 運行時檢查 支持共享庫).
每一個變型(variant)的某些方面(如是否支持使用R9)是由運行環境決定的. 所以:
(1). 代碼嚴格遵循基本標準來保證各個變型(variant)的PCS兼容性是可能的.
(2). 遵循一個變型(variant)標準的代碼一般不兼容其它變型(variant)代碼.
(3). 遵循基本標準或一個變型(variant)標準的代碼不能保證必定兼容使用一樣標準的執行環境. 一個運行環境可能須要除PCS外其它的需求.
本標準除介紹外還分四個小節:
(1). 數據佈局.
(2). 棧佈局與函數調用.
(3). Variations available for processor extensions, or when the execution environment restricts the addressing model.
(4). The C and C++ language bindings for plain data types.
本標準不規範公開可見的C / C++語言實體表示(這是在CPPABI中規範的). 一樣它不要求不可見的語言實體表示.
3. 介紹
AAPCS由第五版APCS與第三版TPCS構成. AAPCS自己又是組成完整ARM架構ABI的一部分.
3.1. 設計目的
AAPCS的目的是:
(1). 平等的支持Thumb狀態與ARM狀態.
(2). 支持Thumb狀態與ARM狀態的切換.
(3). 支持在高性能ARM架構上高效執行.
(4). 明確區分強制要求與自行選擇(implementation discretion).
(5). 最小化與ATPCS的二進制差別.
3.2. 遵循守則(Conformance)
AAPCS定義了單獨編譯與彙編的程序如何組合工做. 在這些程序間有一個外部可見的接口. 一般狀況下, 不是全部的外部可見的軟件接口都是公開可見或任意使用的.
事實上, (由目標代碼格式嚴格定義的)機器層面的外部可見的概念與更高層面上, (系統定義或應用程序定義的)面向應用程序的外部可見的概念是不一樣的.
AAPCS的遵循要求(注1):
(1). 在任什麼時候候棧空間限制與棧對齊規則都必須遵照(見5.1.1. 通用棧限制).
(2). 在靜態連接階段, 每一個使用BL類型的控制轉移指令的調用都必須遵照使用IP寄存器的規範(見5.3.1.1. 連接器對IP的使用).
(3). 每一個公共可見接口(public visible interface)的程序都遵照相關PCS變型(variant).
(4). 每一個公共可見接口(public visible interface)的數據元素都遵照數據佈局的規則(2).
注1: 遵循本定義可最大化執行自由度.
i.e. 若是已知外部可見接口的兩側使用相同編譯器編譯那麼該接口不是公共可見的, AAPCS容許接口作私有的約定如使用額外的參數寄存器或使用非標準格式傳遞參數.
儘管如此, 棧不變性必須仍被保持, 不然程序調用鏈上其它遵循規範的程序就可能失敗. 使用IP的規則必須被遵照不然靜態連接器可能生成一個不起做用的執行程序.
Conformance at a publicly visible interface does not depend on what happens behind that interface. Thus, for example, a tree of non-public, non-conforming calls can conform because the root of the tree offers a publicly visible, conforming interface and the other constraints are satisfied.
注2: 數據元素包括: 接口定義的程序參數, 接口定義的靜態數據及全部經過接口傳遞的指針指向的數據.
4. 數據類型與對齊
4.1. 基本數據類型
以下表所示, 基本數據類型的字節大小與字節對齊. NULL指針永遠表明全部位均爲零.
類型 機器類型 字節大小 字節對齊 備註
integral unsigned byte 1 1 字符
signed byte 1 1
unsigned half-word 2 2
signed half-word 2 2
unsigned word 4 4
signed word 4 4
unsigned double-word 8 8
signed double-word 8 8
floating point half precision 2 2 見4.1.1 半精度浮點
single precision 4 4 浮點數的編碼見[ARM ARM] C2章節 VFP編程模型 2.1.1 單精度格式與2.1.2 雙精度格式
double precision 8 8
Containerized vector 64-bit vector 8 8 見4.1.2 矩陣向量(Containerized vector)
128-bit vector 16 16
Pointer Data pointer 4 4 指針計算應爲無符號
Code pointer 4 4 代碼指針的位0表明目標指令類型(0爲ARM, 1爲Thumb)
4.1.1. 半精度浮點
VFPv3架構的一個可選的擴展提供硬件支持半精度值. 目前支持兩種格式: IEEE754r指定的格式與另外一種提供額外範圍(但沒有NaNs或無窮大)的格式. AAPCS的基本標準指定使用IEEE754r的變型(variant)但兩種格式都可以被程序變型(variant)使用.
4.1.2. 矩陣向量(Containerized vector)
矩陣向量(Containerized vector)的內容對大多數PCS標準是不透明的, 對其佈局的惟一要求是內存格式(基本類型在內存中存儲的方式)與在程序調用接口時不一樣類型寄存器的映射. 若是一門語言綁定了數據類型直接映射到矩陣向量(Containerized vector)的定義那麼它必須定義是如何映射的.
4.2. 字節序
從軟件角度看, 內存是一組可尋址的字節數組. ABI支持兩種由硬件實現的內存視圖.
(1). 在小端內存視圖下一個數據對象的最低有效字節是該數據對象所佔內存的最低字節地址.
(2). 在小端內存視圖下一個數據對象的最低有效字節是該數據對象所佔內存的最高字節地址.
一個對象的最低有效位永遠是位0.
全部對象都是統一字節序, 即映射能夠對應更大或更小的對象. 一個雙字在內存中的映射以下所示:
大端字節序數據對象在內存中佈局
Data Object Memory
|31 ............................ 0|
----------------------------------- ---------
|MSB | | |LSB | ---> |M+3 |
----------------------------------- ---------
| | |------------------> |M+2 |
| | ---------
| |--------------------------> |M+1 |
| ---------
|----------------------------------> |M+0 |
---------
小端字節序數據對象在內存中佈局
Data Object Memory
---------
|----------------------------------> |M+3 |
| ---------
| |--------------------------> |M+2 |
| | ---------
| | |------------------> |M+1 |
----------------------------------- ---------
|MSB | | |LSB | ---> |M+0 |
----------------------------------- ---------
|31 ............................ 0|
4.3. 複合類型
複合類型是一種或多種基本數據類型的集合但以單一實體在程序調用層級被操做. 複合類型能夠是:
(1). 一個成員順序排布在內存中的結構體(Aggregate).
(2). 一個每一個成員都具備相同地址的聯合體.
(3). 一個基本類型是其它類型的數組.
複合類型的定義是遞歸的, 即複合類型能夠包含另外一個複合類型做爲其成員.
(1). The member alignment of an element of a composite type is the alignment of that member after the application of any language alignment modifiers to that member.
(2). 複合類型的天然對齊方式是取每一個複合類型的"頂層"成員的對齊的最大值, 在整個複合類型的對齊調整以前.
4.3.1. 結構體(Aggregate)
(1). 結構體(Aggregate)的對齊應以其最大的組成成員對齊.
(2). 結構體(Aggregate)的大小應該是其對齊的最小倍數同時可以容納全部的成員.
4.3.2. 聯合體
(1). 聯合體的對齊應以其最大的組成成員對齊.
(2). 聯合體的大小應該是其對齊的最小倍數同時可以容納最大的成員.
4.3.3. 數組
(1). 數組的對齊應以其基本類型對齊.
(2). 數組的大小應該是其基本類型的大小乘以數組元素個數.
4.3.4 位域
結構體(Aggregate)的基本數據類型成員可被細分爲位域; 若是位域成員未使用的部分有充足的空間能夠在天然對齊的地址上存放以後的成員則以後的成員可使用該位域成員未使用的部分空間. 爲計算結構體(Aggregate)的對齊, 位域類型成員應以字段的基本類型爲對齊(注1). 結構體(Aggregate)中位域的佈局應根據使用語言定義的.
4.3.5. 奇次結構體(Homogeneous Aggregate)
奇次結構體(Homogeneous Aggregate)是一種複合類型, 組成它的全部基本數據類型都是相同的. The test for homogeneity is applied after data layout is completed and without regard to access control or other source language restrictions.
由矩陣向量(Containerized vector)構成的結構體(Aggregate)被認爲是Homogeneous的若是全部成員都是相同大小, 即便矩陣向量(Containerized vector)內部的格式不相同. i.e. 一個包含9字節向量4個半字向量的結構體知足奇次結構體(Homogeneous Aggregate)的要求.
奇次結構體(Homogeneous Aggregate)有基本類型, 該基本類型爲每一個元素的基本數據類型. 奇次結構體(Homogeneous Aggregate)的總大小是該基本類型乘以元素個數, 它的對齊是以其基本類型對齊爲準.
注1: 這是爲容許C結構體struct {int a:8; char b[7];} 大小爲8字節且以4字節對齊.
5. 基本程序調用標準
基本標準定義了(ARM指令集與Thumb指令集通用的)機器層面的, 只與核心寄存器相關的調用標準. 它應被應用於無浮點硬件或高度須要Tbumb代碼相關的系統中.
5.1. 機器寄存器
ARM架構定義了一套核心指令集與許多由協處理器執行的額外指令. 核心指令集能夠訪問核心寄存器, 而協處理器能夠爲特定操做提供額外的寄存器.
5.1.1. 核心寄存器
ARM與Thumb指令集共可見16個32位核心寄存器. 它們以r0-r15或R0-R15標記. 寄存器名字在彙編語言中能夠用大寫或小寫表示. 在本規範中大寫表明該寄存器在PCS中有固定做用. 下表總結了本標準中核心寄存器的做用. 除核心寄存器外還有一個狀態寄存器(CPSR)可被符合標準的代碼(conforming code)訪問.
寄存器 別名 特殊名 程序調用標準中做用
r15 PC 程序計數器.
r14 LR 連接寄存器.
r13 SP 棧指針.
r12 IP 程序調用過程當中備份寄存器.
r11 v8 變量寄存器8.
r10 v7 變量寄存器7.
r9 v6 / SB / TR 平臺寄存器, 該寄存器意義由平臺標準指定.
r8 v5 變量寄存器5.
r7 v4 變量寄存器4.
r6 v3 變量寄存器3.
r5 v2 變量寄存器2.
r4 v1 變量寄存器1.
r3 a4 參數 / 備份寄存器4.
r2 a3 參數 / 備份寄存器3.
r1 a2 參數 / 結果 / 備份寄存器2.
r0 a1 參數 / 結果 / 備份寄存器1.
前四個寄存器(r0-r3)用來在子程序調用時傳遞參數並當函數返回時返回結果. 同時它們也用於子程序中暫存當即數(但一般只在子程序內部).
寄存器r12(IP)在程序與子程序調用時被連接器用做備份寄存器(具體見5.3.1.1. 連接器對IP的使用), 同時它也能夠在子程序中暫存當即數.
寄存器r9的做用是平臺指定的. 虛擬平臺能夠將任何做用交給r9寄存器並書面說明使用方法. i.e. 它能夠被設計用來做爲靜態基址(static base)在一個位置無關的數據模型中, 或被設計爲線程寄存器(thread register)在一個線程本地存儲的環境中. 對這個寄存器的使用要求調用過程當中保存的值是永久的. 對於沒有這些特殊需求的虛擬平臺可將r9設計爲額外的參數寄存器v6.
寄存器r4-r8, r10, r11被用來保存程序的局部變量. 其中僅v1-v4被Thumb指令集使用, 但AAPCS並不要求Thumb代碼只能使用這些寄存器.
子程序必須保護r4-r8, r10, r11與SP(以及一些PCS變型(variant)中將r9做爲v6)寄存器的內容.
不論何種PCS變型(variant), r12-r15都有特殊做用, 分別別稱爲IP, SP, LR, PC.
CPSR是一個全局寄存器, 它有以下屬性:
(1). 當進入公共接口(public interface)或從接口返回時, 位N, Z, C, V及Q(27-31位)與位GE[3:0](16-19位)是未定義的. 只有在支持這些特性的處理器上執行程序位Q與GE[3:0]纔可被修改.
(2). 在ARM 6架構上, 位E可被(在小端字節序或big-endian-8模式下執行的)應用程序用做暫時的改變訪問內存時數據的字節序. 應用程序必須有指定的字節序且在進入公共接口(public interface)或從接口返回時設置位E必須遵照應用程序指定的字節序.
(3). 位T(5位)與位J(24位)是程序執行狀態位. 只有被用來修改這些位的指令才能修改它們.
(4). 位A, I, F與M[4:0](0-7位)是特權位且僅能被設計在特權模式下顯式操做的程序修改.
(5). 全部其它位均爲保留位且不能被修改. 不論它們爲0或爲1或在公共接口(public interface)調用時是否保持其含義均是未定義的.
5.1.1.1. 操做大於32位的數據
大於32位的基本類型能夠在函數調用時做爲參數傳入或做爲結果返回. 當這些類型保存在覈心寄存器中時必須遵照如下規則:
(1). 一個雙字大小的類型經過兩個連續的寄存器傳遞(i.e. r0與r1, r2與r3). 值經過單個LDM指令將從內存中加載到寄存器中.
(2). 一個四字大小的矩陣向量(Containerized vector)經過四個連續的寄存器傳遞. 值經過單個LDM指令將從內存中加載到寄存器中.
5.1.2. 協處理器寄存器
機器寄存器組可經過附加寄存器擴展, 這些附加寄存器在協處理器指令空間中使用指令訪問. 使用這些不用來傳遞參數或返回結果的協處理器寄存器是兼容基本標準的. 每一個協處理器可能有額外的管理自身的寄存器的規則.
注意: 即便協處理器不用來傳遞參數, 有些語言運行時支持的特性要求瞭解程序中所有協處理器的狀態以保證正常運行(i.e. C語言中setjmp()與C++異常機制).
5.1.2.1. VFP寄存器使用規則(VFP v2 v3與高級SIMD擴展)
VFP-v2協處理器有32個單精度寄存器s0-s31, 同時支持以16個雙精度寄存器d0-d15形式訪問(d0包括s0, s1, d1包括s2, s3, 依次類推). 此外根據不一樣實現還有3個及以上的系統寄存器.
VFP-v3增長額外16個雙精度定時器d16-d31, 但它們不支持以單精度方式訪問.
高級SMID擴展使用VFP寄存器組, 使用雙精度寄存器做爲64位矢量, 以及定義四字寄存器做爲128位矢量(q0包括d0, d1, q1包括d2, d3, 依次類推).
寄存器s16-s31(d8-d15, q4-q7)在子程序調用時必須被保護, 寄存器s0-s15(d0-d7, q0-q3)無需被保護(且在標準程序調用變型(variant)中可被用於傳遞參數或返回結果), 寄存器d16-d31(q8-q15)若是存在, 無需保護.
FPSCR是惟一可被符合標準的代碼(conforming code)訪問的寄存器. 它是一個有如下特性的全局寄存器:
(1). 狀態碼位(28-31位), cumulative saturation位(QC, 27位)與cumulative exception-status位(0-4位)在公共接口(public interface)調用時不被保護.
(2). 異常控制位(8-12位), 取整模式位(22-23位)與flush-to-zero位(24位)的修改可經過調用特定的支持函數且會影響到應用程序的全局狀態.
(3). 長度位(16-18位)與跨距位(20-21位)必須在進入與返回接口時保持爲零.
(4). 全部其它位均爲保留位且不能被修改. 不論它們爲0或爲1或在公共接口(public interface)調用時是否保持其含義均是未定義的.
5.2. 進程, 內存與棧
AAPCS應用於單一線程的程序(如下簡稱進程). 一個進程有一個由底層的機器寄存器定義的程序狀態與它可訪問的內存內容. 一個進程的內存一般能夠分爲五類:
(1). 代碼(被執行的程序), 對進程而言它必須是可讀的但不須要可寫.
(2). 只讀靜態數據.
(3). 可寫靜態數據.
(4). 堆.
(5). 棧.
可寫靜態數據又可進一步細分爲初始化數據, 清零初始化數據, 未初始化數據. 除棧外其它類型不須要佔用單一連續內存區域. 一個進程必須有代碼與棧, 但能夠沒有其它類型內存.
堆是一塊(或若干)由進程本身管理(i.e. 使用C malloc函數)的內存區域, 一般用於建立動態數據對象.
符合標準的程序必須只能執行被設計用來存放代碼的內存區域中的指令.
5.2.1. 棧
棧是一塊用來存儲局部變量與當參數寄存器不足時傳遞額外參數給子程序的連續內存區域. 棧的實現是滿降棧(full-descending)且當前地址保存在寄存器SP中. 一般狀況下棧有一個基址與長度限制, 但程序在實際運行時沒法肯定二者的值. 棧能夠是固定大小也能夠是動態擴展的(經過向下調整棧長度限制). 棧維護的規則有兩條: 一組任什麼時候候都必須遵照的約束與一條額外的在公共接口(public interface)中遵照的約束.
5.2.1.1. 通用棧約束
任什麼時候候如下約束都要被遵照:
(1). 棧長限制 < SP <= 棧基址, 棧指針必須落在棧空間內.
(2). SP % 4 == 0, 棧指針必須以單字對齊.
(3). 一個進程只能訪問(讀寫)整個棧中以[SP, 棧基址 - 1]的閉區間(SP是寄存器r13的值).
注意: 這意味着爲知足棧約束如下格式的指令可能會失敗, 即便寄存器指向棧空間.
ldmxx reg, {..., sp, ...}
若是指令的執行在sp被加載後中斷了, 棧指針將沒法被恢復, 所以重啓指令可能會違反第三條約束.
5.2.1.2. 棧在公共接口(public interface)中的約束
在公共接口(public interface)中棧還需遵照如下約束:
(1). SP % 8 == 0, 棧指針必須以雙字對齊.
5.3. 子程序調用
ARM指令集與Thumb指令集均包含一個基本的子程序調用指令BL, 用於執行帶連接的跳轉操做. 執行BL指令的結果是將程序計數器(PC)的下一個值(即返回地址)傳入連接寄存器(LR)並將目的地址傳入程序計數器(PC). 連接寄存器的位0置位表明BL指令從Thumb狀態執行的, 置零表明BL指令從ARM狀態執行的. 指令執行結果是將控制轉移到目的地址, 將LR中的返回地址做爲額外的參數傳給被調用的子程序. 當返回地址從新裝載回PC時控制返回到BL的下一條指令(見5.6. 相互轉化).
一個子程序調用能夠由任何具備該做用的指令序列組成, 舉例而言, 在ARM模式下若想調用一個以寄存器r4尋址的子程序並(在子程序結束後)控制返回到接下來的指令, 僅需:
mov LR, PC
bx r4
...
注意: 以上序列將不在Thumb狀態起做用由於設置LR的指令不會將表明Thunb狀態的位傳遞到LR[0].
在ARM v5架構下ARM狀態與Thumb狀態均提供BLX指令, 它能夠調用一個以寄存器尋址的子程序並正確的將返回地址設置爲程序計數器的下一個值爲程序計數器的下一個值爲程序計數器的下一個值爲程序計數器的下一個值爲程序計數器的下一個值爲程序計數器的下一個值爲程序計數器的下一個值爲程序計數器的下一個值爲程序計數器的下一個值.
5.3.1.1. 連接器對IP的使用
ARM狀態與Thumb狀態下BL指令均沒法尋址32位空間, 因此連接器在調用程序與被調用子程序間插入膠合代碼(veneer)是必要的. 膠合代碼(veneer)也能夠用來支持ARM-Thumb狀態相互轉換或動態連接. 任何插入的膠合代碼(veneer)必須保護除IP(r12)之外的全部寄存器及狀態碼標記位. 符合標準的程序必須假定一段修改了IP的膠合代碼(veneer)可能會插入任何跳轉指令用於重定位以支持程序互聯或長分支跳轉. a conforming program must assume that a veneer that alters IP may be inserted at any branch instruction that is exposed to a relocation that supports inter-working or long branches.
注意: R_ARM_CALL, R_ARM_JUMP24, R_ARM_PC24, R_ARM_THM_CALL, R_ARM_THM_JUMP24與R_ARM_THM_JUMP19是具備這些屬性的ELF重定位類型. 詳情見[AAELF].
5.4. 結果返回
函數返回的結果須要遵照的規則是由結果的類型決定的, 對於基本標準:
(1). 類型是半精度浮點的返回值存儲在r0的低16位中返回.
(2). 類型是長度小於4字節的基本數據類型的返回值以零擴展或符號擴展爲單字後存儲在r0中返回.
(3). 類型是單字長度的基本數據類型的返回值(i.e. int, float)存儲在r0中返回.
(4). 類型是雙字長度的基本數據類型的返回值(i.e. long long, double及64位矩陣向量(Containerized vector))存儲在r0與r1中返回.
(5). 類型是128位的矩陣向量(Containerized vector)的返回值存儲在r0-r3中返回.
(6). 類型是長度不大於4字節的複合數據類型存儲在r0中返回. 返回值的格式是假設結果存儲在以單字對齊的內存地址上並經過一個一個LDR指令加載到r0中, 任何r0中超過結果邊界的位都是未指定的值.
(7). 類型是長度大於4字節或(不管調用程序仍是被調用程序)都不能靜態的決定長度的複合數據類型, 其返回值存儲在函數被調用時傳遞的額外參數所指向的內存地址上, 用於保存結果的內存在函數調用期間任意時間點都可能被修改.
5.5. 傳遞參數
基本標準容許經過核心寄存器r0-r3及棧傳遞參數. 對於只需少許參數的子程序使用寄存器傳遞參數能夠極大減小調用開銷.
參數傳遞能夠用兩級抽象模型:
(1). 從源語言參數到機器類型的映射.
(2). 機器類型的集合來產生最終的參數列表.
從源語言參數到機器類型的映射是由每種語言分開描述並指定的(C與C++語言相關內容見7 ARM C與C++映射), 其結果是一個將要傳遞給子程序的有序的參數列表.
接下來的描述中會假設有許多協處理器能夠用來傳遞或接收參數. 協處理器寄存器分爲許多類型. 一個參數至可能是一類協處理器寄存器的候選對象. 一個參數如適合分配在一個協處理器寄存器上則被稱爲協處理器寄存器候選對象(CPRC).
在基本標準中沒有參數是協處理器寄存器的候選對象.
變參函數必須老是整理(marshaling)已使其符合基本標準.
對於調用者而言, 在整理(marshaling)以前需先保證足夠的棧空間(已被分配)來保存存儲在棧上的參數: 實際應用中所須要的棧空間在參數整理(marshaling)完之前是未知的. 被調用者可修改任何用來傳遞調用者參數的棧空間.
當一個複合類型參數(部分或所有)被分配給核心寄存器, 其表現至關於參數先被存儲到以字對齊的內存地址上而後使用合適的複數加載指令將其加載到連續的寄存器中.
階段A. 初始化
本階段僅在參數處理以前出現一次.
A.1. 下一個核心寄存器編號(NCRN)被設置爲r0.
A.2.cp. 開始協處理器參數寄存器初始化.
A.3. 下一個存儲參數棧地址(NSAA)被設置爲當前棧指針值(SP).
A.4. 若是子程序是將返回值保存在內存中的函數則返回值的地址將放在r0中且NCRN被設置爲r1.
階段B. 預填充與擴展參數
對於每一個在列表中的參數都需遵照如下原則中的第一條.
B.1. 若是參數是複合類型且其長度不能被(調用者或被調用者)靜態決定, 那麼需將參數拷貝至內存並將參數自己用指向該拷貝的指針替換.
B.2. 若是參數是整數的基本數據類型且小於單字, 那麼需將參數以零擴展或符號擴展至一個字並將其長度設置爲4字節. 若是參數是半精度浮點類型, 則將它的長度設置爲4字節並將其當作拷貝至32位寄存器的低位且其他位填充未指定數據.
B.3.cp. 若是參數是CPRC那麼任何對協處理器寄存器類的準備規則都需應用.
B.4. 若是參數是複合類型且其大小不是4字節的倍數, 那麼它的大小須要向上對齊到最近的4的倍數.
B.5. 若是參數是調整過對齊的類型那麼它以實際參數的拷貝傳遞參數, 其拷貝的對齊按以下規則. 對於基本數據類型, 其對齊以該基本類型的天然對齊爲準. 對於複合數據類型, 拷貝的對齊須要以4字節對齊(若是其天然對齊不大於4字節)或8字節對齊(若是其天然對齊大於等於8字節). 拷貝的對齊適用於整理(marshaling)規則.
階段C. 參數分配給寄存器與棧
對於列表中每一個參數依次應用如下規則直至參數被分配.
C.1.cp. 若是參數是CPRC且有足夠的對應類型的未分配的協處理器寄存器, 則參數被分配給協處理器寄存器.
C.2.cp. 若是參數是CPRC且任何對應類型的未分配的協處理器寄存器均被標記爲不能使用, 則向上調整NSAA直至其地址與參數對齊而後將參數拷貝至調整後的NSAA, NSAA進一步增加參數長度的大小.
C.3. 若是參數須要以雙字對齊, NCRN需向上對齊到偶數個寄存器編號.
C.4. 若是參數以字爲單位的大小不超過r4減去NCRN, 參數將被拷貝至以NCRN開始的核心寄存器, NCRN增長被使用的寄存器個數的大小. 若是使用一個LDM命令將值從內存裝載到寄存器中, 則連續的寄存器保存參數的各個部分. 至此參數完成分配.
C.5. 若是NCRN小於r4且NSAA等於SP參數將被分開存儲在覈心寄存器與棧上. 參數的第一部分被拷貝到以NCRN開始直至r3的核心寄存器中, 其他的部分被拷貝至以NSAA開始的棧上. 而後NCRN被設置爲r4且NSAA增加參數長度減去傳參寄存器個數的大小. 至此參數完成分配.
C.6. 將NCRN設置爲r4.
C.7. 若是參數要求雙字對齊則NSAA向上對齊到雙字.
C.8. 將參數拷貝至NSAA, NSAA增加參數長度的大小.
須要注意的是以上算法對除C與C++之外的語言作出了規定由於它提供了傳遞數組與動態長度的值. 規則是讓調用者老是可以靜態決定用於存放不經過寄存器傳遞的參數的棧空間的大小, 即使函數是變參的.
進一步能夠觀察到如下幾點:
(1). 初始棧地址是傳遞給子程序的棧指針的值. 所以編譯過程當中可能須要運行兩次以上算法, 第一次肯定所需棧空間大小, 第二次肯定最終的棧地址.
(2). 一個雙字對齊的類型老是存儲在以偶數起始的核心寄存器內, 或雙字對齊的棧地址, 即便它不是結構體(Aggregate)的第一個參數.
(3). 參數首先被分配在寄存器中且僅(有參數寄存器不夠用時)額外的參數才保存在棧上.
(4). 基本數據類型的參數老是所有保存在寄存器中或所有保存在棧上.
(5). 根據C.5.規則至多隻有一個參數可被分開保存在寄存器與棧上.
(6). CPRC對象可被保存在協處理器寄存器中或棧上, 但不能保存在覈心處理器中.
(7). 因一個參數至多隻能是一類協處理器寄存器的候選者, 該規則對多個協處理器在不影響其使用狀況下一樣適用.
(8). 一個參數只能被分配在覈心寄存器與棧上若是它以前的CPRC已被分配在協處理器寄存器中.
5.6. 相互轉化
AAPCS要求全部子程序調用與返回均支持ARM狀態與Thumb狀態相互轉化. 這對編譯各種ARM架構影響以下:
ARMv5與ARMv6
經過函數指針的調用應使用如下方式之一:
blx Rm ;對於正常子程序調用
bx Rm ;對於尾調用
使用bl<cond>或b<cond>的函數調用須要連接器生成的膠合代碼(veneer), 若是產生了狀態轉換. 所以有時使用一個帶有無條件bl指令的指令序列會更高效.
返回序列可能會使用載入多個操做來直接裝載PC或合適的bx指令.
如下傳統的返回方式在有狀態轉換時沒法使用:
mov PC, Rm
ARMv4T
除ARMv5的約束外, ARMv4T還有如下額外約束:
涉及狀態改變且使用bl的調用一樣須要連接器生成的代碼.
經過函數指針的調用必須使用對應ARM狀態的指令序列.
mov LR, PC
bx Rm
可是該指令序列不適用於Thumb狀態, 因此一般使用一個bl指令外加膠合代碼(veneer)來替代bx的做用.
返回的指令序列必須恢復被保存的寄存器且使用bx指令來返回調用者.
ARMv4
ARMv4架構既不支持Thumb狀態又不支持bx指令, 所以它不徹底兼容AAPCS.
推薦對ARMv4的代碼使用ARMv4T相互轉化的序列進行編譯, 但因全部bx指令均服從R_ARM_V4BX重定位[AAELF], 一個連接器連接的代碼可能會將全部bx Rm類指令轉變爲mov PC, Rm. 但可重定位文件仍與此標準兼容.
6. 標準變型(variant)
本節內容僅適用於非變參函數, 對於變參函數老是使用基本標準來參數傳遞與結果返回.
6.1. VFP與高級SIMD寄存器參數
本變型(variant)改變了浮點值在調用程序與子程序間傳遞的方式且提高了性能, 當存在VFP協處理器或高級SIMD擴展時.
6.1.1. 寄存器與內存格式之間的映射
使用VFP在接口調用時傳遞參數以下所示:
(1). 半精度浮點類型以將其從內存拷貝至單精度寄存器的低16位方式傳遞.
(2). 單精度浮點類型以將其從內存拷貝至單精度寄存器(使用VLDR指令)的方式傳遞.
(3). 雙精度浮點類型以將其從內存拷貝至雙精度寄存器(使用VLDR指令)的方式傳遞.
(4). 64位矩陣向量(Containerized vector)類型以將其從內存拷貝至64位矢量寄存器(Dn)(使用VLDR指令)的方式傳遞.
(5). 128位矩陣向量(Containerized vector)類型以將其從內存拷貝至128位矢量寄存器(Qn)(使用一條VLDM指令及兩個份量的64位矢量寄存器, i.e. VLDM r0, {d2, d3}將傳遞q1)的方式傳遞.
6.1.2. 程序調用
調用存儲寄存器的集合與基本標準相同(5.1.2.1. VFP寄存器使用規則).
6.1.2.1. VFP協處理器候選
對VFP而言如下參數類型是VFP CPRC:
(1). 半精度浮點.
(2). 單精度浮點.
(3). 雙精度浮點.
(4). 64位或128位矩陣向量(Containerized vector).
(5). 有一到四個基本類型是單精度浮點或雙精度浮點的奇次結構體(Homogeneous Aggregate).
(6). 有一到四個基本類型是64位矩陣向量(Containerized vector)的奇次結構體(Homogeneous Aggregate).
(7). 有一到四個基本類型是128位矩陣向量(Containerized vector)的奇次結構體(Homogeneous Aggregate).
注意: 變參函數中沒有VFP CPRC.
6.1.2.2. 結果返回
一個類型知足VFP CPRC條件的結果會從以最小的寄存器號起始的恰當的連續VFP寄存器中返回. 全部其它類型按基本標準返回.
6.1.2.3. 參數傳遞
有一類VFP協處理器寄存器類使用s0-s15(d0-d7)來傳遞參數. 如下是VFP協處理器守則:
A.2.vfp 浮點參數寄存器被標記爲未分配.
B.3.vfp 無事可作.
C.1.vfp 若是參數是一個VFP CPRC且存在足夠的未分配的對應類型的連續VFP寄存器則參數被分配到最低編碼起始的寄存器.
C.2.vfp 若是參數是一個VFP CPRC且任何未分配的VFP寄存器均被標記爲不可以使用, 則NSAA向上調整直到它正確的以參數大小對齊再將參數拷貝至調整後NSAA起始的棧上. NSAA再增長參數的大小. 至此參數完成分配.
注意規則要求回填因前面參數的對齊約束致使跳過的未使用的寄存器, 只要沒有VFP CPRC被分配到棧上回填就會一直持續.
6.2. 可選格式(alternative format)的半精度浮點值
代碼可被編譯爲使用可選格式(alternative format)的半精度浮點值的程序. 傳遞參數與返回結果的守則能夠按基本標準或VFP與高級SIMD守則.
6.3. 讀寫位置無關(RWPI)
爲要求讀寫位置無關(i.e. 單一地址空間類DLL模型)的執行環境而編譯與彙編的代碼使用靜態基地址來尋址可寫數據. 核心寄存器r9重命名爲SB並用於保存靜態基地址: 所以該寄存器任什麼時候候都不能用於保存其它數據(注1).
注1: 儘管未被標準受權, 編譯器一般經過加載SB偏移再加上SB基址來獲得靜態數據的地址. 偏移一般是一個32位的值, 從文字池(literal pool)中裝載的PC相關的值. 在靜態連接時字面值一般受R_ARM_SBREL32類型重定位. 數據地址相對於SB的偏移是可執行文件佈局的一項屬性, 它是在靜態連接時固定的. 它不依賴數據在何處載入, 它是在運行時由SB捕獲的.
6.4. 變型(variant)兼容性
第6章描述的標準變型(variant)所產生的代碼是與基本標準不兼容的. 儘管如此仍然存在跨越兼容多個變型(variant)的代碼子集.
本節描述了理論層面各個變型(variant)的兼容性. 可是工具鏈是否接受使用不一樣標準編譯的兼容對象, 仍是拒絕非兼容對象, 是由具體實現決定的.
6.4.1. VFP與基本標準兼容性
以VFP調用標準編譯的代碼若是未使用浮點或矩陣向量(Containerized vector)做爲參數或結果則兼容基本標準(反之亦然), 或者若是程序是變參程序.
6.4.2. RWPI與基本標準兼容性
以基本標準編譯的代碼若是未使用寄存器r9則與RWPI調用標準兼容. 可是平臺ABI可能進一步限制具備兼容性的代碼子集.
6.4.3. VFP與RWPI標準兼容性
VFP標準變型(variant)與RWPI尋址變型(variant)的結合創造了第三種變型(variant). 以上描述的規則的有機結合決定了代碼是否具備兼容性.
6.4.4. 半精度格式兼容性
The set of values that can be represented in Alternative format differs from the set that can be represented in IEEE754r format rendering code built to use either format incompatible with code that uses the other. Never-the-less, most code will make no use of either format and will therefore be compatible with both variants.
7. ARM C與C++語言映射
本章描述了ARM編譯器如何將C特性映射到機器層面標準. C++做爲C擴展的超集它一樣描述了映射C++的特性.
7.1. 數據類型
7.1.1. 算術類型
C算術類型與基本數據類型的映射以下表所述:
C/C++類型 機器類型 備註
char unsigned byte LDRB指令是無符號的.
unsigned char unsigned byte
signed char signed byte
[signed] short signed half word
unsigned short unsigned half word
[signed] int signed word
unsigned int unsigned word
[signed] long signed word
unsigned long unsigned word
[signed] long long signed double word 僅C99.
unsigned long long unsigned double word 僅C99.
__fp16 half precision(IEEE754r or Alternative) 見ACLE. 在變參函數調用中以雙精度值傳遞.
float single precision(IEEE754)
double double precision(IEEE754)
long double double precision(IEEE754)
float _Imaginary single precision(IEEE754) 僅C99.
double _Imaginary double precision(IEEE754) 僅C99.
long double _Imaginary double precision(IEEE754) 僅C99.
float _Complex 2 single precision(IEEE754) 僅C99. 佈局是struct {float re; float im;};.
double _Complex 2 double precision(IEEE754) 僅C99. 佈局是struct {float re; float im;};.
long double _Complex 2 double precision(IEEE754) 僅C99. 佈局是struct {float re; float im;};.
_Bool/bool unsigned byte 僅C99. 假=0, 真=1.
wchar_t see text C++內建, C中用typedef定義, 類型由平臺決定.
wchar_t的首選類型是unsigned int. 然而一個虛擬平臺可能選擇unsigned short來替代. 一個平臺標準必須書面說明它的類型.
7.1.2. 指針類型
指針的容器按下表所述, C++的引用類型是視做指針的一種實現:
指針類型 機器類型 備註
T * 數據指針 T爲任意數據類型
T (*F)() 代碼指針 F爲任意函數類型
T& 數據指針 C++引用
7.1.3. 枚舉類型
本ABI將枚舉類型的表示方法的選擇交由平臺ABI(不管是標準定義的仍是實際使用的)或交由接口協議若是沒有定義平臺ABI.
(1). 一個枚舉類型一般佔據單字(int或unsigned int). 若是單字長度不能表明全部的枚舉值則該類型佔據雙字(long long或unsigned long long).
(2). 枚舉類型的存儲容器的類型是以能包含該枚舉所有枚舉值的最小整型.
討論:
C與C++語言標準對枚舉類型的定義沒有涉及二進制接口的定義且遺留如下問題:
(1). 枚舉類型的容器是否有固定大小(正如大多數系統環境所但願的)或其大小不超過所保存的枚舉值的大小(正如大多數嵌入式用戶所但願的)?
(2). 當一個枚舉值(i.e. MAXINT+1)溢出其容器(i.e. int)會發生什麼?
(3). 枚舉類型的值(在C/C++要求的轉換後)是有符號仍是無符號的?
關於最後一個問題C與C++語言標準聲明:
(1). [C]每一個枚舉類型都須要兼容整型類型. 類型的選擇是實現定義的, 但它必須可以表示全部枚舉成員的值.
(2). [C++]枚舉類型不是整型但...枚舉類型的值可被轉換爲如下類型的值: int, unsigned int, long, unsigned long.
基於本ABI, 聲明容許定義了可移植二進制包接口的頭文件以一種嚴格遵循的可移植的方式強迫其客戶採用一個32位有符號(int或long)表示一個枚舉類型(經過定義一個負枚舉值一個正枚舉值並確保枚舉數的範圍超過16位且不超過32位). 不然必須經過調用平臺ABI或分離的接口定義來創建對二進制表示的通用解釋.
7.1.4. 額外類型
C與C++均要求系統提供基於基本類型的額外類型定義. 一般這些類型是經過包含適當的頭文件來定義的. 然而在C++中基礎類型size_t()能夠無需使用任何頭文件而簡單使用::operator new()來暴露它, 而va_list的定義由編譯器內部實現. 一個遵照AAPCS的對象必須遵照如下定義.
類型定義 基礎類型 備註
size_t unsgined int For consistent C++ mangling of ::operator new().
va_list struct __va_list {void *__ap;} va_list可尋址參數列表的任意對象.
所以第一個參數對象因以單字對齊(全部對象均至少以單字對齊).
但任何雙字對齊的對象均在正確的雙字對齊的地址上. 在C++中__va_list是std命令空間中的.
7.1.5. volatile數據類型
數據類型的聲明能夠用volatile描述符描述. 編譯器不會移除任何對volatile數據類型的訪問除非它能證實包含該訪問的代碼永遠不會執行; 然而編譯器會忽略自動變量的volatile描述符除非函數調用setjmp(). 結構體或聯合體的volatile描述符被解釋爲遞歸的應用到組成結構的每一個基本數據類型的描述符. 訪問帶volatile描述符的基本數據類型必須老是訪問整個類型. 指定結構體或聯合體的成員是volatile的的行爲是未定義的. 一樣的, 改變描述符或其大小的類型轉換也是未定義的行爲.
不是全部ARM架構都提供以各類寬度訪問類型; 舉例而言, 早於ARMv4的架構沒有以16位訪問的指令, 一樣也沒有64位訪問的指令. 所以處理器中內存系統對部分或所有內存有嚴格的總線寬度限制. 這種狀況下對volatile類型的惟一保證是類型的每個字節都會精確訪問一次且任何包含volatile數據且不屬於該類型的字節都不作訪問. 然而, 若是編譯器有一條可用指令剛好能訪問該類型, 則它應該使用該指令而非選擇更小或更大的方式訪問.
7.1.6. 結構體, 聯合體與類佈局
結構體與聯合體經過組成它們的基本數據類型設計佈局(見4.3. 複合類型), 全部成員以聲明順序排布. 額外針對C++非POD類的佈局規則在CPPABI中描述.
7.1.7 位域
一個位域可能包含任意多個整型(包括枚舉與布爾量). 一個位域序列按聲明順序使用如下規則佈局.
對於每一個位域, 其類型容器是:
(1). 它的聲明類型若是它的大小不超過它聲明類型的大小.
(2). 不大於它大小的最大整型類型若是它的大小超過了它聲明類型的大小(見7.1.7.3. 超長的位域).
容器類型有助於包含結構體(aggregate)的對齊, 這樣的方式這種類型不會出現零長度或匿名位域的例外.
注意C++標準聲明匿名位域不是一個成員, 因此非零長度匿名位域是否有助於結構體(aggregate)對齊是不肯定的, 在本ABI中是的.
每一個位域的內容由它的容器類型的一個實例徹底包含.
一開始咱們定義位域的佈局不大於其容器類型.
7.1.7.1 不大於其容器的位域
假設F爲咱們須要肯定地址的位域, 咱們定義其容器地址CA(F)爲字節地址
CA(F) = &(container(F));
該地址永遠天然對齊其容器類型, 即
CA(F) % sizeof(container(F)) == 0.
F相對容器的位偏移K(F)的定義依賴字節序:
(1). 對於大端字節序K(F)是從容器最高有效位到位域的最高有效位的偏移.
(2). 對於小端字節序K(F)是從容器最低有效位到位域的最低有效位的偏移.
能夠經過加載位域的容器, 根據字節序, K(F), 容器大小及位寬來設置偏移與掩碼, 若有必要再作符號擴展, 來獲得位域.
F的位地址BA(F)如今能夠定義爲:
BA(F) = CA(F) * 8 + K(F);
對於位地址BA落在容器寬度C與對齊A(A小於等於C)(均以位爲單位), 定義未分配容器位(UCB)爲:
UCB(BA, C, A) = C - (BA % A);
進一步定義截斷函數(truncation function):
TRUNCATE(X, Y) = Y * [X / Y];
即乘以倍數Y後最大不超過X.
如今咱們能夠定義下一個容器位地址(NCBA), 噹噹前容器有足夠空間保存下一個位域時就會使用到:
NCBA(BA, A) = TRUNCATE(BA + A - 1, A);
在佈局一個位域序列的每一個階段時都有:
(1). 當前位地址(CBA).
(2). 容器地址C與對齊地址A, 由將要被佈局的位域類型決定(8, 16, 32, ...).
(3). 位域寬度W.
對每一個位域, 其排布由
(1). 若是寬度W爲零, 設置CBA = NCBA(CBA, A).
(2). 若是W > UCB(CBA, C, A), 設置CBA = NCBA(CBA, A).
(3). 設置BA(F) = CBA.
(4). 設置CBA = CBA + W.
注意AAPCS不容許對外暴露的接口包含填充結構體或位域. However a scheme for laying out packed bit-fields can be achieved by reducing the alignment, A, in the above rules to below that of the natural container type. ARMCC uses an alignment of A=8 in these cases, but GCC uses an alignment of A=1.
7.1.7.2. 位域提取表達式
爲訪問寬度W, 容器寬度C, 位地址BA(F)的位域F:
(1). 裝載天然對齊的字節地址爲TRUNCATE(BA(F), C) / 8的容器到寄存器R(或兩個寄存器若是容器是64位的).
(2). 設置Q = MAX(32, C).
(3). 小端字節序狀況下設置R = (R << ((Q - W) - (BA MOD C))) >> (Q - W).
(4). 大端字節序狀況下設置R = (R << (BA MOD C)) >> (Q - W).
long long位域使用64位移位操做; 一般狀況下這些表達式能夠簡化爲32位操做(見7.1.7.5. Volatile bit-fields preserving number and width of container accesses for volatile bit-fields).
7.1.7.3. 超長的位域
C++容許位域的寬度規格超過其容器大小, 其分配規則在[GC++ABI]中規定. 仍使用上述的符號, 超長的位域寬度爲W, 容器的寬度爲C, 對齊爲A:
(1). 選擇一個新的容器寬度C', 其基本數據類型的寬度的最大值小於等於W. 該容器的對齊是A'. 注意C'大於等於C, A'大於等於A.
(2). 若是C'大於UCB(CBA, C', A')則設置CBA=NCBA(CBA, A'). 這確保了位域被放在下一個容器的起始地址.
(3). 使用(C, C', A')代替(W, C, A)來分配一個普通位域.
(4). 設置CBA=CBA+W-C.
注意儘管標準C++沒有long long數據類型, 但這是該語言常見的一種擴展. 爲避免出現這類類型引發超長位域佈局的改變規則描述根據基本數據類型(見4.1. 基本數據類型)64位整型老是存在.
超長的位域的訪問能夠經過訪問其容器類型.
7.1.7.4. 組合位域與非位域成員
一個位域的容器可能跨越非位域成員. 爲決定位域成員的佈局CBA被設爲第一個未分配位在處理非位域類型後.
注意任何在處理位域成員前的結構體填充均視做結構體的一部分且在決定CBA時必須考慮進去.
當一個非位域成員跟隨一個位域成員時, 它被放在已分配位域後最低可接受的地址.
注意當佈局基本數據類型時考慮它們全是寬度等於其容器的位域是可能的. 7.1.7.1.中的規則位域不得大於其容器能夠用來決定結構體的地址.
7.1.7.5. Volatile bit-fields preserving number and width of container accesses
當一個volatile位域被讀取時, 必須使用該容器類型寬度的訪問方式精確的讀容器一次.
當一個volatile位域被讀取時, 必須使用該容器類型寬度的訪問方式精確的讀寫容器各一次. 兩次訪問操做不是原子的.
屢次訪問贊成volatile位域, 或同一容器的額外volatile位域不會被同步. 舉例而言一個位域的增長老是須要兩次讀與一次寫操做實現.
注意即便位域的寬度與對齊暗示可使用更小的類型來提高效率, volatile訪問規則仍需被遵照. 對於寫操做而言即便整個容器的內容都被替換讀的過程仍必須進行.
若是容器跨越兩個volatile位域則訪問一個位域會觸發訪問另一個位域. i.e. struct S {volatile int a:8; volatile char b:2;}; 訪問a將會訪問b, 但反過來卻不是.
若是非volatile位域的容器跨越volatile位域那麼訪問非volatile位域是否觸發對volatile位域的訪問是未定義的.
7.2. 參數傳遞轉換
子程序調用的參數列表是經過獲取用戶參數的被指定的順序來造成的.
(1). 對C而言每一個參數都是經過源代碼中指定值造成的, 除了那些經過第一個元素的地址傳遞的數組.
(2). 對C++而言一個隱式this參數做爲一個額外參數在第一個用戶參數以前傳遞, 其它編組C++參數的規則見CPPABI.
(3). 對變參函數而言, 省略參數中的float參數被轉換爲double.
而後按程序調用標準守則(見5.5. 參數傳遞)或對應變型(variant)處理參數列表.
附錄A. 高級SIMD擴展的支持 略.