假设有一个静态库二进制文件,由于某种原因,库里没带版本信息,但又想知道它是哪个版本的。那只能重新编译各个版本,然后将生成的文件与这个库进行二进制对比。本来是期望同一个版本的代码,多次编译出来的文件,应该是二进制完全一致的,但实际上,即使是同一个版本的代码,每次编译出来的结果或多或少都有一些差异。因此,只能选择差异最小的,认为这个库就是该版本。
从编译器的角度出发,相同的代码在相同的环境下编译,是要求产生完全一致的结果的。不能说这次编译,把代码段A放在代码段B之前,下次编译又把代码段A放在代码段B之后。同样的,不能说这次编译把某条语句优化成汇编指令A,下次编译又把该条语句优化成汇编指令B。
其实,相同版本代码在相同环境下编译出不同的结果,差异的往往是时间戳,build-id等信息。为了每次编译都得到相同的结果,可以比较一下每次编译结果的差异,看看差异具体是在哪些段,然后分别针对处理。
从目前的测试来看,动态库是比较好的,每次编译产生的结果基本都是一致的,差异的地方是因为代码里使用了 __TIME__等编译宏。静态库稍微复杂一些,有差异是因为ar引入了时间戳和uid,pid,解决办法是对ar使用-D选项(use zero for timestamps and uids/gids)。对内核驱动文件(ko)的处理相对来说麻烦一些。它产生差异是因为build-id的引入,每次编译.note.gnu.build-id段都会不同。本来把--build-id=none传给链接器(-Wl,--build-id=none)应该是可以解决这个问题的。但在交叉编译的环境下,这样指定好像是无效的,.note.gnu.build-id段还是照样产生。想来应该是这里的指定被内核里的相关配置覆盖了,没有生效。最终的解决办法是,修改内核顶层目录的Makefile,注释掉了下面两行:
KBUILD_LDFLAGS_MODULE += $(LDFLAGS_BUILD_ID)
LDFLAGS_vmlinux += $(LDFLAGS_BUILD_ID)