ZHCADC4A September   2011  – March 2014

 

  1.   1
  2. 简介
    1. 1.1  ABI - C6000
    2. 1.2  范围
    3. 1.3  ABI 变体
    4. 1.4  工具链和互操作性
    5. 1.5 
    6. 1.6  目标文件的类型
    7. 1.7 
    8. 1.8  C6000 架构概述
    9. 1.9  参考文档
    10. 1.10 代码片段表示法
  3. 数据表示
    1. 2.1 基本类型
    2. 2.2 寄存器中的数据
    3. 2.3 存储器中的数据
    4. 2.4 复数类型
    5. 2.5 结构体和联合体
    6. 2.6 数组
    7. 2.7 位字段
      1. 2.7.1 易失性位字段
    8. 2.8 枚举类型
  4. 调用约定
    1. 3.1 调用和返回
      1. 3.1.1 返回地址计算
      2. 3.1.2 调用指令
      3. 3.1.3 返回指令
      4. 3.1.4 流水线约定
      5. 3.1.5 弱函数
    2. 3.2 寄存器惯例
    3. 3.3 实参传递
    4. 3.4 返回值
    5. 3.5 通过引用传递并返回的结构体和联合体
    6. 3.6 编译器辅助函数的约定
    7. 3.7 段间调用的暂存寄存器
    8. 3.8 设置 DP
  5. 数据分配和寻址
    1. 4.1 数据段和数据区段
    2. 4.2 静态数据的分配和寻址
      1. 4.2.1 静态数据的寻址方法
        1. 4.2.1.1 near DP 相对寻址
        2. 4.2.1.2 Far DP 相对寻址
        3. 4.2.1.3 绝对寻址
        4. 4.2.1.4 GOT 间接寻址
        5. 4.2.1.5 PC 相对寻址
      2. 4.2.2 静态数据的放置约定
        1. 4.2.2.1 放置的抽象约定
        2. 4.2.2.2 寻址的抽象约定
        3. 4.2.2.3 链接器要求
      3. 4.2.3 静态数据的初始化
    3. 4.3 自动变量
    4. 4.4 帧布局
      1. 4.4.1 栈对齐
      2. 4.4.2 寄存器保存顺序
        1. 4.4.2.1 大端字节序对交换
        2. 4.4.2.2 示例
      3. 4.4.3 DATA_MEM_BANK
      4. 4.4.4 C64x+ 特定的堆栈布局
        1. 4.4.4.1 _ _C6000_push_rts 布局
        2. 4.4.4.2 紧凑帧布局
    5. 4.5 堆分配对象
  6. 代码分配和寻址
    1. 5.1 计算代码标签的地址
      1. 5.1.1 代码的绝对寻址
      2. 5.1.2 PC 相对寻址
      3. 5.1.3 同一段内的 PC 相对寻址
      4. 5.1.4 短偏移 PC 相对寻址 (C64x)
      5. 5.1.5 基于 GOT 的代码寻址
    2. 5.2 分支
    3. 5.3 调用
      1. 5.3.1 直接 PC 相对调用
      2. 5.3.2 Far Call Trampoline
      3. 5.3.3 间接调用
    4. 5.4 寻址紧凑指令
  7. 动态链接的寻址模型
    1. 6.1 术语和概念
    2. 6.2 动态链接机制概述
    3. 6.3 DSO 和 DLL
    4. 6.4 抢占
    5. 6.5 PLT 条目
      1. 6.5.1 直接调用导入函数
      2. 6.5.2 通过绝对地址寻址的 PLT 条目
      3. 6.5.3 通过 GOT 寻址的 PLT 条目
    6. 6.6 全局偏移表
      1. 6.6.1 使用 Near DP 相对寻址的基于 GOT 的引用
      2. 6.6.2 使用 Far DP 相对寻址的基于 GOT 的引用
    7. 6.7 DSBT 模型
      1. 6.7.1 导出函数的进入/退出序列
      2. 6.7.2 避免在内部函数中使用 DP 负载
      3. 6.7.3 函数指针
      4. 6.7.4 中断
      5. 6.7.5 与非 DSBT 代码的兼容性
    8. 6.8 动态链接的性能影响
  8. 线程局部存储分配和寻址
    1. 7.1 关于多线程和线程局部存储
    2. 7.2 术语和概念
    3. 7.3 用户界面
    4. 7.4 ELF 目标文件表示
    5. 7.5 TLS 访问模型
      1. 7.5.1 C6x Linux TLS 模型
        1. 7.5.1.1 通用动态 TLS 访问模型
        2. 7.5.1.2 局部动态 TLS 访问模型
        3. 7.5.1.3 初始可执行文件 TLS 访问模型
          1. 7.5.1.3.1 线程指针
          2. 7.5.1.3.2 初始可执行文件 TLS 寻址
        4. 7.5.1.4 局部可执行文件 TLS 访问模型
      2. 7.5.2 静态可执行文件 TLS 模型
        1. 7.5.2.1 静态可执行文件寻址
        2. 7.5.2.2 静态可执行文件 TLS 运行时架构
        3. 7.5.2.3 静态可执行文件 TLS 分配
          1. 7.5.2.3.1 TLS 初始化映像分配
          2. 7.5.2.3.2 主线程的 TLS 分配
          3. 7.5.2.3.3 线程库的 TLS 区域分配
        4. 7.5.2.4 静态可执行文件 TLS 初始化
          1. 7.5.2.4.1 主线程的 TLS 初始化
          2. 7.5.2.4.2 线程库进行 TLS 初始化
        5. 7.5.2.5 线程指针
      3. 7.5.3 裸机动态链接 TLS 模型
        1. 7.5.3.1 用于裸机动态链接的默认 TLS 寻址
        2. 7.5.3.2 TLS 块创建
    6. 7.6 线程局部符号解析和弱引用
      1. 7.6.1 通用和局部动态 TLS 弱引用寻址
      2. 7.6.2 初始和局部可执行文件 TLS 弱引用寻址
      3. 7.6.3 静态可执行文件和裸机动态 TLS 模型弱引用
  9. 辅助函数 API
    1. 8.1 浮点行为
    2. 8.2 C 辅助函数 API
    3. 8.3 辅助函数的特殊寄存器约定
    4. 8.4 复数类型的辅助函数
    5. 8.5 C99 的浮点辅助函数
  10. 标准 C 库 API
    1. 9.1  保留符号
    2. 9.2  <assert.h> 实现
    3. 9.3  <complex.h> 实现
    4. 9.4  <ctype.h> 实现
    5. 9.5  <errno.h> 实现
    6. 9.6  <float.h> 实现
    7. 9.7  <inttypes.h> 实现
    8. 9.8  <iso646.h> 实现
    9. 9.9  <limits.h> 实现
    10. 9.10 <locale.h> 实现
    11. 9.11 <math.h> 实现
    12. 9.12 <setjmp.h> 实现
    13. 9.13 <signal.h> 实现
    14. 9.14 <stdarg.h> 实现
    15. 9.15 <stdbool.h> 实现
    16. 9.16 <stddef.h> 实现
    17. 9.17 <stdint.h> 实现
    18. 9.18 <stdio.h> 实现
    19. 9.19 <stdlib.h> 实现
    20. 9.20 <string.h> 实现
    21. 9.21 <tgmath.h> 实现
    22. 9.22 <time.h> 实现
    23. 9.23 <wchar.h> 实现
    24. 9.24 <wctype.h> 实现
  11. 10C++ ABI
    1. 10.1  限制 (GC++ABI 1.2)
    2. 10.2  导出模板 (GC++ABI 1.4.2)
    3. 10.3  数据布局(GC++ABI 第 2 章)
    4. 10.4  初始化保护变量 (GC++ABI 2.8)
    5. 10.5  构造函数返回值 (GC++ABI 3.1.5)
    6. 10.6  一次性构建 API (GC++ABI 3.3.2)
    7. 10.7  控制对象构造顺序 (GC++ ABI 3.3.4)
    8. 10.8  还原器 API (GC++ABI 3.4)
    9. 10.9  静态数据 (GC++ ABI 5.2.2)
    10. 10.10 虚拟表和键函数 (GC++ABI 5.2.3)
    11. 10.11 回溯表位置 (GC++ABI 5.3)
  12. 11异常处理
    1. 11.1  概述
    2. 11.2  PREL31 编码
    3. 11.3  异常索引表 (EXIDX)
      1. 11.3.1 指向行外 EXTAB 条目的指针
      2. 11.3.2 EXIDX_CANTUNWIND
      3. 11.3.3 内联 EXTAB 条目
    4. 11.4  异常处理指令表 (EXTAB)
      1. 11.4.1 EXTAB 通用模型
      2. 11.4.2 EXTAB 紧凑模型
      3. 11.4.3 个性化例程
    5. 11.5  回溯指令
      1. 11.5.1 通用序列
      2. 11.5.2 字节编码展开指令
      3. 11.5.3 24 位展开编码
    6. 11.6  描述符
      1. 11.6.1 类型标识符编码
      2. 11.6.2 作用域
      3. 11.6.3 Cleanup 描述符
      4. 11.6.4 catch 描述符
      5. 11.6.5 函数异常规范 (FESPEC) 描述符
    7. 11.7  特殊段
    8. 11.8  与非 C++ 代码交互
      1. 11.8.1 EXIDX 条目自动生成
      2. 11.8.2 手工编码的汇编函数
    9. 11.9  与系统功能交互
      1. 11.9.1 共享库
      2. 11.9.2 覆盖块
      3. 11.9.3 中断
    10. 11.10 TI 工具链中的汇编语言运算符
  13. 12DWARF
    1. 12.1 DWARF 寄存器名称
    2. 12.2 调用帧信息
    3. 12.3 供应商名称
    4. 12.4 供应商扩展
  14. 13ELF 目标文件(处理器补充)
    1. 13.1 注册供应商名称
    2. 13.2 ELF 标头
    3. 13.3
      1. 13.3.1 段索引
      2. 13.3.2 段类型
      3. 13.3.3 扩展段标头属性
      4. 13.3.4 子段
      5. 13.3.5 特殊段
      6. 13.3.6 段对齐
    4. 13.4 符号表
      1. 13.4.1 符号类型
      2. 13.4.2 通用块符号
      3. 13.4.3 符号名称
      4. 13.4.4 保留符号名称
      5. 13.4.5 映射符号
    5. 13.5 重定位
      1. 13.5.1 重定位类型
      2. 13.5.2 重定位操作
      3. 13.5.3 未解析的弱引用的重定位
  15. 14ELF 程序加载和动态链接(处理器补充)
    1. 14.1 程序标头
      1. 14.1.1 基址
      2. 14.1.2 段内容
      3. 14.1.3 绑定段和只读段
      4. 14.1.4 线程局部存储
    2. 14.2 程序加载
    3. 14.3 动态链接
      1. 14.3.1 程序解释器
      2. 14.3.2 动态段
      3. 14.3.3 共享对象依赖关系
      4. 14.3.4 全局偏移量表
      5. 14.3.5 过程链接表
      6. 14.3.6 抢占式
      7. 14.3.7 初始化和终止
    4. 14.4 裸机动态链接模型
      1. 14.4.1 文件类型
      2. 14.4.2 ELF 标识
      3. 14.4.3 可见性和绑定
      4. 14.4.4 数据寻址
      5. 14.4.5 代码寻址
      6. 14.4.6 动态信息
  16. 15Linux ABI
    1. 15.1  文件类型
    2. 15.2  ELF 标识
    3. 15.3  程序标头和段
    4. 15.4  数据寻址
      1. 15.4.1 数据区段基表 (DSBT)
      2. 15.4.2 全局偏移量表 (GOT)
    5. 15.5  代码寻址
    6. 15.6  延迟绑定
    7. 15.7  可见性
    8. 15.8  抢占式
    9. 15.9  “作为自有导入”占先
    10. 15.10 程序加载
    11. 15.11 动态信息
    12. 15.12 初始化和终止函数
    13. 15.13 Linux 模型摘要
  17. 16符号版本控制
    1. 16.1 ELF 符号版本控制概述
    2. 16.2 版本段标识
  18. 17构建属性
    1. 17.1 C6000 ABI 构建属性子段
    2. 17.2 C6000 构建属性标签
  19. 18复制表和变量初始化
    1. 18.1 复制表格式
    2. 18.2 压缩的数据格式
      1. 18.2.1 RLE
      2. 18.2.2 LZSS 格式
    3. 18.3 变量初始化
  20. 19扩展程序标头属性
    1. 19.1 编码
    2. 19.2 属性标签定义
    3. 19.3 扩展程序标头属性段格式
  21. 20修订历史记录

字节编码展开指令

个性化例程 PR0、PR1 和 PR2 使用字节编码的指令序列来说明如何展开帧。前几条指令被封装到 EXTAB 第一个字的剩余三个字节中;附加指令被封装到后续字中。最后一个字中未使用的字节由“RET B3”指令填充。

尽管指令是字节编码的,但它们始终封装成从 MSB 开始的 32 位字。因此,在小端字节序模式下,第一个展开指令将不会位于最低地址字节。

个性化例程 PR0 最多允许三条展开指令,所有这些指令都存储在第一个 EXTAB 字中。如果有三个以上的展开指令,则必须使用其他个性化例程之一。

GUID-59BA2E98-7DFC-4DAA-A556-3B41DB5F1AFB-low.gif

对于 PR1 和 PR2,位 23-16 编码展开指令的额外 32 位字的数量,该数量可为 0。

GUID-96D09DE5-7B2B-4CAD-8571-4D28DE64F66B-low.gif

表 11-2 总结了展开指令集。表格后面对每条指令进行了更详细的介绍。

表 11-2 堆栈展开指令
编码指令说明
00kk kkkkSP += (k << 3) + 8将 SP 递增,增量为一个小常数
1101 0010
kkkk kkkk
...
SP += (ULEB128 << 3) + 0x408将 SP 递增,增量为一个 ULEB128 编码的常数
1000 0000
0000 0000
CANTUNWIND函数无法展开,但可能会捕获异常
100x xxxx
xxxx xxxx
POP bitmask弹出一个或多个寄存器 [x != 0]
101x xxxx
xxxx xxxx
POP bitmask从 C64x + 压缩帧 [x!= 0] 中弹出一个或多个寄存器
1100 nnnn
xxxx xxxx
...
POP registern 表示要弹出的寄存器数量,这些寄存器在后面的 4 位半字节中进行编码
1101 0000MV FP, SP从 FP 恢复 SP 而不是将 SP 递增
1101 0001_ _C6000_pop_rts模拟对 _ _C6000_pop_rts 的调用
1110 0111RET B3此帧的展开完成
1110 xxxxRETURN 或恢复 B3b3:= 寄存器 x (x != B3)

所有其他位模式均保留。

以下各段详细说明了展开指令的解释。

小增量

GUID-16A547D8-F966-480D-9F87-A3E994042BC2-low.gif

k 的值从编码的低 6 位中提取。此指令可以使 SP 递增一个介于 0x8 到 0x200 之间的值,包括边界值。0x208 到 0x400 范围内的增量应该用这些指令中的两个来完成。

 

大增量

GUID-46ADB864-DB46-4156-A7EB-E0FD2DCC89E6-low.gif

值 ULEB128 在 8 位操作码之后的字节中进行 ULEB128 编码。此指令可以将 SP 递增 0x408 或更大的值。增量小于 0x408 应使用 1 条或 2 条小增量指令实现。

 

CANTUNWIND

GUID-1F86C2BF-298C-47BD-9849-A06121E58853-low.gif

此指令指示函数不能展开,通常是因为它是中断函数。但是,中断函数仍然可以有 try/catch 代码,因此 EXIDX_CANTUNWIND 不适用。

POP Bitmask

GUID-44B937CE-1B8A-493B-973C-110B47241078-low.gif

这条两个字节的指令指示:根据位掩码指定,最多应该从虚拟栈弹出 13 个被调用者保存的寄存器。恢复寄存器的顺序必须与它们在安全调试 顺序中的出现顺序相同。

当使用“POP bitmask”指令弹出任何寄存器时,SP 首先根据被调用者保存的寄存器区域的大小隐式递增,四舍五入为最多 8 个字节。这是对任何显式 SP 增量指令的补充。但是,如果使用过“MV FP, SP”指令,则“POP bitmask”不会隐式递增 SP。

POP Bitmask; C64x+ Compact Frame

GUID-784371A1-D1FE-4FA5-9311-90E5427B1796-low.gif

与 POP Bitmask 相同,但指示使用 C64x+ 紧凑帧 布局,这可能会在堆栈上留下空洞以有利于使用 SP 自动递减存储。展开程序必须知道用于放置空洞并进行相应补偿的算法。

POP Register

GUID-FE806046-D63B-4841-A2FF-8E38F96450D5-low.gif

如果编译器无法保持安全调试顺序,或者对于选择不同布局的编译器,可以个别弹出每个被调用者保存的寄存器。4 位操作码后的前四位指示要弹出的寄存器数量。每个后续的 4 位半字节表示被调用者保存的寄存器的编码,或表示空洞 的特殊值 0xF。如果指示有空洞,则应递减虚拟 SP,但不应弹出寄存器。

4 位寄存器编码如下:

表 11-3 展开指令中的寄存器编码
编码寄存器编码寄存器
0000A151000A14
0001B151001A13
0010B141010A12
0011B131011A11
0100B121100A10
0101B111101被保留
0110B101110保留
0111B31111“空洞”

MV FP, SP

GUID-DB569B53-BE8D-4CC5-AC0A-F0DBD35E207B-low.gif

此指令从 FP (A15) 恢复 SP,而不是递增 SP。当 FP 可用时,只需从 FP 恢复 SP 值会容易一些。对于 DATA_MEM_BANK 布局,这可能是恢复 SP 的唯一方法。

_ _C6000_pop_rts

GUID-9EB48F0F-E1C6-4A41-B575-7CD0CDE30824-low.gif

此指令指示所有寄存器恢复都通过调用 _ _C6000_pop_rts 来完成。此函数的行为应由展开程序进行模拟。_ _C6000_pop_rts 隐式恢复 B3 并执行 RET B3。

恢复 B3

GUID-2E71C9BF-05F1-42E5-AD9C-98850983F8BF-low.gif

如果 r 表示 B3 以外的任何寄存器,则此指令对用于从“reg”恢复 B3 的“MV reg, B3”进行编码。如果 POP 会覆盖寄存器,则必须在任何 POP 指令之前执行此操作。

RET B3

GUID-EE7AE81B-C2BA-4A26-BBB5-B40891CD555F-low.gif

此指令对模拟的 return 进行编码,表示此帧的展开已完成。请注意,编码与“恢复 B3”相同,但源寄存器指示为 B3 本身。

每个展开指令序列都以显式或隐式“RET B3”结束。可以从显式展开指令中省略此指令,展开程序将隐式添加它。