假設有一個靜態(tài)庫二進制文件,由于某種原因,庫里沒帶版本信息,但又想知道它是哪個版本的。那只能重新編譯各個版本,然后將生成的文件與這個庫進行二進制對比。本來是期望同一個版本的代碼,多次編譯出來的文件,應該是二進制完全一致的,但實際上,即使是同一個版本的代碼,每次編譯出來的結(jié)果或多或少都有一些差異。因此,只能選擇差異最小的,認為這個庫就是該版本。
從編譯器的角度出發(fā),相同的代碼在相同的環(huán)境下編譯,是要求產(chǎn)生完全一致的結(jié)果的。不能說這次編譯,把代碼段A放在代碼段B之前,下次編譯又把代碼段A放在代碼段B之后。同樣的,不能說這次編譯把某條語句優(yōu)化成匯編指令A,下次編譯又把該條語句優(yōu)化成匯編指令B。
其實,相同版本代碼在相同環(huán)境下編譯出不同的結(jié)果,差異的往往是時間戳,build-id等信息。為了每次編譯都得到相同的結(jié)果,可以比較一下每次編譯結(jié)果的差異,看看差異具體是在哪些段,然后分別針對處理。
從目前的測試來看,動態(tài)庫是比較好的,每次編譯產(chǎn)生的結(jié)果基本都是一致的,差異的地方是因為代碼里使用了 __TIME__等編譯宏。靜態(tài)庫稍微復雜一些,有差異是因為ar引入了時間戳和uid,pid,解決辦法是對ar使用-D選項(use zero for timestamps and uids/gids)。對內(nèi)核驅(qū)動文件(ko)的處理相對來說麻煩一些。它產(chǎn)生差異是因為build-id的引入,每次編譯.note.gnu.build-id段都會不同。本來把--build-id=none傳給鏈接器(-Wl,--build-id=none)應該是可以解決這個問題的。但在交叉編譯的環(huán)境下,這樣指定好像是無效的,.note.gnu.build-id段還是照樣產(chǎn)生。想來應該是這里的指定被內(nèi)核里的相關(guān)配置覆蓋了,沒有生效。最終的解決辦法是,修改內(nèi)核頂層目錄的Makefile,注釋掉了下面兩行:
KBUILD_LDFLAGS_MODULE += $(LDFLAGS_BUILD_ID)
LDFLAGS_vmlinux += $(LDFLAGS_BUILD_ID)