RISC-V 目标用户指南¶
介绍¶
RISC-V 目标为实现支持的 RISC-V 规范变体的处理器提供代码生成。它位于 llvm/lib/Target/RISCV 目录中。
规范文档¶
RISC-V 规范已经过多次修订。LLVM 旨在实现最新批准的标准 RISC-V 基础 ISA 和 ISA 扩展版本,并具有务实的差异。最新规范可以在以下网址找到:https://github.com/riscv/riscv-isa-manual/releases/。
RISC-V International 官方规范页面 也值得查看,但往往明显滞后于上面链接的规范。请务必查看 wiki 以获取尚未集成的扩展,并注意,此外,我们有时会支持尚未批准的扩展(这些扩展将被标记为实验性 - 见下文)并支持各种供应商特定的扩展(见下文)。
当前已知的与规范的差异是
无条件允许来自 zifencei、zicsr、zicntr 和 zihpm 的指令,而无需将它们限制于已启用的扩展。规范的先前修订版本在基础 ISA 中包含了这些指令,我们保留此行为以避免破坏现有代码。如果规范的未来修订版本将这些操作码重用于其他扩展,我们可能需要重新评估此选择,因此建议用户迁移构建系统,以便不依赖于此。
允许命名 CSR,而无需限制于特定扩展。这适用于所有 CSR 名称,而不仅仅是 zicsr、zicntr 和 zihpm 中的名称。
z*、s*和x*前缀扩展名称的顺序在用户指定的 ISA 命名字符串(例如-march)中未强制执行。
我们目前积极决定不支持多个规范修订版本。我们承认未来可能需要这样做,但积极推迟围绕处理此问题的决策制定,直到我们有真实硬件已发货的具体示例以及之后对规范进行的不兼容更改。
基础 ISA¶
该规范定义了五个基础指令集:RV32I、RV32E、RV64I、RV64E 和 RV128I。目前,LLVM 完全支持 RV32I 和 RV64I。RV32E 和 RV64E 仅由基于汇编的工具支持。不支持 RV128I。
指定目标三元组
表 118 RISC-V 架构¶ 架构
描述
riscv32XLEN=32 的 RISC-V(即 RV32I 或 RV32E)
riscv64XLEN=64 的 RISC-V(即 RV64I 或 RV64E)
要选择 E 变体 ISA(例如 RV32E 而不是 RV32I),请使用基本架构字符串(例如 riscv32)和扩展 e。
配置文件¶
可以使用 -march 而不是标准 ISA 命名字符串来传递受支持的配置文件名称。当前支持的配置文件
rvi20u32rvi20u64rva20u64rva20s64rva22u64rva22s64rva23u64rva23s64rvb23u64rvb23s64
请注意,您还可以附加要启用的其他扩展名称,例如 rva20u64_zicond 将除了 rva20u64 配置文件中的扩展外,还启用 zicond 扩展。
除非指定了 -menable-experimental-extensions(或等效于其他工具),否则不能使用尚未批准的配置文件。这适用于以下配置文件
rvm23u32
扩展¶
下表提供了已批准的扩展的状态摘要,因此具有最终规范。在相关时,支持的详细注释如下。
表 119 按状态划分的已批准扩展¶ 扩展
状态
A支持
B支持
C支持
D支持
F支持
E支持 (参见注释)
H汇编支持
M支持
Sha支持
Shcounterenw汇编支持 (参见注释)
Shgatpa汇编支持 (参见注释)
Shtvala汇编支持 (参见注释)
Shvsatpa汇编支持 (参见注释)
Shvstvala汇编支持 (参见注释)
Shvstvecd汇编支持 (参见注释)
Smaia支持
Smcdeleg支持
Smcsrind支持
Smdbltrp支持
Smepmp支持
Smmpm支持
Smnpm支持
Smrnmi汇编支持
Smstateen汇编支持
Ssaia支持
Ssccfg支持
Ssccptr汇编支持 (参见注释)
Sscofpmf汇编支持
Sscounterenw汇编支持 (参见注释)
Sscsrind支持
Ssdbltrp支持
Ssnpm支持
Sspm支持
Ssqosid汇编支持
Ssstateen汇编支持 (参见注释)
Ssstrict汇编支持 (参见注释)
Sstc汇编支持
Sstvala汇编支持 (参见注释)
Sstvecd汇编支持 (参见注释)
Ssu64xl汇编支持 (参见注释)
Supm支持
Svade汇编支持 (参见注释)
Svadu汇编支持
Svbare汇编支持 (参见注释)
Svinval汇编支持
Svnapot汇编支持
Svpbmt支持
Svvptc支持
V支持
Za128rs支持 (参见注释)
Za64rs支持 (参见注释)
Zaamo汇编支持
Zabha支持
Zacas支持 (参见注释)
Zalrsc汇编支持
Zama16b支持 (参见注释)
Zawrs汇编支持
Zba支持
Zbb支持
Zbc支持
Zbkb支持 (参见注释)
Zbkc支持
Zbkx支持 (参见注释)
Zbs支持
Zca支持
Zcb支持
Zcd支持
Zcf支持
Zcmop支持
Zcmp支持
Zcmt汇编支持
Zdinx支持
Zfa支持
Zfbfmin支持
Zfh支持
Zfhmin支持
Zfinx支持
Zhinx支持
Zhinxmin支持
Zic64b支持 (参见注释)
Zicbom汇编支持
Zicbop支持
Zicboz汇编支持
Ziccamoa支持 (参见注释)
Ziccif支持 (参见注释)
Zicclsm支持 (参见注释)
Ziccrse支持 (参见注释)
Zicntr(参见注释)
Zicond支持
Zicsr(参见注释)
Zifencei(参见注释)
Zihintntl支持
Zihintpause汇编支持
Zihpm(参见注释)
Zimop支持
Zkn支持
Zknd支持 (参见注释)
Zkne支持 (参见注释)
Zknh支持 (参见注释)
Zksed支持 (参见注释)
Zksh支持 (参见注释)
Zk支持
Zkr支持
Zks支持
Zkt支持
Zmmul支持
Ztso支持
Zvbb支持
Zvbc支持 (参见注释)
Zve32x(部分) 支持
Zve32f(部分) 支持
Zve64x支持
Zve64f支持
Zve64d支持
Zvfbfmin支持
Zvfbfwma支持
Zvfh支持
Zvfhmin支持
Zvkb支持
Zvkg支持 (参见注释)
Zvkn支持 (参见注释)
Zvknc支持 (参见注释)
Zvkned支持 (参见注释)
Zvkng支持 (参见注释)
Zvknha支持 (参见注释)
Zvknhb支持 (参见注释)
Zvks支持 (参见注释)
Zvksc支持 (参见注释)
Zvksed支持 (参见注释)
Zvksg支持 (参见注释)
Zvksh支持 (参见注释)
Zvkt支持
Zvl32b(部分) 支持
Zvl64b支持
Zvl128b支持
Zvl256b支持
Zvl512b支持
Zvl1024b支持
Zvl2048b支持
Zvl4096b支持
Zvl8192b支持
Zvl16384b支持
Zvl32768b支持
Zvl65536b支持
- 汇编支持
LLVM 在汇编中支持相关的指令。所有与汇编相关的工具(例如汇编器、反汇编器、llvm-objdump 等)都受支持。编译器和链接器将接受扩展名称,并且链接的二进制文件将包含适当的 ELF 标志和属性,以反映命名扩展的使用。
- 支持
编译器完全支持。这包括汇编支持中的所有内容,以及(如果相关)指令的 C 语言内联函数以及编译器通过模式匹配来识别可以降级为相关指令的惯用模式。
E对 RV32E/RV64E 和 ilp32e/lp64e ABI 的支持是实验性的。为了与 GCC 中 ilp32e 的实现兼容,我们不使用对齐的寄存器来传递可变参数。此外,对于长度为 2*XLEN 的类型,我们将堆栈对齐设置为 4 个字节。
Zbkb,Zbkx对这些指令的模式匹配支持不完整。
Zknd,Zkne,Zknh,Zksed,Zksh不存在模式匹配。因此,这些指令只能从汇编器或通过内联函数调用来使用。
Zvbc,Zvkg,Zvkn,Zvknc,Zvkned,Zvkng,Zvknha,Zvknhb,Zvks,Zvks,Zvks,Zvksc,Zvksed,Zvksg,Zvksh。不存在模式匹配。因此,这些指令只能从汇编器或通过内联函数调用来使用。
Zve32x,Zve32f,Zvl32bLLVM 当前在编译期间假定最小 VLEN(向量寄存器宽度)为 64 位,因此 Zve32x 和 Zve32f 仅在 VLEN>=64 的情况下受支持。汇编支持没有此限制。
Zicntr,Zicsr,Zifencei,Zihpm在基础 I 规范的 2.0 和 2.1 版本之间,进行了一项向后不兼容的更改,以从基础 ISA 中删除选定的指令和 CSR。这些指令被分组到一组新的扩展中,但不再是基础 ISA 所必需的。此更改在规范文档中的“Document Version 20190608-Base-Ratified 序言”中部分描述(未提及
zicntr和zihpm位)。LLVM 当前实现了基础规范的 2.1 版本。为了保持兼容性,接受来自这些扩展的指令,而无需在-march字符串中。LLVM 也允许在-march字符串中显式指定扩展。
Za128rs,Za64rs,Zama16b,Zic64b,Ziccamoa,Ziccif,Zicclsm,Ziccrse,Shcounterenvw,Shgatpa,Shtvala,Shvsatpa,Shvstvala,Shvstvecd,Ssccptr,Sscounterenw,Ssstateen,Ssstrict,Sstvala,Sstvecd,Ssu64xl,Svade,Svbare这些扩展被定义为 RISC-V 配置文件规范 的一部分。它们本身不引入任何新功能,而是描述现有的硬件功能。
Zacas由于 ABI 兼容性,编译器不会在 RV32 上生成 amocas.d 或在 RV64 上生成 amocas.q。这些只能在汇编器中使用。
原子操作 ABI¶
在撰写本文时,为 RISC-V 定义了三种原子操作映射 (ABI)。截至 LLVM 19,LLVM 默认为 “A6S”,它与原始 “A6” 和未来的 “A7” ABI 都兼容。有关这些映射的更多信息,请参阅 psABI 原子操作文档。
请注意,尽管使用了 “A6S” 映射,但由于在处理包含此属性的文件时,旧版本的 binutils 中存在导致崩溃的错误,因此默认情况下当前不会发出记录映射的 ELF 属性。
实验性扩展¶
LLVM 支持(在不同程度上)许多实验性扩展。所有实验性扩展都以 experimental- 为前缀。明确地,工具链的不同版本之间不保证兼容性,强烈建议普通用户在实验性扩展获得批准之前 *不要* 使用它们。
实验性支持的主要目标是通过提供实现的实际证明来协助批准过程,并简化验证针对大型代码库提出的扩展价值的工作。实验性扩展预计要么过渡到批准状态,要么最终被删除。关于是否接受实验性扩展的决定目前完全是根据具体情况而定的;如果您想提出一个,强烈建议参加每两周一次的 RISC-V 同步电话会议。
experimental-zalasrLLVM 实现了 0.0.5 草案规范。
experimental-zicfilp,experimental-zicfissLLVM 实现了 1.0 发布规范。
experimental-zvbc32e,experimental-zvkgsLLVM 实现了 0.7 发布规范。
experimental-sdext,experimental-sdtrigLLVM 实现了 1.0-rc4 规范。
experimental-smctr,experimental-ssctrLLVM 实现了 1.0-rc3 规范。
experimental-svukteLLVM 实现了 0.3 草案规范。
要从 clang 使用实验性扩展,您必须将 -menable-experimental-extensions 添加到命令行,并指定您正在使用的实验性扩展的确切版本。要将实验性扩展与 LLVM 的内部开发人员工具(例如 llc、llvm-objdump、llvm-mc)一起使用,您必须以 experimental- 为扩展名称添加前缀。请注意,您无需使用内部工具指定版本,并且不应在 clang 中包含 experimental- 前缀。
供应商扩展¶
供应商扩展是由 RISC-V International 未标准化的扩展,而是由硬件供应商定义的。术语供应商扩展大致与 RISC-V 非特权 ISA 规范第 I 卷第 1.3 节中 非标准 扩展的定义相对应。特别是,我们期望最终接受 自定义 扩展和 不符合标准 的扩展。
是否包含供应商扩展将根据具体情况考虑。所有提案都应提交给每两周一次的 RISC-V 同步电话会议进行讨论。有关可能考虑的因素的一般概念,请参阅 Clang 文档。
我们的目的是遵循 riscv-non-isa/riscv-toolchain-conventions 中描述的命名约定。对此命名的例外情况需要有充分的理由。
当前支持的供应商扩展是
XTHeadBaLLVM 实现了阿里巴巴平头哥半导体 中指定的 THeadBa(地址生成)供应商定义的指令。指令以 th. 为前缀,如规范中所述。
XTHeadBbLLVM 实现了阿里巴巴平头哥半导体 中指定的 THeadBb(基本位操作)供应商定义的指令。指令以 th. 为前缀,如规范中所述。
XTHeadBsLLVM 实现了阿里巴巴平头哥半导体 中指定的 THeadBs(单比特操作)供应商定义的指令。指令以 th. 为前缀,如规范中所述。
XTHeadCondMovLLVM 实现了阿里巴巴平头哥半导体 中指定的 THeadCondMov(条件移动)供应商定义的指令。指令以 th. 为前缀,如规范中所述。
XTHeadCmoLLVM 实现了阿里巴巴平头哥半导体 中指定的 THeadCmo(缓存管理操作)供应商定义的指令。指令以 th. 为前缀,如规范中所述。
XTHeadFMemIdxLLVM 实现了阿里巴巴平头哥半导体 中指定的 THeadFMemIdx(浮点索引内存操作)供应商定义的指令。指令以 th. 为前缀,如规范中所述。
XTheadMacLLVM 实现了阿里巴巴平头哥半导体 中指定的 XTheadMac(乘法累加指令)供应商定义的指令。指令以 th. 为前缀,如规范中所述。
XTHeadMemIdxLLVM 实现了阿里巴巴平头哥半导体 中指定的 THeadMemIdx(索引内存操作)供应商定义的指令。指令以 th. 为前缀,如规范中所述。
XTHeadMemPairLLVM 实现了阿里巴巴平头哥半导体 中指定的 THeadMemPair(双 GPR 内存操作)供应商定义的指令。指令以 th. 为前缀,如规范中所述。
XTHeadSyncLLVM 实现了阿里巴巴平头哥半导体 中指定的 THeadSync(多核同步指令)供应商定义的指令。指令以 th. 为前缀,如规范中所述。
XTHeadVdotLLVM 实现了阿里巴巴平头哥半导体 发布的 THeadV 系列自定义指令规范的 1.0.0 版本。所有指令都以 th. 为前缀,如规范和上面链接的 riscv-toolchain-convention 文档中所述。
XVentanaCondOpsLLVM 实现了 Ventana Micro Systems 发布的 VTx 系列自定义指令规范的 1.0.0 版本。所有指令都以 vt. 为前缀,如规范和上面链接的 riscv-toolchain-convention 文档中所述。这些指令目前仅适用于 riscv64。
XSfvcpLLVM 实现了 SiFive 发布的 SiFive 向量协处理器接口 (VCIX) 软件规范的 1.1.0 版本。所有指令都以 sf.vc. 为前缀,如规范和上面链接的 riscv-toolchain-convention 文档中所述。
XSfvqmaccdod,XSfvqmaccqoqLLVM 实现了 SiFive 发布的 SiFive Int8 矩阵乘法扩展规范的 1.1.0 版本。所有指令都以 sf. 为前缀,如上面链接的规范中所述。
XsfvfnrclipxfqfLLVM 实现了 SiFive 发布的 FP32 到 int8 范围剪裁指令扩展规范的 1.0.0 版本。所有指令都以 sf. 为前缀,如上面链接的规范中所述。
XsfvfwmaccqqqLLVM 实现了 SiFive 发布的矩阵乘法累加指令扩展规范的 1.0.0 版本。所有指令都以 sf. 为前缀,如上面链接的规范中所述。
XCVbitmanipLLVM 实现了 OpenHW Group 发布的 CORE-V 位操作自定义指令规范的 1.0.0 版本。所有指令都以 cv. 为前缀,如规范中所述。
XCVelwLLVM 实现了 OpenHW Group 发布的 CORE-V 事件加载自定义指令规范的 1.0.0 版本。所有指令都以 cv. 为前缀,如规范中所述。这些指令目前仅适用于 riscv32。
XCVmacLLVM 实现了 OpenHW Group 发布的 CORE-V 乘法累加 (MAC) 自定义指令规范的 1.0.0 版本。所有指令都以 cv.mac 为前缀,如规范中所述。这些指令目前仅适用于 riscv32。
XCVmemLLVM 实现了 OpenHW Group 发布的 CORE-V 后增量加载和存储自定义指令规范的 1.0.0 版本。所有指令都以 cv. 为前缀,如规范中所述。这些指令目前仅适用于 riscv32。
XCValuLLVM 实现了 Core-V 发布的 Core-V ALU 自定义指令规范的 1.0.0 版本。所有指令都以 cv. 为前缀,如规范中所述。这些指令目前仅适用于 riscv32。
XCVsimdLLVM 实现了 OpenHW Group 发布的 CORE-V SIMD 自定义指令规范的 1.0.0 版本。所有指令都以 cv. 为前缀,如规范中所述。
XCVbiLLVM 实现了 OpenHW Group 发布的 CORE-V 立即分支自定义指令规范的 1.0.0 版本。所有指令都以 cv. 为前缀,如规范中所述。这些指令目前仅适用于 riscv32。
XSiFivecdiscarddloneLLVM 实现了 SiFive 中指定的 SiFive sf.cdiscard.d.l1 指令。
XSiFivecflushdloneLLVM 实现了 SiFive 中指定的 SiFive sf.cflush.d.l1 指令。
XSfceaseLLVM 实现了 SiFive 中指定的 SiFive sf.cease 指令。
XwchcLLVM 实现了 WCH / 南京沁恒微电子在某些青稞内核中提供的自定义压缩操作码。供应商将这些操作码称为 “XW”。
experimental-XqccmpLLVM 实现了 Qualcomm 发布的 16 位 Push/Pop 指令和双重移动扩展规范的 0.1 版本。所有指令都以 qc. 为前缀,如规范中所述。
experimental-XqciaLLVM 实现了 Qualcomm 发布的 Qualcomm uC 算术扩展规范的 0.4 版本。所有指令都以 qc. 为前缀,如规范中所述。这些指令仅适用于 riscv32。
experimental-XqciacLLVM 实现了 Qualcomm 发布的 Qualcomm uC 加载-存储地址计算扩展规范的 0.3 版本。所有指令都以 qc. 为前缀,如规范中所述。这些指令仅适用于 riscv32。
experimental-XqcibmLLVM 实现了 Qualcomm 发布的 Qualcomm uC 位操作扩展规范的 0.4 版本。所有指令都以 qc. 为前缀,如规范中所述。这些指令仅适用于 riscv32。
experimental-XqcicliLLVM 实现了 Qualcomm 发布的 Qualcomm uC 条件加载立即数扩展规范的 0.2 版本。所有指令都以 qc. 为前缀,如规范中所述。这些指令仅适用于 riscv32。
experimental-XqcicmLLVM 实现了 Qualcomm 发布的 Qualcomm uC 条件移动扩展规范的 0.2 版本。所有指令都以 qc. 为前缀,如规范中所述。这些指令仅适用于 riscv32。
experimental-XqcicsLLVM 实现了 Qualcomm 发布的 Qualcomm uC 条件选择扩展规范的 0.2 版本。所有指令都以 qc. 为前缀,如规范中所述。这些指令仅适用于 riscv32。
experimental-XqcicsrLLVM 实现了 Qualcomm 发布的 Qualcomm uC CSR 扩展规范的 0.2 版本。所有指令都以 qc. 为前缀,如规范中所述。这些指令仅适用于 riscv32。
experimental-XqciintLLVM 实现了 Qualcomm 发布的 Qualcomm uC 中断扩展规范的 0.2 版本。所有指令都以 qc. 为前缀,如规范中所述。这些指令仅适用于 riscv32。
experimental-XqciliaLLVM 实现了 Qualcomm 发布的 Qualcomm uC 大型立即数算术扩展规范的 0.2 版本。所有指令都以 qc. 为前缀,如规范中所述。这些指令仅适用于 riscv32。
experimental-XqciloLLVM 实现了 Qualcomm 发布的 Qualcomm uC 大型偏移加载存储扩展规范的 0.2 版本。所有指令都以 qc. 为前缀,如规范中所述。这些指令仅适用于 riscv32。
experimental-XqcilsmLLVM 实现了 Qualcomm 发布的 Qualcomm uC 加载存储多重扩展规范的 0.2 版本。所有指令都以 qc. 为前缀,如规范中所述。这些指令仅适用于 riscv32。
experimental-XqcislsLLVM 实现了 Qualcomm 发布的 Qualcomm uC 缩放加载存储扩展规范的 0.2 版本。所有指令都以 qc. 为前缀,如规范中所述。这些指令仅适用于 riscv32。
XmipscmoveLLVM 实现了 MIPS p8700 处理器 <https://mips.com/products/hardware/p8700/> 的条件移动。
XmipslspLLVM 实现了 MIPS p8700 处理器 <https://mips.com/products/hardware/p8700/> 的加载/存储对指令。
experimental-XRivosVisniLLVM 实现了 Rivos 向量整数小型新指令扩展规范的 0.1 版本。
experimental-XRivosVizipLLVM 实现了 Rivos 向量寄存器压缩扩展规范的 0.1 版本。
实验性 C 内联函数¶
在某些情况下,扩展本身是非实验性的,但该扩展的 C 内联函数仍然是实验性的。要从 clang 中使用此类扩展的 C 内联函数,您必须在命令行中添加 -menable-experimental-extensions。 这目前适用于以下扩展:
没有扩展具有实验性内联函数。
长(>32 位)指令支持¶
RISC-V 是一种可变长度 ISA,但标准目前仅定义了 16 位和 32 位指令。 该规范描述了更长的指令编码,但这些编码尚未批准。
LLVM 反汇编器 llvm-objdump 确实使用了规范中描述的更长指令编码来猜测指令长度(最多 176 位),并将相应地对编码字节的反汇编视图进行分组。
用于 RISC-V 的 LLVM 集成汇编器支持两种不同的 .insn 指令,用于汇编 LLVM 尚不支持的指令
.insn type, args*接受已知的指令类型和字段列表。 如果您的指令符合现有的指令类型,则强烈建议您使用此指令变体。.insn [ length , ] encoding接受(可选的)显式长度(以字节为单位)和指令的原始编码。 当给定显式长度时,此变体可以编码长达 64 位的指令。 指令的编码部分必须给出指令的所有位,用户不会填充任何位。 当不使用可选长度时,此指令变体将使用原始编码的 LSB 来确定指令是 16 位还是 32 位长。 LLVM 不会推断指令可能超过 32 位 - 在这种情况下,用户必须显式给出长度。
强烈建议使用 .insn 指令来汇编不支持的指令,而不是 .word 或 .hword,因为它将生成正确的映射符号,将字标记为指令而不是数据。
全局指针 (GP) 放松和小型数据限制¶
一些 RISC-V psABI 变体保留了 gp (x3) 用作“全局指针”,以提高生成数据地址的效率。
要使用此功能,您需要执行以下所有操作
使用
medlow(也称为small)代码模型;不要将
gp寄存器用于任何其他用途(某些平台将其用于影子堆栈,而另一些平台将其用作临时寄存器 – 如Tag_RISCV_x3_reg_usage构建属性所示);使用 Clang 的
-mrelax选项编译您的对象,以在可重定位对象上启用放松注释(这是默认设置,但-mno-relax禁用这些放松注释);为位置相关的静态可执行文件编译(不是共享库,并且
-fno-PIC/-fno-pic/-fno-pie);以及使用 LLD 的
--relax-gp选项。
LLD 将放松(重写)任何代码序列,这些代码序列具体化了 __global_pointer$ 2048 字节范围内的地址(如果使用且尚不存在,则将定义该地址),而是使用 gp 和正确的(有符号)12 位立即数生成地址。 与具体化完整的 32 位地址值相比,这通常至少节省一条指令。
一个进程中只能有一个 gp 值(因为当调用共享库中的函数时,gp 不会更改),因此该符号仅被定义,并且此放松仅针对可执行文件执行,而不针对共享库执行。 链接器期望可执行文件的启动代码在运行任何用户代码之前,将 __global_pointer$(来自可执行文件)的值放入 gp 中。
可以说,此寻址模式最有效的用途是用于较小的全局变量,因为较大的全局变量在被访问时可能需要更多的加载或存储,因此可以分摊具体化高位的成本。
因此,编译器可以将较小的全局变量放入名称以 .sdata 或 .sbss 开头的 section 中(与名称以 .data 和 .bss 开头的 section 匹配)。 LLD 知道将 global_pointer$ 符号定义在这些 section 附近,并将这些 section 布局在与 .data section 相邻的位置。
Clang 的 -msmall-data-limit= 选项控制全局变量被视为小的阈值大小(以字节为单位)。 -msmall-data-limit=0 禁用以 .sdata 和 .sbss 开头的 section 的使用。 -msmall-data-limit= 选项不会移动具有显式数据 section 的全局变量,如果您使用 -fdata-sections,则会将全局变量保留在单独的 section 中。
小数据限制阈值也用于将小的常量分隔到名称以 .srodata 开头的 section 中。 LLD 不会将这些 section 与 .sdata 和 .sbss section 放在一起,因为 .srodata section 是只读的,而其他两个是可写的。 相反,.srodata section 放置在与 .rodata 相邻的位置。
数据表明,这些选项可以在一系列基准测试中产生显着改进。
