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 中.

