Page 128 - 《软件学报》2024年第6期
P. 128

2704                                                       软件学报  2024  年第  35  卷第  6  期


                 映射表来加速间接分支跳转, 为了避免映射表过于庞大, 该方法只处理函数入口点、返回地址、函数指针地址
                 以及虚函数这     4  种间接跳转. LAT   [17] 为每一个包含间接分支的基本块增加一个私有缓存以保存分支目标地址,
                 提高查找效率. Huang    等人  [153] 在每个基本块的头部插入比较跳转指令, 将间接跳转目标地址预测转移到基本块
                 内部完成.
                    为了降低间接分支跳转产生的控制流切换开销, Pin               [32] 使用间接分支链将所有间接分支指令关联起来, 将间接
                 跳转转化为间接目标地址移动和预测目标地址的直接跳转. DynamoRIO                    [43] 通过查找哈希表的方法将间接跳转连
                 接起来. 相比于    DynamoRIO, Pin  采用的间接链接机制更加灵活和高效. 文献           [154] 在构建  Trace 时内联间接分支,
                 将间接跳转比较运算转移到          Trace 块内完成. Chen  等人  [155] 将所有包含间接跳转操作的基本块合并成一个超级块
                 并在超级块内完成分支跳转操作.
                    针对静态翻译无法确定间接分支跳转目标地址的难题, Kinder 等人                   [156] 提出基于数据流分析重构出近似完整
                 的程序控制流图, 获取程序的分支跳转目标地址. 王军等人                  [157] 提出在解析间接跳转指令时加入异常处理指令. 异
                 常探测方法用于确定目标跳转地址并回填, 执行多轮探测直至完成所有目标地址的回填. 类似地, Di Federico 等人                         [158]
                 提出在静态翻译时预收集程序全局数据的基础上, 引入表达式跟踪与数据流范围分析来确定基本块边界, 从而确
                         测试集执行时间, 发现目标代码执行时间占比达
                 定跳转目的地址. 这些研究在静态翻译阶段确定间接分支跳转目标地址的问题上取得了重要突破.

                 4.2.3    代码缓存优化
                    缓存已翻译代码可有效避免重复翻译, 代码缓存设计是当前二进制翻译系统的普遍做法                             [21,133,159,160] . 在二进制
                 翻译执行过程中, 当不确定后续执行代码块时, 优先从缓存中查找, 如果未命中再切换到翻译器开展翻译. 对于缓
                 存的查找也会带来额外的代码查找开销. Chen             等人  [133] 改进了解释执行的代码处理方式, 对解释执行的代码进行
                 缓存, 当程序再次执行时优先从缓存中查询, 提升了基于解释执行方法的翻译效率. 代码缓存方法降低了指令翻译
                 效率, 但是也会带来额外的代码查找开销. QEMU             采用“快速查找+慢速查找”的两级缓存查找方法, 优先基于快速
                 查找从热路径代码组成的缓存空间中查找, 如未命中再切换到慢速查找对所有缓存进行遍历, 效率较低. Yue 等人                               [21]
                 改进了   QEMU  在两级缓存查找时采用的缓存置换策略, 以页为单位对缓存代码进行划分和热度标记, 减少了缓存
                 替换颠簸. Pico  [15] 优化了  QEMU  中翻译块缓存和相关查找机制, 改进哈希函数并构建新的哈希表, 提升了缓存代
                 码的查找效率.
                    对于运行时间短或者包含大量冷代码的程序来说, 代码缓存摊销翻译成本的效果十分有限. 对于无明显热路
                 径代码的应用, 冷代码翻译与执行开销也是影响整个系统性能的关键                       [159] . Wang  等人  [159] 研究发现在  GUI 应用中,
                 90%  的翻译时间花费在冷代码处理上. 为了进一步提高冷代码翻译效率, Wang                    等人  [160] 提出持久性常驻缓存代码
                 的方法, 允许相同或不同的应用程序在执行时复用同一份缓存代码, 进一步减少了翻译过程带来的开销.
                    此外, 对于多线程应用翻译, 存在缓存资源访问竞争和数据同步开销问题. 针对此问题, Hong                         等人  [154] 提出私
                 有化每个执行线程的缓存表来避免数据访问竞争. 对于多线程中缓存同步策略的优化, COREMU                             [28] 采用延迟失效
                 策略解决多线程页失效的同步问题, 减少了多线程之间的数据同步开销.

                 4.3   代码生成优化
                    翻译开销优化和运行时优化有效降低了二进制翻译器带来的开销. 然而, 翻译后代码作为本地重复执行的目
                 标程序, 对其更深层次的优化可以进一步提升二进制翻译效率. 本文基于                       QEMU  完成  x86-to-SW64  的翻译, 统计
                 SPEC2006                                      95%  以上. 此外, Wang  等人  [160] 研究发现对于计算密集
                 型的应用程序, 二进制翻译过程大约有            90%  的时间开销花费在目标代码执行上, 由此可见生成高质量的目标代码
                 对提升翻译效率至关重要. 然而, 源平台和目标平台之间在寄存器约定、存储单元、指令集功能等方面存在较大
                 差异, 反映到目标代码上, 则存在访问内存频繁、代码膨胀率高、指令模拟低效等不足. 利用目标平台特性来改进
                 目标代码生成质量, 从而缓解体系结构差异带来的低效翻译问题.

                 4.3.1    寄存器优化
                    Ibrahim  等人  [161] 统计  Windows 7  操作系统中指令对寄存器的访问需求, 发现超过        75%  的指令执行需要访问
   123   124   125   126   127   128   129   130   131   132   133