替换编译器

1. 替换范围

wfuzz-cc编译器如同其他编译器一样,可以直接链接二进制的目标文件或者动态库文件。 这些二进制文件只要是ABI兼容的,就可以使用,并不需要将全部的编译单元都使用wfuzz-cc编译。 但未使用wfuzz-cc编译的代码,不会有插桩。 在实际测试时,不会收集这部分代码的运行时信息,因此,生成器对它们也不会有任何针对性的优化。

一般来说,我们自己需要测的代码,需要使用wfuzz-cc编译器来编译。 而第三方库,不是我们系统的一部分,则可以使用其他编译器,或者直接使用二进制发布的版本。 但这个规则并不是绝对的,可以根据需要调整。 如果第三方库很重要,是我们系统核心功能的提供者,而我们的代码只做了浅层包装, 那就应该针对它们也使用替换的编译器。 另一方面,如果我们系统很大,有些通用的基础功能,并不是测试关注的重点, 那也可以使用默认编译器编译这部分,可以降低编译期和运行期的开销,增加测试效率。

2. 常见构建系统的适配

如果要集成模糊测试,第一个步骤是先替换编译器,确认项目能够使用wfuzz-cc编译器编译出来。 这个步骤的难易程度取决于您的项目使用了哪个构建系统,以及构建配置的灵活性。

对于常见的构建系统,例如Automake、CMake、QMake等,一般都支持CC/CXX环境变量。 您可以通过环境变量直接指定编译器,例如:

export CC=wfuzz-cc CXX=wfuzz-c++
./configure
make

如果您使用了自定义的构建系统,就需要找到构建系统中实际定义编译器的地方,进行替换。

3. 编译程序

替换编译器后,由于我们需要针对目标程序进行插桩,编译时间和编译器内存占用都会有所增加。 一般来说,替换后的编译时间是替换前的1.5-2倍。

有些构建系统在替换编译器时,并不会重新编译,此时您需要清理构建临时文件后再重新编译, 保证所有文件都是最新的。

4. 验证二进制文件

有时候,构建系统可能并不展示实际的编译命令,而是显示一些简要的信息。 此时通过阅读这些简要信息,可能并不能判断程序实际用了什么编译器。

如果不确定编译器替换是否真的成功,可以使用以下的命令,验证最终的二进制文件确实是通过wfuzz-cc编译的:

objdump -t TARGET | grep __wfuzz

将这个命令的 TARGET 替换为编译出的二进制文件名称,可以是可执行程序,也可以是动态库。

这个命令会显示二进制文件的符号表,wfuzz-cc在编译时会自动加一些符号,这些符号均以 __wfuzz 为开始。 看到这些符号就可以确认编译器替换确实成功了。