Page 89 - 《软件学报》2025年第7期
P. 89

3010                                                       软件学报  2025  年第  36  卷第  7  期


                 家族  (GCC  和  Clang) 之间的相关性并不明确. 因此, 后续      O2NMatcher 方法设计中会着重考虑以上的相关性, 以提
                 高     O2NMatcher 在多种类函数内联情况下的处理能力.

                 4   面向函数内联场景的二进制到源代码函数相似性检测方法

                    如图  5  所示, 面向函数内联场景的二进制到源代码函数相似性检测方法. O2NMatcher 的工作流程分为                       3  个部
                 分: 特征提取、内联函数调用预测及源代码函数集合生成.

                                    特征抽取              内联函数调用预测             源代码函数集合生成
                                FCG 构建               ECOCCJ48               根节点
                                                     模型训练                   选取
                  开源软件
                                函数调用                 ECOCCJ48              调用边               源代码函数集合
                                特征抽取                 模型预测                   扩展


                             源代码项目     源代码函数    函数调用     特征     ECOCCJ48 分类器  普通函数调用     内联函数调用
                                                 图 5 O2NMatcher 的工作流程

                    由于发生过内联的二进制函数是通过内联了某些函数调用而生成的, O2NMatcher 首先识别这些内联的函数
                 调用, 然后执行内联操作以生成源代码函数集合.

                 4.1   特征抽取

                    通常讲, 编译器一般通过衡量内联某个函数调用的成本和收益来决定是否进行内联. 因此, 本节选取了一些能
                 够影响内联成本和收益的特征. 所选特征列于表               2  中.

                                             表 2 内联函数调用预测预测所选特征

                         对象        部分                                特征
                                         语句总数, while语句数, switch语句数, case语句数, if语句数, for语句数, 返回语句数, 声
                                  函数体
                     调用函数与被调             明语句数, 表达式语句数
                         用函数      函数定义                    Inline关键字数量, Static关键字数量
                                  函数调用                         调用次数, 被调用次数
                                         路径长度, 是否位于for循环内, 是否位于while循环内, 是否位于switch语句内, 是否位
                                   位置
                        调用指令             于if条件内
                                   参数                        参数总数量, 常量参数数量

                    特征主要来自于两个部分: 调用函数与被调用函数, 以及调用指令.

                 4.1.1    调用函数与被调用函数
                    调用函数与被调用函数的属性会影响内联被调用函数的成本和收益. 成本主要来源于函数内联带来的二进制
                 文件的体积膨胀, 而收益主要来源于内联所减少的函数调用开销. 本节将从函数体、函数定义及函数调用这                                   3  个
                 部分出发, 介绍本文所选取的用于内联函数调用预测的特征.
                    在函数体中, O2NMatcher 提取了不同类型的指令数量作为特征. 例如, 语句总数表示所有语句的数量, 而
                 while 语句数表示   while 循环语句的数量. 这些指令的计数代表了函数的体积大小, 这表明了内联该函数的成本.

                 简单来说, 被调用函数越复杂, 内联该函数调用的成本就越高.
                    例如在图    2  中, 函数  dtls1_get_record  有接近  170  行代码, 而函数  dtls1_process_buffered_records 只有不到  30
                 行代码, 相比之下, 函数      dtls1_process_buffered_records 被内联的成本远远低于函数   dtls1_get_record, 因此在图  2
                 中, 函数  dtls1_process_buffered_records 被内联到了函数  dtls1_get_record  中.
   84   85   86   87   88   89   90   91   92   93   94