Page 27 - 《软件学报》2025年第12期
P. 27
5408 软件学报 2025 年第 36 卷第 12 期
如图 4 所示, 在静态链接模式下, swLLVM 编译器采用!ldmhigh/!ldmlow 重定位对 LDM 变量进行相对偏移寻
址, 以规避基于全局偏移表 (global offset table, GOT) 间接寻址的!literal 重定位所引入的额外访存开销 [22] . 其中,
!literal 重定位需要 ldl 和 stw 两次访存, 而!ldmhigh/!ldmlow 重定位仅需要 stw 一次访存.
# !literal example # !ldmhigh/!ldmlow example
ldi $t1, 1($zero) ldi $t1, 1($zero)
ldl $t0, a($gp) !literal ldih $t0, a($zero) !ldmhigh
stw $t1, 0($t0) stw $t1, a($t0) !ldmlow
图 4 !literal 与!ldmhigh/!ldmlow 重定位的汇编示例
若动态链接模式继续沿用该实现方案, 那么每个动态库的.ldm 段均从相同物理地址开始编址. 这种做法会引
发一个问题, 即不同动态库中的 LDM 变量可能产生地址冲突, 具体情形可参见图 5. 在该示例中, 由于 libB.so 中
的 Callee 函数可能会使用到 libA.so 中静态声明的 LDM 数组 a[64], LDM 变量地址冲突可能会导致程序运行结果
出现错误.
Virtual addr space Physical
… addr space
…
libA.so
.ldm
… …
a[64] #offset=0x20 0x20: …
… …
Map …
Address
… a 0x40: …
conflict
libB.so 0x60: … b
.ldm …
… 0x80: …
…
b[64] #offset=0x40
…
… …
图 5 动态链接模式下 LDM 变量地址冲突的示例
为了有效满足 Julia 等动态应用对片上存储空间的访问需求, 并尽可能避免额外的性能开销, 我们在 swLLVM
中设计并实现了一种针对动态链接模式的片上存储空间优化访问方法. 对于在动态库中静态声明的 LDM 变量,
swLLVM 编译器继续使用!ldmhigh/!ldmlow 重定位进行相对偏移寻址, 以确保片上存储空间的访问效率. 同时, 为
了让动态链接器能够准确识别和处理上述重定位, 我们在编译器和二进制工具链中新增了两种重定位类型
(R_SW_64_LDMHI 和 R_SW_64_LDMLO), 并且在构建动态库的重定位表时详细登记相关的重定位信息. 图 6 清
晰地展示了图 5 中的 libA.so 动态库在实施上述访存优化后的重定位表内容.
$ readelf -r libA.so
Relocation section '.rela.dyn' at offset 0x10ee8 contains 2 entries:
Offset Info Type Sym. Value Sym. Name + Addend
0000000014a8 00330000002a R_SW_64_LDMHI 0000000010000000 a + 0
0000000014b0 00330000002b R_SW_64_LDMLO 0000000010000000 a + 0
…
图 6 LDM 访存优化后的动态库重定位表信息
在动态库的加载过程中, 动态链接器会执行!ldmhigh/!ldmlow 重定位的修正操作, 具体流程参见算法 1. 首先,
动态链接器利用操作系统提供的 mmap() 接口为当前动态库的.ldm 段分配物理地址, 记为 ldm_pstart. 然后, 动态
链接器遍历当前动态库的重定位表 relaTable, 特别关注 R_SW_64_LDMHI 和 R_SW_64_LDMLO 两类重定位信
息. 对于上述重定位对应的 LDM 变量, 根据其所在.ldm 段的起始物理地址 ldm_pstart 以及该变量在.ldm 段内的相
对偏移量 offset, 动态链接器能够精确计算出该变量的实际物理地址, 记为 ldm_paddr. 最后, 针对不同的重定位类
型, 动态链接器根据 ldm_paddr 计算和修正相应汇编指令的偏移字段.

